[maven-release-plugin] copy for tag 1.0.0-M32

git-svn-id: https://svn.apache.org/repos/asf/directory/shared/tags/1.0.0-M32@1708627 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/trunk/LICENSE b/trunk/LICENSE
new file mode 100644
index 0000000..b6f663f
--- /dev/null
+++ b/trunk/LICENSE
@@ -0,0 +1,228 @@
+
+                                 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.
+
+==================================================================================================
+slf4j 1.7.10 license:
+--------------------------------------------------------------------------------------------------
+Copyright (c) 2004-2013 QOS.ch
+All rights reserved.
+
+Permission is hereby granted, free  of charge, to any person obtaining
+a  copy  of this  software  and  associated  documentation files  (the
+"Software"), to  deal in  the Software without  restriction, including
+without limitation  the rights to  use, copy, modify,  merge, publish,
+distribute,  sublicense, and/or sell  copies of  the Software,  and to
+permit persons to whom the Software  is furnished to do so, subject to
+the following conditions:
+
+The  above  copyright  notice  and  this permission  notice  shall  be
+included in all copies or substantial portions of the Software.
+
+THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/trunk/NOTICE b/trunk/NOTICE
new file mode 100644
index 0000000..cd94e3c
--- /dev/null
+++ b/trunk/NOTICE
@@ -0,0 +1,6 @@
+Apache Directory LDAP API
+Copyright 2003-2014 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/trunk/README.txt b/trunk/README.txt
new file mode 100755
index 0000000..13378f8
--- /dev/null
+++ b/trunk/README.txt
@@ -0,0 +1,23 @@
+This distribution includes cryptographic software.  The country in 
+   which you currently reside may have restrictions on the import, 
+   possession, use, and/or re-export to another country, of 
+   encryption software.  BEFORE using any encryption software, please 
+   check your country's laws, regulations and policies concerning the
+   import, possession, or use, and re-export of encryption software, to 
+   see if this is permitted.  See <http://www.wassenaar.org/> for more
+   information.
+
+   The U.S. Government Department of Commerce, Bureau of Industry and
+   Security (BIS), has classified this software as Export Commodity 
+   Control Number (ECCN) 5D002.C.1, which includes information security
+   software using or performing cryptographic functions with asymmetric
+   algorithms.  The form and manner of this Apache Software Foundation
+   distribution makes it eligible for export under the License Exception
+   ENC Technology Software Unrestricted (TSU) exception (see the BIS 
+   Export Administration Regulations, Section 740.13) for both object 
+   code and source code.
+
+   The following provides more details on the included cryptographic
+   software:
+
+   http://www.bouncycastle.org/
diff --git a/trunk/all/pom.xml b/trunk/all/pom.xml
new file mode 100644
index 0000000..8896e7e
--- /dev/null
+++ b/trunk/all/pom.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-all</artifactId>
+  <name>Apache Directory API All</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-ber</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-dsml-engine</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-dsml-parser</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-client-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-standalone</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-aci</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-sp</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-trigger</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-net-mina</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-schema-converter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-schema-data</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+              <artifactSet>
+                <includes>
+                  <include>${project.groupId}</include>
+                </includes>
+              </artifactSet>
+              <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
+              <createSourcesJar>true</createSourcesJar>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/all/src/main/appended-resources/META-INF/LICENSE b/trunk/all/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/all/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/all/src/main/appended-resources/META-INF/NOTICE b/trunk/all/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/all/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/asn1/api/pom.xml b/trunk/asn1/api/pom.xml
new file mode 100644
index 0000000..405bae4
--- /dev/null
+++ b/trunk/asn1/api/pom.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-asn1-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-asn1-api</artifactId>
+  <name>Apache Directory API ASN.1 API</name>
+  <packaging>bundle</packaging>
+
+  <description>ASN.1 API</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.asn1.api</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.asn1;version=${project.version};-noimport:=true,
+              org.apache.directory.api.asn1.util;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.i18n;version=${project.version}
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Asn1Object.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Asn1Object.java
new file mode 100644
index 0000000..39e2205
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Asn1Object.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1;
+
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * An abstract class which implements basic TLV operations.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Asn1Object
+{
+    /**
+     * Compute the object length, which is the sum of all inner length.
+     * 
+     * @return The object's computed length
+     */
+    int computeLength();
+
+
+    /**
+     * Encode the object to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The encoded PDU.
+     * @throws EncoderException if the buffer can't be encoded
+     */
+    ByteBuffer encode( ByteBuffer buffer ) throws EncoderException;
+}
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Decoder.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Decoder.java
new file mode 100755
index 0000000..fafdd48
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Decoder.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.asn1;
+
+
+/**
+ * <p>
+ * Provides the highest level of abstraction for Decoders. This is the sister
+ * interface of {@link Encoder}. All Decoders implement this common generic
+ * interface.
+ * </p>
+ * <p>
+ * Allows a user to pass a generic Object to any Decoder implementation in the
+ * codec package.
+ * </p>
+ * <p>
+ * One of the two interfaces at the center of the codec package.
+ * </p>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Decoder
+{
+
+    /**
+     * Decodes an "encoded" Object and returns a "decoded" Object. Note that the
+     * implementation of this interface will try to cast the Object parameter to
+     * the specific type expected by a particular Decoder implementation. If a
+     * {@link java.lang.ClassCastException} occurs this decode method will throw
+     * a DecoderException.
+     * 
+     * @param object an object to "decode"
+     * @return a 'decoded" object
+     * @throws DecoderException a decoder exception can be thrown for any number of reasons.
+     * Some good candidates are that the parameter passed to this method is null, a param 
+     * cannot be cast to the appropriate type for a specific encoder.
+     */
+    Object decode( Object object ) throws DecoderException;
+}
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/DecoderException.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/DecoderException.java
new file mode 100755
index 0000000..da4c932
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/DecoderException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.asn1;
+
+
+/**
+ * Thrown when a Decoder has encountered a failure condition during a decode.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DecoderException extends Exception
+{
+    /** Declares the Serial Version Uid */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a DecoderException
+     * 
+     * @param message A message with meaning to a human
+     */
+    public DecoderException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a DecoderException
+     * 
+     * @param message A message with meaning to a human
+     * @param cause The Exception which caused the error
+     */
+    public DecoderException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Encoder.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Encoder.java
new file mode 100644
index 0000000..9ebe90f
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/Encoder.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.asn1;
+
+
+/**
+ * <p>
+ * Provides the highest level of abstraction for Encoders. This is the sister
+ * interface of {@link Decoder}. Every
+ * implementation of Encoder provides this common generic interface whic allows
+ * a user to pass a generic Object to any Encoder implementation in the codec
+ * package.
+ * </p>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Encoder
+{
+    /**
+     * Encodes an "Object" and returns the encoded content as an Object. The
+     * Objects here may just be <code>byte[]</code> or <code>String</code>s
+     * depending on the implementation used.
+     * 
+     * @param object An object to encode
+     * @return An "encoded" Object
+     * @throws EncoderException an encoder exception is thrown if the encoder experiences a
+     * failure condition during the encoding process.
+     */
+    Object encode( Object object ) throws EncoderException;
+}
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/EncoderException.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/EncoderException.java
new file mode 100755
index 0000000..d8bcc39
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/EncoderException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.asn1;
+
+
+/**
+ * Thrown when there is a failure condition during the encoding process. This
+ * exception is thrown when an Encoder encounters a encoding specific exception
+ * such as invalid data, inability to calculate a checksum, characters outside
+ * of the expected range.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EncoderException extends Exception
+{
+    /** Declares the Serial Version Uid */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of this exception with an useful message.
+     * 
+     * @param message a useful message relating to the encoder specific error.
+     */
+    public EncoderException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a new instance of this exception with an useful message.
+     * 
+     * @param message a useful message relating to the encoder specific error.
+     * @param cause The parent exception
+     */
+    public EncoderException( String message, Exception cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/package.html b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/package.html
new file mode 100644
index 0000000..f153128
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/package.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ *   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.
+-->
+</head>
+<body bgcolor="white">
+
+Provides the fundamental stateful codec interfaces.
+
+
+<h2>Package Specification</h2>
+
+<ul>
+  <li><a href="codec/stateful">##### REFER TO ANY SPECIFICATIONS HERE #####</a></li>
+</ul>
+
+<h2>Related Documentation</h2>
+
+For overviews, tutorials, examples, guides, and tool documentation, please see:
+<ul>
+  <li><a href="http://directory.apache.org/subprojects/asn1/index.html">ASN.1 Project</a></li>
+  <li><a href="http://directory.apache.org/subprojects/asn1/codec-stateful/index.html">Stateful Codecs</a></li>
+  <li><a href="http://directory.apache.org/subprojects/asn1/ber-codec/index.html">ASN.1 BER Codecs</a></li>
+</ul>
+
+<!-- Put @see and @since tags down here. -->
+
+</body>
+</html>
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/Asn1StringUtils.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/Asn1StringUtils.java
new file mode 100644
index 0000000..6757a79
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/Asn1StringUtils.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.util;
+
+
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * Little helper class for the asn1 package.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Asn1StringUtils
+{
+    /** Hex chars */
+    private static final byte[] HEX_CHAR = new byte[]
+        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+    /**
+     * The empty byte[]
+     */
+    public static final byte[] EMPTY_BYTES = new byte[]
+        {};
+
+
+    private Asn1StringUtils()
+    {
+    }
+
+    /**
+     * Helper function that dump a byte in hex form
+     *
+     * @param octet The byte to dump
+     * @return A string representation of the byte
+     */
+    public static String dumpByte( byte octet )
+    {
+        try
+        {
+            return new String( new byte[]
+                { '0', 'x', HEX_CHAR[( octet & 0x00F0 ) >> 4], HEX_CHAR[octet & 0x000F] }, "UTF-8" );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            // Can't happen
+            return "";
+        }
+    }
+
+
+    /**
+     * Helper function that dump an array of bytes in hex form
+     *
+     * @param buffer The bytes array to dump
+     * @return A string representation of the array of bytes
+     */
+    public static String dumpBytes( byte[] buffer )
+    {
+        if ( buffer == null )
+        {
+            return "";
+        }
+
+        StringBuffer sb = new StringBuffer();
+
+        for ( byte b : buffer )
+        {
+            sb.append( "0x" ).append( ( char ) ( HEX_CHAR[( b & 0x00F0 ) >> 4] ) ).append(
+                ( char ) ( HEX_CHAR[b & 0x000F] ) ).append( " " );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Return UTF-8 encoded byte[] representation of a String
+     *
+     * @param string The string to be transformed to a byte array
+     * @return The transformed byte array
+     */
+    public static byte[] getBytesUtf8( String string )
+    {
+        if ( string == null )
+        {
+            return new byte[0];
+        }
+
+        try
+        {
+            return string.getBytes( "UTF-8" );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            return EMPTY_BYTES;
+        }
+    }
+
+
+    /**
+     * Transform a string to an array of ASCII bytes, where the byte array will contain
+     * only values in [0, 127].
+     *
+     * @param string The byte array to transform
+     * @return The resulting string
+     */
+    public static byte[] asciiStringToByte( String string )
+    {
+        if ( ( string == null ) || ( string.length() == 0 ) )
+        {
+            return EMPTY_BYTES;
+        }
+
+        byte[] result = new byte[string.length()];
+
+        for ( int i = 0; i < result.length; i++ )
+        {
+            result[i] = ( byte ) string.charAt( i );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/BitString.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/BitString.java
new file mode 100644
index 0000000..0143b90
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/BitString.java
@@ -0,0 +1,269 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.util;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Implement the Bit String primitive type. A BitString is internally stored as
+ * an array of byte.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BitString
+{
+    /** A null MutableString */
+    public static final BitString EMPTY_STRING = new BitString( 1 );
+
+    /** The number of unused bits in the last byte */
+    private int nbUnusedBits;
+
+    /** The string is stored in a byte array */
+    private byte[] bytes;
+
+    /** Actual length of the byte array */
+    private int nbBytes;
+
+    /** Actual length of the bit string */
+    private int nbBits;
+
+
+    /**
+     * Creates a BitString with a specific length (length is the number of
+     * bits).
+     *
+     * @param length The BitString length (it's a number of bits)
+     */
+    public BitString( int length )
+    {
+        if ( length <= 0 )
+        {
+            // This is not allowed
+            throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00029_NULL_OR_NEG_LENGTH_NOT_ALLOWED ) );
+        }
+
+        nbBits = length;
+
+        // As we store values in bytes, we must divide the length by 8
+        nbBytes = ( length / 8 );
+
+        if ( ( length % 8 ) != 0 )
+        {
+            nbBytes += 1;
+        }
+
+        nbUnusedBits = ( 8 - ( length % 8 ) ) & 0x07;
+
+        bytes = new byte[nbBytes];
+    }
+
+
+    /**
+     * Creates a BitString from a byte[]. As the first byte is the number of unused bits
+     * in the last byte, we have to ignore it.
+     *
+     * @param bytes The value to store. The first byte contains the number of
+     * unused bits
+     */
+    public BitString( byte[] bytes )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) )
+        {
+            nbBits = -1;
+            return;
+        }
+
+        setData( bytes );
+    }
+
+
+    /**
+     * Set a new BitString in the BitString. It will replace the old BitString,
+     * and reset the current length with the new one.
+     *
+     * @param data The string to store
+     */
+    public void setData( byte[] data )
+    {
+        if ( ( data == null ) || ( data.length == 0 ) )
+        {
+            nbBits = -1;
+            return;
+        }
+
+        // The first byte contains the number of unused bits
+        nbUnusedBits = data[0] & 0x07;
+        nbBytes = data.length - 1;
+        nbBits = ( nbBytes * 8 ) - nbUnusedBits;
+        this.bytes = new byte[nbBytes];
+
+        // We have to transfer the data
+        for ( int i = 0; i < nbBytes; i++ )
+        {
+            this.bytes[i] = data[i + 1];
+        }
+    }
+
+
+    /**
+     * Get the representation of a BitString. A first byte containing the number
+     * of unused bits is added
+     *
+     * @return A byte array which represent the BitString
+     */
+    public byte[] getData()
+    {
+        byte[] copy = new byte[bytes.length + 1];
+
+        System.arraycopy( bytes, 0, copy, 1, bytes.length );
+        copy[0] = ( byte ) nbUnusedBits;
+
+        return copy;
+    }
+
+
+    /**
+     * Get the number of unused bits
+     *
+     * @return A byte which represent the number of unused bits
+     */
+    public byte getUnusedBits()
+    {
+        return ( byte ) nbUnusedBits;
+    }
+
+
+    /**
+     * Set a bit at a specified position.
+     * The bits are stored from left to right.
+     * For instance, if we have 10 bits, then they are coded as b0 b1 b2 b3 b4 b5 b6 b7 - b8 b9 x x x x x x
+     *
+     * @param pos The bit to set
+     */
+    public void setBit( int pos )
+    {
+        if ( ( pos < 0 ) || ( pos > nbBits ) )
+        {
+            throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00030_BIT_NUMBER_OUT_OF_BOUND ) );
+        }
+
+        int posBytes = pos >>> 3;
+        int bitNumber = 7 - pos % 8;
+        byte mask = ( byte ) ( 1 << bitNumber );
+
+        bytes[posBytes] |= mask;
+    }
+
+
+    /**
+     * Clear a bit at a specified position.
+     * The bits are stored from left to right.
+     * For instance, if we have 10 bits, then they are coded
+     * as b0 b1 b2 b3 b4 b5 b6 b7 - b8 b9 x x x x x x
+     *
+     * @param pos The bit to clear
+     */
+    public void clearBit( int pos )
+    {
+        if ( ( pos < 0 ) || ( pos > nbBits ) )
+        {
+            throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00030_BIT_NUMBER_OUT_OF_BOUND ) );
+        }
+
+        int posBytes = pos >>> 3;
+        int bitNumber = 7 - pos % 8;
+        byte mask = ( byte ) ( 1 << bitNumber );
+
+        bytes[posBytes] &= ~mask;
+    }
+
+
+    /**
+     * Get the bit stored into the BitString at a specific position.
+     * The bits are stored from left to right, the LSB on the left and the
+     * MSB on the right.<br/>
+     * For instance, if we have 10 bits, then they are coded as
+     * b0 b1 b2 b3 - b4 b5 b6 b7 - b8 b9 x x - x x x x
+     * <pre>
+     * With '1001 000x', where x is an unused bit,
+     *       ^ ^    ^
+     *       | |    |
+     *       | |    |
+     *       | |    +----- getBit(6) = 0
+     *       | +---------- getBit(2) = 0
+     *       +------------ getBit(0) = 1
+     * </pre>
+     * @param pos The position of the requested bit.
+     *
+     * @return <code>true</code> if the bit is set, <code>false</code> otherwise
+     */
+    public boolean getBit( int pos )
+    {
+        if ( pos > nbBits )
+        {
+            throw new IndexOutOfBoundsException( I18n.err( I18n.ERR_00031_CANNOT_FIND_BIT, pos, nbBits ) );
+        }
+
+        int posBytes = pos >>> 3;
+        int bitNumber = 7 - pos % 8;
+        byte mask = ( byte ) ( 1 << bitNumber );
+
+        int res = bytes[posBytes] & mask;
+
+        return res != 0;
+    }
+
+
+    /**
+     * @return The number of bits stored in this BitString
+     */
+    public int size()
+    {
+        return nbBits;
+    }
+
+
+    /**
+     * Return a native String representation of the BitString.
+     *
+     * @return A String representing the BitString
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        for ( int i = 0; i < nbBits; i++ )
+        {
+            if ( getBit( i ) )
+            {
+                sb.append( '1' );
+            }
+            else
+            {
+                sb.append( '0' );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/Oid.java b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/Oid.java
new file mode 100644
index 0000000..f8b7fbd
--- /dev/null
+++ b/trunk/asn1/api/src/main/java/org/apache/directory/api/asn1/util/Oid.java
@@ -0,0 +1,400 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1.util;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * An immutable representation of an object identifier that provides conversion 
+ * between their <code>String</code>, and encoded <code>byte[]</code> 
+ * representations.
+ * 
+ * <p> The encoding of OID values is performed according to 
+ * <a href='http://www.itu.int/rec/T-REC-X.690/en'>itu X.690</a> section 8.19.
+ * Specifically:</p>
+ * 
+ * <p><b>8.19.2</b> The contents octets shall be an (ordered) list of encodings
+ * of subidentifiers (see 8.19.3 and 8.19.4) concatenated together. Each 
+ * subidentifier is represented as a series of (one or more) octets. Bit 8 of 
+ * each octet indicates whether it is the last in the series: bit 8 of the last 
+ * octet is zero; bit 8 of each preceding octet is one. Bits 7 to 1 of the 
+ * octets in the series collectively encode the subidentifier. Conceptually, 
+ * these groups of bits are concatenated to form an unsigned binary number whose 
+ * most significant bit is bit 7 of the first octet and whose least significant 
+ * bit is bit 1 of the last octet. The subidentifier shall be encoded in the 
+ * fewest possible octets, that is, the leading octet of the subidentifier shall 
+ * not have the value 0x80. </p>
+ * 
+ * <p><b>8.19.3</b> The number of subidentifiers (N) shall be one less than the 
+ * number of object identifier components in the object identifier value being 
+ * encoded.</p>
+ * 
+ * <p><b>8.19.4</b> The numerical value of the first subidentifier is derived 
+ * from the values of the first two object identifier components in the object 
+ * identifier value being encoded, using the formula:
+ * <br /><code>(X*40) + Y</code><br /> 
+ * where X is the value of the first object identifier component and Y is the 
+ * value of the second object identifier component. <i>NOTE – This packing of 
+ * the first two object identifier components recognizes that only three values 
+ * are allocated from the root node, and at most 39 subsequent values from nodes 
+ * reached by X = 0 and X = 1.</i></p>
+ * 
+ * <p>For example, the OID "2.123456.7" would be turned into a list of 2 values:
+ * <code>[((2*80)+123456), 7]</code>.  The first of which, 
+ * <code>123536</code>, would be encoded as the bytes 
+ * <code>[0x87, 0xC5, 0x10]</code>, the second would be <code>[0x07]</code>,
+ * giving the final encoding <code>[0x87, 0xC5, 0x10, 0x07]</code>.</p>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Oid
+{
+    /** A byte[] representation of an OID */
+    private byte[] oidBytes;
+    
+    /** The OID as a String */
+    private String oidString;
+
+
+    /**
+     * Creates a new instance of Oid.
+     *
+     * @param oidString The OID as a String
+     * @param oidBytes The OID as a byte[]
+     */
+    private Oid( String oidString, byte[] oidBytes )
+    {
+        this.oidString = oidString;
+        this.oidBytes = new byte[oidBytes.length];
+        System.arraycopy( oidBytes, 0, this.oidBytes, 0, oidBytes.length );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object other )
+    {
+        return ( other instanceof Oid )
+            && oidString.equals( ( ( Oid ) other ).oidString );
+    }
+
+
+    /**
+     * Decodes an OID from a <code>byte[]</code>.
+     * 
+     * @param oidBytes The encoded<code>byte[]</code>
+     * @return A new Oid
+     * @throws DecoderException When the OID is not valid
+     */
+    public static Oid fromBytes( byte[] oidBytes ) throws DecoderException
+    {
+        if ( oidBytes == null || oidBytes.length < 1 )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, Arrays.toString( oidBytes ) ) );
+        }
+
+        StringBuilder builder = null;
+        long value = 0;
+
+        for ( int i = 0; i < oidBytes.length; i++ )
+        {
+            value |= oidBytes[i] & 0x7F;
+
+            if ( oidBytes[i] < 0 )
+            {
+                // leading 1, so value continues
+                value = value << 7;
+            }
+            else
+            {
+                // value completed
+                if ( builder == null )
+                {
+                    builder = new StringBuilder();
+
+                    // first value special processing
+                    if ( value >= 80 )
+                    {
+                        // starts with 2
+                        builder.append( 2 );
+                        value = value - 80;
+                    }
+                    else
+                    {
+                        // starts with 0 or 1
+                        long one = value / 40;
+                        long two = value % 40;
+
+                        if ( ( one < 0 ) || ( one > 2 ) || ( two < 0 ) || ( ( one < 2 ) && ( two > 39 ) ) )
+                        {
+                            throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID,
+                                Arrays.toString( oidBytes ) ) );
+                        }
+
+                        if ( one < 2 )
+                        {
+                            builder.append( one );
+                            value = two;
+                        }
+                    }
+                }
+
+                // normal processing
+                builder.append( '.' ).append( value );
+                value = 0;
+            }
+        }
+
+        if ( builder == null )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, Arrays.toString( oidBytes ) ) );
+        }
+
+        return new Oid( builder.toString(), oidBytes );
+    }
+
+
+    /**
+     * Returns an OID object representing <code>oidString</code>.  
+     *  
+     * @param oidString The string representation of the OID
+     * @return A new Oid
+     * @throws DecoderException  When the OID is not valid
+     */
+    public static Oid fromString( String oidString ) throws DecoderException
+    {
+        if ( ( oidString == null ) || oidString.isEmpty() )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, "" ) );
+        }
+
+        Queue<Long> segments = new LinkedList<Long>();
+
+        for ( String segment : oidString.split( "\\.", -1 ) )
+        {
+            try
+            {
+                segments.add( Long.parseLong( segment ) );
+            }
+            catch ( NumberFormatException nfe )
+            {
+                throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oidString ), nfe );
+            }
+        }
+
+        // first segment special case
+        ByteBuffer buffer = new ByteBuffer();
+        Long segmentOne = segments.poll();
+
+        if ( ( segmentOne == null ) || ( segmentOne < 0 ) || ( segmentOne > 2 ) )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oidString ) );
+        }
+
+        // second segment special case
+        Long segment = segments.poll();
+
+        if ( ( segment == null ) || ( segment < 0 ) || ( ( segmentOne < 2 ) && ( segment > 39 ) ) )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oidString ) );
+        }
+
+        buffer.append( ( segmentOne * 40 ) + segment );
+
+        // the rest
+        while ( ( segment = segments.poll() ) != null )
+        {
+            buffer.append( segment );
+        }
+
+        return new Oid( oidString, buffer.toByteArray() );
+    }
+
+
+    /**
+     * Returns the length of the encoded <code>byte[]</code> representation.
+     * 
+     * @return The length of the byte[]
+     */
+    public int getEncodedLength()
+    {
+        return oidBytes.length;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        return oidString.hashCode();
+    }
+
+
+    /**
+     * Returns true if <code>oidString</code> is a valid string representation
+     * of an OID.  This method simply calls {@link #fromString(String)} and 
+     * returns true if no exception was thrown.  As such, it should not be used 
+     * in an attempt to check if a string is a valid OID before calling 
+     * {@link #fromString(String)}.
+     * 
+     * @param oidString The string to test
+     * @return True, if <code>oidString</code> is valid
+     */
+    public static boolean isOid( String oidString )
+    {
+        try
+        {
+            Oid.fromString( oidString );
+
+            return true;
+        }
+        catch ( DecoderException e )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Returns the <code>byte[]</code> representation of the OID. The 
+     * <code>byte[]</code> that is returned is <i>copied</i> from the internal
+     * value so as to preserve the immutability of an OID object.  If the 
+     * output of a call to this method is intended to be written to a stream,
+     * the {@link #writeBytesTo(OutputStream)} should be used instead as it will
+     * avoid creating this copy. 
+     * 
+     * @return The encoded <code>byte[]</code> representation of the OID.
+     */
+    public byte[] toBytes()
+    {
+        return Arrays.copyOf( oidBytes, oidBytes.length );
+    }
+
+
+    /**
+     * Returns the string representation of the OID.
+     * 
+     * @return The string representation of the OID
+     */
+    @Override
+    public String toString()
+    {
+        return oidString;
+    }
+
+
+    /**
+     * Writes the bytes respresenting this OID to the provided buffer.  This 
+     * should be used in preference to the {@link #toBytes()} method in order
+     * to prevent the creation of copies of the actual <code>byte[]</code>.
+     * 
+     * @param buffer The buffer to write the bytes into
+     * @throws IOException If we can't inject the OID into a ByteBuffer 
+     */
+    public void writeBytesTo( java.nio.ByteBuffer buffer )
+    {
+        buffer.put( oidBytes );
+    }
+
+
+    /**
+     * Writes the bytes respresenting this OID to the provided stream.  This 
+     * should be used in preference to the {@link #toBytes()} method in order
+     * to prevent the creation of copies of the actual <code>byte[]</code>.
+     * 
+     * @param outputStream The stream to write the bytes to
+     * @throws IOException When we can't write the OID into a Stream
+     */
+    public void writeBytesTo( OutputStream outputStream ) throws IOException
+    {
+        outputStream.write( oidBytes );
+    }
+
+    /**
+     * 
+     * Internal helper class for converting a long value to a properly encoded byte[]
+     */
+    private static final class ByteBuffer
+    {
+        /** The Buffer the OID will be written in */
+        private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+
+        /**
+         * Writes a Long into a ByteBuffer
+         * 
+         * @param value The long value to write
+         * @return A ByteBufffer containing the converted Long
+         */
+        public ByteBuffer append( long value )
+        {
+            write( value, false );
+            
+            return this;
+        }
+
+
+        /**
+         * Write a long into the buffe, and a flag indicating that there are more 
+         * to write
+         *
+         * @param value The value to write
+         * @param hasMore The flag indicati,ng there is more to write into the buffer
+         */
+        private void write( long value, boolean hasMore )
+        {
+            long remaining = value >> 7;
+        
+            if ( remaining > 0 )
+            {
+                write( remaining, true );
+            }
+            
+            buffer.write( hasMore
+                ? ( byte ) ( ( 0x7F & value ) | 0x80 )
+                : ( byte ) ( 0x7F & value ) );
+        }
+
+
+        /**
+         * Convert the Buffer to a byte[]
+         * 
+         * @return The byte[] containing the Long
+         */
+        public byte[] toByteArray()
+        {
+            return buffer.toByteArray();
+        }
+    }
+}
diff --git a/trunk/asn1/api/src/site/site.xml b/trunk/asn1/api/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/asn1/api/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/asn1/api/src/test/java/org/apache/directory/api/asn1/util/BitStringTest.java b/trunk/asn1/api/src/test/java/org/apache/directory/api/asn1/util/BitStringTest.java
new file mode 100644
index 0000000..c49fc4e
--- /dev/null
+++ b/trunk/asn1/api/src/test/java/org/apache/directory/api/asn1/util/BitStringTest.java
@@ -0,0 +1,280 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Bit String primitive
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BitStringTest
+{
+    /**
+     * Test a null BitString
+     */
+    @Test
+    public void testBitStringNull()
+    {
+
+        BitString bitString = new BitString( 1 );
+
+        bitString.setData( null );
+
+        try
+        {
+            bitString.getBit( 0 );
+            fail( "Should not reach this point ..." );
+        }
+        catch ( IndexOutOfBoundsException ioobe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test an empty BitString
+     */
+    @Test
+    public void testBitStringEmpty()
+    {
+
+        BitString bitString = new BitString( 1 );
+
+        bitString.setData( new byte[]
+            {} );
+
+        try
+        {
+            bitString.getBit( 0 );
+            fail( "Should not reach this point ..." );
+        }
+        catch ( IndexOutOfBoundsException ioobe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test a single bit BitString
+     */
+    @Test
+    public void testSingleBitBitString() throws DecoderException
+    {
+
+        BitString bitString = new BitString( new byte[]
+            { 0x07, ( byte ) 0x80 } );
+
+        assertEquals( true, bitString.getBit( 0 ) );
+    }
+
+
+    /**
+     * Test a 32 bits BitString
+     */
+    @Test
+    public void test32BitsBitString() throws DecoderException
+    {
+
+        BitString bitString = new BitString( 32 );
+
+        bitString.setData( new byte[]
+            { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+
+        for ( int i = 0; i < 32; i++ )
+        {
+            assertEquals( true, bitString.getBit( i ) );
+        }
+    }
+
+
+    /**
+     * Test a 33 bits BitString
+     */
+    @Test
+    public void test33BitsBitString() throws DecoderException
+    {
+
+        BitString bitString = new BitString( 33 );
+
+        bitString.setData( new byte[]
+            { 0x07, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0x80 } );
+
+        for ( int i = 0; i < 33; i++ )
+        {
+            assertEquals( true, bitString.getBit( i ) );
+        }
+
+        assertEquals( true, bitString.getBit( 32 ) );
+    }
+
+
+    /**
+     * Test all bits from 0 to 128 BitString
+     */
+    @Test
+    public void test0to128BitString() throws DecoderException
+    {
+
+        // bit number 14
+        BitString bitString14 = new BitString( 14 );
+
+        bitString14.setData( new byte[]
+            { 0x02, ( byte ) 0xFF, ( byte ) 0xFC } );
+
+        for ( int i = 0; i < 14; i++ )
+        {
+            assertEquals( true, bitString14.getBit( i ) );
+        }
+
+        // bit number 31
+        BitString bitString31 = new BitString( 31 );
+
+        bitString31.setData( new byte[]
+            { 0x01, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFE } );
+
+        for ( int i = 0; i < 31; i++ )
+        {
+            assertEquals( true, bitString31.getBit( i ) );
+        }
+
+        // bit number 128
+        BitString bitString128 = new BitString( 128 );
+
+        bitString128.setData( new byte[]
+            { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
+                ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
+                ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+
+        for ( int i = 0; i < 128; i++ )
+        {
+            assertEquals( true, bitString128.getBit( i ) );
+        }
+    }
+
+
+    @Test
+    public void testBitStringSet()
+    {
+        BitString bitString = new BitString( 32 );
+
+        byte[] bytes = new byte[]
+            { 0x00, ( byte ) 0xAA, 0x11, ( byte ) 0x88, ( byte ) 0xFE };
+
+        int[] bits = new int[]
+            {
+                1, 0, 1, 0, 1, 0, 1, 0,
+                0, 0, 0, 1, 0, 0, 0, 1,
+                1, 0, 0, 0, 1, 0, 0, 0,
+                1, 1, 1, 1, 1, 1, 1, 0
+        };
+
+        for ( int i = 0; i < bits.length; i++ )
+        {
+            if ( bits[i] == 1 )
+            {
+                bitString.setBit( i );
+            }
+        }
+
+        assertEquals( Asn1StringUtils.dumpBytes( bytes ), Asn1StringUtils.dumpBytes( bitString.getData() ) );
+    }
+
+
+    @Test
+    public void testBitStringSetBit()
+    {
+        BitString bitString = new BitString( 32 );
+
+        int[] bits = new int[]
+            {
+                1, 0, 1, 0, 1, 0, 1, 0,
+                0, 0, 0, 1, 0, 0, 0, 1,
+                1, 0, 0, 0, 1, 0, 0, 0, // After modification, will become 8A
+                1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                0
+        };
+
+        for ( int i = 0; i < bits.length; i++ )
+        {
+            if ( bits[i] == 1 )
+            {
+                bitString.setBit( i );
+            }
+        }
+
+        bitString.setBit( 9 );
+        byte[] bytesModified = new byte[]
+            { 0x00, ( byte ) 0xAA, 0x51, ( byte ) 0x88, ( byte ) 0xFE };
+
+        assertEquals( Asn1StringUtils.dumpBytes( bytesModified ), Asn1StringUtils.dumpBytes( bitString.getData() ) );
+    }
+
+
+    @Test
+    public void testBitStringClearBit()
+    {
+        BitString bitString = new BitString( 32 );
+
+        int[] bits = new int[]
+            {
+                1, 0, 1, 0, 1, 0, 1, 0,
+                0, 0, 0, 1, 0, 0, 0, 1,
+                1, 0, 0, 0, 1, 0, 0, 0,
+                1, 1, 1, 1, 1, 1, 1, 0
+        };
+
+        for ( int i = 0; i < bits.length; i++ )
+        {
+            if ( bits[i] == 1 )
+            {
+                bitString.setBit( i );
+            }
+        }
+
+        bitString.clearBit( 11 );
+        byte[] bytesModified = new byte[]
+            { 0x00, ( byte ) 0xAA, 0x01, ( byte ) 0x88, ( byte ) 0xFE };
+
+        assertEquals( Asn1StringUtils.dumpBytes( bytesModified ), Asn1StringUtils.dumpBytes( bitString.getData() ) );
+    }
+}
diff --git a/trunk/asn1/api/src/test/java/org/apache/directory/api/asn1/util/OidTest.java b/trunk/asn1/api/src/test/java/org/apache/directory/api/asn1/util/OidTest.java
new file mode 100644
index 0000000..c2fca70
--- /dev/null
+++ b/trunk/asn1/api/src/test/java/org/apache/directory/api/asn1/util/OidTest.java
@@ -0,0 +1,465 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class OidTest
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger( OidTest.class );
+
+
+    @Test
+    public void speed()
+    {
+        byte[] bytes = new byte[]
+            { 0x2A, ( byte ) 0x86, 0x48, ( byte ) 0x86, ( byte ) 0xF7, 0x12, 0x01, 0x02, 0x02 };
+        String string = new String( "1.2.840.113554.1.2.2" );
+
+        long start = System.nanoTime();
+        for ( int i = 0; i < 1000; i++ )
+        {
+            Arrays.equals( bytes, bytes );
+        }
+        LOGGER.debug( "byte[]: {}", ( System.nanoTime() - start ) );
+
+        start = System.nanoTime();
+        for ( int i = 0; i < 1000; i++ )
+        {
+            string.equals( string );
+        }
+        LOGGER.debug( "String: {}", ( System.nanoTime() - start ) );
+    }
+
+
+    @Test
+    public void fromBytes() throws DecoderException
+    {
+        // first byte
+        for ( int i = 0; i < 2; i++ )
+        { // [0..2]
+            for ( int j = 0; j < 40; j++ )
+            { // [0..39]
+                assertEquals( i + "." + j,
+                    Oid.fromBytes( new byte[]
+                        { ( byte ) ( i * 40 + j ) } )
+                        .toString() );
+            }
+        }
+
+        assertEquals( "1.2.840.113554.1.2.2",
+            Oid.fromBytes( new byte[]
+                {
+                    0x2A, ( byte ) 0x86, 0x48, ( byte ) 0x86, ( byte ) 0xF7, 0x12, 0x01, 0x02, 0x02
+            } ).toString() );
+
+        assertEquals( "2.123456",
+            Oid.fromBytes( new byte[]
+                { ( byte ) 0x87, ( byte ) 0xC5, 0x10 } ).toString() );
+
+    }
+
+
+    @Test
+    public void test2dot123456() throws DecoderException
+    {
+        String expectedString = "2.123456";
+        byte[] expectedBytes = new byte[]
+            { ( byte ) 0x87, ( byte ) 0xC5, 0x10 };
+
+        LOGGER.debug( "b_to_b: " + Arrays.toString( Oid.fromBytes( expectedBytes ).toBytes() ) );
+        assertTrue( Arrays.equals( expectedBytes, Oid.fromBytes( expectedBytes ).toBytes() ) );
+
+        LOGGER.debug( "s_to_b: " + Arrays.toString( Oid.fromString( expectedString ).toBytes() ) );
+        assertTrue( Arrays.equals( expectedBytes, Oid.fromString( expectedString ).toBytes() ) );
+
+        LOGGER.debug( "b_to_s: " + Oid.fromBytes( expectedBytes ).toString() );
+        assertEquals( expectedString, Oid.fromBytes( expectedBytes ).toString() );
+
+        LOGGER.debug( "s_to_s: " + Oid.fromString( expectedString ).toString() );
+        assertEquals( expectedString, Oid.fromString( expectedString ).toString() );
+    }
+
+
+    @Test
+    public void fromString() throws DecoderException
+    {
+        // first byte
+        for ( int i = 0; i < 2; i++ )
+        { // [0..2]
+            for ( int j = 0; j < 40; j++ )
+            { // [0..39]
+                assertTrue( Arrays.equals( new byte[]
+                    { ( byte ) ( i * 40 + j ) },
+                    Oid.fromString( i + "." + j ).toBytes() ) );
+            }
+        }
+
+        assertTrue( Arrays.equals(
+            new byte[]
+                { 0x2A, ( byte ) 0x86, 0x48, ( byte ) 0x86, ( byte ) 0xF7, 0x12, 0x01, 0x02, 0x02 },
+            Oid.fromString( "1.2.840.113554.1.2.2" ).toBytes() ) );
+    }
+
+
+    /**
+     * Test a null NewOid
+     */
+    @Test
+    public void testNewOidNull()
+    {
+        try
+        {
+            Oid.fromBytes( ( byte[] ) null );
+            fail( "Should not reach this point ..." );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test an empty NewOid
+     */
+    @Test
+    public void testNewOidEmpty()
+    {
+        try
+        {
+            Oid.fromBytes( new byte[]
+                {} );
+            fail( "Should not reach this point ..." );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test itu-t NewOid tree
+     */
+    @Test
+    public void testNewOidItuT()
+    {
+        try
+        {
+            Oid oid = null;
+
+            // itu-t(0), recommendation(0), series a-z (0..26)
+            for ( int i = 1; i < 27; i++ )
+            {
+                oid = Oid.fromBytes( new byte[]
+                    { 0x00, ( byte ) i } );
+                assertEquals( "0.0." + i, oid.toString() );
+            }
+
+            // itu-t(0), question(1)
+            oid = Oid.fromBytes( new byte[]
+                { 0x01 } );
+            assertEquals( "0.1", oid.toString() );
+
+            // itu-t(0), administration(2), country(202 .. 748)
+            for ( int i = 202; i < 748; i++ )
+            {
+                oid = Oid.fromBytes( new byte[]
+                    { 0x02, ( byte ) ( ( i / 128 ) | 0x0080 ), ( byte ) ( i % 128 ) } );
+                assertEquals( "0.2." + i, oid.toString() );
+            }
+
+            // itu-t(0), network-operator(3), operator(2023 .. 41363)
+            for ( int i = 2023; i < 41363; i++ )
+            {
+                if ( i < ( 128 * 128 ) )
+                {
+                    oid = Oid.fromBytes( new byte[]
+                        { 0x03, ( byte ) ( ( i / 128 ) | 0x0080 ), ( byte ) ( i % 128 ) } );
+                    assertEquals( "0.3." + i, oid.toString() );
+                }
+                else
+                {
+                    oid = Oid.fromBytes( new byte[]
+                        { 0x03, ( byte ) ( ( i / ( 128 * 128 ) ) | 0x0080 ),
+                            ( byte ) ( ( ( i / 128 ) % 128 ) | 0x0080 ), ( byte ) ( i % 128 ) } );
+                    assertEquals( "0.3." + i, oid.toString() );
+                }
+            }
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test iso NewOid tree
+     */
+    @Test
+    public void testNewOidIso()
+    {
+
+        Oid oid = null;
+
+        try
+        {
+            // iso(1), standard(0)
+            oid = Oid.fromBytes( new byte[]
+                { 40 + 0 } );
+            assertEquals( "1.0", oid.toString() );
+
+            // iso(1), registration-authority(1)
+            oid = Oid.fromBytes( new byte[]
+                { 40 + 1 } );
+            assertEquals( "1.1", oid.toString() );
+
+            // iso(1), member-body(2)
+            oid = Oid.fromBytes( new byte[]
+                { 40 + 2 } );
+            assertEquals( "1.2", oid.toString() );
+
+            // iso(1), identified-organization(3) | org(3) | organization(3)
+            oid = Oid.fromBytes( new byte[]
+                { 40 + 3 } );
+            assertEquals( "1.3", oid.toString() );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test joint-iso-itu-t NewOid tree
+     */
+    @Test
+    public void testNewOidJointIsoItuT()
+    {
+        Oid oid = null;
+
+        try
+        {
+            // joint-iso-itu-t(2), presentation(0)
+            oid = Oid.fromBytes( new byte[]
+                { 80 + 0 } );
+            assertEquals( "2.0", oid.toString() );
+
+            // joint-iso-itu-t(2), asn1(1)
+            oid = Oid.fromBytes( new byte[]
+                { 80 + 1 } );
+            assertEquals( "2.1", oid.toString() );
+
+            // joint-iso-itu-t(2), association-control(2)
+            oid = Oid.fromBytes( new byte[]
+                { 80 + 2 } );
+            assertEquals( "2.2", oid.toString() );
+
+            // joint-iso-itu-t(2), reliable-transfer(3)
+            oid = Oid.fromBytes( new byte[]
+                { 80 + 3 } );
+            assertEquals( "2.3", oid.toString() );
+
+            // ...
+            // joint-iso-itu-t(2), upu(40)
+            oid = Oid.fromBytes( new byte[]
+                { 80 + 40 } );
+            assertEquals( "2.40", oid.toString() );
+
+            // ...
+            // joint-iso-itu-t(2), xxx(100)
+            oid = Oid.fromBytes( new byte[]
+                { ( byte ) ( 0x81 ), 0x34 } );
+            assertEquals( "2.100", oid.toString() );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test valid String NewOids
+     */
+    @Test
+    public void testNewOidStringGood()
+    {
+        Oid oid = null;
+
+        try
+        {
+            oid = Oid.fromString( "0.0" );
+            assertEquals( "0.0", oid.toString() );
+
+            oid = Oid.fromString( "0.0.0.0.0" );
+            assertEquals( "0.0.0.0.0", oid.toString() );
+
+            oid = Oid.fromString( "0.1.2.3.4" );
+            assertEquals( "0.1.2.3.4", oid.toString() );
+
+            oid = Oid.fromString( "2.123456" );
+            assertEquals( "2.123456", oid.toString() );
+
+            oid = Oid.fromString( "1.2.840.113554.1.2.2" );
+            assertEquals( "1.2.840.113554.1.2.2", oid.toString() );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test invalid String NewOids
+     */
+    @Test
+    public void testNewOidStringBad()
+    {
+        assertFalse( Oid.isOid( "0" ) );
+        assertFalse( Oid.isOid( "0." ) );
+        assertFalse( Oid.isOid( "." ) );
+        assertFalse( Oid.isOid( "0.1.2." ) );
+        assertFalse( Oid.isOid( "3.1" ) );
+        assertFalse( Oid.isOid( "0..1" ) );
+        assertFalse( Oid.isOid( "0..12" ) );
+        assertFalse( Oid.isOid( "0.a.2" ) );
+        assertFalse( Oid.isOid( "0.123456" ) );
+        assertFalse( Oid.isOid( "1.123456" ) );
+    }
+
+
+    /**
+     * Test Spnego NewOid
+     */
+    @Test
+    public void testNewOidSpnego()
+    {
+        Oid oid = null;
+
+        try
+        {
+            oid = Oid.fromBytes( new byte[]
+                { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02 } );
+            assertEquals( "1.3.6.1.5.5.2", oid.toString() );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test Kerberos V5 NewOid
+     */
+    @Test
+    public void testNewOidKerberosV5()
+    {
+        Oid oid = null;
+
+        try
+        {
+            oid = Oid.fromBytes( new byte[]
+                { 0x2a, ( byte ) 0x86, 0x48, ( byte ) 0x86, ( byte ) 0xf7, 0x12, 0x01, 0x02, 0x02 } );
+            assertEquals( "1.2.840.113554.1.2.2", oid.toString() );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test NewOids bytes
+     */
+    @Test
+    public void testNewOidBytes()
+    {
+        Oid oid = null;
+        Oid oid2 = null;
+
+        try
+        {
+            oid = Oid.fromString( "0.0" );
+            oid2 = Oid.fromBytes( oid.toBytes() );
+            assertEquals( oid.toString(), oid2.toString() );
+
+            oid = Oid.fromString( "0.0.0.0.0" );
+            oid2 = Oid.fromBytes( oid.toBytes() );
+            assertEquals( oid.toString(), oid2.toString() );
+
+            oid = Oid.fromString( "0.1.2.3.4" );
+            assertTrue( Arrays.equals( new byte[]
+                { 0x01, 0x02, 0x03, 0x04 }, oid.toBytes() ) );
+            oid2 = Oid.fromBytes( oid.toBytes() );
+            assertEquals( oid.toString(), oid2.toString() );
+
+            oid = Oid.fromString( "2.123456" );
+            oid2 = Oid.fromBytes( oid.toBytes() );
+            assertEquals( oid.toString(), oid2.toString() );
+
+            oid = Oid.fromString( "1.2.840.113554.1.2.2" );
+            oid2 = Oid.fromBytes( oid.toBytes() );
+            assertEquals( oid.toString(), oid2.toString() );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test NewOid Equals
+     */
+    @Test
+    public void testNewOidEqualsPerf() throws DecoderException
+    {
+        String s1 = "1.2.840.113554.1.2.2.1.2.840.113554.1.2.2.1.2.840.113554.1.2.2";
+        String s2 = "1.2.840.113554.1.2.2.1.2.840.113554.1.2.2.1.2.840.113554.1.2.2";
+        String s3 = "1.3.6.1.5.5.2";
+
+        Oid oid1 = Oid.fromString( s1 );
+        Oid oid2 = Oid.fromString( s2 );
+        Oid oid3 = Oid.fromString( s3 );
+
+        assertTrue( oid1.equals( oid2 ) );
+        assertFalse( oid1.equals( oid3 ) );
+        assertFalse( oid2.equals( oid3 ) );
+    }
+}
diff --git a/trunk/asn1/api/src/test/resources/log4j.properties b/trunk/asn1/api/src/test/resources/log4j.properties
new file mode 100755
index 0000000..f337ec7
--- /dev/null
+++ b/trunk/asn1/api/src/test/resources/log4j.properties
@@ -0,0 +1,23 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+
+log4j.logger.org.apache.directory.api.asn1.util=DEBUG
\ No newline at end of file
diff --git a/trunk/asn1/ber/pom.xml b/trunk/asn1/ber/pom.xml
new file mode 100644
index 0000000..3c3c8f3
--- /dev/null
+++ b/trunk/asn1/ber/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-asn1-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-asn1-ber</artifactId>
+  <name>Apache Directory API ASN.1 BER</name>
+  <packaging>bundle</packaging>
+
+  <description>A BER Codec Implementation for ASN.1</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-api</artifactId>
+    </dependency> 
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency> 
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>findbugs</groupId>
+      <artifactId>annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.asn1.ber</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.asn1.actions;version=${project.version};-noimport:=true,
+              org.apache.directory.api.asn1.ber;version=${project.version};-noimport:=true,
+              org.apache.directory.api.asn1.ber.grammar;version=${project.version};-noimport:=true,
+              org.apache.directory.api.asn1.ber.tlv;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.asn1.util;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion}
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadBitString.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadBitString.java
new file mode 100644
index 0000000..4a0fd8d
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadBitString.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.actions;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used read a BITSTRING from a TLV
+ * 
+ * @param C The container type
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractReadBitString<C extends Asn1Container> extends GrammarAction<C>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AbstractReadBitString.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new AbstractReadByteArray action.
+     * 
+     * @param name the action's name
+     */
+    public AbstractReadBitString( String name )
+    {
+        super( name );
+    }
+
+
+    /**
+     * Gives a byte array to be set to the appropriate field of the ASN.1 object
+     * present in the container
+     *
+     * @param data the data of the read TLV present in byte array format
+     * @param container the container holding the ASN.1 object
+     */
+    protected abstract void setBitString( byte[] data, C container );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final void action( C container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // The Length should not be null, and should be 5
+        if ( tlv.getLength() != 5 )
+        {
+            LOG.error( I18n.err( I18n.ERR_04066 ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
+        }
+
+        byte[] data = tlv.getValue().getData();
+        setBitString( data, container );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "BITSTRING value : {}", Strings.dumpBytes( data ) );
+        }
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadInteger.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadInteger.java
new file mode 100644
index 0000000..38cf791
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadInteger.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.actions;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to read an integer value
+ *
+ * @param C The container type
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractReadInteger<E extends Asn1Container> extends GrammarAction<E>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AbstractReadInteger.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** the acceptable minimum value for the expected value to be parsed */
+    private int minValue = 0;
+
+    /** the acceptable maximum value for the expected value to be parsed */
+    private int maxValue = Integer.MAX_VALUE;
+
+
+    /**
+     * Instantiates a new AbstractReadInteger action.
+     * 
+     * @param name the action's name
+     */
+    public AbstractReadInteger( String name )
+    {
+        super( name );
+    }
+
+
+    /**
+     *
+     * Creates a new instance of AbstractReadInteger.
+     *
+     * @param name the action's name
+     * @param minValue the acceptable minimum value for the expected value to be read
+     * @param maxValue the acceptable maximum value for the value to be read
+     */
+    public AbstractReadInteger( String name, int minValue, int maxValue )
+    {
+        super( name );
+
+        this.minValue = minValue;
+        this.maxValue = maxValue;
+    }
+
+
+    /**
+     *
+     * set the integer value to the appropriate field of ASN.1 object present in the container
+     *
+     * @param value the integer value
+     * @param container the ASN.1 object's container
+     */
+    protected abstract void setIntegerValue( int value, E container );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final void action( E container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // The Length should not be null
+        if ( tlv.getLength() == 0 )
+        {
+            LOG.error( I18n.err( I18n.ERR_04066 ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
+        }
+
+        BerValue value = tlv.getValue();
+
+        try
+        {
+            int number = IntegerDecoder.parse( value, minValue, maxValue );
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "read integer value : {}", number );
+            }
+
+            setIntegerValue( number, container );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            LOG.error( I18n.err( I18n.ERR_04070, Strings.dumpBytes( value.getData() ), ide
+                .getLocalizedMessage() ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( ide.getMessage(), ide );
+        }
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadOctetString.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadOctetString.java
new file mode 100644
index 0000000..2a18807
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/AbstractReadOctetString.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.actions;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to read an OCTET STRING value
+ *
+ * @param C The container type
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractReadOctetString<C extends Asn1Container> extends GrammarAction<C>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AbstractReadOctetString.class );
+
+    /** the acceptable maximum value for the expected value to be parsed */
+    private boolean canBeNull = Boolean.FALSE;
+
+
+    /**
+     * Instantiates a new AbstractReadInteger action.
+     * 
+     * @param name the action's name
+     */
+    public AbstractReadOctetString( String name )
+    {
+        super( name );
+    }
+
+
+    /**
+     * Instantiates a new AbstractReadInteger action.
+     *
+     * @param name the action's name
+     * @param canBeNull Tells if the byte array can be null or not
+     */
+    public AbstractReadOctetString( String name, boolean canBeNull )
+    {
+        super( name );
+
+        this.canBeNull = canBeNull;
+    }
+
+
+    /**
+     * Sets the OCTET STRING value to the appropriate field of ASN.1 object present in the container
+     *
+     * @param value the OCTET STRING value
+     * @param container the ASN.1 object's container
+     */
+    protected abstract void setOctetString( byte[] value, C container );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final void action( C container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // The Length should not be null
+        if ( ( tlv.getLength() == 0 ) && ( !canBeNull ) )
+        {
+            LOG.error( I18n.err( I18n.ERR_04066 ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
+        }
+
+        BerValue value = tlv.getValue();
+
+        // The data should not be null
+        if ( ( value.getData() == null ) && ( !canBeNull ) )
+        {
+            LOG.error( I18n.err( I18n.ERR_04066 ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
+        }
+
+        setOctetString( value.getData(), container );
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/CheckNotNullLength.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/CheckNotNullLength.java
new file mode 100644
index 0000000..3287378
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/actions/CheckNotNullLength.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.actions;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An action that checks the length is not null
+ *
+ * @param C The container type
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CheckNotNullLength<C extends Asn1Container> extends GrammarAction<C>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( CheckNotNullLength.class );
+
+
+    /**
+     * Instantiates the action.
+     */
+    public CheckNotNullLength()
+    {
+        super( "Check that the length is not null" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( C container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // The Length should not be null
+        if ( tlv.getLength() == 0 )
+        {
+            LOG.error( I18n.err( I18n.ERR_04066 ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
+        }
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/AbstractContainer.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/AbstractContainer.java
new file mode 100644
index 0000000..a8f961c
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/AbstractContainer.java
@@ -0,0 +1,349 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+
+
+/**
+ * This class is the abstract container used to store the current state of a PDU
+ * being decoded. It also stores the grammars used to decode the PDU, and all
+ * the informations needed to decode a PDU.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractContainer implements Asn1Container
+{
+    /** All the possible grammars */
+    private Grammar<?> grammar;
+
+    /** The current state of the decoding */
+    private TLVStateEnum state;
+
+    /** The current transition */
+    private Enum<?> transition;
+
+    /** The current TLV */
+    private TLV tlv;
+
+    /** The parent TLV */
+    private TLV parentTLV;
+
+    /** The grammar end transition flag */
+    private boolean grammarEndAllowed;
+
+    /** A counter for the decoded bytes */
+    private int decodedBytes;
+
+    /** The maximum allowed size for a PDU. Default to MAX int value */
+    private int maxPDUSize = Integer.MAX_VALUE;
+
+    /** The incremental id used to tag TLVs */
+    private int id = 0;
+
+    /** The Stream being decoded */
+    private ByteBuffer stream;
+
+    /** A flag telling if the Value should be accumulated before being decoded
+     * for constructed types */
+    private boolean gathering = false;
+
+
+    /**
+     * Creates a new instance of AbstractContainer with a starting state.
+     *
+     */
+    protected AbstractContainer()
+    {
+        state = TLVStateEnum.TAG_STATE_START;
+    }
+
+
+    /**
+     * Creates a new instance of AbstractContainer with a starting state.
+     *
+     * @param stream the buffer containing the data to decode
+     */
+    protected AbstractContainer( ByteBuffer stream )
+    {
+        state = TLVStateEnum.TAG_STATE_START;
+        this.stream = stream;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Grammar<?> getGrammar()
+    {
+        return grammar;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setGrammar( Grammar<?> grammar )
+    {
+        this.grammar = grammar;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public TLVStateEnum getState()
+    {
+        return state;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setState( TLVStateEnum state )
+    {
+        this.state = state;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isGrammarEndAllowed()
+    {
+        return grammarEndAllowed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setGrammarEndAllowed( boolean grammarEndAllowed )
+    {
+        this.grammarEndAllowed = grammarEndAllowed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Enum<?> getTransition()
+    {
+        return transition;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTransition( Enum<?> transition )
+    {
+        this.transition = transition;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCurrentTLV( TLV currentTLV )
+    {
+        this.tlv = currentTLV;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public TLV getCurrentTLV()
+    {
+        return this.tlv;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public TLV getParentTLV()
+    {
+        return parentTLV;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setParentTLV( TLV parentTLV )
+    {
+        this.parentTLV = parentTLV;
+    }
+
+
+    /**
+     * Clean the container for the next usage.
+     */
+    public void clean()
+    {
+        tlv = null;
+        parentTLV = null;
+        transition = ( ( States ) transition ).getStartState();
+        state = TLVStateEnum.TAG_STATE_START;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getNewTlvId()
+    {
+        return id++;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTlvId()
+    {
+        return tlv.getId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getDecodedBytes()
+    {
+        return decodedBytes;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDecodedBytes( int decodedBytes )
+    {
+        this.decodedBytes = decodedBytes;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void incrementDecodedBytes( int nb )
+    {
+        decodedBytes += nb;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getMaxPDUSize()
+    {
+        return maxPDUSize;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMaxPDUSize( int maxPDUSize )
+    {
+        if ( maxPDUSize > 0 )
+        {
+            this.maxPDUSize = maxPDUSize;
+        }
+        else
+        {
+            this.maxPDUSize = Integer.MAX_VALUE;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteBuffer getStream()
+    {
+        return stream;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setStream( ByteBuffer stream )
+    {
+        this.stream = stream;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rewind()
+    {
+
+        int start = stream.position() - 1 - tlv.getLengthNbBytes();
+        stream.position( start );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void updateParent()
+    {
+        TLV parentTlv = tlv.getParent();
+
+        while ( ( parentTlv != null ) && ( parentTlv.getExpectedLength() == 0 ) )
+        {
+            parentTlv = parentTlv.getParent();
+        }
+
+        this.parentTLV = parentTlv;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isGathering()
+    {
+        return gathering;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setGathering( boolean gathering )
+    {
+        this.gathering = gathering;
+    }
+
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/Asn1Container.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/Asn1Container.java
new file mode 100644
index 0000000..207df47
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/Asn1Container.java
@@ -0,0 +1,227 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+
+
+/**
+ * Every ASN1 container must implement this interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Asn1Container
+{
+    /**
+     * Gets the current stream containing the bytes to decode
+     *
+     * @return The current stream
+     */
+    ByteBuffer getStream();
+
+
+    /**
+     * Stores the Stream being decoded
+     *
+     * @param stream The stream being decoded
+     */
+    void setStream( ByteBuffer stream );
+
+
+    /**
+     * Gets the current grammar state
+     *
+     * @return Returns the current grammar state
+     */
+    TLVStateEnum getState();
+
+
+    /**
+     * Sets the new current state
+     *
+     * @param state The new state
+     */
+    void setState( TLVStateEnum state );
+
+
+    /**
+     * Gets the currentTLV
+     *
+     * @return Returns the current TLV being decoded
+     */
+    TLV getCurrentTLV();
+
+
+    /**
+     * Sets the current TLV
+     *
+     * @param tlv The current TLV
+     */
+    void setCurrentTLV( TLV tlv );
+
+
+    /**
+     * Gets the grammar
+     *
+     * @return Returns the grammar used to decode a LdapMessage.
+     */
+    @SuppressWarnings("rawtypes")
+    Grammar getGrammar();
+
+
+    /**
+     * Sets the grammar
+     *
+     * @param grammar The grammar to set
+     */
+    void setGrammar( Grammar<?> grammar );
+
+
+    /**
+     * Gets the transition
+     *
+     * @return Returns the transition from the previous state to the new state
+     */
+    Enum<?> getTransition();
+
+
+    /**
+     * Updates the transition from a state to another
+     *
+     * @param transition The transition to set
+     */
+    void setTransition( Enum<?> transition );
+
+
+    /**
+     * @return The parent TLV.
+     */
+    TLV getParentTLV();
+
+
+    /**
+     * Sets the parent TLV
+     *
+     * @param parentTLV The new parent TLV
+     */
+    void setParentTLV( TLV parentTLV );
+
+
+    /**
+     * Checks that we can have a end state after this transition
+     *
+     * @return true if this can be the last transition
+     */
+    boolean isGrammarEndAllowed();
+
+
+    /**
+     * Sets the flag to allow a end transition
+     *
+     * @param grammarEndAllowed true or false, depending on the next transition
+     * being an end or not.
+     */
+    void setGrammarEndAllowed( boolean grammarEndAllowed );
+
+
+    /**
+     * Gets a new TLV id
+     * @return a unique value representing the current TLV id
+     */
+    int getNewTlvId();
+
+
+    /**
+     * Gets the current TLV id
+     * @return a unique value representing the current TLV id
+     */
+    int getTlvId();
+
+
+    /**
+     * @return The number of decoded bytes for this message. This is used
+     * to control the PDU size and avoid PDU exceeding the maximum allowed
+     * size to break the server.
+     */
+    int getDecodedBytes();
+
+
+    /**
+     * @param decodedBytes The number of decoded bytes for this message.
+     */
+    void setDecodedBytes( int decodeBytes );
+
+
+    /**
+     * Increment the decodedBytes by the latest received buffer's size.
+     * @param nb The buffer size.
+     */
+    void incrementDecodedBytes( int nb );
+
+
+    /**
+     * @return The maximum PDU size.
+     */
+    int getMaxPDUSize();
+
+
+    /**
+     * Set the maximum PDU size.
+     * @param maxPDUSize The maximum PDU size (if negative or null, will be
+     * replaced by the max integer value)
+     */
+    void setMaxPDUSize( int maxPDUSize );
+
+
+    /**
+     * Move backward in the stream to the first byte for a given TLV. This is useful when we have
+     * read some Tag and Length in order to define the next transition, and if this transition
+     * do a grammar switch.
+     * @param tlv The TLV to roll-back
+     */
+    void rewind();
+
+
+    /**
+     * Update the parent's length
+     */
+    void updateParent();
+
+
+    /**
+     * @return true if the container should gather the value into itself, false
+     * if the decoding of the Value part should be done immediately for
+     * constructed types.
+     */
+    boolean isGathering();
+
+
+    /**
+     * Set the isGathering flag
+     * @param isGathering true to ask the Asn1Decoder to gather the data
+     * into the container. If not set, the default value is 'false'
+     */
+    void setGathering( boolean isGathering );
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/Asn1Decoder.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/Asn1Decoder.java
new file mode 100644
index 0000000..3972a55
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/Asn1Decoder.java
@@ -0,0 +1,856 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1.ber;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.TLVBerDecoderMBean;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.api.asn1.util.Asn1StringUtils;
+import org.apache.directory.api.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A BER TLV Tag component decoder. This decoder instantiate a Tag. The tag
+ * won't be implementations should not copy the handle to the Tag object
+ * delivered but should copy the data if they need it over the long term.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+*/
+public class Asn1Decoder implements TLVBerDecoderMBean
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( Asn1Decoder.class );
+
+    /** A speedup for logger */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** This flag is used to indicate that there are more bytes in the stream */
+    private static final boolean MORE = true;
+
+    /** This flag is used to indicate that there are no more bytes in the stream */
+    private static final boolean END = false;
+
+    /** Flag that is used to allow/disallow the indefinite form of Length */
+    private boolean indefiniteLengthAllowed;
+
+    /** The maximum number of bytes that could be used to encode the Length */
+    private int maxLengthLength;
+
+    /** The maximum number of bytes that could be used to encode the Tag */
+    private int maxTagLength;
+
+
+    /**
+     * A public constructor of an Asn1 Decoder.
+     */
+    public Asn1Decoder()
+    {
+        indefiniteLengthAllowed = false;
+        maxLengthLength = 1;
+        maxTagLength = 1;
+    }
+
+
+    /**
+     * Treat the start of a TLV. It reads the tag and get its value.
+     * 
+     * @param stream The ByteBuffer containing the PDU to decode
+     * @param container The container that stores the current state,
+     * the result and other informations.
+     * @return <code>true</code> if there are more bytes to read, <code>false
+     * </code> otherwise
+     */
+    private boolean treatTagStartState( ByteBuffer stream, Asn1Container container )
+    {
+        if ( stream.hasRemaining() )
+        {
+            byte octet = stream.get();
+
+            TLV tlv = new TLV( container.getNewTlvId() );
+            tlv.setTag( octet );
+
+            // Store the current TLV in the container.
+            container.setCurrentTLV( tlv );
+
+            // Create a link between the current TLV with its parent
+            tlv.setParent( container.getParentTLV() );
+
+            // Switch to the next state, which is the Length decoding
+            container.setState( TLVStateEnum.LENGTH_STATE_START );
+
+            if ( IS_DEBUG )
+            {
+                byte tag = container.getCurrentTLV().getTag();
+                LOG.debug( "Tag {} has been decoded", Asn1StringUtils.dumpByte( tag ) );
+            }
+
+            return MORE;
+        }
+        else
+        {
+            // The stream has been exhausted
+            return END;
+        }
+    }
+
+
+    /**
+     * Dump the current TLV tree
+     * 
+     * @param container The container
+     */
+    private void dumpTLVTree( Asn1Container container )
+    {
+        StringBuffer sb = new StringBuffer();
+        TLV current = container.getCurrentTLV();
+
+        sb.append( "TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append(
+            current.getExpectedLength() ).append( ")" );
+
+        current = current.getParent();
+
+        while ( current != null )
+        {
+            sb.append( "-TLV" ).append( Asn1StringUtils.dumpByte( current.getTag() ) ).append( "(" ).append(
+                current.getExpectedLength() ).append( ")" );
+            current = current.getParent();
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "TLV Tree : {}", sb.toString() );
+        }
+    }
+
+
+    /**
+     * Check if the TLV tree is fully decoded
+     * 
+     * @param container The container
+     * @return <code>true</code> if the TLV has been decoded
+     */
+    private boolean isTLVDecoded( Asn1Container container )
+    {
+        TLV current = container.getCurrentTLV();
+        TLV parent = current.getParent();
+
+        while ( parent != null )
+        {
+            if ( parent.getExpectedLength() != 0 )
+            {
+                return false;
+            }
+
+            parent = parent.getParent();
+        }
+
+        BerValue value = current.getValue();
+
+        if ( ( value != null ) && ( value.getData() != null ) )
+        {
+            return ( current.getExpectedLength() == value.getData().length );
+        }
+        else
+        {
+            return current.getExpectedLength() == 0;
+        }
+    }
+
+
+    /**
+     * Treat the Length start. The tag has been decoded, so we have to deal with
+     * the LENGTH, which can be multi-bytes.
+     * 
+     * @param stream  The ByteBuffer containing the PDU to decode
+     * @param container The container that stores the current state,
+     * the result and other informations.
+     * @return <code>true</code> if there are more bytes to read, <code>false
+     * </code> otherwise
+     * @throws DecoderException Thrown if anything went wrong
+     */
+    private boolean treatLengthStartState( ByteBuffer stream, Asn1Container container ) throws DecoderException
+    {
+        if ( stream.hasRemaining() )
+        {
+            byte octet = stream.get();
+            TLV tlv = container.getCurrentTLV();
+
+            if ( ( octet & TLV.LENGTH_LONG_FORM ) == 0 )
+            {
+                // We don't have a long form. The Length of the Value part is
+                // given by this byte.
+                tlv.setLength( octet );
+                tlv.setLengthNbBytes( 1 );
+
+                container.setState( TLVStateEnum.LENGTH_STATE_END );
+            }
+            else if ( ( octet & TLV.LENGTH_EXTENSION_RESERVED ) != TLV.LENGTH_EXTENSION_RESERVED )
+            {
+                int expectedLength = octet & TLV.LENGTH_SHORT_MASK;
+
+                if ( expectedLength > 4 )
+                {
+                    String msg = I18n.err( I18n.ERR_00005_LENGTH_OVERFLOW );
+                    LOG.error( msg );
+                    throw new DecoderException( msg );
+                }
+
+                tlv.setLength( 0 );
+                tlv.setLengthNbBytes( 1 + expectedLength );
+                tlv.setLengthBytesRead( 1 );
+                container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
+            }
+            else
+            {
+                String msg = I18n.err( I18n.ERR_00006_LENGTH_EXTENSION_RESERVED );
+                LOG.error( msg );
+                throw new DecoderException( msg );
+            }
+
+            return MORE;
+        }
+        else
+        {
+            return END;
+        }
+    }
+
+
+    /**
+     * This function is called when a Length is in the process of being decoded,
+     * but the lack of bytes in the buffer stopped the process.
+     * 
+     * @param stream The ByteBuffer containing the PDU to decode
+     * @param container The container that stores the current state,
+     * the result and other informations.
+     * @return <code>true</code> if there are more bytes to read, <code>false
+     * </code> otherwise
+     */
+    private boolean treatLengthPendingState( ByteBuffer stream, Asn1Container container )
+    {
+        if ( stream.hasRemaining() )
+        {
+            TLV tlv = container.getCurrentTLV();
+            int length = tlv.getLength();
+
+            while ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
+            {
+                byte octet = stream.get();
+
+                if ( IS_DEBUG )
+                {
+                    LOG.debug( "  current byte : {}", Asn1StringUtils.dumpByte( octet ) );
+                }
+
+                tlv.incLengthBytesRead();
+                length = ( length << 8 ) | ( octet & 0x00FF );
+
+                if ( !stream.hasRemaining() )
+                {
+                    tlv.setLength( length );
+
+                    if ( tlv.getLengthBytesRead() < tlv.getLengthNbBytes() )
+                    {
+                        container.setState( TLVStateEnum.LENGTH_STATE_PENDING );
+                        return END;
+                    }
+                    else
+                    {
+                        container.setState( TLVStateEnum.LENGTH_STATE_END );
+                        return MORE;
+                    }
+                }
+            }
+
+            tlv.setLength( length );
+            container.setState( TLVStateEnum.LENGTH_STATE_END );
+
+            return MORE;
+        }
+        else
+        {
+
+            return END;
+        }
+    }
+
+
+    /**
+     * A debug function used to dump the expected length stack.
+     * 
+     * @param tlv The current TLV.
+     * @return A string which represent the expected length stack.
+     */
+    private String getParentLength( TLV tlv )
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append( "TLV expected length stack : " );
+
+        while ( true )
+        {
+            if ( tlv == null )
+            {
+                buffer.append( " - null" );
+                break;
+            }
+            else
+            {
+                buffer.append( " - " ).append( tlv.getExpectedLength() );
+            }
+
+            tlv = tlv.getParent();
+        }
+
+        return buffer.toString();
+    }
+
+
+    /**
+     * The Length is fully decoded. We have to call an action to check the size.
+     * 
+     * @param container The container that stores the current state,
+     * the result and other informations.
+     * @throws DecoderException Thrown if anything went wrong
+     */
+    private void treatLengthEndState( Asn1Container container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv == null )
+        {
+            String msg = I18n.err( I18n.ERR_00007_TLV_NULL );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        int length = tlv.getLength();
+
+        // We will check the length here. What we must control is
+        // that the enclosing constructed TLV expected length is not
+        // exceeded by the current TLV.
+        TLV parentTLV = container.getParentTLV();
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Parent length : {}", getParentLength( parentTLV ) );
+        }
+
+        if ( parentTLV == null )
+        {
+            // This is the first TLV, so we can't check anything. We will
+            // just store this TLV as the root of the PDU
+            tlv.setExpectedLength( length );
+            container.setParentTLV( tlv );
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "Root TLV[{}]", Integer.valueOf( length ) );
+            }
+        }
+        else
+        {
+            // We have a parent, so we will check that its expected length is
+            // not exceeded.
+            int expectedLength = parentTLV.getExpectedLength();
+            int currentLength = tlv.getSize();
+
+            if ( expectedLength < currentLength )
+            {
+                // The expected length is lower than the Value length of the
+                // current TLV. This is an error...
+                LOG.debug( "tlv[{}, {}]", Integer.valueOf( expectedLength ), Integer.valueOf( currentLength ) );
+                throw new DecoderException( I18n.err( I18n.ERR_00008_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH, Integer
+                    .valueOf( currentLength ), Integer.valueOf( expectedLength ) ) );
+            }
+
+            // deal with the particular case where expected length equal
+            // the current length, which means that the parentTLV has been
+            // completed.
+            if ( expectedLength == currentLength )
+            {
+                parentTLV.setExpectedLength( 0 );
+
+                // We also have to check that the current TLV is a constructed
+                // one.
+                // In this case, we have to switch from this parent TLV
+                // to the parent's parent TLV.
+                if ( tlv.isConstructed() )
+                {
+                    // here, we also have another special case : a
+                    // zero length TLV. We must then unstack all
+                    // the parents which length is null.
+                    if ( length == 0 )
+                    {
+                        // We will set the parent to the first parentTLV which
+                        // expectedLength
+                        // is not null, and it will become the new parent TLV
+                        while ( parentTLV != null )
+                        {
+                            if ( parentTLV.getExpectedLength() != 0 )
+                            {
+                                // ok, we have an incomplete parent. we will
+                                // stop the recursion right here
+                                break;
+                            }
+                            else
+                            {
+                                parentTLV = parentTLV.getParent();
+                            }
+                        }
+
+                        container.setParentTLV( parentTLV );
+                    }
+                    else
+                    {
+                        // The new Parent TLV is this Constructed TLV
+                        container.setParentTLV( tlv );
+                    }
+
+                    tlv.setParent( parentTLV );
+                    tlv.setExpectedLength( length );
+                }
+                else
+                {
+                    tlv.setExpectedLength( length );
+
+                    // It's over, the parent TLV has been completed.
+                    // Go back to the parent's parent TLV until we find
+                    // a tlv which is not complete.
+                    while ( parentTLV != null )
+                    {
+                        if ( parentTLV.getExpectedLength() != 0 )
+                        {
+                            // ok, we have an incomplete parent. we will
+                            // stop the recursion right here
+                            break;
+                        }
+                        else
+                        {
+                            parentTLV = parentTLV.getParent();
+                        }
+                    }
+
+                    container.setParentTLV( parentTLV );
+                }
+            }
+            else
+            {
+                // Renew the expected Length.
+                parentTLV.setExpectedLength( expectedLength - currentLength );
+                tlv.setExpectedLength( length );
+
+                if ( tlv.isConstructed() )
+                {
+                    // We have a constructed tag, so we must switch the
+                    // parentTLV
+                    tlv.setParent( parentTLV );
+                    container.setParentTLV( tlv );
+                }
+            }
+
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Length {} has been decoded", Integer.valueOf( length ) );
+        }
+
+        if ( length == 0 )
+        {
+            // The length is 0, so we can't expect a value.
+            container.setState( TLVStateEnum.TLV_STATE_DONE );
+        }
+        else
+        {
+            // Go ahead and decode the value part
+            container.setState( TLVStateEnum.VALUE_STATE_START );
+        }
+    }
+
+
+    /**
+     * Treat the Value part. We will distinguish two cases : - if the Tag is a
+     * Primitive one, we will get the value. - if the Tag is a Constructed one,
+     * nothing will be done.
+     * 
+     * @param stream The ByteBuffer containing the PDU to decode
+     * @param container The container that stores the current state,
+     * the result and other informations.
+     * @return <code>true</code> if there are more bytes to read, <code>false
+     * </code> otherwise
+     */
+    private boolean treatValueStartState( ByteBuffer stream, Asn1Container container )
+    {
+        TLV currentTlv = container.getCurrentTLV();
+
+        if ( TLV.isConstructed( currentTlv.getTag() ) && !container.isGathering() )
+        {
+            container.setState( TLVStateEnum.TLV_STATE_DONE );
+
+            return MORE;
+        }
+        else
+        {
+            int length = currentTlv.getLength();
+            int nbBytes = stream.remaining();
+
+            if ( nbBytes < length )
+            {
+                currentTlv.getValue().init( length );
+                currentTlv.getValue().setData( stream );
+                container.setState( TLVStateEnum.VALUE_STATE_PENDING );
+
+                return END;
+            }
+            else
+            {
+                currentTlv.getValue().init( length );
+                stream.get( currentTlv.getValue().getData(), 0, length );
+                container.setState( TLVStateEnum.TLV_STATE_DONE );
+
+                return MORE;
+            }
+        }
+    }
+
+
+    /**
+     * Treat a pending Value when we get more bytes in the buffer.
+     * 
+     * @param stream The ByteBuffer containing the PDU to decode
+     * @param container The container that stores the current state,
+     * the result and other informations.
+     * @return <code>MORE</code> if some bytes remain in the buffer when the
+     * value has been decoded, <code>END</code> if whe still need to get some
+     * more bytes.
+     */
+    private boolean treatValuePendingState( ByteBuffer stream, Asn1Container container )
+    {
+        TLV currentTlv = container.getCurrentTLV();
+
+        int length = currentTlv.getLength();
+        int currentLength = currentTlv.getValue().getCurrentLength();
+        int nbBytes = stream.remaining();
+
+        if ( ( currentLength + nbBytes ) < length )
+        {
+            currentTlv.getValue().addData( stream );
+            container.setState( TLVStateEnum.VALUE_STATE_PENDING );
+
+            return END;
+        }
+        else
+        {
+            int remaining = length - currentLength;
+            byte[] data = new byte[remaining];
+            stream.get( data, 0, remaining );
+            currentTlv.getValue().addData( data );
+            container.setState( TLVStateEnum.TLV_STATE_DONE );
+
+            return MORE;
+        }
+    }
+
+
+    /**
+     * When the TLV has been fully decoded, we have to execute the associated
+     * action and switch to the next TLV, which will start with a Tag.
+     * 
+     * @param stream The ByteBuffer containing the PDU to decode
+     * @param container The container that stores the current state,
+     * the result and other informations.
+     * @return <code>true</code> if there are more bytes to read, <code>false
+     * </code> otherwise
+     * @throws DecoderException Thrown if anything went wrong
+     */
+    @SuppressWarnings("unchecked")
+    private boolean treatTLVDoneState( ByteBuffer stream, Asn1Container container ) throws DecoderException
+    {
+        if ( IS_DEBUG )
+        {
+            dumpTLVTree( container );
+        }
+
+        // First, we have to execute the associated action
+        container.getGrammar().executeAction( container );
+
+        // Check if the PDU has been fully decoded.
+        if ( isTLVDecoded( container ) )
+        {
+            if ( container.getState() == TLVStateEnum.GRAMMAR_END )
+            {
+                // Change the state to DECODED
+                container.setState( TLVStateEnum.PDU_DECODED );
+            }
+            else
+            {
+                if ( container.isGrammarEndAllowed() )
+                {
+                    // Change the state to DECODED
+                    container.setState( TLVStateEnum.PDU_DECODED );
+                }
+                else
+                {
+                    LOG.error( I18n.err( I18n.ERR_00009_MORE_TLV_EXPECTED ) );
+                    throw new DecoderException( I18n.err( I18n.ERR_00010_TRUNCATED_PDU ) );
+                }
+            }
+        }
+        else
+        {
+            // Then we switch to the Start tag state and free the current TLV
+            container.setState( TLVStateEnum.TAG_STATE_START );
+        }
+
+        return stream.hasRemaining();
+    }
+
+
+    /**
+     * The decoder main function. This is where we read bytes from the stream
+     * and go through the automaton. It's an inifnite loop which stop when no
+     * more bytes are to be read. It can occurs if the ByteBuffer is exhausted
+     * or if the PDU has been fully decoded.
+     * 
+     * @param stream The ByteBuffer containing the PDU to decode
+     * @param container The container that store the state, the result
+     * and other elements.
+     * @throws DecoderException Thrown if anything went wrong!
+     */
+    public void decode( ByteBuffer stream, Asn1Container container ) throws DecoderException
+    {
+        /*
+         * We have to deal with the current state. This is an infinite loop,
+         * which will stop for any of these reasons :
+         * - STATE_END has been reached (hopefully, the most frequent case)
+         * - buffer is empty (it could happen)
+         * - STATE_OVERFLOW : bad situation ! The PDU may be a
+         * malevolous hand crafted ones, that try to "kill" our decoder. We
+         * must log it with all information to track back this case, and punish
+         * the guilty !
+         */
+        boolean hasRemaining = stream.hasRemaining();
+
+        // Increment the PDU size counter.
+        container.incrementDecodedBytes( stream.remaining() );
+
+        if ( container.getDecodedBytes() > container.getMaxPDUSize() )
+        {
+            String message = I18n.err( I18n.ERR_00042_PDU_SIZE_TOO_LONG, container.getDecodedBytes(), container
+                .getMaxPDUSize() );
+            LOG.error( message );
+            throw new DecoderException( message );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( ">>>==========================================" );
+            LOG.debug( "--> Decoding a PDU" );
+            LOG.debug( ">>>------------------------------------------" );
+        }
+
+        while ( hasRemaining )
+        {
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "--- State = {} ---", container.getState() );
+
+                if ( stream.hasRemaining() )
+                {
+                    byte octet = stream.get( stream.position() );
+
+                    LOG.debug( "  current byte : {}", Asn1StringUtils.dumpByte( octet ) );
+                }
+                else
+                {
+                    LOG.debug( "  no more byte to decode in the stream" );
+                }
+            }
+
+            switch ( container.getState() )
+            {
+                case TAG_STATE_START:
+                    // Reset the GrammarEnd flag first
+                    container.setGrammarEndAllowed( false );
+                    hasRemaining = treatTagStartState( stream, container );
+
+                    break;
+
+                case LENGTH_STATE_START:
+                    hasRemaining = treatLengthStartState( stream, container );
+
+                    break;
+
+                case LENGTH_STATE_PENDING:
+                    hasRemaining = treatLengthPendingState( stream, container );
+
+                    break;
+
+                case LENGTH_STATE_END:
+                    treatLengthEndState( container );
+
+                    break;
+
+                case VALUE_STATE_START:
+                    hasRemaining = treatValueStartState( stream, container );
+
+                    break;
+
+                case VALUE_STATE_PENDING:
+                    hasRemaining = treatValuePendingState( stream, container );
+
+                    break;
+
+                case VALUE_STATE_END:
+                    hasRemaining = stream.hasRemaining();
+
+                    // Nothing to do. We will never reach this state
+                    break;
+
+                case TLV_STATE_DONE:
+                    hasRemaining = treatTLVDoneState( stream, container );
+
+                    break;
+
+                case PDU_DECODED:
+                    // We have to deal with the case where there are
+                    // more bytes in the buffer, but the PDU has been decoded.
+                    if ( LOG.isDebugEnabled() )
+                    {
+                        LOG.debug( I18n.err( I18n.ERR_00043_REMAINING_BYTES_FOR_DECODED_PDU ) );
+                    }
+
+                    hasRemaining = false;
+
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "<<<------------------------------------------" );
+
+            if ( container.getState() == TLVStateEnum.PDU_DECODED )
+            {
+                if ( container.getCurrentTLV() != null )
+                {
+                    LOG.debug( "<-- Stop decoding : {}", container.getCurrentTLV().toString() );
+                }
+                else
+                {
+                    LOG.debug( "<-- Stop decoding : null current TLV" );
+                }
+            }
+            else
+            {
+                if ( container.getCurrentTLV() != null )
+                {
+                    LOG.debug( "<-- End decoding : {}", container.getCurrentTLV().toString() );
+                }
+                else
+                {
+                    LOG.debug( "<-- End decoding : null current TLV" );
+                }
+            }
+
+            LOG.debug( "<<<==========================================" );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getMaxLengthLength()
+    {
+        return maxLengthLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getMaxTagLength()
+    {
+        return maxTagLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void disallowIndefiniteLength()
+    {
+        this.indefiniteLengthAllowed = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void allowIndefiniteLength()
+    {
+        this.indefiniteLengthAllowed = true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isIndefiniteLengthAllowed()
+    {
+
+        return indefiniteLengthAllowed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMaxLengthLength( int maxLengthLength ) throws DecoderException
+    {
+        if ( ( this.indefiniteLengthAllowed ) && ( maxLengthLength > 126 ) )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_00011_LENGTH_TOO_LONG_FOR_DEFINITE_FORM ) );
+        }
+
+        this.maxLengthLength = maxLengthLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMaxTagLength( int maxTagLength )
+    {
+        this.maxTagLength = maxTagLength;
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/AbstractGrammar.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/AbstractGrammar.java
new file mode 100644
index 0000000..ee04c27
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/AbstractGrammar.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber.grammar;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.util.Asn1StringUtils;
+import org.apache.directory.api.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The abstract Grammar which is the Mother of all the grammars. It contains
+ * the transitions table.
+ *
+ * @param C The container type
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractGrammar<C extends Asn1Container> implements Grammar<C>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AbstractGrammar.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /**
+     * Table of transitions. It's a two dimension array, the first dimension
+     * indices the states, the second dimension indices the Tag value, so it is
+     * 256 wide.
+     */
+    protected GrammarTransition<C>[][] transitions;
+
+    /** The grammar name */
+    private String name;
+
+
+    /** Default constructor */
+    public AbstractGrammar()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Get the transition associated with the state and tag
+     *
+     * @param state The current state
+     * @param tag The current tag
+     * @return A valid transition if any, or null.
+     */
+    public GrammarTransition<C> getTransition( Enum<?> state, int tag )
+    {
+        return transitions[state.ordinal()][tag & 0x00FF];
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void executeAction( C container ) throws DecoderException
+    {
+
+        Enum<?> currentState = container.getTransition();
+        // We have to deal with the special case of a GRAMMAR_END state
+        if ( ( ( States ) currentState ).isEndState() )
+        {
+            return;
+        }
+
+        byte tagByte = container.getCurrentTLV().getTag();
+
+        // We will loop until no more actions are to be executed
+        @SuppressWarnings("unchecked")
+        GrammarTransition<C> transition = ( ( AbstractGrammar<C> ) container.getGrammar() ).getTransition(
+            currentState,
+            tagByte );
+
+        if ( transition == null )
+        {
+            String errorMessage = I18n.err( I18n.ERR_00001_BAD_TRANSITION_FROM_STATE, currentState,
+                Asn1StringUtils.dumpByte( tagByte ) );
+
+            LOG.error( errorMessage );
+
+            // If we have no more grammar on the stack, then this is an
+            // error
+            throw new DecoderException( errorMessage );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( transition.toString() );
+        }
+
+        if ( transition.hasAction() )
+        {
+            Action<C> action = transition.getAction();
+            action.action( container );
+        }
+
+        container.setTransition( transition.getCurrentState() );
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/Action.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/Action.java
new file mode 100644
index 0000000..0e6bf95
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/Action.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1.ber.grammar;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+
+
+/**
+ * Action interface just contains the method 'action' which must be implemented
+ * in all the implementing classes.
+ * 
+ * @param C The container type
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Action<C extends Asn1Container>
+{
+    /**
+     * The action to be executed.
+     * 
+     * @param container The container which stores the current data
+     * @throws DecoderException Thrown if something went wrong.
+     */
+    void action( C container ) throws DecoderException;
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/Grammar.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/Grammar.java
new file mode 100644
index 0000000..b2157dd
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/Grammar.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber.grammar;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+
+
+/**
+ * The interface which expose common behavior of a Grammar implementer.
+ *
+ * @param C The container type
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Grammar<C extends Asn1Container>
+{
+    /**
+     * This method, when called, execute an action on the current data stored in
+     * the container.
+     *
+     * @param asn1Container Store the data being processed.
+     * @throws DecoderException Thrown when an unrecoverable error occurs.
+     */
+    void executeAction( C asn1Container ) throws DecoderException;
+
+
+    /**
+     * Get the grammar name
+     *
+     * @return Return the grammar's name
+     */
+    String getName();
+
+
+    /**
+     * Set the grammar's name
+     *
+     * @param name The grammar name
+     */
+    void setName( String name );
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/GrammarAction.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/GrammarAction.java
new file mode 100644
index 0000000..a0e9044
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/GrammarAction.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1.ber.grammar;
+
+
+import org.apache.directory.api.asn1.ber.Asn1Container;
+
+
+/**
+ * A top level grammar class that store meta informations about the actions.
+ * Those informations are not mandatory, but they can be useful for debugging.
+ * 
+ * @param C The container type
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class GrammarAction<C extends Asn1Container> implements Action<C>
+{
+    /** The action's name */
+    protected String name;
+
+
+    /** A default constructor */
+    public GrammarAction()
+    {
+    }
+
+
+    /**
+     * Creates a new GrammarAction object.
+     * 
+     * @param name The name of the grammar action
+     */
+    public GrammarAction( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Prints the action's name
+     * 
+     * @return The action's name
+     */
+    public String toString()
+    {
+        return name;
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/GrammarTransition.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/GrammarTransition.java
new file mode 100644
index 0000000..848ae23
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/GrammarTransition.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber.grammar;
+
+
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.asn1.util.Asn1StringUtils;
+
+
+/**
+ * Define a transition between two states of a grammar. It stores the next
+ * state, and the action to execute while executing the transition.
+ * 
+ * @param C The container type
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GrammarTransition<C extends Asn1Container>
+{
+    /** The action associated to the transition */
+    private Action<C> action;
+
+    /** The previous state */
+    private Enum<?> previousState;
+
+    /** The current state */
+    private Enum<?> currentState;
+
+    /** The current tag */
+    private int currentTag;
+
+
+    /**
+     * Creates a new GrammarTransition object.
+     *
+     * @param previousState the previous state
+     * @param currentState The current state
+     * @param currentTag the current TLV's tag
+     * @param action The action to execute. It could be null.
+     */
+    public GrammarTransition( Enum<?> previousState, Enum<?> currentState, int currentTag, Action<C> action )
+    {
+        this.previousState = previousState;
+        this.currentState = currentState;
+        this.action = action;
+        this.currentTag = currentTag;
+    }
+
+
+    /**
+     * Creates a new GrammarTransition object.
+     *
+     * @param previousState the previous state
+     * @param currentState The current state
+     * @param currentTag the current TLV's tag
+     */
+    public GrammarTransition( Enum<?> previousState, Enum<?> currentState, int currentTag )
+    {
+        this.previousState = previousState;
+        this.currentState = currentState;
+        this.currentTag = currentTag;
+    }
+
+
+    /**
+     * Creates a new GrammarTransition object.
+     *
+     * @param previousState the previous state
+     * @param currentState The current state
+     * @param currentTag the current TLV's tag
+     * @param action The action to execute. It could be null.
+     */
+    public GrammarTransition( Enum<?> previousState, Enum<?> currentState, UniversalTag currentTag, Action<C> action )
+    {
+        this.previousState = previousState;
+        this.currentState = currentState;
+        this.action = action;
+        this.currentTag = currentTag.getValue();
+    }
+
+
+    /**
+     * Creates a new GrammarTransition object.
+     *
+     * @param previousState the previous state
+     * @param currentState The current state
+     * @param currentTag the current TLV's tag
+     */
+    public GrammarTransition( Enum<?> previousState, Enum<?> currentState, UniversalTag currentTag )
+    {
+        this.previousState = previousState;
+        this.currentState = currentState;
+        this.currentTag = currentTag.getValue();
+    }
+
+
+    /**
+     * Tells if the transition has an associated action.
+     *
+     * @return <code>true</code> if an action has been associated to the transition
+     */
+    public boolean hasAction()
+    {
+        return action != null;
+    }
+
+
+    /**
+     * @return Returns the action associated with the transition
+     */
+    public Action<C> getAction()
+    {
+        return action;
+    }
+
+
+    /**
+     * @return The current state
+     */
+    public Enum<?> getCurrentState()
+    {
+        return currentState;
+    }
+
+
+    /**
+     * @return The previous state
+     */
+    public Enum<?> getPreviousState()
+    {
+        return previousState;
+    }
+
+
+    /**
+     * @return A representation of the transition as a string.
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "Transition from state <" ).append( previousState ).append( "> " );
+        sb.append( "to state <" ).append( currentState ).append( ">, " );
+        sb.append( "tag <" ).append( Asn1StringUtils.dumpByte( ( byte ) currentTag ) ).append( ">, " );
+        sb.append( "action : " );
+
+        if ( action == null )
+        {
+            sb.append( "no action" );
+        }
+        else
+        {
+            sb.append( action );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/States.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/States.java
new file mode 100644
index 0000000..2fdd0fd
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/grammar/States.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.asn1.ber.grammar;
+
+
+/**
+ * Interface to get custom function from enum when casting.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface States
+{
+    /**
+     * @return True if this is the END_STATE
+     */
+    boolean isEndState();
+
+
+    /**
+     * @return The START_STATE of the enum
+     */
+    Enum<?> getStartState();
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BerValue.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BerValue.java
new file mode 100644
index 0000000..aefbe82
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BerValue.java
@@ -0,0 +1,936 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.util.Asn1StringUtils;
+import org.apache.directory.api.asn1.util.BitString;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * This class stores the data decoded from a TLV.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BerValue
+{
+    /** The data buffer. */
+    private byte[] data;
+
+    /** The current position of the last byte in the data buffer */
+    private int currentPos;
+
+    /** The encoded byte for a TRUE value */
+    public static final byte TRUE_VALUE = ( byte ) 0xFF;
+
+    /** The encoded byte for a FALSE value */
+    public static final byte FALSE_VALUE = ( byte ) 0x00;
+
+    /** Pre-encoded PDUs for a TRUE TLV */
+    private static final byte[] ENCODED_TRUE = new byte[]
+        { 0x01, 0x01, TRUE_VALUE };
+
+    /** Pre-encoded PDUs for a FALSE TLV */
+    private static final byte[] ENCODED_FALSE = new byte[]
+        { 0x01, 0x01, FALSE_VALUE };
+
+    /** Integer limits for encoding : 0x7F */
+    private static final int ONE_BYTE_MAX = ( 1 << 7 ) - 1;
+
+    /** Integer limits for encoding : -0x7F */
+    private static final int ONE_BYTE_MIN = -( 1 << 7 );
+
+    /** Integer limits for encoding : 0x7FFF */
+    private static final int TWO_BYTE_MAX = ( 1 << 15 ) - 1;
+
+    /** Integer limits for encoding : -0x7FFF */
+    private static final int TWO_BYTE_MIN = -( 1 << 15 );
+
+    /** Integer limits for encoding : 0x7FFFFF */
+    private static final int THREE_BYTE_MAX = ( 1 << 23 ) - 1;
+
+    /** Integer limits for encoding : -0x7FFFFF */
+    private static final int THREE_BYTE_MIN = -( 1 << 23 );
+
+    /** Integer limits for encoding : 0x7FFFFFFF */
+    private static final long FOUR_BYTE_MAX = ( 1L << 31 ) - 1L;
+
+    /** Integer limits for encoding : -0x7FFFFFFF */
+    private static final long FOUR_BYTE_MIN = -( 1L << 31 );
+
+    /** Integer limits for encoding : 0x7FFFFFFFFF */
+    private static final long FIVE_BYTE_MAX = ( 1L << 39 ) - 1L;
+
+    /** Integer limits for encoding : -0x7FFFFFFFFF */
+    private static final long FIVE_BYTE_MIN = -( 1L << 39 );
+
+    /** Integer limits for encoding : 0x7FFFFFFFFFFF */
+    private static final long SIX_BYTE_MAX = ( 1L << 47 ) - 1L;
+
+    /** Integer limits for encoding : -0x7FFFFFFFFFFF */
+    private static final long SIX_BYTE_MIN = -( 1L << 47 );
+
+    /** Integer limits for encoding : 0x7FFFFFFFFFFF */
+    private static final long SEVEN_BYTE_MAX = ( 1L << 55 ) - 1L;
+
+    /** Integer limits for encoding : -0x7FFFFFFFFFFF */
+    private static final long SEVEN_BYTE_MIN = -( 1L << 55 );
+
+
+    /**
+     * Creates a new Value from a byte[]
+     *
+     * @param value the associated value
+     */
+    public BerValue( byte[] value )
+    {
+        // Do a copy of the byte array
+        data = new byte[value.length];
+        System.arraycopy( value, 0, data, 0, value.length );
+        currentPos = 0;
+    }
+
+
+    /**
+     * The default constructor.
+     */
+    public BerValue()
+    {
+        data = null;
+        currentPos = 0;
+    }
+
+
+    /**
+     * Initialize the Value
+     *
+     * @param size The data size to allocate.
+     */
+    public void init( int size )
+    {
+        data = new byte[size];
+        currentPos = 0;
+    }
+
+
+    /**
+     * Reset the Value so that it can be reused
+     */
+    public void reset()
+    {
+        data = null;
+        currentPos = 0;
+    }
+
+
+    /**
+     * Get the Values'data
+     *
+     * @return Returns the data.
+     */
+    public byte[] getData()
+    {
+        return data;
+    }
+
+
+    /**
+     * Set a block of bytes in the Value
+     *
+     * @param data The data to set.
+     */
+    public void setData( ByteBuffer data )
+    {
+        int length = data.remaining();
+        data.get( this.data, 0, length );
+        currentPos = length;
+    }
+
+
+    /**
+     * Append some bytes to the data buffer.
+     *
+     * @param buffer The data to append.
+     */
+    public void addData( ByteBuffer buffer )
+    {
+        int length = buffer.remaining();
+        buffer.get( data, currentPos, length );
+        currentPos += length;
+    }
+
+
+    /**
+     * Set a block of bytes in the Value
+     *
+     * @param data The data to set.
+     */
+    public void setData( byte[] data )
+    {
+        System.arraycopy( data, 0, this.data, 0, data.length );
+        currentPos = data.length;
+    }
+
+
+    /**
+     * Append some bytes to the data buffer.
+     *
+     * @param array The data to append.
+     */
+    public void addData( byte[] array )
+    {
+        System.arraycopy( array, 0, this.data, currentPos, array.length );
+        currentPos = array.length;
+    }
+
+
+    /**
+     * @return The number of bytes actually stored
+     */
+    public int getCurrentLength()
+    {
+        return currentPos;
+    }
+
+
+    /**
+     * Utility function that return the number of bytes necessary to store an
+     * integer value. Note that this value must be in [Integer.MIN_VALUE,
+     * Integer.MAX_VALUE].
+     *
+     * @param value The value to store in a byte array
+     * @return The number of bytes necessary to store the value.
+     */
+    public static int getNbBytes( int value )
+    {
+        if ( ( value >= ONE_BYTE_MIN ) && ( value <= ONE_BYTE_MAX ) )
+        {
+            return 1;
+        }
+        else if ( ( value >= TWO_BYTE_MIN ) && ( value <= TWO_BYTE_MAX ) )
+        {
+            return 2;
+        }
+        else if ( ( value >= THREE_BYTE_MIN ) && ( value <= THREE_BYTE_MAX ) )
+        {
+            return 3;
+        }
+        else
+        {
+            return 4;
+        }
+    }
+
+
+    /**
+     * Utility function that return the number of bytes necessary to store a
+     * long value. Note that this value must be in [Long.MIN_VALUE,
+     * Long.MAX_VALUE].
+     *
+     * @param value The value to store in a byte array
+     * @return The number of bytes necessary to store the value.
+     */
+    public static int getNbBytes( long value )
+    {
+        if ( ( value >= ONE_BYTE_MIN ) && ( value <= ONE_BYTE_MAX ) )
+        {
+            return 1;
+        }
+        else if ( ( value >= TWO_BYTE_MIN ) && ( value <= TWO_BYTE_MAX ) )
+        {
+            return 2;
+        }
+        else if ( ( value >= THREE_BYTE_MIN ) && ( value <= THREE_BYTE_MAX ) )
+        {
+            return 3;
+        }
+        else if ( ( value >= FOUR_BYTE_MIN ) && ( value <= FOUR_BYTE_MAX ) )
+        {
+            return 4;
+        }
+        else if ( ( value >= FIVE_BYTE_MIN ) && ( value <= FIVE_BYTE_MAX ) )
+        {
+            return 5;
+        }
+        else if ( ( value >= SIX_BYTE_MIN ) && ( value <= SIX_BYTE_MAX ) )
+        {
+            return 6;
+        }
+        else if ( ( value >= SEVEN_BYTE_MIN ) && ( value <= SEVEN_BYTE_MAX ) )
+        {
+            return 7;
+        }
+        else
+        {
+            return 8;
+        }
+    }
+
+
+    /**
+     * Utility function that return a byte array representing the Value We must
+     * respect the ASN.1 BER encoding scheme :
+     * <pre>
+     * 1) positive integer
+     * - [0 - 0x7F] : 0xVV
+     * - [0x80 - 0xFF] : 0x00 0xVV
+     * - [0x0100 - 0x7FFF] : 0xVV 0xVV
+     * - [0x8000 - 0xFFFF] : 0x00 0xVV 0xVV
+     * - [0x010000 - 0x7FFFFF] : 0xVV 0xVV 0xVV
+     * - [0x800000 - 0xFFFFFF] : 0x00 0xVV 0xVV 0xVV
+     * - [0x01000000 - 0x7FFFFFFF] : 0xVV 0xVV 0xVV 0xVV
+     * 2) Negative number - (~value) + 1
+     * </pre>
+     *
+     * @param value The value to store in a byte array
+     * @return The byte array representing the value.
+     */
+    public static byte[] getBytes( int value )
+    {
+        byte[] bytes = null;
+
+        if ( value >= 0 )
+        {
+            if ( ( value >= 0 ) && ( value <= ONE_BYTE_MAX ) )
+            {
+                bytes = new byte[1];
+                bytes[0] = ( byte ) value;
+            }
+            else if ( ( value > ONE_BYTE_MAX ) && ( value <= TWO_BYTE_MAX ) )
+            {
+                bytes = new byte[2];
+                bytes[1] = ( byte ) value;
+                bytes[0] = ( byte ) ( value >> 8 );
+            }
+            else if ( ( value > TWO_BYTE_MAX ) && ( value <= THREE_BYTE_MAX ) )
+            {
+                bytes = new byte[3];
+                bytes[2] = ( byte ) value;
+                bytes[1] = ( byte ) ( value >> 8 );
+                bytes[0] = ( byte ) ( value >> 16 );
+            }
+            else
+            {
+                bytes = new byte[4];
+                bytes[3] = ( byte ) value;
+                bytes[2] = ( byte ) ( value >> 8 );
+                bytes[1] = ( byte ) ( value >> 16 );
+                bytes[0] = ( byte ) ( value >> 24 );
+            }
+        }
+        else
+        {
+            // On special case : 0x80000000
+            if ( value == 0x80000000 )
+            {
+                bytes = new byte[4];
+                bytes[3] = ( byte ) value;
+                bytes[2] = ( byte ) ( value >> 8 );
+                bytes[1] = ( byte ) ( value >> 16 );
+                bytes[0] = ( byte ) ( value >> 24 );
+            }
+            else
+            {
+                // We have to compute the complement, and add 1
+                //value = ( ~value ) + 1;
+
+                if ( value >= 0xFFFFFF80 )
+                {
+                    bytes = new byte[1];
+                    bytes[0] = ( byte ) value;
+                }
+                else if ( value >= 0xFFFF8000 )
+                {
+                    bytes = new byte[2];
+                    bytes[1] = ( byte ) ( value );
+                    bytes[0] = ( byte ) ( value >> 8 );
+                }
+                else if ( value >= 0xFF800000 )
+                {
+                    bytes = new byte[3];
+                    bytes[2] = ( byte ) value;
+                    bytes[1] = ( byte ) ( value >> 8 );
+                    bytes[0] = ( byte ) ( value >> 16 );
+                }
+                else
+                {
+                    bytes = new byte[4];
+                    bytes[3] = ( byte ) value;
+                    bytes[2] = ( byte ) ( value >> 8 );
+                    bytes[1] = ( byte ) ( value >> 16 );
+                    bytes[0] = ( byte ) ( value >> 24 );
+                }
+            }
+        }
+
+        return bytes;
+    }
+
+
+    /**
+     * Utility function that return a byte array representing the Value.
+     * We must respect the ASN.1 BER encoding scheme : <br>
+     * <pre>
+     * 1) positive integer
+     * - [0 - 0x7F] : 0xVV
+     * - [0x80 - 0xFF] : 0x00 0xVV
+     * - [0x0100 - 0x7FFF] : 0xVV 0xVV
+     * - [0x8000 - 0xFFFF] : 0x00 0xVV 0xVV
+     * - [0x010000 - 0x7FFFFF] : 0xVV 0xVV 0xVV
+     * - [0x800000 - 0xFFFFFF] : 0x00 0xVV 0xVV 0xVV
+     * - [0x01000000 - 0x7FFFFFFF] : 0xVV 0xVV 0xVV 0xVV
+     * 2) Negative number - (~value) + 1
+     * <pre>
+     * They are encoded following the table (the <br>
+     * encode bytes are those enclosed by squared braquets) :<br>
+     * <br>
+     * <pre>
+     *   -1                      -> FF FF FF FF FF FF FF [FF]
+     *   -127                    -> FF FF FF FF FF FF FF [81]
+     *   -128                    -> FF FF FF FF FF FF FF [80]
+     *   -129                    -> FF FF FF FF FF FF [FF 7F]
+     *   -255                    -> FF FF FF FF FF FF [FF 01]
+     *   -256                    -> FF FF FF FF FF FF [FF 00]
+     *   -257                    -> FF FF FF FF FF FF [FE FF]
+     *   -32767                  -> FF FF FF FF FF FF [80 01]
+     *   -32768                  -> FF FF FF FF FF FF [80 00]
+     *   -32769                  -> FF FF FF FF FF [FF 7F FF]
+     *   -65535                  -> FF FF FF FF FF [FF 00 01]
+     *   -65536                  -> FF FF FF FF FF [FF 00 00]
+     *   -65537                  -> FF FF FF FF FF [FE FF FF]
+     *   -8388607                -> FF FF FF FF FF [80 00 01]
+     *   -8388608                -> FF FF FF FF FF [80 00 00]
+     *   -8388609                -> FF FF FF FF [FF 7F FF FF]
+     *   -16777215               -> FF FF FF FF [FF 00 00 01]
+     *   -16777216               -> FF FF FF FF [FF 00 00 00]
+     *   -16777217               -> FF FF FF FF [FE FF FF FF]
+     *   -2147483647             -> FF FF FF FF [80 00 00 01]
+     *   -2147483648             -> FF FF FF FF [80 00 00 00]
+     *   -2147483649             -> FF FF FF [FF 7F FF FF FF]
+     *   -4294967295             -> FF FF FF [FF 00 00 00 01]
+     *   -4294967296             -> FF FF FF [FF 00 00 00 00]
+     *   -4294967297             -> FF FF FF [FE FF FF FF FF]
+     *   -549755813887           -> FF FF FF [80 00 00 00 01]
+     *   -549755813888           -> FF FF FF [80 00 00 00 00]
+     *   -549755813889           -> FF FF [FF 7F FF FF FF FF]
+     *   -1099511627775          -> FF FF [FF 00 00 00 00 01]
+     *   -1099511627776          -> FF FF [FF 00 00 00 00 00]
+     *   -1099511627777          -> FF FF [FE FF FF FF FF FF]
+     *   -140737488355327        -> FF FF [80 00 00 00 00 01]
+     *   -140737488355328        -> FF FF [80 00 00 00 00 00]
+     *   -140737488355329        -> FF [FF 7F FF FF FF FF FF]
+     *   -281474976710655        -> FF [FF 00 00 00 00 00 01]
+     *   -281474976710656        -> FF [FF 00 00 00 00 00 00]
+     *   -281474976710657        -> FF [FE FF FF FF FF FF FF]
+     *   -36028797018963967      -> FF [80 00 00 00 00 00 01]
+     *   -36028797018963968      -> FF [80 00 00 00 00 00 00]
+     *   -36028797018963969      -> [FF 7F FF FF FF FF FF FF]
+     *   -72057594037927936      -> [FF 00 00 00 00 00 00 00]
+     *   -72057594037927937      -> [FE FF FF FF FF FF FF FF]
+     *   -9223372036854775807    -> [80 00 00 00 00 00 00 01]
+     *   -9223372036854775808    -> [80 00 00 00 00 00 00 00]
+     * </pre>
+     * @param value The value to store in a byte array
+     * @return The byte array representing the value.
+     */
+    public static byte[] getBytes( long value )
+    {
+        byte[] bytes = null;
+
+        if ( value >= 0 )
+        {
+            if ( ( value >= 0 ) && ( value <= ONE_BYTE_MAX ) )
+            {
+                bytes = new byte[1];
+                bytes[0] = ( byte ) value;
+            }
+            else if ( ( value > ONE_BYTE_MAX ) && ( value <= TWO_BYTE_MAX ) )
+            {
+                bytes = new byte[2];
+                bytes[1] = ( byte ) value;
+                bytes[0] = ( byte ) ( value >> 8 );
+            }
+            else if ( ( value > TWO_BYTE_MAX ) && ( value <= THREE_BYTE_MAX ) )
+            {
+                bytes = new byte[3];
+                bytes[2] = ( byte ) value;
+                bytes[1] = ( byte ) ( value >> 8 );
+                bytes[0] = ( byte ) ( value >> 16 );
+            }
+            else if ( ( value > THREE_BYTE_MAX ) && ( value <= FOUR_BYTE_MAX ) )
+            {
+                bytes = new byte[4];
+                bytes[3] = ( byte ) value;
+                bytes[2] = ( byte ) ( value >> 8 );
+                bytes[1] = ( byte ) ( value >> 16 );
+                bytes[0] = ( byte ) ( value >> 24 );
+            }
+            else if ( ( value > FOUR_BYTE_MAX ) && ( value <= FIVE_BYTE_MAX ) )
+            {
+                bytes = new byte[5];
+                bytes[4] = ( byte ) value;
+                bytes[3] = ( byte ) ( value >> 8 );
+                bytes[2] = ( byte ) ( value >> 16 );
+                bytes[1] = ( byte ) ( value >> 24 );
+                bytes[0] = ( byte ) ( value >> 32 );
+            }
+            else if ( ( value > FIVE_BYTE_MAX ) && ( value <= SIX_BYTE_MAX ) )
+            {
+                bytes = new byte[6];
+                bytes[5] = ( byte ) value;
+                bytes[4] = ( byte ) ( value >> 8 );
+                bytes[3] = ( byte ) ( value >> 16 );
+                bytes[2] = ( byte ) ( value >> 24 );
+                bytes[1] = ( byte ) ( value >> 32 );
+                bytes[0] = ( byte ) ( value >> 40 );
+            }
+            else if ( ( value > SIX_BYTE_MAX ) && ( value <= SEVEN_BYTE_MAX ) )
+            {
+                bytes = new byte[7];
+                bytes[6] = ( byte ) value;
+                bytes[5] = ( byte ) ( value >> 8 );
+                bytes[4] = ( byte ) ( value >> 16 );
+                bytes[3] = ( byte ) ( value >> 24 );
+                bytes[2] = ( byte ) ( value >> 32 );
+                bytes[1] = ( byte ) ( value >> 40 );
+                bytes[0] = ( byte ) ( value >> 48 );
+            }
+            else
+            {
+                bytes = new byte[8];
+                bytes[7] = ( byte ) value;
+                bytes[6] = ( byte ) ( value >> 8 );
+                bytes[5] = ( byte ) ( value >> 16 );
+                bytes[4] = ( byte ) ( value >> 24 );
+                bytes[3] = ( byte ) ( value >> 32 );
+                bytes[2] = ( byte ) ( value >> 40 );
+                bytes[1] = ( byte ) ( value >> 48 );
+                bytes[0] = ( byte ) ( value >> 56 );
+            }
+        }
+        else
+        {
+            // On special case : 0x80000000
+            if ( value == 0x8000000000000000L )
+            {
+                bytes = new byte[8];
+                bytes[7] = ( byte ) 0x00;
+                bytes[6] = ( byte ) 0x00;
+                bytes[5] = ( byte ) 0x00;
+                bytes[4] = ( byte ) 0x00;
+                bytes[3] = ( byte ) 0x00;
+                bytes[2] = ( byte ) 0x00;
+                bytes[1] = ( byte ) 0x00;
+                bytes[0] = ( byte ) 0x80;
+            }
+            else
+            {
+                // We have to compute the complement, and add 1
+                // value = ( ~value ) + 1;
+
+                if ( value >= 0xFFFFFFFFFFFFFF80L )
+                {
+                    bytes = new byte[1];
+                    bytes[0] = ( byte ) value;
+                }
+                else if ( value >= 0xFFFFFFFFFFFF8000L )
+                {
+                    bytes = new byte[2];
+                    bytes[1] = ( byte ) ( value );
+                    bytes[0] = ( byte ) ( value >> 8 );
+                }
+                else if ( value >= 0xFFFFFFFFFF800000L )
+                {
+                    bytes = new byte[3];
+                    bytes[2] = ( byte ) value;
+                    bytes[1] = ( byte ) ( value >> 8 );
+                    bytes[0] = ( byte ) ( value >> 16 );
+                }
+                else if ( value >= 0xFFFFFFFF80000000L )
+                {
+                    bytes = new byte[4];
+                    bytes[3] = ( byte ) value;
+                    bytes[2] = ( byte ) ( value >> 8 );
+                    bytes[1] = ( byte ) ( value >> 16 );
+                    bytes[0] = ( byte ) ( value >> 24 );
+                }
+                else if ( value >= 0xFFFFFF8000000000L )
+                {
+                    bytes = new byte[5];
+                    bytes[4] = ( byte ) value;
+                    bytes[3] = ( byte ) ( value >> 8 );
+                    bytes[2] = ( byte ) ( value >> 16 );
+                    bytes[1] = ( byte ) ( value >> 24 );
+                    bytes[0] = ( byte ) ( value >> 32 );
+                }
+                else if ( value >= 0xFFFF800000000000L )
+                {
+                    bytes = new byte[6];
+                    bytes[5] = ( byte ) value;
+                    bytes[4] = ( byte ) ( value >> 8 );
+                    bytes[3] = ( byte ) ( value >> 16 );
+                    bytes[2] = ( byte ) ( value >> 24 );
+                    bytes[1] = ( byte ) ( value >> 32 );
+                    bytes[0] = ( byte ) ( value >> 40 );
+                }
+                else if ( value >= 0xFF80000000000000L )
+                {
+                    bytes = new byte[7];
+                    bytes[6] = ( byte ) value;
+                    bytes[5] = ( byte ) ( value >> 8 );
+                    bytes[4] = ( byte ) ( value >> 16 );
+                    bytes[3] = ( byte ) ( value >> 24 );
+                    bytes[2] = ( byte ) ( value >> 32 );
+                    bytes[1] = ( byte ) ( value >> 40 );
+                    bytes[0] = ( byte ) ( value >> 48 );
+                }
+                else
+                {
+                    bytes = new byte[8];
+                    bytes[7] = ( byte ) value;
+                    bytes[6] = ( byte ) ( value >> 8 );
+                    bytes[5] = ( byte ) ( value >> 16 );
+                    bytes[4] = ( byte ) ( value >> 24 );
+                    bytes[3] = ( byte ) ( value >> 32 );
+                    bytes[2] = ( byte ) ( value >> 40 );
+                    bytes[1] = ( byte ) ( value >> 48 );
+                    bytes[0] = ( byte ) ( value >> 56 );
+                }
+            }
+        }
+
+        return bytes;
+    }
+
+
+    /**
+     * Encode a String value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param string The String to be encoded. It is supposed to be UTF-8
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, String string ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( UniversalTag.OCTET_STRING.getValue() );
+
+            byte[] value = Asn1StringUtils.getBytesUtf8( string );
+
+            buffer.put( TLV.getBytes( value.length ) );
+
+            if ( value.length != 0 )
+            {
+                buffer.put( value );
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode a BIT STRING value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param bitString The BitString to be encoded.
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, BitString bitString ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( UniversalTag.BIT_STRING.getValue() );
+
+            // The BitString length. We add one byte for the unused number
+            // of bits
+            byte[] bytes = bitString.getData();
+            int length = bytes.length;
+
+            buffer.put( TLV.getBytes( length ) );
+            buffer.put( bytes );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode an OctetString value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param bytes The bytes to be encoded
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, byte[] bytes ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( UniversalTag.OCTET_STRING.getValue() );
+
+            if ( ( bytes == null ) || ( bytes.length == 0 ) )
+            {
+                buffer.put( ( byte ) 0 );
+            }
+            else
+            {
+                buffer.put( TLV.getBytes( bytes.length ) );
+                buffer.put( bytes );
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode an OID value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param oid The OID to be encoded
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, Oid oid ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( UniversalTag.OCTET_STRING.getValue() );
+            buffer.put( TLV.getBytes( oid.getEncodedLength() ) );
+
+            if ( oid.getEncodedLength() != 0 )
+            {
+                oid.writeBytesTo( buffer );
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode an integer value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param value The integer to be encoded
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, int value ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( UniversalTag.INTEGER.getValue() );
+            buffer.put( ( byte ) getNbBytes( value ) );
+            buffer.put( getBytes( value ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode a long value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param value The long to be encoded
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, long value ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( UniversalTag.INTEGER.getValue() );
+            buffer.put( ( byte ) getNbBytes( value ) );
+            buffer.put( getBytes( value ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode an integer value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param tag The tag if it's not an UNIVERSAL one
+     * @param value The integer to be encoded
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, byte tag, int value ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( tag );
+            buffer.put( ( byte ) getNbBytes( value ) );
+            buffer.put( getBytes( value ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode an enumerated value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param value The integer to be encoded
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encodeEnumerated( ByteBuffer buffer, int value ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            buffer.put( UniversalTag.ENUMERATED.getValue() );
+            buffer.put( TLV.getBytes( getNbBytes( value ) ) );
+            buffer.put( getBytes( value ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Encode a boolean value
+     *
+     * @param buffer The PDU in which the value will be put
+     * @param bool The boolean to be encoded
+     * @throws EncoderException if the PDU in which the value should be encoded is
+     * two small
+     */
+    public static void encode( ByteBuffer buffer, boolean bool ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER ) );
+        }
+
+        try
+        {
+            if ( bool )
+            {
+                buffer.put( ENCODED_TRUE );
+            }
+            else
+            {
+                buffer.put( ENCODED_FALSE );
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL ), boe );
+        }
+    }
+
+
+    /**
+     * Return a string representing the Value
+     *
+     * @return A string representing the value
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append( "DATA" );
+
+        if ( data != null )
+        {
+            sb.append( '[' );
+            sb.append( Asn1StringUtils.dumpBytes( data ) );
+            sb.append( ']' );
+        }
+        else
+        {
+            return "[]";
+        }
+
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BooleanDecoder.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BooleanDecoder.java
new file mode 100644
index 0000000..2ee8890
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BooleanDecoder.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Parse and decode a Boolean value.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class BooleanDecoder
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( BooleanDecoder.class );
+
+
+    private BooleanDecoder()
+    {
+    }
+
+    /**
+     * Parse a Value containing a byte[] and send back a boolean.
+     *
+     * @param value The Value to parse
+     * @return A boolean.
+     * @throws BooleanDecoderException Thrown if the Value does not contains a boolean
+     */
+    public static boolean parse( BerValue value ) throws BooleanDecoderException
+    {
+        byte[] bytes = value.getData();
+
+        if ( Strings.isEmpty( bytes ) )
+        {
+            throw new BooleanDecoderException( I18n.err( I18n.ERR_00034_0_BYTES_LONG_BOOLEAN ) );
+        }
+
+        if ( bytes.length != 1 )
+        {
+            throw new BooleanDecoderException( I18n.err( I18n.ERR_00035_N_BYTES_LONG_BOOLEAN ) );
+        }
+
+        if ( ( bytes[0] != 0 ) && ( bytes[0] != ( byte ) 0xFF ) )
+        {
+            LOG.warn( "A boolean must be encoded with a 0x00 or a 0xFF value" );
+        }
+
+        return bytes[0] != 0;
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BooleanDecoderException.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BooleanDecoderException.java
new file mode 100644
index 0000000..b761fbd
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BooleanDecoderException.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+/**
+ * Thrown when a BooleanDecoder has encountered a failure condition
+ * during a decode.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BooleanDecoderException extends Exception
+{
+    /** Declares the Serial Version Uid */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a BooleanDecoderException
+     * 
+     * @param message A message with meaning to a human
+     */
+    public BooleanDecoderException( String message )
+    {
+        super( message );
+    }
+
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java
new file mode 100644
index 0000000..153d4e5
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java
@@ -0,0 +1,223 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Parse and decode an Integer value.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class IntegerDecoder
+{
+    /** A mask used to get only the necessary bytes */
+    private static final int[] MASK = new int[]
+        { 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF };
+
+
+    private IntegerDecoder()
+    {
+    }
+
+
+    /**
+     * Parse a byte buffer and send back an integer, controlling that this number
+     * is in a specified interval.
+     *
+     * @param value The Value containing the byte[] to parse
+     * @param min Lowest value allowed, included
+     * @param max Highest value allowed, included
+     * @return An integer
+     * @throws IntegerDecoderException Thrown if the byte[] does not contains an integer
+     */
+    public static int parse( BerValue value, int min, int max ) throws IntegerDecoderException
+    {
+        int result = parseInt( value );
+
+        if ( ( result >= min ) && ( result <= max ) )
+        {
+            return result;
+        }
+        else
+        {
+            throw new IntegerDecoderException( I18n.err( I18n.ERR_00038_VALUE_NOT_IN_RANGE, min, max ) );
+        }
+    }
+
+
+    /**
+     * Parse a byte buffer and send back an integer
+     *
+     * @param value The byte buffer to parse
+     * @return An integer
+     * @throws IntegerDecoderException Thrown if the byte stream does not contains an integer
+     */
+    public static int parse( BerValue value ) throws IntegerDecoderException
+    {
+        return parseInt( value );
+    }
+
+
+    /**
+     * Helper method used to parse the integer. We don't check any minimal or maximal
+     * bound.
+     * An BER encoded int can be either positive or negative. It uses the minimum
+     * number of byts necessary to encode the value. The high order bit gives the
+     * sign of the integer : if it's 1, then it's a negative value, otherwise it's
+     * a positive value. Integer with a high order bit set to 1 but prefixed by a 0x00
+     * are positive. If the integer is negative, then the 2 complement value is
+     * stored<br/>
+     * Here are a few samples :
+     * <ul>
+     * <li>0x02 0x01 0x00 : integer 0</li>
+     * <li>0x02 0x01 0x01 : integer 1</li>
+     * <li>0x02 0x01 0x7F : integer 127</li>
+     * <li>0x02 0x01 0x80 : integer -128</li>
+     * <li>0x02 0x01 0x81 : integer -127</li>
+     * <li>0x02 0x01 0xFF : integer -1</li>
+     * <li>0x02 0x02 0x00 0x80 : integer 128</li>
+     * <li>0x02 0x02 0x00 0x81 : integer 129</li>
+     * <li>0x02 0x02 0x00 0xFF : integer 255</li>
+     * </ul>
+     * and so on...
+     */
+    private static int parseInt( BerValue value ) throws IntegerDecoderException
+    {
+        int result = 0;
+
+        byte[] bytes = value.getData();
+
+        if ( Strings.isEmpty( bytes ) )
+        {
+            throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
+        }
+
+        boolean positive = true;
+
+        switch ( bytes.length )
+        {
+            case 5:
+                if ( bytes[0] == 0x00 )
+                {
+                    if ( ( bytes[1] & ( byte ) 0x80 ) != ( byte ) 0x80 )
+                    {
+                        throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
+                    }
+
+                    result = bytes[1] & 0x00FF;
+                    result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+                    result = ( result << 8 ) | ( bytes[3] & 0x00FF );
+                    result = ( result << 8 ) | ( bytes[4] & 0x00FF );
+                }
+                else
+                {
+                    throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
+                }
+
+                break;
+
+            case 4:
+                if ( bytes[0] == 0x00 )
+                {
+                    result = bytes[1] & 0x00FF;
+                }
+                else
+                {
+                    result = bytes[0] & 0x00FF;
+
+                    if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                    {
+                        positive = false;
+                    }
+
+                    result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+                }
+
+                result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+                result = ( result << 8 ) | ( bytes[3] & 0x00FF );
+
+                break;
+
+            case 3:
+                if ( bytes[0] == 0x00 )
+                {
+                    result = bytes[1] & 0x00FF;
+                }
+                else
+                {
+                    result = bytes[0] & 0x00FF;
+
+                    if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                    {
+                        positive = false;
+                    }
+
+                    result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+                }
+
+                result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+
+                break;
+
+            case 2:
+                if ( bytes[0] == 0x00 )
+                {
+                    result = bytes[1] & 0x00FF;
+                }
+                else
+                {
+                    result = bytes[0] & 0x00FF;
+
+                    if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                    {
+                        positive = false;
+                    }
+
+                    result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+                }
+
+                break;
+
+            case 1:
+                result = ( result << 8 ) | ( bytes[0] & 0x00FF );
+
+                if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                {
+                    positive = false;
+                }
+
+                break;
+
+            default:
+                throw new IntegerDecoderException( I18n.err( I18n.ERR_00037_ABOVE_4_BYTES_INTEGER ) );
+        }
+
+        if ( !positive )
+        {
+            result = -( ( ( ~result ) + 1 ) & MASK[bytes.length - 1] );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoderException.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoderException.java
new file mode 100755
index 0000000..0b70264
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoderException.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+/**
+ * Thrown when a IntegerDecoder has encountered a failure condition during a
+ * decode.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class IntegerDecoderException extends Exception
+{
+    /** Declares the Serial Version Uid */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a IntegerDecoderException
+     * 
+     * @param message A message with meaning to a human
+     */
+    public IntegerDecoderException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/LongDecoder.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/LongDecoder.java
new file mode 100644
index 0000000..b2929c4
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/LongDecoder.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Parse and decode a Long value.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LongDecoder
+{
+    /** A mask used to get only the necessary bytes */
+    private static final long[] MASK = new long[]
+        { 0x00000000000000FFL, 0x000000000000FFFFL, 0x0000000000FFFFFFL, 0x00000000FFFFFFFFL, 0x000000FFFFFFFFFFL,
+            0x0000FFFFFFFFFFFFL, 0x00FFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL };
+
+
+    private LongDecoder()
+    {
+    }
+
+
+    /**
+     * Parse a byte buffer and send back an long, controlling that this number
+     * is in a specified interval.
+     *
+     * @param value The byte buffer to parse
+     * @param min Lowest value allowed, included
+     * @param max Highest value allowed, included
+     * @return An integer
+     * @throws LongDecoderException Thrown if the byte stream does not contains an integer
+     */
+    public static long parse( BerValue value, long min, long max ) throws LongDecoderException
+    {
+        long result = parseLong( value );
+
+        if ( ( result >= min ) && ( result <= max ) )
+        {
+            return result;
+        }
+        else
+        {
+            throw new LongDecoderException( I18n.err( I18n.ERR_00038_VALUE_NOT_IN_RANGE, min, max ) );
+        }
+    }
+
+
+    /**
+     * Parse a byte buffer and send back an integer
+     *
+     * @param value The byte buffer to parse
+     * @return An integer
+     * @throws LongDecoderException Thrown if the byte stream does not contains an integer
+     */
+    public static long parse( BerValue value ) throws LongDecoderException
+    {
+        return parseLong( value );
+    }
+    
+    
+    /**
+     * Helper method used to parse the long. We don't check any minimal or maximal
+     * bound.
+     */
+    public static long parseLong( BerValue value ) throws LongDecoderException
+    {
+        long result = 0;
+
+        byte[] bytes = value.getData();
+
+        if ( ( bytes == null ) || ( bytes.length == 0 ) )
+        {
+            throw new LongDecoderException( I18n.err( I18n.ERR_00039_0_BYTES_LONG_LONG ) );
+        }
+
+        if ( bytes.length > 8 )
+        {
+            throw new LongDecoderException( I18n.err( I18n.ERR_00039_0_BYTES_LONG_LONG ) );
+        }
+
+        for ( int i = 0; ( i < bytes.length ) && ( i < 9 ); i++ )
+        {
+            result = ( result << 8 ) | ( bytes[i] & 0x00FF );
+        }
+
+        if ( ( bytes[0] & 0x80 ) == 0x80 )
+        {
+            result = -( ( ( ~result ) + 1 ) & MASK[bytes.length - 1] );
+        }
+        
+        return result;
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/LongDecoderException.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/LongDecoderException.java
new file mode 100644
index 0000000..b448a06
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/LongDecoderException.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+/**
+ * Thrown when a LongDecoder has encountered a failure condition during a
+ * decode.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LongDecoderException extends Exception
+{
+
+    /** Declares the Serial Version Uid */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a LongDecoderException
+     * 
+     * @param message A message with meaning to a human
+     */
+    public LongDecoderException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLV.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLV.java
new file mode 100644
index 0000000..28f350b
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLV.java
@@ -0,0 +1,459 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import org.apache.directory.api.asn1.util.Asn1StringUtils;
+
+
+/**
+ * This class is used to store Tags, Lengths and Values decoded from a PDU.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TLV
+{
+    /** The current Tag being processed */
+    private byte tag;
+
+    /** The current Length being processed */
+    private int length;
+
+    /** The number of byte to store the Length being processed */
+    private int lengthNbBytes;
+
+    /** The number of length's bytes currently read */
+    private int lengthBytesRead;
+
+    /** The current Value being processed */
+    private BerValue value;
+
+    /** An identity for the TLV. It store the TLV hashCode */
+    private int id;
+
+    /**
+     * Reference the TLV which contains the current TLV, if any. As the
+     * enclosing TLV of a PDU does not have parent, it can be null in this case.
+     * Otherwise, it must point to a constructed TLV
+     */
+    private TLV parent;
+
+    /**
+     * The expected length of the TLV's elements, if the current TLV is a
+     * constructed TLV.
+     */
+    private int expectedLength;
+
+    /** tag flag for the primitive/constructed bit - 0010 0000 - 0x20 */
+    public static final byte CONSTRUCTED_FLAG = 0x20;
+
+    /** mask to get the type class value */
+    public static final byte TYPE_CLASS_MASK = ( byte ) 0xC0;
+
+    /** value for the universal type class */
+    public static final byte TYPE_CLASS_UNIVERSAL = 0x00;
+
+    /** tag mask for the short tag format - 0001 1111 - 0x1F */
+    public static final int SHORT_MASK = 0x1F;
+
+    /** A mask to get the Length form */
+    public static final int LENGTH_LONG_FORM = 0x0080;
+
+    /** Value of the reserved extension */
+    public static final int LENGTH_EXTENSION_RESERVED = 0x7F;
+
+    /** A mask to get the long form value */
+    public static final int LENGTH_SHORT_MASK = 0x007F;
+
+    /** A speedup for single bytes length */
+    private static final byte[][] ONE_BYTE = new byte[128][];
+
+    // Initialize an array of byte[] used for encoding lengths below 128
+    static
+    {
+        for ( int i = 0; i < 128; i++ )
+        {
+            ONE_BYTE[i] = new byte[1];
+            ONE_BYTE[i][0] = ( byte ) i;
+        }
+    }
+
+
+    /**
+     * Creates a new TLV object.
+     * 
+     * @param id the TLV's id
+     */
+    public TLV( int id )
+    {
+        tag = 0;
+        length = 0;
+        lengthNbBytes = 0;
+        value = new BerValue();
+        this.id = id;
+
+        expectedLength = 0;
+    }
+
+
+    /**
+     * Checks to see if the tag is constructed.
+     * 
+     * @param tag the TLV's tag
+     * @return true if constructed, false if primitive
+     */
+    public static boolean isConstructed( byte tag )
+    {
+        return ( tag & CONSTRUCTED_FLAG ) != 0;
+    }
+
+
+    /**
+     * Checks to see if the current tlv's tag is constructed.
+     * 
+     * @return true if constructed, false if primitive
+     */
+    public boolean isConstructed()
+    {
+        return ( tag & CONSTRUCTED_FLAG ) != 0;
+    }
+
+
+    /**
+     * Checks to see if the tag represented by this Tag is primitive or
+     * constructed.
+     * 
+     * @param tag the tag to be checked
+     * @return true if it is primitive, false if it is constructed
+     */
+    public static boolean isPrimitive( byte tag )
+    {
+        return ( tag & CONSTRUCTED_FLAG ) == 0;
+    }
+
+
+    /**
+     * Tells if the tag is Universal or not
+     * 
+     * @param tag the tag to be checked
+     * @return true if it is primitive, false if it is constructed
+     */
+    public static boolean isUniversal( byte tag )
+    {
+        return ( tag & TYPE_CLASS_MASK ) == TYPE_CLASS_UNIVERSAL;
+    }
+
+
+    /**
+     * Reset the TLV, so it can be reused for the next PDU decoding.
+     */
+    public void reset()
+    {
+        tag = 0;
+        length = 0;
+        lengthNbBytes = 0;
+        value.reset();
+
+        expectedLength = 0;
+    }
+
+
+    /**
+     * @return Returns the tag.
+     */
+    public byte getTag()
+    {
+        return tag;
+    }
+
+
+    /**
+     * Set a tag value for this TLV.
+     * 
+     * @param tag the tag field for this TLV.
+     */
+    public void setTag( byte tag )
+    {
+        this.tag = tag;
+    }
+
+
+    /**
+     * @return Returns the value.
+     */
+    public BerValue getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * The TLV size is calculated by adding the Tag's size, the Length's size
+     * and the Value's length, if any.
+     * 
+     * @return Returns the size of the TLV.
+     */
+    public int getSize()
+    {
+        return 1 + lengthNbBytes + length;
+    }
+
+
+    /**
+     * Utility function that return the number of bytes necessary to store the
+     * length
+     * 
+     * @param length The length to store in a byte array
+     * @return The number of bytes necessary to store the length.
+     * @see <a href="http://en.wikipedia.org/wiki/X.690#Length_Octets">X.690</a>
+     */
+    public static int getNbBytes( int length )
+    {
+        if ( length >= 0 )
+        {
+            if ( length < 128 )
+            {
+                return 1;
+            }
+            else if ( length < 256 )
+            {
+                return 2;
+            }
+            else if ( length < 65536 )
+            {
+                return 3;
+            }
+            else if ( length < 16777216 )
+            {
+                return 4;
+            }
+            else
+            {
+                return 5;
+            }
+        }
+        else
+        {
+            return 5;
+        }
+    }
+
+
+    /**
+     * Utility function that return a byte array representing the length
+     * 
+     * @param length The length to store in a byte array
+     * @return The byte array representing the length.
+     */
+    public static byte[] getBytes( int length )
+    {
+        if ( length >= 0 )
+        {
+            if ( length < 128 )
+            {
+                return ONE_BYTE[length];
+            }
+            else
+            {
+                byte[] bytes = new byte[getNbBytes( length )];
+
+                if ( length < 256 )
+                {
+                    bytes[0] = ( byte ) 0x81;
+                    bytes[1] = ( byte ) length;
+                }
+                else if ( length < 65536 )
+                {
+                    bytes[0] = ( byte ) 0x82;
+                    bytes[1] = ( byte ) ( length >> 8 );
+                    bytes[2] = ( byte ) ( length & 0x00FF );
+                }
+                else if ( length < 16777216 )
+                {
+                    bytes[0] = ( byte ) 0x83;
+                    bytes[1] = ( byte ) ( length >> 16 );
+                    bytes[2] = ( byte ) ( ( length >> 8 ) & 0x00FF );
+                    bytes[3] = ( byte ) ( length & 0x00FF );
+                }
+                else
+                {
+                    bytes[0] = ( byte ) 0x84;
+                    bytes[1] = ( byte ) ( length >> 24 );
+                    bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
+                    bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
+                    bytes[4] = ( byte ) ( length & 0x00FF );
+                }
+
+                return bytes;
+            }
+        }
+        else
+        {
+            byte[] bytes = new byte[getNbBytes( length )];
+
+            bytes[0] = ( byte ) 0x84;
+            bytes[1] = ( byte ) ( length >> 24 );
+            bytes[2] = ( byte ) ( ( length >> 16 ) & 0x00FF );
+            bytes[3] = ( byte ) ( ( length >> 8 ) & 0x00FF );
+            bytes[4] = ( byte ) ( length & 0x00FF );
+
+            return bytes;
+        }
+    }
+
+
+    /**
+     * @return The parent.
+     */
+    public TLV getParent()
+    {
+        return parent;
+    }
+
+
+    /**
+     * @param parent The parent to set.
+     */
+    public void setParent( TLV parent )
+    {
+        this.parent = parent;
+    }
+
+
+    /**
+     * Get the TLV expected length.
+     * 
+     * @return The expectedLength.
+     */
+    public int getExpectedLength()
+    {
+        return expectedLength;
+    }
+
+
+    /**
+     * Set the new expected length of the current TLV.
+     * 
+     * @param expectedLength The expectedLength to set.
+     */
+    public void setExpectedLength( int expectedLength )
+    {
+        this.expectedLength = expectedLength;
+    }
+
+
+    /**
+     * @return The number of bytes necessary to store the TLV's length
+     */
+    public int getLengthNbBytes()
+    {
+        return lengthNbBytes;
+    }
+
+
+    /**
+     * Set the number of bytes we should use to store the TLV's length.
+     * 
+     * @param lengthNbBytes The number of bytes necessary to store the TLV's length
+     */
+    public void setLengthNbBytes( int lengthNbBytes )
+    {
+        this.lengthNbBytes = lengthNbBytes;
+    }
+
+
+    /**
+     * @return the TLV's length
+     */
+    public int getLength()
+    {
+        return length;
+    }
+
+
+    /**
+     * Set the TLV's length
+     *
+     * @param length the TLV's length
+     */
+    public void setLength( int length )
+    {
+        this.length = length;
+    }
+
+
+    /**
+     * @return The currently read TLV's length bytes
+     */
+    public int getLengthBytesRead()
+    {
+        return lengthBytesRead;
+    }
+
+
+    /**
+     * Set the currently read TLV's length bytes.
+     * 
+     * @param lengthBytesRead the currently read TLV's length bytes
+     */
+    public void setLengthBytesRead( int lengthBytesRead )
+    {
+        this.lengthBytesRead = lengthBytesRead;
+    }
+
+
+    /**
+     * Increment the number of bytes read for this TLV
+     *
+     */
+    public void incLengthBytesRead()
+    {
+        lengthBytesRead++;
+    }
+
+
+    /**
+     * @return The TLV's ID
+     */
+    public int getId()
+    {
+        return id;
+    }
+
+
+    /**
+     * Get a String representation of the TLV
+     * 
+     * @return A String
+     */
+    public String toString()
+    {
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "TLV[ " );
+        sb.append( Asn1StringUtils.dumpByte( tag ) ).append( ", " );
+        sb.append( length ).append( ", " );
+        sb.append( value.toString() );
+        sb.append( "]" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLVBerDecoderMBean.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLVBerDecoderMBean.java
new file mode 100644
index 0000000..ce39c42
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLVBerDecoderMBean.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+
+
+/**
+ * A MBean used to get stats on the decoding process.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface TLVBerDecoderMBean
+{
+    /**
+     * Set the number of bytes that can be used to encode the Value length,
+     * including the first byte. Max is 127 if the Length use a definite form,
+     * default is 1
+     * 
+     * @param length the number of byte to use
+     * @throws DecoderException Thrown if the indefinite length is 
+     * allowed or if the length's Length is above 126 bytes
+     */
+    void setMaxLengthLength( int length ) throws DecoderException;
+
+
+    /**
+     * Set the maximum number of bytes that should be used to encode a Tag
+     * label, including the first byte. Default is 1, no maximum
+     * 
+     * @param length The length to use
+     */
+    void setMaxTagLength( int length );
+
+
+    /** Allow indefinite length. */
+    void allowIndefiniteLength();
+
+
+    /** Disallow indefinite length. */
+    void disallowIndefiniteLength();
+
+
+    /**
+     * Get the actual maximum number of bytes that can be used to encode the
+     * Length
+     * 
+     * @return The maximum bytes of the Length
+     */
+    int getMaxLengthLength();
+
+
+    /**
+     * Get the actual maximum number of bytes that can be used to encode the Tag
+     * 
+     * @return The maximum length of the Tag
+     */
+    int getMaxTagLength();
+
+
+    /**
+     * Tell if indefinite length form could be used for Length
+     * 
+     * @return <code>true</code> if the Indefinite form is allowed
+     */
+    boolean isIndefiniteLengthAllowed();
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLVStateEnum.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLVStateEnum.java
new file mode 100644
index 0000000..f1254af
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/TLVStateEnum.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+/**
+ * Stores the different states of a PDU parsing.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum TLVStateEnum
+{
+    /** Start means that the deconding hasn't read the first byte */
+    TAG_STATE_START,
+
+    /** Pending means that the Type Tag is contained in more that one byte */
+    TAG_STATE_PENDING,
+
+    /** End means that the Type is totally read */
+    TAG_STATE_END,
+
+    /**
+     * Overflow could have two meaning : either there are more than 5 bytes to
+     * encode the value (5 bytes = 5bits + 4*7 bits = 33 bits) or the value that
+     * is represented by those bytes is over MAX_INTEGER
+     */
+    TAG_STATE_OVERFLOW,
+
+    /** Start means that the decoding hasn't read the first byte */
+    LENGTH_STATE_START,
+
+    /** Pending means that the Type length is contained in more that one byte */
+    LENGTH_STATE_PENDING,
+
+    /** End means that the Length is totally read */
+    LENGTH_STATE_END,
+
+    /** Start means that the decoding hasn't read the first byte */
+    VALUE_STATE_START,
+
+    /** Pending means that the Type Value is contained in more that one byte */
+    VALUE_STATE_PENDING,
+
+    /** End means that the Value is totally read */
+    VALUE_STATE_END,
+
+    /** The decoding of a TLV is done */
+    TLV_STATE_DONE,
+
+    /** The decoding of a PDU is done */
+    PDU_DECODED,
+
+    /** The ending state */
+    GRAMMAR_END
+}
diff --git a/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/UniversalTag.java b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/UniversalTag.java
new file mode 100644
index 0000000..ba0d8d1
--- /dev/null
+++ b/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/UniversalTag.java
@@ -0,0 +1,296 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+/**
+ * Enum for ASN.1 UNIVERSAL class tags. The tags values are constructed using
+ * the SNACC representation for tags without the primitive/constructed bit. This
+ * is done because several bit, octet and character string types can be encoded
+ * as primitives or as constructed types to chunk the value out.
+ * <p>
+ * These tags can have one of the following values:
+ * </p>
+ * <p>
+ * </p>
+ * <table border="1" cellspacing="1" width="60%">
+ * <tr>
+ * <th>Id</th>
+ * <th>Usage</th>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 0]</td>
+ * <td>reserved for BER</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 1]</td>
+ * <td>BOOLEAN</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 2]</td>
+ * <td>INTEGER</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 3]</td>
+ * <td>BIT STRING</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 4]</td>
+ * <td>OCTET STRING</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 5]</td>
+ * <td>NULL</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 6]</td>
+ * <td>OBJECT IDENTIFIER</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 7]</td>
+ * <td>ObjectDescriptor</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 8]</td>
+ * <td>EXTERNAL, INSTANCE OF</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 9]</td>
+ * <td>REAL</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 10]</td>
+ * <td>ENUMERATED</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 11]</td>
+ * <td>EMBEDDED PDV</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 12]</td>
+ * <td>UTF8String</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 13]</td>
+ * <td>RELATIVE-OID</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 14]</td>
+ * <td>reserved for future use</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 15]</td>
+ * <td>reserved for future use</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 16]</td>
+ * <td>SEQUENCE, SEQUENCE OF</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 17]</td>
+ * <td>SET, SET OF</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 18]</td>
+ * <td>NumericString</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 19]</td>
+ * <td>PrintableString</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 20]</td>
+ * <td>TeletexString, T61String</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 21]</td>
+ * <td>VideotexString</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 22]</td>
+ * <td>IA5String</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 23]</td>
+ * <td>UTCTime</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 24]</td>
+ * <td>GeneralizedTime</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 25]</td>
+ * <td>GraphicString</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 26]</td>
+ * <td>VisibleString, ISO646String</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 27]</td>
+ * <td>GeneralString</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 28]</td>
+ * <td>UniversalString</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 29]</td>
+ * <td>CHARACTER STRING</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 30]</td>
+ * <td>BMPString</td>
+ * </tr>
+ * <tr>
+ * <td>[UNIVERSAL 31]</td>
+ * <td>reserved for future use</td>
+ * </tr>
+ * </table>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum UniversalTag
+{
+    /** value for the tag */
+    RESERVED_0(( byte ) 0),
+
+    /** value for the tag */
+    BOOLEAN(( byte ) 1),
+
+    /** value for the tag */
+    INTEGER(( byte ) 2),
+
+    /** value for the tag */
+    BIT_STRING(( byte ) 3),
+
+    /** value for the tag */
+    OCTET_STRING(( byte ) 4),
+
+    /** value for the tag */
+    NULL(( byte ) 5),
+
+    /** value for the tag */
+    OBJECT_IDENTIFIER(( byte ) 6),
+
+    /** value for the tag */
+    OBJECT_DESCRIPTOR(( byte ) 7),
+
+    /** value for the tag */
+    EXTERNAL_INSTANCE_OF(( byte ) 8),
+
+    /** value for the tag */
+    REAL(( byte ) 9),
+
+    /** value for the tag */
+    ENUMERATED(( byte ) 0x0A),
+
+    /** value for the tag */
+    EMBEDDED_PDV(( byte ) 0x0B),
+
+    /** value for the tag */
+    UTF8_STRING(( byte ) 0x0C),
+
+    /** value for the tag */
+    RELATIVE_OID(( byte ) 0x0D),
+
+    /** value for the tag */
+    RESERVED_14(( byte ) 0x0E),
+
+    /** value for the tag */
+    RESERVED_15(( byte ) 0x0F),
+
+    /** value for the tag */
+    SEQUENCE_SEQUENCE_OF(( byte ) 0x10),
+
+    /** value for the tag */
+    SET_SET_OF(( byte ) 0x11),
+
+    /** value for the tag */
+    NUMERIC_STRING(( byte ) 0x12),
+
+    /** value for the tag */
+    PRINTABLE_STRING(( byte ) 0x13),
+
+    /** value for the tag */
+    TELETEX_STRING(( byte ) 0x14),
+
+    /** value for the tag */
+    VIDEOTEX_STRING(( byte ) 0x15),
+
+    /** value for the tag */
+    IA5_STRING(( byte ) 0x16),
+
+    /** value for the tag */
+    UTC_TIME(( byte ) 0x17),
+
+    /** value for the tag */
+    GENERALIZED_TIME(( byte ) 0x18),
+
+    /** value for the tag */
+    GRAPHIC_STRING(( byte ) 0x19),
+
+    /** value for the tag */
+    VISIBLE_STRING(( byte ) 0x1A),
+
+    /** value for the tag */
+    GENERAL_STRING(( byte ) 0x1B),
+
+    /** value for the tag */
+    UNIVERSAL_STRING(( byte ) 0x1C),
+
+    /** value for the tag */
+    CHARACTER_STRING(( byte ) 0x1D),
+
+    /** value for the tag */
+    BMP_STRING(( byte ) 0x1E),
+
+    /** value for the tag */
+    RESERVED_31(( byte ) 0x1F),
+
+    /** SEQUENCE TAG */
+    SEQUENCE(( byte ) 0x30),
+
+    /** SET TAG */
+    SET(( byte ) 0x31);
+
+    /** The internal value */
+    private byte value;
+
+
+    /**
+     * Creates a new instance of UniversalTag.
+     *
+     * @param value The tag value
+     */
+    private UniversalTag( byte value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The UniversalTag value
+     */
+    public byte getValue()
+    {
+        return value;
+    }
+}
diff --git a/trunk/asn1/ber/src/site/site.xml b/trunk/asn1/ber/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/asn1/ber/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/LengthTest.java b/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/LengthTest.java
new file mode 100644
index 0000000..320b0e6
--- /dev/null
+++ b/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/LengthTest.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * This class is used to test the Length class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LengthTest
+{
+
+    /**
+     * Test the getNbBytes method
+     */
+    @Test
+    public void testLengthGetNbBytes()
+    {
+        assertEquals( "1 expected", 1, TLV.getNbBytes( 0 ) );
+        assertEquals( "1 expected", 1, TLV.getNbBytes( 1 ) );
+        assertEquals( "1 expected", 1, TLV.getNbBytes( 127 ) );
+        assertEquals( "2 expected", 2, TLV.getNbBytes( 128 ) );
+        assertEquals( "2 expected", 2, TLV.getNbBytes( 255 ) );
+        assertEquals( "3 expected", 3, TLV.getNbBytes( 256 ) );
+        assertEquals( "3 expected", 3, TLV.getNbBytes( 65535 ) );
+        assertEquals( "4 expected", 4, TLV.getNbBytes( 65536 ) );
+        assertEquals( "4 expected", 4, TLV.getNbBytes( 16777215 ) );
+        assertEquals( "5 expected", 5, TLV.getNbBytes( 16777216 ) );
+        assertEquals( "5 expected", 5, TLV.getNbBytes( 0xFFFFFFFF ) );
+    }
+
+
+    /**
+     * Test the getBytes method
+     */
+    @Test
+    public void testLengthGetBytes()
+    {
+        assertTrue( Arrays.equals( new byte[]
+            { 0x01 }, TLV.getBytes( 1 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { 0x7F }, TLV.getBytes( 127 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { ( byte ) 0x81, ( byte ) 0x80 }, TLV.getBytes( 128 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { ( byte ) 0x81, ( byte ) 0xFF }, TLV.getBytes( 255 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { ( byte ) 0x82, 0x01, 0x00 }, TLV.getBytes( 256 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { ( byte ) 0x82, ( byte ) 0xFF, ( byte ) 0xFF }, TLV.getBytes( 65535 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { ( byte ) 0x83, 0x01, 0x00, 0x00 }, TLV.getBytes( 65536 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { ( byte ) 0x83, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF }, TLV.getBytes( 16777215 ) ) );
+        assertTrue( Arrays.equals( new byte[]
+            { ( byte ) 0x84, 0x01, 0x00, 0x00, 0x00 }, TLV.getBytes( 16777216 ) ) );
+        assertTrue( Arrays
+            .equals( new byte[]
+                { ( byte ) 0x84, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF }, TLV
+                .getBytes( 0xFFFFFFFF ) ) );
+    }
+}
diff --git a/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java b/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java
new file mode 100644
index 0000000..c515439
--- /dev/null
+++ b/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java
@@ -0,0 +1,212 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Primitives
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PrimitivesTest
+{
+    /**
+     * Test the Integer Primitive
+     */
+    @Test
+    public void testIntegerPrimitive() throws IntegerDecoderException
+    {
+        BerValue value = new BerValue();
+
+        value.init( 1 );
+        value.setData( new byte[]
+            { 0x00 } ); // res = 0
+        assertEquals( 0, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 1 );
+        value.setData( new byte[]
+            { 0x01 } ); // res = 1
+        assertEquals( 1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 1 );
+        value.setData( new byte[]
+            { ( byte ) 0xFF } ); // res = 255
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { ( byte ) 0x00, ( byte ) 0xFF } ); // res = 255
+        assertEquals( 255, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { 0x00, 0x01 } ); // res = 1
+        assertEquals( 1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { 0x01, 0x00 } ); // res = 256
+        assertEquals( 256, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { 0x01, 0x01 } ); // res = 257
+        assertEquals( 257, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { 0x01, ( byte ) 0xFF } ); // res = 511
+        assertEquals( 511, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { 0x02, 0x00 } ); // res = 512
+        assertEquals( 512, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { 0x7F, ( byte ) 0xFF } ); // res = 32767
+        assertEquals( 32767, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { ( byte ) 0x80, 0x00 } ); // res = -32768
+        assertEquals( -32768, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { ( byte ) 0xFF, ( byte ) 0xFF } ); // res = -65535
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        value.setData( new byte[]
+            { 0x00, ( byte ) 0xFF, ( byte ) 0xFF } ); // res = 65535
+        assertEquals( 65535, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        // res = 65536
+        value.setData( new byte[]
+            { 0x01, 0x00, 0x00 } );
+        assertEquals( 65536, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        // res = 8388607
+        value.setData( new byte[]
+            { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( 8388607, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        // res = -8388608
+        value.setData( new byte[]
+            { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00 } );
+        assertEquals( -8388608, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        // res = -1
+        value.setData( new byte[]
+            { ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 4 );
+        // res = 16777215
+        value.setData( new byte[]
+            { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( 16777215, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 4 );
+        // res = 2^31 - 1 = MaxInt
+        value.setData( new byte[]
+            { ( byte ) 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( Integer.MAX_VALUE, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 4 );
+        // res = 2^31 = MinInt
+        value.setData( new byte[]
+            { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } );
+        assertEquals( Integer.MIN_VALUE, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 4 );
+        // res = -1
+        value.setData( new byte[]
+            { ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 5 );
+        // res = 2^31 = MinInt
+        value.setData( new byte[]
+            { 0x00, ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } );
+        assertEquals( Integer.MIN_VALUE, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 5 );
+        // res = 2^31 = MinInt
+        value.setData( new byte[]
+            { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        try
+        {
+            value.init( 5 );
+            // res = 2^31 = MinInt
+            value.setData( new byte[]
+                { 0x00, ( byte ) 0x7F, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } ); // res
+            IntegerDecoder.parse( value );
+            fail();
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            // Expected
+        }
+    }
+} // end class TLVTagDecoderTest
diff --git a/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/ValueTest.java b/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/ValueTest.java
new file mode 100644
index 0000000..7b860e5
--- /dev/null
+++ b/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/ValueTest.java
@@ -0,0 +1,793 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.asn1.ber.tlv;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.util.Asn1StringUtils;
+import org.apache.directory.api.asn1.util.BitString;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+
+/**
+ * This class is used to test the Value class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ValueTest
+{
+
+    /**
+     * Test the getNbBytes method for an int value
+     */
+    @Test
+    public void testValueIntGetNbBytes()
+    {
+        assertEquals( 1, BerValue.getNbBytes( 0x00000000 ) );
+        assertEquals( 1, BerValue.getNbBytes( 0x00000001 ) );
+        assertEquals( 2, BerValue.getNbBytes( 0x000000FF ) );
+        assertEquals( 2, BerValue.getNbBytes( 0x00000100 ) );
+        assertEquals( 3, BerValue.getNbBytes( 0x0000FFFF ) );
+        assertEquals( 3, BerValue.getNbBytes( 0x00010000 ) );
+        assertEquals( 4, BerValue.getNbBytes( 0x00FFFFFF ) );
+        assertEquals( 4, BerValue.getNbBytes( 0x01000000 ) );
+        assertEquals( 1, BerValue.getNbBytes( -1 ) );
+        assertEquals( 4, BerValue.getNbBytes( 0x7FFFFFFF ) );
+        assertEquals( 1, BerValue.getNbBytes( 0xFFFFFFFF ) );
+    }
+
+
+    /**
+     * Test the getNbBytes method for a long value
+     */
+    @Test
+    public void testValueLongGetNbBytes()
+    {
+        assertEquals( 1, BerValue.getNbBytes( 0x0000000000000000L ) );
+        assertEquals( 1, BerValue.getNbBytes( 0x0000000000000001L ) );
+        assertEquals( 2, BerValue.getNbBytes( 0x00000000000000FFL ) );
+        assertEquals( 2, BerValue.getNbBytes( 0x0000000000000100L ) );
+        assertEquals( 3, BerValue.getNbBytes( 0x000000000000FFFFL ) );
+        assertEquals( 3, BerValue.getNbBytes( 0x0000000000010000L ) );
+        assertEquals( 4, BerValue.getNbBytes( 0x0000000000FFFFFFL ) );
+        assertEquals( 4, BerValue.getNbBytes( 0x0000000001000000L ) );
+        assertEquals( 5, BerValue.getNbBytes( 0x00000000FFFFFFFFL ) );
+        assertEquals( 5, BerValue.getNbBytes( 0x0000000100000000L ) );
+        assertEquals( 6, BerValue.getNbBytes( 0x000000FFFFFFFFFFL ) );
+        assertEquals( 6, BerValue.getNbBytes( 0x0000010000000000L ) );
+        assertEquals( 7, BerValue.getNbBytes( 0x0000FFFFFFFFFFFFL ) );
+        assertEquals( 7, BerValue.getNbBytes( 0x0001000000000000L ) );
+        assertEquals( 8, BerValue.getNbBytes( 0x00FFFFFFFFFFFFFFL ) );
+        assertEquals( 8, BerValue.getNbBytes( 0x0100000000000000L ) );
+        assertEquals( 1, BerValue.getNbBytes( -1L ) );
+        assertEquals( 8, BerValue.getNbBytes( 0x7FFFFFFFFFFFFFFFL ) );
+        assertEquals( 1, BerValue.getNbBytes( 0xFFFFFFFFFFFFFFFFL ) );
+    }
+
+
+    /**
+     * Test the generation of an Integer Value
+     *
+     */
+    @Test
+    public void testGetBytesInt()
+    {
+        int[] positiveValues = new int[]
+             {
+                 0x00, 0x01, 0x7F,
+                 0x0080, 0x0081, 0x7FFF,
+                 0x008000, 0x008001, 0x7FFFFF,
+                 0x00800000, 0x00800001, 0x7FFFFFFF
+             };
+
+         byte[][] expectedPositiveBytes = new byte[][]
+             {
+                 // 1 byte
+                 { 0x00 }, 
+                 { 0x01 }, 
+                 { 0x7F },
+                 
+                 // 2 bytes
+                { 0x00, ( byte ) 0x80 },
+                { 0x00, ( byte ) 0x81 },
+                { 0x7F, ( byte ) 0xFF },
+
+                 // 3 bytes
+                { 0x00, ( byte ) 0x80, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF },
+
+                 // 4 bytes
+                { 0x00, ( byte ) 0x80, 0x00, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x00, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF }
+             };
+
+         int[] negativeValues = new int[]
+             {
+                 // 1 byte
+                 -1, -127, -128,  
+                             
+                 // 2 bytes
+                 -129, -255, -256, -257, -32767, -32768,
+
+                 // 3 bytes
+                 -32769, -65535, -65536, -65537, -8388607, -8388608,
+
+                 // 4 bytes
+                 -8388609, -16777215, -16777216, -16777217, -2147483647, -2147483648,
+             };
+
+         byte[][] expectedNegativeBytes = new byte[][]
+             {
+                 // 1 byte
+                { ( byte ) 0xFF },
+                { ( byte ) 0x81 },
+                { ( byte ) 0x80 },
+     
+                 // 2 bytes
+                { ( byte ) 0xFF, 0x7F },
+                { ( byte ) 0xFF, 0x01 },
+                { ( byte ) 0xFF, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x01 },
+                { ( byte ) 0x80, 0x00 },
+     
+                 // 3 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00 },
+     
+                 // 4 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00 }
+             };
+
+         int i = 0;
+         
+         for ( int value:positiveValues )
+         {
+             byte[] bb = BerValue.getBytes( value );
+             assertEquals( expectedPositiveBytes[i].length, bb.length );
+             assertTrue( Arrays.equals( expectedPositiveBytes[i], bb ) );
+             i++;
+         }
+         
+        i = 0;
+         
+         for ( int value:negativeValues )
+         {
+             byte[] bb = BerValue.getBytes( value );
+             assertEquals( expectedNegativeBytes[i].length, bb.length );
+             assertTrue( Arrays.equals( expectedNegativeBytes[i], bb ) );
+             i++;
+         }
+
+        byte[] bb = BerValue.getBytes( 0x00000000 );
+        assertEquals( 1, bb.length );
+        assertEquals( 0, bb[0] );
+
+        bb = BerValue.getBytes( 0x00000001 );
+        assertEquals( 1, bb.length );
+        assertEquals( 1, bb[0] );
+
+        bb = BerValue.getBytes( 0x0000007F );
+        assertEquals( 1, bb.length );
+        assertEquals( 0x7F, bb[0] );
+
+        bb = BerValue.getBytes( 0x00000080 );
+        assertEquals( 2, bb.length );
+        assertEquals( 0x00, bb[0] );
+        assertEquals( ( byte ) 0x80, bb[1] );
+
+        bb = BerValue.getBytes( 0x000000FF );
+        assertEquals( 2, bb.length );
+        assertEquals( 0x00, bb[0] );
+        assertEquals( ( byte ) 0xFF, bb[1] );
+
+        bb = BerValue.getBytes( 0x00007FFF );
+        assertEquals( 2, bb.length );
+        assertEquals( 0x7F, bb[0] );
+        assertEquals( ( byte ) 0xFF, bb[1] );
+
+        bb = BerValue.getBytes( 0x00008000 );
+        assertEquals( 3, bb.length );
+        assertEquals( 0x00, bb[0] );
+        assertEquals( ( byte ) 0x80, bb[1] );
+        assertEquals( 0x00, bb[2] );
+
+        bb = BerValue.getBytes( 0x0000FFFF );
+        assertEquals( 3, bb.length );
+        assertEquals( 0x00, bb[0] );
+        assertEquals( ( byte ) 0xFF, bb[1] );
+        assertEquals( ( byte ) 0xFF, bb[2] );
+
+        bb = BerValue.getBytes( 0x00010000 );
+        assertEquals( 3, bb.length );
+        assertEquals( 0x01, bb[0] );
+        assertEquals( 0x00, bb[1] );
+        assertEquals( 0x00, bb[2] );
+
+        bb = BerValue.getBytes( 0x007FFFFF );
+        assertEquals( 3, bb.length );
+        assertEquals( 0x7F, bb[0] );
+        assertEquals( ( byte ) 0xFF, bb[1] );
+        assertEquals( ( byte ) 0xFF, bb[2] );
+
+        bb = BerValue.getBytes( 0x00800000 );
+        assertEquals( 4, bb.length );
+        assertEquals( 0x00, bb[0] );
+        assertEquals( ( byte ) 0x80, bb[1] );
+        assertEquals( 0x00, bb[2] );
+        assertEquals( 0x00, bb[3] );
+
+        bb = BerValue.getBytes( 0x00FFFFFF );
+        assertEquals( 4, bb.length );
+        assertEquals( 0x00, bb[0] );
+        assertEquals( ( byte ) 0xFF, bb[1] );
+        assertEquals( ( byte ) 0xFF, bb[2] );
+        assertEquals( ( byte ) 0xFF, bb[3] );
+
+        bb = BerValue.getBytes( 0x01000000 );
+        assertEquals( 4, bb.length );
+        assertEquals( 0x01, bb[0] );
+        assertEquals( 0x00, bb[1] );
+        assertEquals( 0x00, bb[2] );
+        assertEquals( 0x00, bb[3] );
+
+        bb = BerValue.getBytes( 0x7FFFFFFF );
+        assertEquals( 4, bb.length );
+        assertEquals( 0x7F, bb[0] );
+        assertEquals( ( byte ) 0xFF, bb[1] );
+        assertEquals( ( byte ) 0xFF, bb[2] );
+        assertEquals( ( byte ) 0xFF, bb[3] );
+
+        bb = BerValue.getBytes( 0x80000000 );
+        assertEquals( 4, bb.length );
+        assertEquals( ( byte ) 0x80, bb[0] );
+        assertEquals( ( byte ) 0x00, bb[1] );
+        assertEquals( ( byte ) 0x00, bb[2] );
+        assertEquals( ( byte ) 0x00, bb[3] );
+        
+        bb = BerValue.getBytes( 0xFFFFFFFF );
+        assertEquals( 1, bb.length );
+        assertEquals( ( byte ) 0xFF, bb[0] );
+        
+        bb = BerValue.getBytes( 0xFFFFFF80 );
+        assertEquals( 1, bb.length );
+        assertEquals( ( byte ) 0x80, bb[0] );
+
+        bb = BerValue.getBytes( 0xFFFFFF7F );
+        assertEquals( 2, bb.length );
+        assertEquals( ( byte ) 0xFF, bb[0] );
+        assertEquals( 0x7F, bb[1] );
+
+        bb = BerValue.getBytes( 0xFFFFFF00 );
+        assertEquals( 2, bb.length );
+        assertEquals( ( byte ) 0xFF, bb[0] );
+        assertEquals( 0x00, bb[1] );
+
+        bb = BerValue.getBytes( 0xFFFF8000 );
+        assertEquals( 2, bb.length );
+        assertEquals( ( byte ) 0x80, bb[0] );
+        assertEquals( 0x00, bb[1] );
+
+        bb = BerValue.getBytes( 0xFFFF7FFF );
+        assertEquals( 3, bb.length );
+        assertEquals( ( byte ) 0xFF, bb[0] );
+        assertEquals( 0x7F, bb[1] );
+        assertEquals( ( byte ) 0xFF, bb[2] );
+
+        bb = BerValue.getBytes( 0xFFFF0000 );
+        assertEquals( 3, bb.length );
+        assertEquals( ( byte ) 0xFF, bb[0] );
+        assertEquals( 0x00, bb[1] );
+        assertEquals( 0x00, bb[2] );
+
+        bb = BerValue.getBytes( 0xFF800000 );
+        assertEquals( 3, bb.length );
+        assertEquals( ( byte ) 0x80, bb[0] );
+        assertEquals( 0x00, bb[1] );
+        assertEquals( 0x00, bb[2] );
+
+        bb = BerValue.getBytes( 0xFF7FFFFF );
+        assertEquals( 4, bb.length );
+        assertEquals( ( byte ) 0xFF, bb[0] );
+        assertEquals( 0x7F, bb[1] );
+        assertEquals( ( byte ) 0xFF, bb[2] );
+        assertEquals( ( byte ) 0xFF, bb[3] );
+
+        bb = BerValue.getBytes( 0xFF000000 );
+        assertEquals( 4, bb.length );
+        assertEquals( ( byte ) 0xFF, bb[0] );
+        assertEquals( 0x00, bb[1] );
+        assertEquals( 0x00, bb[2] );
+        assertEquals( 0x00, bb[3] );
+
+        bb = BerValue.getBytes( 0x80000000 );
+        assertEquals( 4, bb.length );
+        assertEquals( ( byte ) 0x80, bb[0] );
+        assertEquals( 0x00, bb[1] );
+        assertEquals( 0x00, bb[2] );
+        assertEquals( 0x00, bb[3] );
+    }
+
+
+    /**
+     * Test the generation of a Long Value
+     *
+     */
+    @Test
+    public void testGetBytesLong()
+    {
+        long[] positiveValues = new long[]
+            {
+                0x00L, 0x01L, 0x7FL,
+                0x0080L, 0x0081L, 0x7FFFL,
+                0x008000L, 0x008001L, 0x7FFFFFL,
+                0x00800000L, 0x00800001L, 0x7FFFFFFFL,
+                0x0080000000L, 0x0080000001L, 0x7FFFFFFFFFL,
+                0x008000000000L, 0x008000000001L, 0x7FFFFFFFFFFFL,
+                0x00800000000000L, 0x00800000000001L, 0x7FFFFFFFFFFFFFL,
+                0x0080000000000000L, 0x0080000000000001L, 0x7FFFFFFFFFFFFFFFL
+            };
+        
+        byte[][] expectedPositiveBytes = new byte[][]
+            {
+                // 1 byte
+                { 0x00 }, 
+                { 0x01 }, 
+                { 0x7F },
+                
+                // 2 bytes
+                { 0x00, ( byte ) 0x80 },
+                { 0x00, ( byte ) 0x81 },
+                { 0x7F, ( byte ) 0xFF },
+
+                // 3 bytes
+                { 0x00, ( byte ) 0x80, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF },
+
+                // 4 bytes
+                { 0x00, ( byte ) 0x80, 0x00, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x00, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+
+                // 5 bytes
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+
+                // 6 bytes
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x00, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+
+                // 7 bytes
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+
+                // 8 bytes
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                { 0x00, ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
+                    ( byte ) 0xFF }
+            };
+
+        long[] negativeValues = new long[]
+            {
+                // 1 byte
+                -1L, -127L, -128L,  
+                            
+                // 2 bytes
+                -129L, -255L, -256L, -257L, -32767L, -32768L,
+
+                // 3 bytes
+                -32769L, -65535L, -65536L, -65537L, -8388607L, -8388608L,
+
+                // 4 bytes
+                -8388609L, -16777215L, -16777216L, -16777217L, -2147483647L, -2147483648L,
+
+                // 5 bytes
+                -2147483649L, -4294967295L, -4294967296L, -4294967297L, -549755813887L, -549755813888L,
+
+                // 6 bytes
+                -549755813889L, -1099511627775L, -1099511627776L, 
+                -1099511627777L, -140737488355327L, -140737488355328L,
+
+                // 7 bytes
+                -140737488355329L, -281474976710655L, -281474976710656L,
+                -281474976710657L, -36028797018963967L, -36028797018963968L,
+                
+                // 8 bytes
+                -36028797018963969L, -72057594037927935L, -72057594037927936L,
+                -72057594037927937L, -9223372036854775807L, -9223372036854775808L
+            };
+        
+        byte[][] expectedNegativeBytes = new byte[][]
+            {
+                // 1 byte
+                { ( byte ) 0xFF },
+                { ( byte ) 0x81 },
+                { ( byte ) 0x80 },
+    
+                // 2 bytes
+                { ( byte ) 0xFF, 0x7F },
+                { ( byte ) 0xFF, 0x01 },
+                { ( byte ) 0xFF, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x01 },
+                { ( byte ) 0x80, 0x00 },
+    
+                // 3 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00 },
+    
+                // 4 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00 },
+    
+                // 5 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00 },
+    
+                // 6 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    
+                // 7 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
+                    ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+    
+                // 8 bytes
+                { ( byte ) 0xFF, 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
+                    ( byte ) 0xFF },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                { ( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
+                    ( byte ) 0xFF, ( byte ) 0xFF },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+                { ( byte ) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+            };
+
+        int i = 0;
+        
+        for ( long value:positiveValues )
+        {
+            byte[] bb = BerValue.getBytes( value );
+            assertEquals( expectedPositiveBytes[i].length, bb.length );
+            assertTrue( Arrays.equals( expectedPositiveBytes[i], bb ) );
+            i++;
+        }
+        
+        i = 0;
+        
+        for ( long value:negativeValues )
+        {
+            byte[] bb = BerValue.getBytes( value );
+            assertEquals( expectedNegativeBytes[i].length, bb.length );
+            assertTrue( Arrays.equals( expectedNegativeBytes[i], bb ) );
+            i++;
+        }
+    }
+
+
+    @Test
+    public void testEncodeInt2Bytes()
+    {
+        byte[] encoded = BerValue.getBytes( 128 );
+
+        assertEquals( 0x00, encoded[0] );
+        assertEquals( ( byte ) 0x80, encoded[1] );
+
+        encoded = BerValue.getBytes( -27066 );
+
+        assertEquals( ( byte ) 0x96, encoded[0] );
+        assertEquals( 0x46, encoded[1] );
+
+    }
+
+
+    @Test
+    public void testEncodeInt3Bytes()
+    {
+
+        byte[] encoded = BerValue.getBytes( 32787 );
+
+        assertEquals( 0x00, encoded[0] );
+        assertEquals( ( byte ) 0x80, encoded[1] );
+        assertEquals( ( byte ) 0x13, encoded[2] );
+    }
+
+
+    @Test
+    public void testEncodeInt()
+    {
+        byte[] encoded = null;
+        int[] testedInt = new int[]
+            { 
+                Integer.MIN_VALUE, 
+                -2147483647, 
+                -16777216, 
+                -16777215, 
+                -8388608, 
+                -8388607, 
+                -65536, 
+                -65535, 
+                -32768, 
+                -32767,
+                -256, 
+                -255, 
+                -128, 
+                -127, 
+                -1, 
+                0, 
+                1, 
+                127, 
+                128, 
+                255, 
+                256, 
+                32767, 
+                32768, 
+                65535, 
+                65536, 
+                8388607, 
+                8388608,
+                16777215, 
+                16777216, 
+                Integer.MAX_VALUE };
+
+        for ( int i:testedInt )
+        {
+            encoded = BerValue.getBytes( i );
+
+            int value = new BigInteger( encoded ).intValue();
+
+            assertEquals( i, value );
+        }
+    }
+
+
+    /**
+     * Test the decoding of integer values
+     */
+    @Test
+    public void testDecodeInt() throws Exception
+    {
+        byte[] encoded = null;
+        int[] testedInt = new int[]
+            { 
+                Integer.MIN_VALUE, 
+                -2147483647, 
+                -16777216, 
+                -16777215, 
+                -8388608, 
+                -8388607, 
+                -65536, 
+                -65535, 
+                -32768, 
+                -32767,
+                -256, 
+                -255, 
+                -128, 
+                -127, 
+                -1, 0, 
+                1, 
+                127, 
+                128, 
+                255, 
+                256, 
+                32767, 
+                32768, 
+                65535, 
+                65536, 
+                8388607, 
+                8388608,
+                16777215, 
+                16777216, 
+                Integer.MAX_VALUE };
+
+        for ( int i:testedInt )
+        {
+            encoded = new BigInteger( Integer.toString( i ) ).toByteArray();
+
+            int value = IntegerDecoder.parse( new BerValue( encoded ) );
+
+            assertEquals( i, value );
+        }
+    }
+    
+
+
+    /**
+     * Test the decoding of long values
+     */
+    @Test
+    public void testDecodeLong() throws Exception
+    {
+        byte[] encoded = null;
+        long[] testedLong = new long[]
+            { 
+                Long.MIN_VALUE, 
+                -9223372036854775808L,
+                -9223372036854775807L,
+                -72057594037927937L,
+                -72057594037927936L,
+                -72057594037927935L,
+                -36028797018963969L,
+                -36028797018963968L,
+                -36028797018963967L,
+                -281474976710657L,
+                -281474976710656L,
+                -281474976710655L,
+                -140737488355329L,
+                -140737488355328L,
+                -140737488355327L,
+                -1099511627777L,
+                -1099511627776L,
+                -1099511627775L,
+                -549755813889L,
+                -549755813888L,
+                -549755813887L,
+                -4294967297L,
+                -4294967296L,
+                -4294967295L,
+                -2147483649L,
+                -2147483648L,
+                -2147483647L, 
+                -16777216L, 
+                -16777215L, 
+                -8388608L, 
+                -8388607L, 
+                -65536L, 
+                -65535L, 
+                -32769L,
+                -32768L, 
+                -32767L,
+                -257L,
+                -256L, 
+                -255L, 
+                -129L,
+                -128L, 
+                -127L, 
+                -1L, 
+                0L, 
+                1L, 
+                127L, 
+                128L, 
+                255L, 
+                256L, 
+                32767L, 
+                32768L, 
+                32769L, 
+                65535L, 
+                65536L, 
+                8388607L, 
+                8388608L,
+                8388609L,
+                2147483647L,
+                2147483648L,
+                2147483649L,
+                549755813887L,
+                549755813888L,
+                549755813889L,
+                140737488355327L,
+                140737488355328L,
+                140737488355329L,
+                36028797018963967L,
+                36028797018963967L,
+                36028797018963967L,
+                Long.MAX_VALUE };
+
+        for ( long i:testedLong )
+        {
+            encoded = new BigInteger( Long.toString( i ) ).toByteArray();
+
+            long value = LongDecoder.parse( new BerValue( encoded ) );
+
+            assertEquals( i, value );
+        }
+    }
+    
+
+
+    @Test
+    public void testNewByteArrayValue()
+    {
+        byte[] bb = new byte[]
+            { 0x01, ( byte ) 0xFF };
+
+        BerValue v = new BerValue( bb );
+        byte[] vv = v.getData();
+
+        assertEquals( 0x01, vv[0] );
+        assertEquals( ( byte ) 0xFF, vv[1] );
+
+        bb[0] = 0x00;
+        assertEquals( 0x01, vv[0] );
+    }
+
+    
+    @Test
+    public void testEncodeBitString()
+    {
+        BitString bs = new BitString( 10 );
+        bs.setBit( 9 );
+        
+        ByteBuffer buffer = ByteBuffer.allocate( 5 );
+        
+        try
+        {
+            BerValue.encode( buffer, bs );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+        
+        assertEquals( "0x03 0x03 0x06 0x00 0x40 ", Asn1StringUtils.dumpBytes( buffer.array() )  );
+    }
+}
+
diff --git a/trunk/asn1/pom.xml b/trunk/asn1/pom.xml
new file mode 100644
index 0000000..440e995
--- /dev/null
+++ b/trunk/asn1/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-asn1-parent</artifactId>
+  <name>Apache Directory API ASN.1 Parent</name>
+  <inceptionYear>2003</inceptionYear>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>api</module>
+    <module>ber</module>
+  </modules>
+</project>
diff --git a/trunk/asn1/src/site/site.xml b/trunk/asn1/src/site/site.xml
new file mode 100644
index 0000000..b6ec180
--- /dev/null
+++ b/trunk/asn1/src/site/site.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="modules" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/distribution/pom.xml b/trunk/distribution/pom.xml
new file mode 100644
index 0000000..a9378c8
--- /dev/null
+++ b/trunk/distribution/pom.xml
@@ -0,0 +1,231 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>apache-ldap-api</artifactId>
+  <name>Apache Directory LDAP API Distribution</name>
+  <packaging>pom</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-client-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-aci</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-schema-converter</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-schema-data</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-all</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+  </dependencies>
+
+
+  <profiles>
+    <profile>
+      <id>apache-release</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-install-plugin</artifactId>
+            <configuration>
+              <createChecksum>true</createChecksum>
+            </configuration>
+          </plugin> 
+
+          <plugin>
+            <artifactId>maven-dependency-plugin</artifactId>
+            <executions>
+              <!-- Package additional jars that are no runtime dependencies -->
+              <execution>
+                <id>additional-jars</id>
+                <phase>package</phase>
+                <goals>
+                  <goal>copy</goal>
+                </goals>
+                <configuration>
+                  <outputDirectory>${project.build.directory}/additional-jars</outputDirectory>
+                  <artifactItems>
+                    <artifactItem>
+                      <groupId>org.slf4j</groupId>
+                      <artifactId>slf4j-log4j12</artifactId>
+                    </artifactItem>
+                    
+                    <artifactItem>
+                      <groupId>org.slf4j</groupId>
+                      <artifactId>slf4j-api</artifactId>
+                    </artifactItem>
+                    
+                    <artifactItem>
+                      <groupId>antlr</groupId>
+                      <artifactId>antlr</artifactId>
+                    </artifactItem>
+                    
+                    <artifactItem>
+                      <groupId>commons-collections</groupId>
+                      <artifactId>commons-collections</artifactId>
+                    </artifactItem>
+                    
+                    <artifactItem>
+                      <groupId>log4j</groupId>
+                      <artifactId>log4j</artifactId>
+                    </artifactItem>
+                  </artifactItems>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+
+          <plugin>
+            <artifactId>maven-assembly-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>package</id>
+                <phase>package</phase>
+                <configuration>
+                  <tarLongFileMode>gnu</tarLongFileMode>
+                  <descriptors>
+                    <descriptor>src/main/assembly/bin.xml</descriptor>
+                    <descriptor>src/main/assembly/src.xml</descriptor>
+                  </descriptors>
+                </configuration>
+                <goals>
+                  <goal>single</goal>
+                </goals>
+              </execution>
+
+              <execution>
+                <id>anon</id>
+                <phase>package</phase>
+                <configuration>
+                  <tarLongFileMode>gnu</tarLongFileMode>
+                  <descriptors>
+                    <descriptor>src/main/assembly/anon.xml</descriptor>
+                  </descriptors>
+                  <archive>
+                    <manifest>
+                      <mainClass>org.apache.directory.ldap.client.api.LdifAnonymizer</mainClass>
+                    </manifest>
+                  </archive>
+                  <finalName>anon-${project.version}.jar</finalName>
+                </configuration>
+                <goals>
+                  <goal>single</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+
+          <plugin>
+            <groupId>org.apache.geronimo.genesis.plugins</groupId>
+            <artifactId>tools-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>verify-legal-files</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>verify-legal-files</goal>
+                </goals>
+                <configuration>
+                  <!-- avoid false positive, as we add a '-bin' or '-src' to the base directory -->
+                  <strict>false</strict>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/trunk/distribution/src/main/assembly/anon.xml b/trunk/distribution/src/main/assembly/anon.xml
new file mode 100644
index 0000000..17ef68d
--- /dev/null
+++ b/trunk/distribution/src/main/assembly/anon.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>anon</id>
+
+  <formats>
+    <format>jar</format>
+  </formats>
+
+  <baseDirectory>anon-${project-version}.jar</baseDirectory>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  
+  <dependencySets>
+    <dependencySet>
+      <outputDirectory>/</outputDirectory>
+      <includes>
+        <!-- The LDAP API dependencies -->
+        <include>org.apache.directory.api:api-asn1-api:jar:${project.version}</include>
+        <include>org.apache.directory.api:api-i18n:jar:${project.version}</include>
+        <include>org.apache.directory.api:api-ldap-client-api:jar:${project.version}</include>
+        <include>org.apache.directory.api:api-ldap-extras-aci:jar:${project.version}</include>
+        <include>org.apache.directory.api:api-ldap-model:jar:${project.version}</include>
+        <include>org.apache.directory.api:api-ldap-schema-converter:jar:${project.version}</include>
+        <include>org.apache.directory.api:api-ldap-schema-data:jar:${project.version}</include>
+        <include>org.apache.directory.api:api-util:jar:${project.version}</include>
+
+        <!-- The external dependencies -->
+        <include>antlr:antlr:jar:${antlr.version}</include>
+        <include>commons-collections:commons-collections:jar:${commons.collections.version}</include>
+        <include>log4j:log4j:jar:${log4j.version}</include>
+        <include>org.slf4j:slf4j-api:jar:${slf4j.api.version}</include>
+        <include>org.slf4j:slf4j-log4j12:jar:${slf4j.log4j12.version}</include>
+      </includes>
+      <unpack>true</unpack>
+    </dependencySet>
+  </dependencySets>
+</assembly>
diff --git a/trunk/distribution/src/main/assembly/bin.xml b/trunk/distribution/src/main/assembly/bin.xml
new file mode 100644
index 0000000..62113bd
--- /dev/null
+++ b/trunk/distribution/src/main/assembly/bin.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/assembly-1.1.0-SNAPSHOT.xsd">
+    <id>bin</id>
+    <formats>
+        <format>zip</format>
+        <format>tar.gz</format>
+    </formats>
+    <baseDirectory>${project.build.finalName}-bin</baseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>src/main/release</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>**</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>target/additional-jars</directory>
+            <outputDirectory>/lib</outputDirectory>
+        </fileSet>
+    </fileSets>
+    <dependencySets>
+        <dependencySet>
+            <outputDirectory>/lib</outputDirectory>
+            <unpack>false</unpack>
+            <scope>runtime</scope>
+        </dependencySet>
+    </dependencySets>
+</assembly>
diff --git a/trunk/distribution/src/main/assembly/src.xml b/trunk/distribution/src/main/assembly/src.xml
new file mode 100644
index 0000000..4daa8b9
--- /dev/null
+++ b/trunk/distribution/src/main/assembly/src.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/assembly-1.1.0-SNAPSHOT.xsd">
+    <id>src</id>
+    <formats>
+        <format>zip</format>
+        <format>tar.gz</format>
+    </formats>
+    <baseDirectory>${project.build.finalName}-src</baseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>${project.basedir}/..</directory>
+            <outputDirectory>/</outputDirectory>
+            <useDefaultExcludes>true</useDefaultExcludes>
+            <excludes>
+                <exclude>/</exclude>
+                <exclude>LICENSE</exclude>
+                <exclude>NOTICE</exclude>
+                <exclude>**/.*/**</exclude>
+                <exclude>**/*.log</exclude>
+                <exclude>**/${project.build.directory}/**</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>src/main/release</directory>
+            <outputDirectory>/</outputDirectory>
+            <includes>
+                <include>**</include>
+            </includes>
+        </fileSet>
+    </fileSets>
+</assembly>
diff --git a/trunk/distribution/src/main/release/LICENSE b/trunk/distribution/src/main/release/LICENSE
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/trunk/distribution/src/main/release/LICENSE
@@ -0,0 +1,203 @@
+
+                                 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.
+
diff --git a/trunk/distribution/src/main/release/NOTICE b/trunk/distribution/src/main/release/NOTICE
new file mode 100644
index 0000000..6dd29ad
--- /dev/null
+++ b/trunk/distribution/src/main/release/NOTICE
@@ -0,0 +1,33 @@
+Apache Directory LDAP API Distribution
+Copyright 2003-2014 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+Additional copyright notices and license terms applicable are
+present in the 'licenses' directory.
+
+This product uses Apache Ant (http://ant.apache.org/).
+
+This product includes/uses Apache Commons (http://commons.apache.org/).
+
+This product includes/uses Apache Loggin Services (http://logging.apache.org/).
+
+This product includes/uses Apache Felix (http://felix.apache.org/).
+
+This product uses Apache Maven (http://maven.apache.org/).
+
+This product includes/uses Apache Mina (http://mina.apache.org/).
+
+This product includes/uses software, AntLR Parser Generator (http://www.antlr.org/).
+
+This product uses software, JUnit (http://junit.org),
+developed by JUnit (http://www.junit.org)
+
+This product includes/uses software, dom4j (http://dom4j.org),
+developed by MetaStuff Ltd.  (http://sourceforge.net/projects/dom4j).
+
+This product includes/uses software, SLF4J API Module (http://www.slf4j.org),
+developed by QOS.ch  (http://www.qos.ch)
+
+This product includes/uses software, XMLPullParser 3 - xpp3:xpp3:jar:1.1.3.4.O (http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1/)
diff --git a/trunk/distribution/src/main/release/licenses/antlr-LICENSE.txt b/trunk/distribution/src/main/release/licenses/antlr-LICENSE.txt
new file mode 100644
index 0000000..afe00dc
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/antlr-LICENSE.txt
@@ -0,0 +1,19 @@
+ANTLR 2 (http://www.antlr2.org/license.html) :
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of ANTLR, 
+or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR and 
+have developed a nice tool with the output, please mention that you developed it 
+using ANTLR. In addition, we ask that the headers remain intact in our source 
+code. As long as these guidelines are kept, we expect to continue enhancing this 
+system and expect to make other tools available as they are completed. 
+
diff --git a/trunk/distribution/src/main/release/licenses/dom4j-LICENSE.txt b/trunk/distribution/src/main/release/licenses/dom4j-LICENSE.txt
new file mode 100644
index 0000000..9438437
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/dom4j-LICENSE.txt
@@ -0,0 +1,33 @@
+dom4j 1.6.1 (http://dom4j.sourceforge.net/dom4j-1.6.1/license.html) :
+
+Redistribution and use of this software and associated documentation 
+("Software"), with or without modification, are permitted provided that the 
+following conditions are met:
+
+   1. Redistributions of source code must retain copyright statements and 
+notices. Redistributions must also contain a copy of this document.
+   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 name "DOM4J" must not be used to endorse or promote products derived 
+from this Software without prior written permission of MetaStuff, Ltd. For 
+written permission, please contact dom4j-info@metastuff.com.
+   4. Products derived from this Software may not be called "DOM4J" nor may 
+"DOM4J" appear in their names without prior written permission of MetaStuff, Ltd. 
+DOM4J is a registered trademark of MetaStuff, Ltd.
+   5. Due credit should be given to the DOM4J Project - 
+http://dom4j.sourceforge.net
+
+THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``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 METASTUFF, LTD. 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.
+
+Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
+
diff --git a/trunk/distribution/src/main/release/licenses/slf4j-LICENSE.txt b/trunk/distribution/src/main/release/licenses/slf4j-LICENSE.txt
new file mode 100644
index 0000000..4c349fd
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/slf4j-LICENSE.txt
@@ -0,0 +1,24 @@
+SLF4J (http://www.slf4j.org/license.html)
+
+ Copyright (c) 2004-2008 QOS.ch
+ All rights reserved.
+
+ Permission is hereby granted, free  of charge, to any person obtaining
+ a  copy  of this  software  and  associated  documentation files  (the
+ "Software"), to  deal in  the Software without  restriction, including
+ without limitation  the rights to  use, copy, modify,  merge, publish,
+ distribute,  sublicense, and/or sell  copies of  the Software,  and to
+ permit persons to whom the Software  is furnished to do so, subject to
+ the following conditions:
+ 
+ The  above  copyright  notice  and  this permission  notice  shall  be
+ included in all copies or substantial portions of the Software.
+ 
+ THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+ EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+ MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.dom-documentation.txt b/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.dom-documentation.txt
new file mode 100644
index 0000000..5438a3e
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.dom-documentation.txt
@@ -0,0 +1,86 @@
+xml-commons/java/external/LICENSE.dom-documentation.txt $Id: LICENSE.dom-documentation.txt,v 1.1 2002/01/31 23:13:42 curcuru Exp $

+

+

+This license came from: http://www.w3.org/Consortium/Legal/copyright-documents-19990405

+

+

+W3C® DOCUMENT NOTICE AND LICENSE

+Copyright © 1994-2001 World

+Wide Web Consortium, <a href="http://www.w3.org/">World

+Wide Web Consortium</a>, (<a href=

+"http://www.lcs.mit.edu/">Massachusetts Institute of

+Technology</a>, <a href="http://www.inria.fr/">Institut National de

+Recherche en Informatique et en Automatique</a>, <a href=

+"http://www.keio.ac.jp/">Keio University</a>). All Rights Reserved.

+http://www.w3.org/Consortium/Legal/

+

+Public documents on the W3C site are provided by the copyright

+holders under the following license. The software or Document Type 

+Definitions (DTDs) associated with W3C specifications are governed

+by the Software Notice. By using and/or copying this document, or the

+W3C document from which this statement is linked, you (the

+licensee) agree that you have read, understood, and will comply

+with the following terms and conditions:

+

+Permission to use, copy, and distribute the contents of this

+document, or the W3C document from which this statement is linked,

+in any medium for any purpose and without fee or royalty is hereby

+granted, provided that you include the following on ALL

+copies of the document, or portions thereof, that you use:

+

+A link or URL to the original W3C document.

+

+The pre-existing copyright notice of the original author, or if

+it doesn't exist, a notice of the form: "Copyright © [$date-of-document] World Wide Web

+Consortium, (Massachusetts

+Institute of Technology, Institut National de Recherche en Informatique et en

+Automatique, Keio

+University). All Rights Reserved.

+http://www.w3.org/Consortium/Legal/" (Hypertext is preferred, but a

+textual representation is permitted.)

+

+If it exists, the STATUS of the W3C document.

+

+When space permits, inclusion of the full text of this NOTICE 

+should be provided. We request that authorship

+attribution be provided in any software, documents, or other items

+or products that you create pursuant to the implementation of the

+contents of this document, or any portion thereof.

+

+No right to create modifications or derivatives of W3C documents

+is granted pursuant to this license. However, if additional 

+requirements (documented in the Copyright

+FAQ) are satisfied, the right to create modifications or

+derivatives is sometimes granted by the W3C to individuals

+complying with those requirements.

+

+THIS DOCUMENT IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO

+REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT

+NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A

+PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS

+OF THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE

+IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY

+PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.

+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT,

+SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE

+DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS

+THEREOF.

+

+The name and trademarks of copyright holders may NOT be used in

+advertising or publicity pertaining to this document or its

+contents without specific, written prior permission. Title to

+copyright in this document will at all times remain with copyright

+holders.

+

+----------------------------------------------------------------------------

+This formulation of W3C's notice and license became active on

+April 05 1999 so as to account for the treatment of DTDs, schema's and 

+bindings. See the older formulation for the policy prior to this date. 

+Please see

+our Copyright FAQ for common questions

+about using materials from our site, including specific terms and

+conditions for packages like libwww, Amaya, and Jigsaw. 

+Other questions about this notice can be directed to site-policy@w3.org.

+

+webmaster

+(last updated by reagle on 1999/04/99.)
\ No newline at end of file
diff --git a/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.dom-software.txt b/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.dom-software.txt
new file mode 100644
index 0000000..0546e6f
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.dom-software.txt
@@ -0,0 +1,74 @@
+xml-commons/java/external/LICENSE.dom-software.txt $Id: LICENSE.dom-software.txt,v 1.1 2002/01/31 23:13:42 curcuru Exp $

+

+

+This license came from: http://www.w3.org/Consortium/Legal/copyright-software-19980720

+

+

+W3C® SOFTWARE NOTICE AND LICENSE

+Copyright © 1994-2001 World

+Wide Web Consortium, <a href="http://www.w3.org/">World

+Wide Web Consortium</a>, (<a href=

+"http://www.lcs.mit.edu/">Massachusetts Institute of

+Technology</a>, <a href="http://www.inria.fr/">Institut National de

+Recherche en Informatique et en Automatique</a>, <a href=

+"http://www.keio.ac.jp/">Keio University</a>). All Rights Reserved.

+http://www.w3.org/Consortium/Legal/

+

+This W3C work (including software, documents, or other related

+items) is being provided by the copyright holders under the

+following license. By obtaining, using and/or copying this work,

+you (the licensee) agree that you have read, understood, and will

+comply with the following terms and conditions:

+Permission to use, copy, modify, and distribute this software

+and its documentation, with or without modification,  for any

+purpose and without fee or royalty is hereby granted, provided that

+you include the following on ALL copies of the software and

+documentation or portions thereof, including modifications, that

+you make:

+

+The full text of this NOTICE in a location viewable to users of

+the redistributed or derivative work.

+

+Any pre-existing intellectual property disclaimers, notices, or

+terms and conditions. If none exist, a short notice of the

+following form (hypertext is preferred, text is permitted) should

+be used within the body of any redistributed or derivative code:

+"Copyright © [$date-of-software] World Wide Web Consortium, (Massachusetts Institute of

+Technology, Institut National de

+Recherche en Informatique et en Automatique, Keio University). All Rights Reserved.

+http://www.w3.org/Consortium/Legal/"

+

+Notice of any changes or modifications to the W3C files,

+including the date changes were made. (We recommend you provide 

+URIs to the location from which the code is derived.)

+

+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND

+COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR

+IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF

+MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE

+USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD

+PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.

+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT,

+SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE

+SOFTWARE OR DOCUMENTATION.

+

+The name and trademarks of copyright holders may NOT be used in

+advertising or publicity pertaining to the software without

+specific, written prior permission. Title to copyright in this

+software and any associated documentation will at all times remain

+with copyright holders.

+____________________________________

+This formulation of W3C's notice and license became active on

+August 14 1998 so as to improve compatibility with GPL. This

+version ensures that W3C software licensing terms are no more

+restrictive than GPL and consequently W3C software may be

+distributed in GPL packages. See the older formulation for the

+policy prior to this date. Please see our Copyright FAQ for common 

+questions about using materials from

+our site, including specific terms and conditions for packages like

+libwww, Amaya, and Jigsaw. 

+Other questions about this notice can be

+directed to site-policy@w3.org.

+

+webmaster

+(last updated $Date: 2002/01/31 23:13:42 $)
\ No newline at end of file
diff --git a/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.sax.txt b/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.sax.txt
new file mode 100644
index 0000000..86bc63c
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/xml-apis-LICENSE.sax.txt
@@ -0,0 +1,23 @@
+xml-commons/java/external/LICENSE.sax.txt $Id: LICENSE.sax.txt,v 1.1 2002/01/31 23:26:48 curcuru Exp $

+

+

+This license came from: http://www.megginson.com/SAX/copying.html

+  However please note future versions of SAX may be covered 

+  under http://saxproject.org/?selected=pd

+

+

+This page is now out of date -- see the new SAX site at 

+http://www.saxproject.org/ for more up-to-date

+releases and other information. Please change your bookmarks.

+

+

+SAX2 is Free!

+

+I hereby abandon any property rights to SAX 2.0 (the Simple API for

+XML), and release all of the SAX 2.0 source code, compiled code, and

+documentation contained in this distribution into the Public Domain.

+SAX comes with NO WARRANTY or guarantee of fitness for any

+purpose.

+

+David Megginson, david@megginson.com

+2000-05-05
\ No newline at end of file
diff --git a/trunk/distribution/src/main/release/licenses/xml-apis-README.dom.txt b/trunk/distribution/src/main/release/licenses/xml-apis-README.dom.txt
new file mode 100644
index 0000000..92ab7f6
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/xml-apis-README.dom.txt
@@ -0,0 +1,33 @@
+xml-commons/java/external/README.dom.txt $Id: README.dom.txt,v 1.1 2002/01/31 23:13:42 curcuru Exp $

+

+

+HEAR YE, HEAR YE!

+

+

+All of the .java software and associated documentation about 

+the DOM in this repository are distributed under the license 

+from the W3C, which is provided herein.

+

+

+LICENSE.dom-software.txt covers all software from the W3C 

+including the following items in the xml-commons project:

+

+    xml-commons/java/external/src/org/w3c

+      and all subdirectories

+

+LICENSE.dom-documentation.txt covers all documentation from the W3C 

+including the following items in the xml-commons project:

+

+    xml-commons/java/external/xdocs/dom

+      and all subdirectories

+

+The actual DOM Java Language Binding classes in xml-commons came from: 

+    http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/java-binding.html

+	The original versions are tagged 'DOM_LEVEL_2'

+

+The specification of DOM Level 2's various parts is at:

+    http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/

+    http://www.w3.org/TR/2000/REC-DOM-Level-2-Views-20001113/

+	http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/

+	http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/

+	http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/
\ No newline at end of file
diff --git a/trunk/distribution/src/main/release/licenses/xml-apis-README.sax.txt b/trunk/distribution/src/main/release/licenses/xml-apis-README.sax.txt
new file mode 100644
index 0000000..1bee542
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/xml-apis-README.sax.txt
@@ -0,0 +1,24 @@
+xml-commons/java/external/README.sax.txt $Id: README.sax.txt,v 1.1 2002/01/31 23:26:48 curcuru Exp $

+

+

+HEAR YE, HEAR YE!

+

+

+All of the .java software and associated documentation about 

+SAX in this repository are distributed freely in the 

+public domain.

+

+

+LICENSE.sax.txt covers all software and documentation from the 

+megginson.com including the following in the xml-commons project:

+

+    xml-commons/java/external/src/org/xml/sax

+      and all subdirectories

+    xml-commons/java/external/xdocs/sax

+      and all subdirectories

+

+

+The actual SAX classes in xml-commons came from: 

+    http://www.megginson.com/Software/index.html

+	The original versions are tagged 'SAX-2_0-r2-prerelease'

+

diff --git a/trunk/distribution/src/main/release/licenses/xml-apis-README.txt b/trunk/distribution/src/main/release/licenses/xml-apis-README.txt
new file mode 100644
index 0000000..02bab9b
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/xml-apis-README.txt
@@ -0,0 +1,22 @@
+xml-commons/README.txt $Id: README.txt,v 1.1 2002/01/31 23:42:49 curcuru Exp $

+

+

+HEAR YE, HEAR YE!

+

+

+Software and documentation in this repository are covered under 

+a number of different licenses.

+

+

+Most files under xml-commons/java/external/ are covered 

+under their respective LICENSE.*.txt files; see the matching 

+README.*.txt files for descriptions.

+

+Note that xml-commons/java/external/build.xml and 

+xml-commons/java/external/src/manifest.commons are 

+both covered under the Apache Software License.

+

+

+All files not otherwise noted are covered under the 

+Apache Software License in LICENSE.txt including all 

+files under xml-commons/java/src

diff --git a/trunk/distribution/src/main/release/licenses/xpp3-LICENSE.txt b/trunk/distribution/src/main/release/licenses/xpp3-LICENSE.txt
new file mode 100644
index 0000000..f1dc36c
--- /dev/null
+++ b/trunk/distribution/src/main/release/licenses/xpp3-LICENSE.txt
@@ -0,0 +1,47 @@
+XPP3 (http://caldersphere.rubyforge.org/jrexml/files/lib/xpp3_LICENSE_txt.html) :
+
+Indiana University Extreme! Lab Software License
+
+Version 1.1.1
+
+Copyright (c) 2002 Extreme! Lab, Indiana University. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, 
+this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright notice, 
+this list of conditions and the following disclaimer in the documentation 
+and/or other materials provided with the distribution.
+   3. The end-user documentation included with the redistribution, if any, must 
+include the following acknowledgment:
+
+  "This product includes software developed by the Indiana University
+  Extreme! Lab (http://www.extreme.indiana.edu/)."
+
+Alternately, this acknowledgment may appear in the software itself, if and 
+wherever such third-party acknowledgments normally appear.
+
+   1. The names "Indiana Univeristy" and "Indiana Univeristy Extreme! Lab"
+
+must not be used to endorse or promote products derived from this software 
+without prior written permission. For written permission, please contact 
+www.extreme.indiana.edu/.
+
+   1. Products derived from this software may not use "Indiana Univeristy"
+
+name nor may "Indiana Univeristy" appear in their name, without prior written 
+permission of the Indiana University.
+
+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 AUTHORS, 
+COPYRIGHT HOLDERS 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.
+
diff --git a/trunk/dsml/engine/pom.xml b/trunk/dsml/engine/pom.xml
new file mode 100644
index 0000000..4cf44d8
--- /dev/null
+++ b/trunk/dsml/engine/pom.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-dsml-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+
+  <artifactId>api-dsml-engine</artifactId>
+  <name>Apache Directory LDAP API DSML Engine</name>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-dsml-parser</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-client-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.xpp3</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.dom4j</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.dsmlv2.engine</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.dsmlv2.engine;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.dsmlv2;version=${project.version},
+              org.apache.directory.api.dsmlv2.response;version=${project.version},
+              org.apache.directory.api.dsmlv2.request;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.model.cursor;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.apache.directory.ldap.client.api;version=${project.version},
+              org.dom4j;version=${dom4j.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              org.xmlpull.v1;version=${xpp3.version}
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/dsml/engine/src/main/java/org/apache/directory/api/dsmlv2/engine/Dsmlv2Engine.java b/trunk/dsml/engine/src/main/java/org/apache/directory/api/dsmlv2/engine/Dsmlv2Engine.java
new file mode 100644
index 0000000..fc41fd2
--- /dev/null
+++ b/trunk/dsml/engine/src/main/java/org/apache/directory/api/dsmlv2/engine/Dsmlv2Engine.java
@@ -0,0 +1,814 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.engine;
+
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.OnError;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder;
+import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
+import org.apache.directory.api.dsmlv2.response.AddResponseDsml;
+import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
+import org.apache.directory.api.dsmlv2.response.BindResponseDsml;
+import org.apache.directory.api.dsmlv2.response.CompareResponseDsml;
+import org.apache.directory.api.dsmlv2.response.DelResponseDsml;
+import org.apache.directory.api.dsmlv2.response.ErrorResponse;
+import org.apache.directory.api.dsmlv2.response.ErrorResponse.ErrorResponseType;
+import org.apache.directory.api.dsmlv2.response.ExtendedResponseDsml;
+import org.apache.directory.api.dsmlv2.response.ModDNResponseDsml;
+import org.apache.directory.api.dsmlv2.response.ModifyResponseDsml;
+import org.apache.directory.api.dsmlv2.response.SearchResponseDsml;
+import org.apache.directory.api.dsmlv2.response.SearchResultDoneDsml;
+import org.apache.directory.api.dsmlv2.response.SearchResultEntryDsml;
+import org.apache.directory.api.dsmlv2.response.SearchResultReferenceDsml;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.Request;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * This is the DSMLv2Engine. It can be use to execute operations on a LDAP Server and get the results of these operations.
+ * The format used for request and responses is the DSMLv2 format.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Dsmlv2Engine
+{
+    /** The user. */
+    protected String user;
+
+    /** The password. */
+    protected String password;
+
+    /** The LDAP connection */
+    protected LdapConnection connection;
+
+    /** The DSVMv2 parser. */
+    protected Dsmlv2Parser parser;
+
+    /** The continue on error flag. */
+    protected boolean continueOnError;
+
+    /** The exit flag. */
+    protected boolean exit = false;
+
+    /** The batch request. */
+    protected BatchRequestDsml batchRequest;
+
+    /** The batch response. */
+    protected BatchResponseDsml batchResponse = new BatchResponseDsml();
+
+    protected Dsmlv2Grammar grammar = new Dsmlv2Grammar();
+
+    /** flag to indicate to generate the response in a SOAP envelope */
+    protected boolean generateSoapResp = false;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( Dsmlv2Engine.class );
+    
+    private static final String BODY_ENVELOPE = "</Body></Envelope>";
+
+
+    /**
+     * Creates a new instance of Dsmlv2Engine.
+     * 
+     * @param host the server host
+     * @param port the server port
+     * @param user the server admin Dn
+     * @param password the server admin's password
+     */
+    public Dsmlv2Engine( String host, int port, String user, String password )
+    {
+        this.user = user;
+        this.password = password;
+
+        connection = new LdapNetworkConnection( host, port );
+    }
+
+
+    /**
+     * Creates a new instance of Dsmlv2Engine.
+     *
+     * @param connection an unbound active connection
+     * @param user the user name to be used to bind this connection to the server
+     * @param password user's credentials
+     */
+    public Dsmlv2Engine( LdapConnection connection, String user, String password )
+    {
+        this.user = user;
+        this.password = password;
+
+        this.connection = connection;
+    }
+
+
+    /**
+     * Processes the file given and return the result of the operations
+     * 
+     * @param dsmlInput the DSMLv2 formatted request input
+     * @return the XML response in DSMLv2 Format
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public String processDSML( String dsmlInput ) throws XmlPullParserException
+    {
+        parser = new Dsmlv2Parser( grammar );
+        parser.setInput( dsmlInput );
+
+        return processDSML();
+    }
+
+
+    /**
+     * Processes the file given and return the result of the operations
+     * 
+     * @param fileName the path to the file
+     * @return the XML response in DSMLv2 Format
+     * @throws XmlPullParserException if an error occurs in the parser
+     * @throws FileNotFoundException if the file does not exist
+     */
+    public String processDSMLFile( String fileName ) throws XmlPullParserException, FileNotFoundException
+    {
+        parser = new Dsmlv2Parser( grammar );
+        parser.setInputFile( fileName );
+
+        return processDSML();
+    }
+
+
+    /**
+     * Process the given file and optionally writing the output to the
+     * output stream(if not null)
+     *
+     * @param file the DSML file
+     * @param respStream the output stream to which response will be written, skipped if null
+     * @throws Exception If the processing fails
+     */
+    public void processDSMLFile( File file, OutputStream respStream ) throws Exception
+    {
+        parser = new Dsmlv2Parser( grammar );
+        parser.setInputFile( file.getAbsolutePath() );
+
+        processDSML( respStream );
+    }
+
+
+    /**
+     * Uses the default UTF-8 encoding for processing the DSML
+     * 
+     * @see #processDSML(InputStream, String, OutputStream)
+     */
+    public void processDSML( InputStream inputStream, OutputStream out ) throws Exception
+    {
+        processDSML( inputStream, "UTF-8", out );
+    }
+
+
+    /**
+     * Processes the DSML request(s) from the given input stream with the specified encoding
+     * and writes the response to the output stream
+     * 
+     * @param inputStream the input stream for DSML batch request
+     * @param inputEncoding encoding to be used while reading the DSML request data
+     * @param out the output stream to which DSML response will be written
+     * @throws Exception If the processing fails
+     */
+    public void processDSML( InputStream inputStream, String inputEncoding, OutputStream out ) throws Exception
+    {
+        parser = new Dsmlv2Parser( grammar );
+        parser.setInput( inputStream, inputEncoding );
+        processDSML( out );
+    }
+
+
+    /**
+     * Processes the Request document
+     * 
+     * @return the XML response in DSMLv2 Format
+     */
+    private String processDSML()
+    {
+        try
+        {
+            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+            processDSML( byteOut );
+            return new String( byteOut.toByteArray(), "UTF-8" );
+        }
+        catch ( IOException e )
+        {
+            LOG.error( "Failed to process the DSML", e );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Processes the DSML batch request and writes the response of each operation will be
+     * written to the given response stream if it is not null
+     *
+     * @param outStream the stream to which the responses will be written, can be null
+     * @throws IOException If we had an issue while reading or writing the data
+     */
+    protected void processDSML( OutputStream outStream ) throws IOException
+    {
+        BufferedWriter respWriter = null;
+
+        if ( outStream != null )
+        {
+            respWriter = new BufferedWriter( new OutputStreamWriter( outStream ) );
+
+            if ( generateSoapResp )
+            {
+                respWriter.write( "<Envelope " );
+
+                Namespace soapNs = new Namespace( null, "http://www.w3.org/2001/12/soap-envelope" );
+                soapNs.write( respWriter );
+
+                respWriter.write( "><Body>" );
+            }
+        }
+
+        // Binding to LDAP Server
+        try
+        {
+            bind( 1 );
+        }
+        catch ( Exception e )
+        {
+            LOG.warn( "Failed to bind", e );
+
+            // Unable to connect to server
+            // We create a new ErrorResponse and return the XML response.
+            ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.COULD_NOT_CONNECT, e
+                .getLocalizedMessage() );
+
+            batchResponse.addResponse( errorResponse );
+
+            if ( respWriter != null )
+            {
+                respWriter.write( batchResponse.toDsml() );
+                if ( generateSoapResp )
+                {
+                    respWriter.write( BODY_ENVELOPE );
+                }
+
+                respWriter.flush();
+            }
+
+            return;
+        }
+
+        // Processing BatchRequest:
+        //    - Parsing and Getting BatchRequest
+        //    - Getting and registering options from BatchRequest
+        try
+        {
+            processBatchRequest();
+        }
+        catch ( XmlPullParserException e )
+        {
+            // We create a new ErrorResponse and return the XML response.
+            ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
+                I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
+
+            batchResponse.addResponse( errorResponse );
+
+            if ( respWriter != null )
+            {
+                respWriter.write( batchResponse.toDsml() );
+                if ( generateSoapResp )
+                {
+                    respWriter.write( BODY_ENVELOPE );
+                }
+
+                respWriter.flush();
+            }
+
+            return;
+        }
+
+        if ( respWriter != null )
+        {
+            StringBuilder sb = new StringBuilder();
+
+            sb.append( "<batchResponse " );
+
+            sb.append( ParserUtils.DSML_NAMESPACE.asXML() );
+
+            // a space to separate the namespace declarations
+            sb.append( " " );
+
+            sb.append( ParserUtils.XSD_NAMESPACE.asXML() );
+
+            // a space to separate the namespace declarations
+            sb.append( " " );
+
+            sb.append( ParserUtils.XSI_NAMESPACE.asXML() );
+
+            sb.append( " requestID=\"" );
+            sb.append( batchRequest.getRequestID() );
+            sb.append( "\">" );
+
+            respWriter.write( sb.toString() );
+        }
+
+        // Processing each request:
+        //    - Getting a new request
+        //    - Checking if the request is well formed
+        //    - Sending the request to the server
+        //    - Getting and converting reponse(s) as XML
+        //    - Looping until last request
+        DsmlDecorator<? extends Request> request = null;
+
+        try
+        {
+            request = parser.getNextRequest();
+        }
+        catch ( XmlPullParserException e )
+        {
+            LOG.warn( "Failed while getting next request", e );
+
+            int reqId = 0;
+
+            // We create a new ErrorResponse and return the XML response.
+            ErrorResponse errorResponse = new ErrorResponse( reqId, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
+                I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
+
+            batchResponse.addResponse( errorResponse );
+
+            if ( respWriter != null )
+            {
+                respWriter.write( batchResponse.toDsml() );
+
+                if ( generateSoapResp )
+                {
+                    respWriter.write( BODY_ENVELOPE );
+                }
+
+                respWriter.flush();
+            }
+
+            return;
+        }
+
+        // (Request == null when there's no more request to process)
+        while ( request != null )
+        {
+            // Checking the request has a requestID attribute if Processing = Parallel and ResponseOrder = Unordered
+            if ( ( batchRequest.getProcessing().equals( Processing.PARALLEL ) )
+                && ( batchRequest.getResponseOrder().equals( ResponseOrder.UNORDERED ) )
+                && ( request.getDecorated().getMessageId() <= 0 ) )
+            {
+                // Then we have to send an errorResponse
+                ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n
+                    .err( I18n.ERR_03002 ) );
+
+                if ( respWriter != null )
+                {
+                    writeResponse( respWriter, errorResponse );
+                }
+                else
+                {
+                    batchResponse.addResponse( errorResponse );
+                }
+
+                break;
+            }
+
+            try
+            {
+                processRequest( request, respWriter );
+            }
+            catch ( Exception e )
+            {
+                LOG.warn( "Failed to process request", e );
+
+                // We create a new ErrorResponse and return the XML response.
+                ErrorResponse errorResponse = new ErrorResponse( request.getDecorated().getMessageId(),
+                    ErrorResponseType.GATEWAY_INTERNAL_ERROR, I18n.err(
+                        I18n.ERR_03003, e.getMessage() ) );
+
+                if ( respWriter != null )
+                {
+                    writeResponse( respWriter, errorResponse );
+                }
+                else
+                {
+                    batchResponse.addResponse( errorResponse );
+                }
+
+                break;
+            }
+
+            // Checking if we need to exit processing (if an error has occurred if onError == Exit)
+            if ( exit )
+            {
+                break;
+            }
+
+            // Getting next request
+            try
+            {
+                request = parser.getNextRequest();
+            }
+            catch ( XmlPullParserException e )
+            {
+                // We create a new ErrorResponse and return the XML response.
+                ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
+                    I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
+
+                if ( respWriter != null )
+                {
+                    writeResponse( respWriter, errorResponse );
+                }
+                else
+                {
+                    batchResponse.addResponse( errorResponse );
+                }
+
+                break;
+            }
+        }
+
+        if ( respWriter != null )
+        {
+            respWriter.write( "</batchResponse>" );
+
+            if ( generateSoapResp )
+            {
+                respWriter.write( BODY_ENVELOPE );
+            }
+
+            respWriter.flush();
+        }
+    }
+
+
+    /**
+     * Writes the response to the writer of the underlying output stream
+     * 
+     * @param respWriter The writer used to write the response
+     * @param respDsml The decorator containing the response
+     * @throws IOException If we had an error while writing the DSML response
+     */
+    protected void writeResponse( BufferedWriter respWriter, DsmlDecorator<?> respDsml ) throws IOException
+    {
+        if ( respWriter != null )
+        {
+            Element xml = respDsml.toDsml( null );
+            xml.write( respWriter );
+        }
+    }
+
+
+    /**
+     * @return the generateSoapResp
+     */
+    public boolean isGenerateSoapResp()
+    {
+        return generateSoapResp;
+    }
+
+
+    /**
+     * @param generateSoapResp the generateSoapResp to set
+     */
+    public void setGenerateSoapResp( boolean generateSoapResp )
+    {
+        this.generateSoapResp = generateSoapResp;
+    }
+
+
+    /**
+     * @return the batchResponse
+     */
+    public BatchResponseDsml getBatchResponse()
+    {
+        return batchResponse;
+    }
+
+
+    /**
+     * @return the connection
+     */
+    public LdapConnection getConnection()
+    {
+        return connection;
+    }
+
+
+    /**
+     * Processes a single request
+     * 
+     * @param request the request to process
+     * @param respWriter The writer used to store the DSML response
+     * @exception Exception If we had an error while processing the request
+     */
+    protected void processRequest( DsmlDecorator<? extends Request> request, BufferedWriter respWriter )
+        throws Exception
+    {
+        ResultCodeEnum resultCode = null;
+
+        switch ( request.getDecorated().getType() )
+        {
+            case ABANDON_REQUEST:
+                connection.abandon( ( AbandonRequest ) request );
+                return;
+
+            case ADD_REQUEST:
+                AddResponse response = connection.add( ( AddRequest ) request );
+                resultCode = response.getLdapResult().getResultCode();
+                AddResponseDsml addResponseDsml = new AddResponseDsml( connection.getCodecService(), response );
+                writeResponse( respWriter, addResponseDsml );
+
+                break;
+
+            case BIND_REQUEST:
+                BindResponse bindResponse = connection.bind( ( BindRequest ) request );
+                resultCode = bindResponse.getLdapResult().getResultCode();
+                BindResponseDsml authResponseDsml = new BindResponseDsml( connection.getCodecService(), bindResponse );
+                writeResponse( respWriter, authResponseDsml );
+
+                break;
+
+            case COMPARE_REQUEST:
+                CompareResponse compareResponse = connection.compare( ( CompareRequest ) request );
+                resultCode = compareResponse.getLdapResult().getResultCode();
+                CompareResponseDsml compareResponseDsml = new CompareResponseDsml( connection.getCodecService(),
+                    compareResponse );
+                writeResponse( respWriter, compareResponseDsml );
+
+                break;
+
+            case DEL_REQUEST:
+                DeleteResponse delResponse = connection.delete( ( DeleteRequest ) request );
+                resultCode = delResponse.getLdapResult().getResultCode();
+                DelResponseDsml delResponseDsml = new DelResponseDsml( connection.getCodecService(), delResponse );
+                writeResponse( respWriter, delResponseDsml );
+
+                break;
+
+            case EXTENDED_REQUEST:
+                ExtendedResponse extendedResponse = connection.extended( ( ExtendedRequest ) request );
+                resultCode = extendedResponse.getLdapResult().getResultCode();
+                ExtendedResponseDsml extendedResponseDsml = new ExtendedResponseDsml( connection.getCodecService(),
+                    extendedResponse );
+                writeResponse( respWriter, extendedResponseDsml );
+
+                break;
+
+            case MODIFY_REQUEST:
+                ModifyResponse modifyResponse = connection.modify( ( ModifyRequest ) request );
+                resultCode = modifyResponse.getLdapResult().getResultCode();
+                ModifyResponseDsml modifyResponseDsml = new ModifyResponseDsml( connection.getCodecService(),
+                    modifyResponse );
+                writeResponse( respWriter, modifyResponseDsml );
+
+                break;
+
+            case MODIFYDN_REQUEST:
+                ModifyDnResponse modifyDnResponse = connection.modifyDn( ( ModifyDnRequest ) request );
+                resultCode = modifyDnResponse.getLdapResult().getResultCode();
+                ModDNResponseDsml modDNResponseDsml = new ModDNResponseDsml( connection.getCodecService(),
+                    modifyDnResponse );
+                writeResponse( respWriter, modDNResponseDsml );
+
+                break;
+
+            case SEARCH_REQUEST:
+                SearchCursor searchResponses = connection.search( ( SearchRequest ) request );
+
+                SearchResponseDsml searchResponseDsml = new SearchResponseDsml( connection.getCodecService() );
+
+                if ( respWriter != null )
+                {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append( "<searchResponse" );
+
+                    if ( request.getDecorated().getMessageId() > 0 )
+                    {
+                        sb.append( " requestID=\"" );
+                        sb.append( request.getDecorated().getMessageId() );
+                        sb.append( '"' );
+                    }
+
+                    sb.append( '>' );
+
+                    respWriter.write( sb.toString() );
+                }
+
+                while ( searchResponses.next() )
+                {
+                    Response searchResponse = searchResponses.get();
+
+                    if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_ENTRY )
+                    {
+                        SearchResultEntry searchResultEntry = ( SearchResultEntry ) searchResponse;
+
+                        SearchResultEntryDsml searchResultEntryDsml = new SearchResultEntryDsml(
+                            connection.getCodecService(), searchResultEntry );
+                        searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
+                            searchResultEntryDsml );
+
+                        if ( respWriter != null )
+                        {
+                            writeResponse( respWriter, searchResultEntryDsml );
+                        }
+                        else
+                        {
+                            searchResponseDsml.addResponse( searchResultEntryDsml );
+                        }
+                    }
+                    else if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_REFERENCE )
+                    {
+                        SearchResultReference searchResultReference = ( SearchResultReference ) searchResponse;
+
+                        SearchResultReferenceDsml searchResultReferenceDsml = new SearchResultReferenceDsml(
+                            connection.getCodecService(), searchResultReference );
+                        searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
+                            searchResultReferenceDsml );
+
+                        if ( respWriter != null )
+                        {
+                            writeResponse( respWriter, searchResultReferenceDsml );
+                        }
+                        else
+                        {
+                            searchResponseDsml.addResponse( searchResultReferenceDsml );
+                        }
+                    }
+                }
+
+                SearchResultDone srDone = searchResponses.getSearchResultDone();
+
+                if ( srDone != null )
+                {
+                    resultCode = srDone.getLdapResult().getResultCode();
+
+                    SearchResultDoneDsml srdDsml = new SearchResultDoneDsml( connection.getCodecService(), srDone );
+
+                    if ( respWriter != null )
+                    {
+                        writeResponse( respWriter, srdDsml );
+                        respWriter.write( "</searchResponse>" );
+                    }
+                    else
+                    {
+                        searchResponseDsml.addResponse( srdDsml );
+                        batchResponse.addResponse( searchResponseDsml );
+                    }
+                }
+
+                break;
+
+            case UNBIND_REQUEST:
+                connection.unBind();
+                break;
+
+            default:
+                throw new IllegalStateException( "Unexpected request tpye " + request.getDecorated().getType() );
+        }
+
+        if ( ( !continueOnError ) && ( resultCode != null ) && ( resultCode != ResultCodeEnum.SUCCESS )
+            && ( resultCode != ResultCodeEnum.COMPARE_TRUE ) && ( resultCode != ResultCodeEnum.COMPARE_FALSE )
+            && ( resultCode != ResultCodeEnum.REFERRAL ) )
+        {
+            // Turning on Exit flag
+            exit = true;
+        }
+    }
+
+
+    /**
+     * Processes the BatchRequest
+     * <ul>
+     *     <li>Parsing and Getting BatchRequest</li>
+     *     <li>Getting and registering options from BatchRequest</li>
+     * </ul>
+     * 
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    protected void processBatchRequest() throws XmlPullParserException
+    {
+        // Parsing BatchRequest
+        parser.parseBatchRequest();
+
+        // Getting BatchRequest
+        batchRequest = parser.getBatchRequest();
+
+        if ( OnError.RESUME.equals( batchRequest.getOnError() ) )
+        {
+            continueOnError = true;
+        }
+        else if ( OnError.EXIT.equals( batchRequest.getOnError() ) )
+        {
+            continueOnError = false;
+        }
+
+        if ( ( batchRequest.getRequestID() != 0 ) && ( batchResponse != null ) )
+        {
+            batchResponse.setRequestID( batchRequest.getRequestID() );
+        }
+    }
+
+
+    /**
+     * Binds to the ldap server
+     * 
+     * @param messageId the message Id
+     * @throws EncoderException If we had an issue while encoding the request
+     * @throws DecoderException If we had an issue while decoding the request
+     * @throws IOException If we had an issue while transmitting the request or re ceiving the response
+     */
+    protected void bind( int messageId ) throws LdapException, EncoderException, DecoderException, IOException
+    {
+        if ( ( connection != null ) && connection.isAuthenticated() )
+        {
+            return;
+        }
+
+        if ( connection == null )
+        {
+            throw new IOException( I18n.err( I18n.ERR_03101_MISSING_CONNECTION_TO ) );
+        }
+
+        BindRequest bindRequest = new BindRequestImpl();
+        bindRequest.setSimple( true );
+        bindRequest.setCredentials( Strings.getBytesUtf8( password ) );
+        bindRequest.setName( user );
+        bindRequest.setVersion3( true );
+        bindRequest.setMessageId( messageId );
+
+        BindResponse bindResponse = connection.bind( bindRequest );
+
+        if ( bindResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
+        {
+            LOG.warn( "Error : {}", bindResponse.getLdapResult().getDiagnosticMessage() );
+        }
+    }
+}
diff --git a/trunk/dsml/engine/src/site/site.xml b/trunk/dsml/engine/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/dsml/engine/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/dsml/parser/pom.xml b/trunk/dsml/parser/pom.xml
new file mode 100644
index 0000000..be14365
--- /dev/null
+++ b/trunk/dsml/parser/pom.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-dsml-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+
+  <artifactId>api-dsml-parser</artifactId>
+  <name>Apache Directory LDAP API DSML Parser</name>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-standalone</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.dom4j</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.xpp3</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>findbugs</groupId>
+      <artifactId>annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <groupId>org.apache.maven.plugins</groupId>
+        <configuration>
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target</workingDirectory>
+            <felix.cache.rootdir>
+              ${project.build.directory}
+            </felix.cache.rootdir>
+            <felix.cache.locking>
+              false
+            </felix.cache.locking>
+            <org.osgi.framework.storage>
+              osgi-cache
+            </org.osgi.framework.storage>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.dsmlv2.parser</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.dsmlv2;version=${project.version};-noimport:=true,
+              org.apache.directory.api.dsmlv2.response;version=${project.version};-noimport:=true,
+              org.apache.directory.api.dsmlv2.request;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.asn1.util;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.codec.api;version=${project.version},
+              org.apache.directory.api.ldap.model.entry;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.filter;version=${project.version},
+              org.apache.directory.api.ldap.model.ldif;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.message.controls;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.url;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.dom4j;version=${dom4j.version},
+              org.dom4j.io;version=${dom4j.version},
+              org.dom4j.tree;version=${dom4j.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              org.xmlpull.v1;version=${xpp3.version},
+              javax.xml.transform,
+              javax.xml.transform.stream
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/dsml/parser/src/checkstyle/suppressions.xml b/trunk/dsml/parser/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..2d4cb41
--- /dev/null
+++ b/trunk/dsml/parser/src/checkstyle/suppressions.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <suppress files="org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar" checks="FileLength" />
+    <suppress files="org.apache.directory.api.dsmlv2.response.Dsmlv2ResponseGrammar" checks="FileLength" />
+    <suppress files="org.apache.directory.api.dsmlv2.searchRequest.SearchRequestTest" checks="FileLength" />
+</suppressions>
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/AbstractDsmlMessageDecorator.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/AbstractDsmlMessageDecorator.java
new file mode 100644
index 0000000..9ce15de
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/AbstractDsmlMessageDecorator.java
@@ -0,0 +1,223 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+
+
+/**
+ * An abstract DSML Message decorator base class.
+ *
+ * @param <M> The message to decorate
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractDsmlMessageDecorator<M extends Message>
+    implements DsmlDecorator<M>, Message
+{
+    /** The LDAP message codec */
+    private final LdapApiService codec;
+
+    /** The LDAP message */
+    private final M message;
+
+    /** Map of message controls using OID Strings for keys and Control values */
+    private final Map<String, Control> controls;
+
+    /** The current control */
+    private DsmlControl<? extends Control> currentControl;
+
+
+    /**
+     * Create a new instance of AbstractDsmlMessageDecorator
+     * 
+     * @param codec The codec to use
+     * @param message The message to decorate
+     */
+    public AbstractDsmlMessageDecorator( LdapApiService codec, M message )
+    {
+        this.codec = codec;
+        this.message = message;
+        controls = new HashMap<String, Control>();
+    }
+
+
+    /**
+     * Get the current Control Object
+     * 
+     * @return The current Control Object
+     */
+    public DsmlControl<? extends Control> getCurrentControl()
+    {
+        return currentControl;
+    }
+
+
+    /**
+     * @return The codec to use to encode or decode this message
+     */
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return message.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Control> getControls()
+    {
+        return controls;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Control getControl( String oid )
+    {
+        return controls.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasControl( String oid )
+    {
+        return controls.containsKey( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message addControl( Control control )
+    {
+        Control decorated;
+        DsmlControl<? extends Control> decorator;
+
+        if ( control instanceof DsmlControl )
+        {
+            decorator = ( DsmlControl<?> ) control;
+            decorated = decorator.getDecorated();
+        }
+        else
+        {
+            decorator = new DsmlControl<Control>( codec, codec.newControl( control ) );
+            decorated = control;
+        }
+
+        message.addControl( decorated );
+        controls.put( control.getOid(), decorator );
+        currentControl = decorator;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message addAllControls( Control[] controlsToAdd )
+    {
+        for ( Control control : controlsToAdd )
+        {
+            addControl( control );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message removeControl( Control control )
+    {
+        controls.remove( control.getOid() );
+        message.removeControl( control );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getMessageId()
+    {
+        return message.getMessageId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object get( Object key )
+    {
+        return message.get( key );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object put( Object key, Object value )
+    {
+        return message.put( key, value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message setMessageId( int messageId )
+    {
+        message.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public M getDecorated()
+    {
+        return message;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/AbstractGrammar.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/AbstractGrammar.java
new file mode 100644
index 0000000..a58c949
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/AbstractGrammar.java
@@ -0,0 +1,166 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * The abstract Grammar which is the Mother of all the grammars. It contains
+ * the transitions table.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractGrammar implements Grammar
+{
+    /**
+     * Table of transitions. It's a two dimension array, the first dimension
+     * indexes the states, the second dimension indexes the Tag value, so it is
+     * 256 wide.
+     */
+    protected HashMap<Tag, GrammarTransition>[] transitions;
+
+    /** The grammar name */
+    protected String name;
+
+
+    /**
+     * Returns the grammar's name
+     * 
+     * @return The grammar name
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * Sets the grammar's name
+     * 
+     * @param name the name to set
+     */
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Gets the transition associated with the state and tag
+     * 
+     * @param state The current state
+     * @param tag The current tag
+     * @return A valid transition if any, or null.
+     */
+    public GrammarTransition getTransition( Enum<Dsmlv2StatesEnum> state, Tag tag )
+    {
+        return transitions[state.ordinal()].get( tag );
+    }
+
+
+    /**
+     * Gets the states of the current grammar
+     * 
+     * @return Returns the statesEnum.
+     */
+    public Enum<Dsmlv2StatesEnum>[] getStatesEnum()
+    {
+        return Dsmlv2StatesEnum.values();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void executeAction( Dsmlv2Container container ) throws XmlPullParserException, IOException
+    {
+        XmlPullParser xpp = container.getParser();
+
+        int eventType = xpp.getEventType();
+
+        do
+        {
+            switch ( eventType )
+            {
+                case XmlPullParser.START_DOCUMENT:
+                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
+                    break;
+
+                case XmlPullParser.END_DOCUMENT:
+                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
+                    break;
+
+                case XmlPullParser.START_TAG:
+                    processTag( container, Tag.START );
+                    break;
+
+                case XmlPullParser.END_TAG:
+                    processTag( container, Tag.END );
+                    break;
+
+                default:
+                    break;
+            }
+
+            eventType = xpp.next();
+        }
+        while ( eventType != XmlPullParser.END_DOCUMENT );
+    }
+
+
+    /**
+     * Processes the task required in the grammar to the given tag type
+     *
+     * @param container the DSML container
+     * @param tagType the tag type
+     * @throws XmlPullParserException when an error occurs during the parsing
+     */
+    private void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
+    {
+        XmlPullParser xpp = container.getParser();
+
+        String tagName = Strings.toLowerCase( xpp.getName() );
+
+        GrammarTransition transition = getTransition( container.getState(), new Tag( tagName, tagType ) );
+
+        if ( transition != null )
+        {
+            container.setState( transition.getNextState() );
+
+            if ( transition.hasAction() )
+            {
+                GrammarAction action = transition.getAction();
+                action.action( container );
+            }
+        }
+        else
+        {
+            throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
+        }
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Action.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Action.java
new file mode 100644
index 0000000..42d1ef5
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Action.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * IAction interface just contains the method 'action' which must be implemented
+ * in all the implementation classes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Action
+{
+    /**
+     * The action to be executed.
+     * 
+     * @param container the container which stores the current data
+     * @throws XmlPullParserException thrown if something went wrong.
+     */
+    void action( Dsmlv2Container container ) throws XmlPullParserException;
+}
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Container.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Container.java
new file mode 100644
index 0000000..69d3781
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Container.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+/**
+ * This interface represents a container that can be used by the parser to store parsed information
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Container
+{
+    /**
+     * Gets the current grammar state
+     * 
+     * @return Returns the current grammar state
+     */
+    Enum<Dsmlv2StatesEnum> getState();
+
+
+    /**
+     * Sets the new current state
+     * 
+     * @param state The new state
+     */
+    void setState( Enum<Dsmlv2StatesEnum> state );
+
+
+    /**
+     * Gets the transition
+     * 
+     * @return Returns the transition from the previous state to the new state
+     */
+    Enum<Dsmlv2StatesEnum> getTransition();
+
+
+    /**
+     * Updates the transition from a state to another
+     * 
+     * @param transition The transition to set
+     */
+    void setTransition( Enum<Dsmlv2StatesEnum> transition );
+
+
+    /**
+     * @return Returns the states.
+     */
+    Enum<Dsmlv2StatesEnum>[] getStates();
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/DsmlControl.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/DsmlControl.java
new file mode 100644
index 0000000..796a01c
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/DsmlControl.java
@@ -0,0 +1,153 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.dom4j.Element;
+
+
+/**
+ * A DSML decorator for a {@link Control}.
+ *
+ * @param <C> The decorated Control
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DsmlControl<C extends Control> implements Control, DsmlDecorator<C>
+{
+    /** The decorated Control */
+    private C decorated;
+
+    /** The encoded value of the control. */
+    protected byte[] value;
+
+    /** The codec service responsible for encoding decoding this object */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of DsmlControl
+     * @param codec The Codec used to encode/decode the Control
+     * @param decorated The decorated control
+     */
+    public DsmlControl( LdapApiService codec, C decorated )
+    {
+        this.codec = codec;
+        this.decorated = decorated;
+    }
+
+
+    /**
+     * @return The LDAP codec service.
+     */
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * Checks to see if this DSML control decorator has a value.
+     *
+     * @return true if the DSML control has a value, false otherwise.
+     */
+    public boolean hasValue()
+    {
+        return value != null;
+    }
+
+
+    /**
+     * Gets the control value
+     * 
+     * @return The control value
+     */
+    public byte[] getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Sets the encoded control value
+     * 
+     * @param value The encoded control value to store
+     */
+    public void setValue( byte[] value )
+    {
+        if ( value != null )
+        {
+            byte[] copy = new byte[value.length];
+            System.arraycopy( value, 0, copy, 0, value.length );
+            this.value = copy;
+        }
+        else
+        {
+            this.value = null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return decorated.getOid();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isCritical()
+    {
+        return decorated.isCritical();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCritical( boolean isCritical )
+    {
+        decorated.setCritical( isCritical );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public C getDecorated()
+    {
+        return decorated;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/DsmlDecorator.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/DsmlDecorator.java
new file mode 100644
index 0000000..b27c243
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/DsmlDecorator.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import org.dom4j.Element;
+
+
+/**
+ * This interface defines the methods that must be implemented to define a DSML Decorator
+ * 
+ * @param <M> The message to decorate
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface DsmlDecorator<M>
+{
+    /**
+     * Converts the request/reponse to its XML representation in the DSMLv2 format
+     * 
+     * @param root the root dom4j Element
+     * @return the dom4j Element corresponding to the entry.
+     */
+    Element toDsml( Element root );
+
+
+    /**
+     * Gets the Message this DsmlDecorator decorates.
+     * 
+     * @return The decorated Message instance
+     */
+    M getDecorated();
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2Container.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2Container.java
new file mode 100644
index 0000000..1e840ad
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2Container.java
@@ -0,0 +1,238 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.xmlpull.v1.XmlPullParser;
+
+
+/**
+ * This class represents the DSML Container.
+ * It used by the DSML Parser to store information.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Dsmlv2Container implements Container
+{
+    /** The current state of the decoding */
+    private Enum<Dsmlv2StatesEnum> state;
+
+    /** The current transition */
+    private Enum<Dsmlv2StatesEnum> transition;
+
+    /** Store the different states for debug purpose */
+    private Enum<Dsmlv2StatesEnum>[] states;
+
+    /** The pool parser */
+    private XmlPullParser parser;
+
+    /** The BatchRequest of the parsing */
+    private BatchRequestDsml batchRequest;
+
+    /** The BatchResponse of the parsing */
+    private BatchResponseDsml batchResponse;
+
+    /**  The associated grammar */
+    private AbstractGrammar grammar;
+
+    /** The codec service */
+    private final LdapApiService codec;
+
+
+    /**
+     * Creates a new LdapMessageContainer object.
+     * 
+     * @param codec the Codec used to encode/decode the messages
+     */
+    public Dsmlv2Container( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * Gets the {@link LdapApiService} associated with this Container.
+     *
+     * @return The codec used to encode/decode the messages
+     */
+    public LdapApiService getLdapCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * Gets the DSML Batch Request
+     * 
+     * @return Returns the Batch Request
+     */
+    public BatchRequestDsml getBatchRequest()
+    {
+        return batchRequest;
+    }
+
+
+    /**
+     * Sets the DSML Batch Request
+     * 
+     * @param batchRequest the Batch Request to set
+     */
+    public void setBatchRequest( BatchRequestDsml batchRequest )
+    {
+        this.batchRequest = batchRequest;
+    }
+
+
+    /**
+     * Gets the DSML Batch Response
+     * 
+     * @return Returns the Batch Response
+     */
+    public BatchResponseDsml getBatchResponse()
+    {
+        return batchResponse;
+    }
+
+
+    /**
+     * Sets the DSML Batch Request
+     * 
+     * @param batchResponse the Batch Response to set
+     */
+    public void setBatchResponse( BatchResponseDsml batchResponse )
+    {
+        this.batchResponse = batchResponse;
+    }
+
+
+    /**
+     * Gets the parser
+     * 
+     * @return the parser
+     */
+    public XmlPullParser getParser()
+    {
+        return parser;
+    }
+
+
+    /**
+     * Sets the parser
+     * 
+     * @param parser the parser to set
+     */
+    public void setParser( XmlPullParser parser )
+    {
+        this.parser = parser;
+    }
+
+
+    /**
+     * Get the current grammar state
+     * 
+     * @return the current grammar state
+     */
+    public Enum<Dsmlv2StatesEnum> getState()
+    {
+        return state;
+    }
+
+
+    /**
+     * Set the new current state
+     * 
+     * @param state the new state
+     */
+    public void setState( Enum<Dsmlv2StatesEnum> state )
+    {
+        this.state = state;
+    }
+
+
+    /**
+     * Get the transition
+     * 
+     * @return the transition from the previous state to the new state
+     */
+    public Enum<Dsmlv2StatesEnum> getTransition()
+    {
+        return transition;
+    }
+
+
+    /**
+     * Update the transition from a state to another
+     * 
+     * @param transition the transition to set
+     */
+    public void setTransition( Enum<Dsmlv2StatesEnum> transition )
+    {
+        this.transition = transition;
+    }
+
+
+    /**
+     * Get the states for this container's grammars
+     * 
+     * @return the states.
+     */
+    public Enum<Dsmlv2StatesEnum>[] getStates()
+    {
+        return states;
+    }
+
+
+    /**
+     * Gets the grammar
+     *
+     * @return the grammar
+     */
+    public AbstractGrammar getGrammar()
+    {
+        return grammar;
+    }
+
+
+    /**
+     * Sets the Grammar
+     * 
+     * @param grammar the grammar to set
+     */
+    public void setGrammar( AbstractGrammar grammar )
+    {
+        this.grammar = grammar;
+    }
+
+
+    /**
+     * Get the transition associated with the state and tag
+     * 
+     * @param currentState the current state
+     * @param currentTag the current tag
+     * @return a valid transition if any, or null.
+     */
+    public GrammarTransition getTransition( Enum<Dsmlv2StatesEnum> currentState, Tag currentTag )
+    {
+        return grammar.getTransition( currentState, currentTag );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2Parser.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2Parser.java
new file mode 100644
index 0000000..f3cb763
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2Parser.java
@@ -0,0 +1,341 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.Request;
+import org.apache.directory.api.util.Strings;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+
+/**
+ * This class represents the DSMLv2 Parser.
+ * It can be used to parse a plain DSMLv2 Request input document or the one inside a SOAP envelop.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Dsmlv2Parser
+{
+    /** The associated DSMLv2 container */
+    private Dsmlv2Container container;
+
+    /**
+     * flag to indicate if the batch request should maintain a list of all the
+     * operation request objects present in the DSML document. Default is true
+     */
+    private boolean storeMsgInBatchReq = true;
+
+    /** The thread safe DSMLv2 Grammar */
+    private Dsmlv2Grammar grammar;
+
+
+    /**
+     * Creates a new instance of Dsmlv2Parser.
+     *
+     * @throws XmlPullParserException if an error occurs during the initialization of the parser
+     */
+    public Dsmlv2Parser() throws XmlPullParserException
+    {
+        this( true );
+    }
+
+
+    /**
+     * Creates a new instance of Dsmlv2Parser.
+     *
+     * @param storeMsgInBatchReq flag to set if the parsed requests should b stored
+     * @throws XmlPullParserException if an error occurs during the initialization of the parser
+     */
+    public Dsmlv2Parser( boolean storeMsgInBatchReq ) throws XmlPullParserException
+    {
+        this.storeMsgInBatchReq = storeMsgInBatchReq;
+
+        this.grammar = new Dsmlv2Grammar();
+        this.container = new Dsmlv2Container( grammar.getLdapCodecService() );
+
+        this.container.setGrammar( grammar );
+
+        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        factory.setNamespaceAware( true );
+        XmlPullParser xpp = factory.newPullParser();
+
+        container.setParser( xpp );
+    }
+
+
+    /**
+     * Creates a new instance of Dsmlv2Parser.
+     *
+     * @throws XmlPullParserException if an error occurs during the initialization of the parser
+     */
+    public Dsmlv2Parser( Dsmlv2Grammar grammar ) throws XmlPullParserException
+    {
+        this.container = new Dsmlv2Container( grammar.getLdapCodecService() );
+        this.container.setGrammar( grammar );
+        this.grammar = grammar;
+
+        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        factory.setNamespaceAware( true );
+        XmlPullParser xpp = factory.newPullParser();
+
+        container.setParser( xpp );
+    }
+
+
+    /**
+     * Sets the input file the parser is going to parse
+     *
+     * @param fileName the name of the file
+     * @throws FileNotFoundException if the file does not exist
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void setInputFile( String fileName ) throws FileNotFoundException, XmlPullParserException
+    {
+        Reader reader = new FileReader( fileName );
+        container.getParser().setInput( reader );
+    }
+
+
+    /**
+     * Sets the input stream the parser is going to process
+     *
+     * @param inputStream contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null)
+     * @param inputEncoding if not null it MUST be used as encoding for inputStream
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
+    {
+        container.getParser().setInput( inputStream, inputEncoding );
+    }
+
+
+    /**
+     * Sets the input string the parser is going to parse
+     *
+     * @param str the string the parser is going to parse
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void setInput( String str ) throws XmlPullParserException
+    {
+        container.getParser().setInput( new StringReader( str ) );
+    }
+
+
+    /**
+     * Launches the parsing on the input
+     * This method will parse the whole DSML document, without considering the flag {@link #storeMsgInBatchReq}
+     * @throws XmlPullParserException when an unrecoverable error occurs
+     * @throws IOException when an IO execption occurs
+     */
+    public void parse() throws XmlPullParserException, IOException
+    {
+        grammar.executeAction( container );
+    }
+
+
+    /**
+     * Launches the parsing of the Batch Request only
+     *
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void parseBatchRequest() throws XmlPullParserException
+    {
+        XmlPullParser xpp = container.getParser();
+
+        int eventType = xpp.getEventType();
+
+        do
+        {
+            switch ( eventType )
+            {
+                case XmlPullParser.START_DOCUMENT:
+                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
+                    break;
+
+                case XmlPullParser.END_DOCUMENT:
+                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
+                    break;
+
+                case XmlPullParser.START_TAG:
+                    processTag( container, Tag.START );
+                    break;
+
+                case XmlPullParser.END_TAG:
+                    processTag( container, Tag.END );
+                    break;
+
+                default:
+                    break;
+            }
+
+            try
+            {
+                eventType = xpp.next();
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03037, ioe.getLocalizedMessage() ), xpp, ioe );
+            }
+        }
+        while ( container.getState() != Dsmlv2StatesEnum.BATCHREQUEST_START_TAG );
+
+        BatchRequestDsml br = container.getBatchRequest();
+
+        if ( br != null )
+        {
+            br.setStoreReq( storeMsgInBatchReq );
+        }
+    }
+
+
+    /**
+     * Processes the task required in the grammar to the given tag type
+     *
+     * @param container the DSML container
+     * @param tagType the tag type
+     * @throws XmlPullParserException when an error occurs during the parsing
+     */
+    private static void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
+    {
+        XmlPullParser xpp = container.getParser();
+
+        String tagName = Strings.toLowerCase( xpp.getName() );
+
+        GrammarTransition transition = container.getTransition( container.getState(), new Tag( tagName, tagType ) );
+
+        if ( transition != null )
+        {
+            container.setState( transition.getNextState() );
+
+            if ( transition.hasAction() )
+            {
+                transition.getAction().action( container );
+            }
+        }
+        else
+        {
+            throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
+        }
+    }
+
+
+    /**
+     * Gets the Batch Request or null if the it has not been parsed yet
+     *
+     * @return the Batch Request or null if the it has not been parsed yet
+     */
+    public BatchRequestDsml getBatchRequest()
+    {
+        return container.getBatchRequest();
+    }
+
+
+    /**
+     * Gets the next Request or null if there's no more request
+     * @return the next Request or null if there's no more request
+     * @throws XmlPullParserException when an error occurs during the parsing
+     */
+    public DsmlDecorator<? extends Request> getNextRequest() throws XmlPullParserException
+    {
+        if ( container.getBatchRequest() == null )
+        {
+            parseBatchRequest();
+        }
+
+        XmlPullParser xpp = container.getParser();
+
+        int eventType = xpp.getEventType();
+        do
+        {
+            while ( eventType == XmlPullParser.TEXT )
+            {
+                try
+                {
+                    xpp.next();
+                }
+                catch ( IOException ioe )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03037, ioe.getLocalizedMessage() ), xpp, ioe );
+                }
+                eventType = xpp.getEventType();
+            }
+
+            switch ( eventType )
+            {
+                case XmlPullParser.START_DOCUMENT:
+                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
+                    break;
+
+                case XmlPullParser.END_DOCUMENT:
+                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
+                    return null;
+
+                case XmlPullParser.START_TAG:
+                    processTag( container, Tag.START );
+                    break;
+
+                case XmlPullParser.END_TAG:
+                    processTag( container, Tag.END );
+                    break;
+
+                default:
+                    break;
+            }
+
+            try
+            {
+                eventType = xpp.next();
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03037, ioe.getLocalizedMessage() ), xpp, ioe );
+            }
+        }
+        while ( container.getState() != Dsmlv2StatesEnum.BATCHREQUEST_LOOP );
+
+        return container.getBatchRequest().getCurrentRequest();
+    }
+
+
+    /**
+     * Parses all the requests
+     *
+     * @throws XmlPullParserException when an error occurs during the parsing
+     */
+    public void parseAllRequests() throws XmlPullParserException
+    {
+        while ( getNextRequest() != null )
+        {
+            continue;
+        }
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2ResponseParser.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2ResponseParser.java
new file mode 100644
index 0000000..e6f78fd
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2ResponseParser.java
@@ -0,0 +1,294 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
+import org.apache.directory.api.dsmlv2.response.Dsmlv2ResponseGrammar;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.util.Strings;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+
+/**
+ * This class represents the DSMLv2 Parser.
+ * It can be used to parse a DSMLv2 Response input.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Dsmlv2ResponseParser
+{
+    /** The associated DSMLv2 container */
+    private Dsmlv2Container container;
+
+
+    /**
+     * Creates a new instance of Dsmlv2ResponseParser.
+     *
+     * @throws XmlPullParserException if an error occurs while the initialization of the parser
+     */
+    public Dsmlv2ResponseParser( LdapApiService codec ) throws XmlPullParserException
+    {
+        this.container = new Dsmlv2Container( codec );
+
+        this.container.setGrammar( Dsmlv2ResponseGrammar.getInstance() );
+
+        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        factory.setNamespaceAware( true );
+        XmlPullParser xpp = factory.newPullParser();
+
+        container.setParser( xpp );
+    }
+
+
+    /**
+     * Sets the input string the parser is going to parse
+     *
+     * @param str the string the parser is going to parse
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void setInput( String str ) throws XmlPullParserException
+    {
+        container.getParser().setInput( new StringReader( str ) );
+    }
+
+
+    /**
+     * Sets the input file the parser is going to parse
+     *
+     * @param fileName the name of the file
+     * @throws FileNotFoundException if the file does not exist
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void setInputFile( String fileName ) throws FileNotFoundException, XmlPullParserException
+    {
+        Reader reader = new FileReader( fileName );
+        container.getParser().setInput( reader );
+    }
+
+
+    /**
+     * Sets the input stream the parser is going to process
+     *
+     * @param inputStream contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null)
+     * @param inputEncoding if not null it MUST be used as encoding for inputStream
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
+    {
+        container.getParser().setInput( inputStream, inputEncoding );
+    }
+
+
+    /**
+     * Launches the parsing on the input
+     * 
+     * @throws XmlPullParserException when an unrecoverable error occurs
+     * @throws IOException when an IO exception occurs
+     */
+    public void parse() throws XmlPullParserException, IOException
+    {
+        Dsmlv2ResponseGrammar grammar = Dsmlv2ResponseGrammar.getInstance();
+
+        grammar.executeAction( container );
+    }
+
+
+    /**
+     * Launches the parsing of the Batch Response only
+     *
+     * @throws XmlPullParserException if an error occurs in the parser
+     */
+    public void parseBatchResponse() throws XmlPullParserException
+    {
+        XmlPullParser xpp = container.getParser();
+
+        int eventType = xpp.getEventType();
+        
+        do
+        {
+            switch ( eventType )
+            {
+                case XmlPullParser.START_DOCUMENT :
+                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
+                    break;
+
+                case XmlPullParser.END_DOCUMENT :
+                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
+                    break;
+
+                case XmlPullParser.START_TAG :
+                    processTag( container, Tag.START );
+                    break;
+
+                case XmlPullParser.END_TAG :
+                    processTag( container, Tag.END );
+                    break;
+
+                default:
+                    break;
+            }
+            
+            try
+            {
+                eventType = xpp.next();
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03037, ioe.getLocalizedMessage() ), xpp, ioe );
+            }
+        }
+        while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP );
+    }
+
+
+    /**
+     * Processes the task required in the grammar to the given tag type
+     *
+     * @param container the DSML container
+     * @param tagType the tag type
+     * @throws XmlPullParserException when an error occurs during the parsing
+     */
+    private static void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
+    {
+        XmlPullParser xpp = container.getParser();
+
+        String tagName = Strings.toLowerCase( xpp.getName() );
+
+        GrammarTransition transition = container.getTransition( container.getState(), new Tag( tagName, tagType ) );
+
+        if ( transition != null )
+        {
+            container.setState( transition.getNextState() );
+
+            if ( transition.hasAction() )
+            {
+                transition.getAction().action( container );
+            }
+        }
+        else
+        {
+            throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
+        }
+    }
+
+
+    /**
+     * Gets the Batch Response or null if the it has not been parsed yet
+     *
+     * @return the Batch Response or null if the it has not been parsed yet
+     */
+    public BatchResponseDsml getBatchResponse()
+    {
+        return container.getBatchResponse();
+    }
+
+
+    /**
+     * Returns the next Request or null if there's no more request
+     * @return the next Request or null if there's no more request
+     * @throws XmlPullParserException when an error occurs during the parsing
+     */
+    public DsmlDecorator<? extends Response> getNextResponse() throws XmlPullParserException
+    {
+        if ( container.getBatchResponse() == null )
+        {
+            parseBatchResponse();
+        }
+
+        XmlPullParser xpp = container.getParser();
+
+        int eventType = xpp.getEventType();
+        do
+        {
+            while ( eventType == XmlPullParser.TEXT )
+            {
+                try
+                {
+                    xpp.next();
+                }
+                catch ( IOException ioe )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03037, ioe.getLocalizedMessage() ), xpp, ioe );
+                }
+                eventType = xpp.getEventType();
+            }
+
+            switch ( eventType )
+            {
+                case XmlPullParser.START_DOCUMENT :
+                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
+                    break;
+
+                case XmlPullParser.END_DOCUMENT :
+                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
+                    return null;
+
+                case XmlPullParser.START_TAG :
+                    processTag( container, Tag.START );
+                    break;
+
+                case XmlPullParser.END_TAG :
+                    processTag( container, Tag.END );
+                    break;
+
+                default:
+                    break;
+            }
+            
+            try
+            {
+                eventType = xpp.next();
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03037, ioe.getLocalizedMessage() ), xpp, ioe );
+            }
+        }
+        while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP );
+
+        return container.getBatchResponse().getCurrentResponse();
+    }
+
+
+    /**
+     * Parses all the responses
+     *
+     * @throws XmlPullParserException when an error occurs during the parsing
+     */
+    public void parseAllResponses() throws XmlPullParserException
+    {
+        while ( getNextResponse() != null )
+        {
+            continue;
+        }
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2StatesEnum.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2StatesEnum.java
new file mode 100644
index 0000000..501c715
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Dsmlv2StatesEnum.java
@@ -0,0 +1,513 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+/**
+ * This class store the Dsml grammar's constants. It is also used for debugging
+ * purpose.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum Dsmlv2StatesEnum
+{
+    /** The initial state of every grammar */
+    INIT_GRAMMAR_STATE,
+
+    /** The ending state for every grammars */
+    GRAMMAR_END,
+
+    //====================================================
+    //  <batchRequest> ... </batchRequest>
+    //====================================================
+    /** The &lt;batchRequest&gt; tag */
+    BATCHREQUEST_START_TAG,
+
+    BATCHREQUEST_LOOP,
+
+    /** The &lt;/batchRequest&gt; tag */
+    BATCHREQUEST_END_TAG,
+
+    //====================================================
+    //  <abandonRequest> ... </abandonRequest>
+    //====================================================
+    /** The &lt;abandonRequest&gt; tag */
+    ABANDON_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    ABANDON_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    ABANDON_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    ABANDON_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    ABANDON_REQUEST_CONTROLVALUE_END_TAG,
+
+    //====================================================
+    //  <addRequest> ... </addRequest>
+    //====================================================
+    /** The &lt;addRequest&gt; tag */
+    ADD_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    ADD_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    ADD_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    ADD_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    ADD_REQUEST_CONTROLVALUE_END_TAG,
+
+    /** The &lt;attr&gt; tag */
+    ADD_REQUEST_ATTR_START_TAG,
+
+    /** The &lt;/attr&gt; tag */
+    ADD_REQUEST_ATTR_END_TAG,
+
+    /** The &lt;value&gt; tag */
+    ADD_REQUEST_VALUE_START_TAG,
+
+    /** The &lt;/value&gt; tag */
+    ADD_REQUEST_VALUE_END_TAG,
+
+    //====================================================
+    //  <authRequest> ... </authRequest>
+    //====================================================
+    /** The &lt;authRequest&gt; tag */
+    AUTH_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    AUTH_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    AUTH_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    AUTH_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    AUTH_REQUEST_CONTROLVALUE_END_TAG,
+
+    //====================================================
+    //  <compareRequest> ... </compareRequest>
+    //====================================================
+    /** The &lt;compareRequest&gt; tag */
+    COMPARE_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    COMPARE_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    COMPARE_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    COMPARE_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    COMPARE_REQUEST_CONTROLVALUE_END_TAG,
+
+    /** The &lt;assertion&gt; tag */
+    COMPARE_REQUEST_ASSERTION_START_TAG,
+
+    /** The &lt;/assertion&gt; tag */
+    COMPARE_REQUEST_ASSERTION_END_TAG,
+
+    /** The &lt;value&gt; tag */
+    COMPARE_REQUEST_VALUE_START_TAG,
+
+    /** The &lt;/value&gt; tag */
+    COMPARE_REQUEST_VALUE_END_TAG,
+
+    //====================================================
+    //  <delRequest> ... </delRequest>
+    //====================================================
+    /** The &lt;delRequest&gt; tag */
+    DEL_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    DEL_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    DEL_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    DEL_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    DEL_REQUEST_CONTROLVALUE_END_TAG,
+
+    //====================================================
+    //  <extendedRequest> ... </extendedRequest>
+    //====================================================
+    /** The &lt;extendedRequest&gt; tag */
+    EXTENDED_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    EXTENDED_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    EXTENDED_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    EXTENDED_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    EXTENDED_REQUEST_CONTROLVALUE_END_TAG,
+
+    /** The &lt;requestName&gt; tag */
+    EXTENDED_REQUEST_REQUESTNAME_START_TAG,
+
+    /** The &lt;/requestName&gt; tag */
+    EXTENDED_REQUEST_REQUESTNAME_END_TAG,
+
+    /** The &lt;requestValue&gt; tag */
+    EXTENDED_REQUEST_REQUESTVALUE_START_TAG,
+
+    /** The &lt;/requestValue&gt; tag */
+    EXTENDED_REQUEST_REQUESTVALUE_END_TAG,
+
+    //====================================================
+    //  <modDNRequest> ... </modDNRequest>
+    //====================================================
+    /** The &lt;modDNRequest&gt; tag */
+    MODIFY_DN_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    MODIFY_DN_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    MODIFY_DN_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    MODIFY_DN_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    MODIFY_DN_REQUEST_CONTROLVALUE_END_TAG,
+
+    //====================================================
+    //  <modifyRequest> ... </modifyRequest>
+    //====================================================
+    /** The &lt;modifyRequest&gt; tag */
+    MODIFY_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    MODIFY_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    MODIFY_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    MODIFY_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    MODIFY_REQUEST_CONTROLVALUE_END_TAG,
+
+    /** The &lt;modification&gt; tag */
+    MODIFY_REQUEST_MODIFICATION_START_TAG,
+
+    /** The &lt;/modification&gt; tag */
+    MODIFY_REQUEST_MODIFICATION_END_TAG,
+
+    /** The &lt;value&gt; tag */
+    MODIFY_REQUEST_VALUE_START_TAG,
+
+    /** The &lt;/value&gt; tag */
+    MODIFY_REQUEST_VALUE_END_TAG,
+
+    //====================================================
+    //  <searchRequest> ... </searchRequest>
+    //====================================================
+    /** The &lt;searchRequest&gt; tag */
+    SEARCH_REQUEST_START_TAG,
+
+    /** The &lt;control&gt; tag */
+    SEARCH_REQUEST_CONTROL_START_TAG,
+
+    /** The &lt;/control&gt; tag */
+    SEARCH_REQUEST_CONTROL_END_TAG,
+
+    /** The &lt;controlValue&gt; tag */
+    SEARCH_REQUEST_CONTROLVALUE_START_TAG,
+
+    /** The &lt;/controlValue&gt; tag */
+    SEARCH_REQUEST_CONTROLVALUE_END_TAG,
+
+    /** The &lt;filter&gt; tag */
+    SEARCH_REQUEST_FILTER_START_TAG,
+
+    /** The &lt;/filter&gt; tag */
+    SEARCH_REQUEST_FILTER_END_TAG,
+
+    /** The &lt;attributes&gt; tag */
+    SEARCH_REQUEST_ATTRIBUTES_START_TAG,
+
+    /** The &lt;/attributes&gt; tag */
+    SEARCH_REQUEST_ATTRIBUTES_END_TAG,
+
+    /** The &lt;attribute&gt; tag */
+    SEARCH_REQUEST_ATTRIBUTE_START_TAG,
+
+    /** The &lt;/attribute&gt; tag */
+    SEARCH_REQUEST_ATTRIBUTE_END_TAG,
+
+    /** The &lt;equalityMatch&gt; tag */
+    SEARCH_REQUEST_EQUALITYMATCH_START_TAG,
+
+    /** The &lt;subStrings&gt; tag */
+    SEARCH_REQUEST_SUBSTRINGS_START_TAG,
+
+    /** The &lt;/subStrings&gt; tag */
+    SEARCH_REQUEST_SUBSTRINGS_END_TAG,
+
+    /** The &lt;greaterOrEqual&gt; tag */
+    SEARCH_REQUEST_GREATEROREQUAL_START_TAG,
+
+    /** The &lt;lessOrEqual&gt; tag */
+    SEARCH_REQUEST_LESSOREQUAL_START_TAG,
+
+    /** The &lt;present&gt; tag */
+    SEARCH_REQUEST_PRESENT_START_TAG,
+
+    /** The &lt;approxMatch&gt; tag */
+    SEARCH_REQUEST_APPROXMATCH_START_TAG,
+
+    /** The &lt;extensibleMatch&gt; tag */
+    SEARCH_REQUEST_EXTENSIBLEMATCH_START_TAG,
+
+    /** The &lt;value&gt; tag */
+    SEARCH_REQUEST_EXTENSIBLEMATCH_VALUE_START_TAG,
+
+    /** The &lt;/value&gt; tag */
+    SEARCH_REQUEST_EXTENSIBLEMATCH_VALUE_END_TAG,
+
+    /** The &lt;initial&gt; tag */
+    SEARCH_REQUEST_INITIAL_START_TAG,
+
+    /** The &lt;/initial&gt; tag */
+    SEARCH_REQUEST_INITIAL_END_TAG,
+
+    /** The &lt;any&gt; tag */
+    SEARCH_REQUEST_ANY_START_TAG,
+
+    /** The &lt;/any&gt; tag */
+    SEARCH_REQUEST_ANY_END_TAG,
+
+    /** The &lt;final&gt; tag */
+    SEARCH_REQUEST_FINAL_START_TAG,
+
+    /** The &lt;/final&gt; tag */
+    SEARCH_REQUEST_FINAL_END_TAG,
+
+    /** The &lt;value&gt; tag */
+    SEARCH_REQUEST_VALUE_START_TAG,
+
+    /** The &lt;/value&gt; tag */
+    SEARCH_REQUEST_VALUE_END_TAG,
+
+    /** The Filter Loop state */
+    SEARCH_REQUEST_FILTER_LOOP,
+
+    //****************
+    // DSML Response 
+    //****************
+
+    /** The Batch Response Loop state */
+    BATCH_RESPONSE_LOOP,
+
+    /** The Error Response Loop state */
+    ERROR_RESPONSE,
+
+    /** The Message Start state */
+    MESSAGE_START,
+
+    /** The Message End state */
+    MESSAGE_END,
+
+    /** The Detail Start state */
+    DETAIL_START,
+
+    /** The Detail End state */
+    DETAIL_END,
+
+    /** The Extended Response state */
+    EXTENDED_RESPONSE,
+
+    /** The Extended Response Control Start state */
+    EXTENDED_RESPONSE_CONTROL_START,
+
+    /** The Extended Response Control End state */
+    EXTENDED_RESPONSE_CONTROL_END,
+
+    /** The Extended Response Control Value Start state */
+    EXTENDED_RESPONSE_CONTROL_VALUE_START,
+
+    /** The Extended Response Control Value End state */
+    EXTENDED_RESPONSE_CONTROL_VALUE_END,
+
+    /** The Extended Response Result Code Start state */
+    EXTENDED_RESPONSE_RESULT_CODE_START,
+
+    /** The Extended Response Result Code End state */
+    EXTENDED_RESPONSE_RESULT_CODE_END,
+
+    /** The Extended Response Error Message Start state */
+    EXTENDED_RESPONSE_ERROR_MESSAGE_START,
+
+    /** The Extended Response Error Message End state */
+    EXTENDED_RESPONSE_ERROR_MESSAGE_END,
+
+    /** The Extended Response Referral Start state */
+    EXTENDED_RESPONSE_REFERRAL_START,
+
+    /** The Extended Response Referral End state */
+    EXTENDED_RESPONSE_REFERRAL_END,
+
+    /** The Response Name Start state */
+    RESPONSE_NAME_START,
+
+    /** The Response Name End state */
+    RESPONSE_NAME_END,
+
+    /** The Response Start state */
+    RESPONSE_START,
+
+    /** The Response End state */
+    RESPONSE_END,
+
+    /** The LDAP Result state */
+    LDAP_RESULT,
+
+    /** The LDAP Result Control Start state */
+    LDAP_RESULT_CONTROL_START,
+
+    /** The LDAP Result Control End state */
+    LDAP_RESULT_CONTROL_END,
+
+    /** The LDAP Result Control Value Start state */
+    LDAP_RESULT_CONTROL_VALUE_START,
+
+    /** The LDAP Result Control Value End state */
+    LDAP_RESULT_CONTROL_VALUE_END,
+
+    /** The LDAP Result Result Code Start state */
+    LDAP_RESULT_RESULT_CODE_START,
+
+    /** The LDAP Result Result Code End state */
+    LDAP_RESULT_RESULT_CODE_END,
+
+    /** The LDAP Result Error Message Start state */
+    LDAP_RESULT_ERROR_MESSAGE_START,
+
+    /** The LDAP Result Error Message End state */
+    LDAP_RESULT_ERROR_MESSAGE_END,
+
+    /** The LDAP Result Referral Start state */
+    LDAP_RESULT_REFERRAL_START,
+
+    /** The LDAP Result Referral End state */
+    LDAP_RESULT_REFERRAL_END,
+
+    /** The LDAP Result End state */
+    LDAP_RESULT_END,
+
+    /** The Search Response state */
+    SEARCH_RESPONSE,
+
+    /** The Search Result Entry state */
+    SEARCH_RESULT_ENTRY,
+
+    /** The Search Result Entry Control Start state */
+    SEARCH_RESULT_ENTRY_CONTROL_START,
+
+    /** The Search Result Entry Control End state */
+    SEARCH_RESULT_ENTRY_CONTROL_END,
+
+    /** The Search Result Entry Control Value Start state */
+    SEARCH_RESULT_ENTRY_CONTROL_VALUE_START,
+
+    /** The Search Result Entry Control Value End state */
+    SEARCH_RESULT_ENTRY_CONTROL_VALUE_END,
+
+    /** The Search Result Entry Attr Start state */
+    SEARCH_RESULT_ENTRY_ATTR_START,
+
+    /** The Search Result Entry Attr End state */
+    SEARCH_RESULT_ENTRY_ATTR_END,
+
+    /** The Search Result Entry Value Start state */
+    SEARCH_RESULT_ENTRY_VALUE_START,
+
+    /** The Search Result Entry Value End state */
+    SEARCH_RESULT_ENTRY_VALUE_END,
+
+    /** The Search Result Entry Loop state */
+    SEARCH_RESULT_ENTRY_LOOP,
+
+    /** The Search Result Reference state */
+    SEARCH_RESULT_REFERENCE,
+
+    /** The Search Result Reference Control Start state */
+    SEARCH_RESULT_REFERENCE_CONTROL_START,
+
+    /** The Search Result Reference Control End state */
+    SEARCH_RESULT_REFERENCE_CONTROL_END,
+
+    /** The Search Result Reference Control Value Start state */
+    SEARCH_RESULT_REFERENCE_CONTROL_VALUE_START,
+
+    /** The Search Result Reference Control Value End state */
+    SEARCH_RESULT_REFERENCE_CONTROL_VALUE_END,
+
+    /** The Search Result Reference Ref Start state */
+    SEARCH_RESULT_REFERENCE_REF_START,
+
+    /** The Search Result Reference Ref End state */
+    SEARCH_RESULT_REFERENCE_REF_END,
+
+    /** The Search Result Reference Loop state */
+    SEARCH_RESULT_REFERENCE_LOOP,
+
+    /** The soap envelop start state */
+    SOAP_ENVELOPE_START_TAG,
+
+    /** The soap envelop end state */
+    SOAP_ENVELOPE_END_TAG,
+
+    /** The soap header start state */
+    SOAP_HEADER_START_TAG,
+
+    /** The soap header end state */
+    SOAP_HEADER_END_TAG,
+
+    /** The soap body start state */
+    SOAP_BODY_START_TAG,
+
+    /** The soap body end state */
+    SOAP_BODY_END_TAG,
+
+    /** The Search Result Done End state */
+    SEARCH_RESULT_DONE_END
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Grammar.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Grammar.java
new file mode 100644
index 0000000..6572eda
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Grammar.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * The interface which expose common behavior of a Grammar implementer.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Grammar
+{
+    /**
+     * This method, when called, executes an action on the current data stored in
+     * the container.
+     * 
+     * @param container the DSML container
+     * @throws XmlPullParserException when an unrecoverable error occurs
+     * @throws IOException when an IO error occurs
+     */
+    void executeAction( Dsmlv2Container container ) throws XmlPullParserException, IOException;
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @return Return the grammar's name
+     */
+    String getName();
+
+
+    /**
+     * Get the statesEnum for the current grammar
+     * 
+     * @return The specific States Enum for the current grammar
+     */
+    Enum<Dsmlv2StatesEnum>[] getStatesEnum();
+
+
+    /**
+     * Set the grammar's name
+     * 
+     * @param name The grammar name
+     */
+    void setName( String name );
+}
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/GrammarAction.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/GrammarAction.java
new file mode 100644
index 0000000..ce76f7d
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/GrammarAction.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+/**
+ * A top level grammar class that store meta informations about the actions.
+ * Those informations are not mandatory, but they can be usefull for debugging.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class GrammarAction implements Action
+{
+    /** The action's name */
+    private String name;
+
+
+    /**
+     * Creates a new GrammarAction object.
+     * 
+     * @param name the name of the create daction
+     */
+    public GrammarAction( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Print the action's name
+     * 
+     * @return the action's name
+     */
+    public String toString()
+    {
+        return name;
+    }
+}
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/GrammarTransition.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/GrammarTransition.java
new file mode 100644
index 0000000..d978a8f
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/GrammarTransition.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+/**
+ * Define a transition between two states of a grammar. It stores the next
+ * state, and the action to execute while transiting.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GrammarTransition
+{
+    /** The next state in the grammar */
+    private Enum<Dsmlv2StatesEnum> nextState;
+
+    /** The action associated to the transition */
+    private GrammarAction action;
+
+    /** The current state */
+    private Enum<Dsmlv2StatesEnum> currentState;
+
+
+    /**
+     * Creates a new GrammarTransition object.
+     * 
+     * @param currentState The current transition
+     * @param nextState The target state
+     * @param action The action to execute. It could be null.
+     */
+    public GrammarTransition( Enum<Dsmlv2StatesEnum> currentState, Enum<Dsmlv2StatesEnum> nextState,
+        GrammarAction action )
+    {
+        this.currentState = currentState;
+        this.nextState = nextState;
+        this.action = action;
+    }
+
+
+    /**
+     * Gets the target state
+     * 
+     * @return the target state.
+     */
+    public Enum<Dsmlv2StatesEnum> getNextState()
+    {
+        return nextState;
+    }
+
+
+    /**
+     * Tells if the transition has an associated action.
+     * 
+     * @return  <code>true</code> if an action has been associated to the transition
+     */
+    public boolean hasAction()
+    {
+        return action != null;
+    }
+
+
+    /**
+     * Gets the action associated with the transition
+     * 
+     * @return the action associated with the transition
+     */
+    public GrammarAction getAction()
+    {
+        return action;
+    }
+
+
+    /**
+     * Returns a representation of the transition as a string
+     * 
+     * @param grammar the grammar which state we want a String from
+     * @param statesEnum the states enum that contains the states' names
+     * @return  a representation of the transition as a string.
+     */
+    public String toString( int grammar, Enum<Dsmlv2StatesEnum> statesEnum )
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "Transition from <" ).append( currentState ).append( "> to <" ).append(
+            nextState ).append( ">, action : " ).append(
+            ( ( action == null ) ? "no action" : action.toString() ) ).append( ">" );
+
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/ParserUtils.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/ParserUtils.java
new file mode 100644
index 0000000..4cdea7a
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/ParserUtils.java
@@ -0,0 +1,348 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.directory.api.dsmlv2.actions.ReadSoapHeader;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Strings;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+import org.dom4j.io.DocumentResult;
+import org.dom4j.io.DocumentSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * This class is a Helper class for the DSML Parser
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ParserUtils
+{
+    /** W3C XML Schema URI. */
+    public static final String XML_SCHEMA_URI = "http://www.w3.org/2001/XMLSchema";
+
+    /** W3C XML Schema Instance URI. */
+    public static final String XML_SCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance";
+
+    /** Base-64 identifier. */
+    public static final String BASE64BINARY = "base64Binary";
+
+    /** XSI namespace prefix. */
+    public static final String XSI = "xsi";
+
+    /** XSD namespace prefix. */
+    public static final String XSD = "xsd";
+
+    /** The DSML namespace */
+    public static final Namespace DSML_NAMESPACE = new Namespace( null, "urn:oasis:names:tc:DSML:2:0:core" );
+
+    /** The XSD namespace */
+    public static final Namespace XSD_NAMESPACE = new Namespace( XSD, XML_SCHEMA_URI );
+
+    /** The XSI namespace */
+    public static final Namespace XSI_NAMESPACE = new Namespace( XSI, XML_SCHEMA_INSTANCE_URI );
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ParserUtils.class );
+
+
+    private ParserUtils()
+    {
+    }
+
+
+    /**
+     * Returns the value of the attribute 'type' of the "XMLSchema-instance' namespace if it exists
+     *
+     * @param xpp the XPP parser to use
+     * @return the value of the attribute 'type' of the "XMLSchema-instance' namespace if it exists
+     */
+    public static String getXsiTypeAttributeValue( XmlPullParser xpp )
+    {
+        String type = null;
+        int nbAttributes = xpp.getAttributeCount();
+
+        for ( int i = 0; i < nbAttributes; i++ )
+        {
+            // Checking if the attribute 'type' from XML Schema Instance namespace is used.
+            if ( xpp.getAttributeName( i ).equals( "type" )
+                && xpp.getNamespace( xpp.getAttributePrefix( i ) ).equals( XML_SCHEMA_INSTANCE_URI ) )
+            {
+                type = xpp.getAttributeValue( i );
+                break;
+            }
+        }
+
+        return type;
+    }
+
+
+    /**
+     * Tells is the given value is a Base64 binary value
+     * 
+     * @param parser the XPP parser to use
+     * @param attrValue the attribute value
+     * @return true if the value of the current tag is Base64BinaryEncoded, false if not
+     */
+    public static boolean isBase64BinaryValue( XmlPullParser parser, String attrValue )
+    {
+        if ( attrValue == null )
+        {
+            return false;
+        }
+
+        // We are looking for something that should look like that: "aNameSpace:base64Binary"
+        // We split the String. The first element should be the namespace prefix and the second "base64Binary"
+        String[] splitedString = attrValue.split( ":" );
+
+        return ( splitedString.length == 2 ) && ( XML_SCHEMA_URI.equals( parser.getNamespace( splitedString[0] ) ) )
+            && ( BASE64BINARY.equals( splitedString[1] ) );
+    }
+
+
+    /**
+     * Indicates if the value needs to be encoded as Base64
+     *
+     * @param value the value to check
+     * @return true if the value needs to be encoded as Base64
+     */
+    public static boolean needsBase64Encoding( Object value )
+    {
+        if ( value instanceof StringValue )
+        {
+            return false;
+        }
+        else if ( value instanceof BinaryValue )
+        {
+            return false;
+        }
+        else if ( value instanceof byte[] )
+        {
+            return true;
+        }
+        else if ( value instanceof String )
+        {
+            return !LdifUtils.isLDIFSafe( ( String ) value );
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Encodes the value as a Base64 String
+     *
+     * @param value the value to encode
+     * @return the value encoded as a Base64 String
+     */
+    public static String base64Encode( Object value )
+    {
+        if ( value instanceof byte[] )
+        {
+            return new String( Base64.encode( ( byte[] ) value ) );
+        }
+        else if ( value instanceof String )
+        {
+            return new String( Base64.encode( Strings.getBytesUtf8( ( String ) value ) ) );
+        }
+
+        return "";
+    }
+
+
+    /**
+     * Parses and verify the parsed value of the requestID
+     * 
+     * @param attributeValue the value of the attribute
+     * @param xpp the XmlPullParser
+     * @return the int value of the resquestID
+     * @throws XmlPullParserException if RequestID isn't an Integer and if requestID is below 0
+     */
+    public static int parseAndVerifyRequestID( String attributeValue, XmlPullParser xpp ) throws XmlPullParserException
+    {
+        try
+        {
+            int requestID = Integer.parseInt( attributeValue );
+
+            if ( requestID < 0 )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03038, requestID ), xpp, null );
+            }
+
+            return requestID;
+        }
+        catch ( NumberFormatException nfe )
+        {
+            throw new XmlPullParserException( I18n.err( I18n.ERR_03039 ), xpp, nfe );
+        }
+    }
+
+
+    /**
+     * Adds Controls to the given Element.
+     *
+     * @param element the element to add the Controls to
+     * @param controls a List of Controls
+     */
+    public static void addControls( LdapApiService codec, Element element, Collection<Control> controls )
+    {
+        if ( controls != null )
+        {
+            for ( Control control : controls )
+            {
+                Element controlElement = element.addElement( "control" );
+
+                if ( control.getOid() != null )
+                {
+                    controlElement.addAttribute( "type", control.getOid() );
+                }
+
+                if ( control.isCritical() )
+                {
+                    controlElement.addAttribute( "criticality", "true" );
+                }
+
+                byte[] value;
+
+                if ( control instanceof CodecControl<?> )
+                {
+                    value = ( ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) control ).getValue();
+                }
+                else
+                {
+                    value = codec.newControl( control ).getValue();
+                }
+
+                if ( value != null )
+                {
+                    if ( ParserUtils.needsBase64Encoding( value ) )
+                    {
+                        element.getDocument().getRootElement().add( XSD_NAMESPACE );
+                        element.getDocument().getRootElement().add( XSI_NAMESPACE );
+
+                        Element valueElement = controlElement.addElement( "controlValue" ).addText(
+                            ParserUtils.base64Encode( value ) );
+                        valueElement.addAttribute( new QName( "type", XSI_NAMESPACE ), ParserUtils.XSD + ":"
+                            + ParserUtils.BASE64BINARY );
+                    }
+                    else
+                    {
+                        controlElement.addElement( "controlValue" ).setText( Arrays.toString( value ) );
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Indicates if a request ID is needed.
+     *
+     * @param container the associated container
+     * @return true if a request ID is needed (ie Processing=Parallel and ResponseOrder=Unordered)
+     * @throws XmlPullParserException if the batch request has not been parsed yet
+     */
+    public static boolean isRequestIdNeeded( Dsmlv2Container container ) throws XmlPullParserException
+    {
+        BatchRequestDsml batchRequest = container.getBatchRequest();
+
+        if ( batchRequest == null )
+        {
+            throw new XmlPullParserException( I18n.err( I18n.ERR_03040 ), container.getParser(), null );
+        }
+
+        return ( ( batchRequest.getProcessing() == Processing.PARALLEL ) && ( batchRequest.getResponseOrder() == ResponseOrder.UNORDERED ) );
+    }
+
+
+    /**
+     * XML Pretty Printer XSLT Transformation
+     * 
+     * @param document the Dom4j Document
+     * @return the transformed document
+     */
+    public static Document styleDocument( Document document )
+    {
+        // load the transformer using JAXP
+        TransformerFactory factory = TransformerFactory.newInstance();
+        Transformer transformer = null;
+
+        try
+        {
+            transformer = factory.newTransformer( new StreamSource( ParserUtils.class
+                .getResourceAsStream( "/org/apache/directory/shared/dsmlv2/DSMLv2.xslt" ) ) );
+        }
+        catch ( TransformerConfigurationException e1 )
+        {
+            LOG.warn( "Failed to create the XSLT transformer", e1 );
+            // return original document
+            return document;
+        }
+
+        // now lets style the given document
+        DocumentSource source = new DocumentSource( document );
+        DocumentResult result = new DocumentResult();
+
+        try
+        {
+            transformer.transform( source, result );
+        }
+        catch ( TransformerException e )
+        {
+            // return original document
+            return document;
+        }
+
+        // return the transformed document
+        Document transformedDoc = result.getDocument();
+        return transformedDoc;
+    }
+
+    /**
+     * GrammarAction that reads the SOAP header data
+     */
+    public static final GrammarAction READ_SOAP_HEADER = new ReadSoapHeader();
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Tag.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Tag.java
new file mode 100644
index 0000000..cb2ea40
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/Tag.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2;
+
+
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * This class represents a XML tag.
+ * <br/>
+ * A XML tag is defined with :
+ * <ul>
+ *      <li>a name</li>
+ *      <li>a type (START tag or END tag)</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Tag
+{
+    /** The name of the tag */
+    private String name;
+
+    /** The type of the tag */
+    private int type;
+
+    /** This int represents a START tag */
+    public static final int START = 0;
+
+    /** This int represents a END tag */
+    public static final int END = 1;
+
+
+    /**
+     * Creates a new instance of Tag.
+     *
+     * @param name the name of the tag
+     * @param type the type of the tag
+     */
+    public Tag( String name, int type )
+    {
+        setName( name );
+        setType( type );
+    }
+
+
+    /**
+     * Gets the name of the tag
+     *
+     * @return the name of the tag
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * Sets the name of the tag
+     *
+     * @param name the name to set
+     */
+    public void setName( String name )
+    {
+        this.name = Strings.toLowerCase( name );
+    }
+
+
+    /**
+     * Gets the type of the tag
+     *
+     * @return the type of the tag
+     */
+    public int getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * Sets the type of the tag
+     *
+     * @param type the type to set
+     */
+    public void setType( int type )
+    {
+        this.type = type;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj instanceof Tag )
+        {
+            Tag tag = ( Tag ) obj;
+            
+            return ( ( this.name.equals( tag.getName() ) ) && ( this.type == tag.getType() ) );
+
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode()
+    {
+        return name.hashCode() + type << 24;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        if ( name != null )
+        {
+            return "<" + ( ( type == Tag.END ) ? "/" : "" ) + name + ">";
+        }
+        else
+        {
+            return "Unknown tag";
+        }
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/actions/ReadSoapHeader.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/actions/ReadSoapHeader.java
new file mode 100644
index 0000000..77701ed
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/actions/ReadSoapHeader.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.dsmlv2.actions;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.dsmlv2.Dsmlv2Container;
+import org.apache.directory.api.dsmlv2.Dsmlv2StatesEnum;
+import org.apache.directory.api.dsmlv2.GrammarAction;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * The action used to read the SOAP Header
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ReadSoapHeader extends GrammarAction
+{
+    /**
+     * Instantiates the action.
+     */
+    public ReadSoapHeader()
+    {
+        super( "Reads SOAP header" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( Dsmlv2Container container ) throws XmlPullParserException
+    {
+        try
+        {
+            XmlPullParser xpp = container.getParser();
+            StringBuilder sb = new StringBuilder();
+
+            String startTag = xpp.getText();
+            sb.append( startTag );
+
+            // string '<' and '>'
+            startTag = startTag.substring( 1, startTag.length() - 1 );
+
+            int tagType = -1;
+            String endTag = "";
+
+            // continue parsing till we get to the end tag of SOAP header
+            // and match the tag values including the namespace
+            while ( !startTag.equals( endTag ) )
+            {
+                tagType = xpp.next();
+                endTag = xpp.getText();
+                sb.append( endTag );
+
+                if ( tagType == XmlPullParser.END_TAG )
+                {
+                    // strip '<', '/' and '>'
+                    endTag = endTag.substring( 2, endTag.length() - 1 );
+                }
+            }
+
+            // change the state to header end
+            container.setState( Dsmlv2StatesEnum.SOAP_HEADER_END_TAG );
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbandonRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbandonRequestDsml.java
new file mode 100644
index 0000000..7fc6bde
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbandonRequestDsml.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.dom4j.Element;
+
+
+/**
+ * DSML Decorator for AbandonRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AbandonRequestDsml extends AbstractRequestDsml<AbandonRequest>
+    implements AbandonRequest
+{
+    /**
+     * Creates a new instance of AbandonRequestDsml.
+     */
+    public AbandonRequestDsml( LdapApiService codec )
+    {
+        super( codec, new AbandonRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of AbandonRequestDsml.
+     *
+     * @param ldapMessage the message to decorate
+     */
+    public AbandonRequestDsml( LdapApiService codec, AbandonRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        // AbandonID
+        if ( getDecorated().getAbandoned() != 0 )
+        {
+            element.addAttribute( "abandonID", "" + getDecorated().getAbandoned() );
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Get the abandoned message ID
+     * 
+     * @return Returns the abandoned MessageId.
+     */
+    public int getAbandonedMessageId()
+    {
+        return getDecorated().getAbandoned();
+    }
+
+
+    /**
+     * Set the abandoned message ID
+     * 
+     * @param abandonedMessageId The abandoned messageID to set.
+     */
+    public AbandonRequest setAbandonedMessageId( int abandonedMessageId )
+    {
+        getDecorated().setAbandoned( abandonedMessageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getAbandoned()
+    {
+        return getDecorated().getAbandoned();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest setAbandoned( int requestId )
+    {
+        getDecorated().setAbandoned( requestId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest addControl( Control control )
+    {
+        return ( AbandonRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest addAllControls( Control[] controls )
+    {
+        return ( AbandonRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest removeControl( Control control )
+    {
+        return ( AbandonRequest ) super.removeControl( control );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbstractRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbstractRequestDsml.java
new file mode 100644
index 0000000..155baa0
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbstractRequestDsml.java
@@ -0,0 +1,142 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.dsmlv2.AbstractDsmlMessageDecorator;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Request;
+import org.dom4j.Element;
+
+
+/**
+ * Abstract class for DSML requests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractRequestDsml<E extends Request>
+    extends AbstractDsmlMessageDecorator<E>
+    implements Request
+{
+    /**
+     * Creates a new instance of AbstractRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public AbstractRequestDsml( LdapApiService codec, E ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * Creates the Request Element and adds RequestID and Controls.
+     *
+     * @param root
+     *      the root element
+     * @return
+     *      the Request Element of the given name containing
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = root.addElement( getRequestName() );
+
+        // Request ID
+        int requestID = getDecorated().getMessageId();
+        if ( requestID > 0 )
+        {
+            element.addAttribute( "requestID", "" + requestID );
+        }
+
+        // Controls
+        ParserUtils.addControls( getCodecService(), element, getDecorated().getControls().values() );
+
+        return element;
+    }
+
+
+    /**
+     * Gets the name of the request according to the type of the decorated element.
+     *
+     * @return
+     *      the name of the request according to the type of the decorated element.
+     */
+    private String getRequestName()
+    {
+        switch ( getDecorated().getType() )
+        {
+            case ABANDON_REQUEST:
+                return "abandonRequest";
+
+            case ADD_REQUEST:
+                return "addRequest";
+
+            case BIND_REQUEST:
+                return "authRequest";
+
+            case COMPARE_REQUEST:
+                return "compareRequest";
+
+            case DEL_REQUEST:
+                return "delRequest";
+
+            case EXTENDED_REQUEST:
+                return "extendedRequest";
+
+            case MODIFYDN_REQUEST:
+                return "modDNRequest";
+
+            case MODIFY_REQUEST:
+                return "modifyRequest";
+
+            case SEARCH_REQUEST:
+                return "searchRequest";
+
+            default:
+                return "error";
+        }
+    }
+
+
+    public int computeLength()
+    {
+        return 0;
+    }
+
+
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasResponse()
+    {
+        return getDecorated().hasResponse();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbstractResultResponseRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbstractResultResponseRequestDsml.java
new file mode 100644
index 0000000..8aed59e
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AbstractResultResponseRequestDsml.java
@@ -0,0 +1,173 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.AbandonListener;
+import org.apache.directory.api.ldap.model.message.AbandonableRequest;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.message.ResultResponseRequest;
+import org.dom4j.Element;
+
+
+/**
+ * Abstract class for DSML requests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractResultResponseRequestDsml<E extends ResultResponseRequest, F extends ResultResponse>
+    extends AbstractRequestDsml<E>
+    implements ResultResponseRequest, AbandonableRequest
+{
+    /**
+     * Creates a new instance of AbstractRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public AbstractResultResponseRequestDsml( LdapApiService codec, E ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * Creates the Request Element and adds RequestID and Controls.
+     *
+     * @param root
+     *      the root element
+     * @return
+     *      the Request Element of the given name containing
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = root.addElement( getRequestName() );
+
+        // Request ID
+        int requestID = getDecorated().getMessageId();
+        if ( requestID > 0 )
+        {
+            element.addAttribute( "requestID", "" + requestID );
+        }
+
+        // Controls
+        ParserUtils.addControls( getCodecService(), element, getDecorated().getControls().values() );
+
+        return element;
+    }
+
+
+    /**
+     * Gets the name of the request according to the type of the decorated element.
+     *
+     * @return
+     *      the name of the request according to the type of the decorated element.
+     */
+    private String getRequestName()
+    {
+        switch ( getDecorated().getType() )
+        {
+            case ABANDON_REQUEST:
+                return "abandonRequest";
+
+            case ADD_REQUEST:
+                return "addRequest";
+
+            case BIND_REQUEST:
+                return "authRequest";
+
+            case COMPARE_REQUEST:
+                return "compareRequest";
+
+            case DEL_REQUEST:
+                return "delRequest";
+
+            case EXTENDED_REQUEST:
+                return "extendedRequest";
+
+            case MODIFYDN_REQUEST:
+                return "modDNRequest";
+
+            case MODIFY_REQUEST:
+                return "modifyRequest";
+
+            case SEARCH_REQUEST:
+                return "searchRequest";
+
+            default:
+                return "error";
+        }
+    }
+
+
+    public int computeLength()
+    {
+        return 0;
+    }
+
+
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ResultResponse getResultResponse()
+    {
+        return getDecorated().getResultResponse();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void abandon()
+    {
+        ( ( AbandonableRequest ) getDecorated() ).abandon();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAbandoned()
+    {
+        return ( ( AbandonableRequest ) getDecorated() ).isAbandoned();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonableRequest addAbandonListener( AbandonListener listener )
+    {
+        ( ( AbandonableRequest ) getDecorated() ).addAbandonListener( listener );
+
+        return this;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AddRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AddRequestDsml.java
new file mode 100644
index 0000000..1b33764
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AddRequestDsml.java
@@ -0,0 +1,314 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddRequestImpl;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+
+
+/**
+ * DSML Decorator for AddRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddRequestDsml
+    extends AbstractResultResponseRequestDsml<AddRequest, AddResponse>
+    implements AddRequest
+{
+
+    /** The current attribute being decoded */
+    private Attribute currentAttribute;
+
+
+    /**
+     * Creates a new getDecoratedMessage() of AddRequestDsml.
+     */
+    public AddRequestDsml( LdapApiService codec )
+    {
+        super( codec, new AddRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of AddRequestDsml.
+    *
+    * @param ldapMessage
+    *      the message to decorate
+    */
+    public AddRequestDsml( LdapApiService codec, AddRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * Create a new attributeValue
+     * 
+     * @param type The attribute's name (called 'type' in the grammar)
+     */
+    public void addAttributeType( String type ) throws LdapException
+    {
+        // do not create a new attribute if we have seen this attributeType before
+        if ( getDecorated().getEntry().get( type ) != null )
+        {
+            currentAttribute = getDecorated().getEntry().get( type );
+            return;
+        }
+
+        // fix this to use AttributeImpl(type.getString().toLowerCase())
+        currentAttribute = new DefaultAttribute( type );
+        getDecorated().getEntry().put( currentAttribute );
+    }
+
+
+    /**
+     * @return Returns the currentAttribute type.
+     */
+    public String getCurrentAttributeType()
+    {
+        return currentAttribute.getId();
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( String value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( Value<?> value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( byte[] value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        // Dn
+        if ( getDecorated().getEntry() != null )
+        {
+            element.addAttribute( "dn", getDecorated().getEntry().getDn().getName() );
+        }
+
+        // Attributes
+        Entry entry = getDecorated().getEntry();
+        if ( entry != null )
+        {
+            for ( Attribute attribute : entry )
+            {
+                Element attributeElement = element.addElement( "attr" );
+                attributeElement.addAttribute( "name", attribute.getId() );
+                // Looping on Values
+                for ( Value<?> value : attribute )
+                {
+                    if ( ParserUtils.needsBase64Encoding( value.getValue() ) )
+                    {
+                        Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
+                        Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
+                        attributeElement.getDocument().getRootElement().add( xsdNamespace );
+                        attributeElement.getDocument().getRootElement().add( xsiNamespace );
+
+                        Element valueElement = attributeElement.addElement( "value" ).addText(
+                            ParserUtils.base64Encode( value.getValue() ) );
+                        valueElement
+                            .addAttribute( new QName( "type", xsiNamespace ), "xsd:" + ParserUtils.BASE64BINARY );
+                    }
+                    else
+                    {
+                        attributeElement.addElement( "value" ).addText( value.getString() );
+                    }
+                }
+            }
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Initialize the Entry.
+     */
+    public void initEntry()
+    {
+    }
+
+
+    /**
+     * Get the entry with its attributes.
+     * 
+     * @return Returns the entry.
+     */
+    public Entry getEntry()
+    {
+        return getDecorated().getEntry();
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to be added
+     */
+    public void addAttributeValue( Object value ) throws LdapException
+    {
+        if ( value instanceof Value<?> )
+        {
+            ( ( AddRequestDsml ) getDecorated() ).addAttributeValue( ( Value<?> ) value );
+        }
+        else if ( value instanceof String )
+        {
+            ( ( AddRequestDsml ) getDecorated() ).addAttributeValue( ( String ) value );
+        }
+        else if ( value instanceof byte[] )
+        {
+            ( ( AddRequestDsml ) getDecorated() ).addAttributeValue( ( byte[] ) value );
+        }
+    }
+
+
+    /**
+     * Get the added Dn
+     * 
+     * @return Returns the entry Dn.
+     */
+    public Dn getEntryDn()
+    {
+        return getDecorated().getEntryDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setEntryDn( Dn entryDn )
+    {
+        getDecorated().setEntryDn( entryDn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setEntry( Entry entry )
+    {
+        getDecorated().setEntry( entry );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest addControl( Control control )
+    {
+        return ( AddRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest addAllControls( Control[] controls )
+    {
+        return ( AddRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest removeControl( Control control )
+    {
+        return ( AddRequest ) super.removeControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AndFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AndFilter.java
new file mode 100644
index 0000000..51bad7e
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AndFilter.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.util.List;
+
+
+/**
+ * And Filter Object to store the And filter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AndFilter extends ConnectorFilter
+{
+    /**
+     * Get the AndFilter.
+     * 
+     * @return Returns the andFilter.
+     */
+    public List<Filter> getAndFilter()
+    {
+        return filterSet;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing an AND filter
+     * 
+     * @return The AND filter string
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( '&' ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AttributeValueAssertion.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AttributeValueAssertion.java
new file mode 100644
index 0000000..ee23b84
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AttributeValueAssertion.java
@@ -0,0 +1,211 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A class to store an attribute value assertion. 
+ * The grammar is :
+ * 
+ * AttributeValueAssertion ::= SEQUENCE {
+ *           attributeDesc   AttributeDescription,
+ *           assertionValue  AssertionValue }
+ *
+ * AttributeDescription ::= LDAPString
+ * 
+ * AssertionValue ::= OCTET STRING
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeValueAssertion
+{
+    // ~ Instance fields
+    // ----------------------------------------------------------------------------
+
+    /** The attribute description */
+    private String attributeDesc;
+
+    /** The assertion value */
+    private Value<?> assertionValue;
+
+
+    /**
+     *
+     * Helper method to render an object which can be a String or a byte[]
+     *
+     * @return A string representing the object
+     */
+    public static String dumpObject( Object object )
+    {
+        if ( object != null )
+        {
+            if ( object instanceof String )
+            {
+                return ( String ) object;
+            }
+            else if ( object instanceof byte[] )
+            {
+                return Strings.dumpBytes( ( byte[] ) object );
+            }
+            else if ( object instanceof StringValue )
+            {
+                return ( ( StringValue ) object ).getValue();
+            }
+            else if ( object instanceof BinaryValue )
+            {
+                return Strings.dumpBytes( ( ( BinaryValue ) object ).getValue() );
+            }
+            else
+            {
+                return "<unknown type>";
+            }
+        }
+        else
+        {
+            return "";
+        }
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * Get the assertion value
+     * 
+     * @return Returns the assertionValue.
+     */
+    public Value<?> getAssertionValue()
+    {
+        return assertionValue;
+    }
+
+
+    /**
+     * Set the assertion value
+     * 
+     * @param assertionValue The assertionValue to set.
+     */
+    public void setAssertionValue( Value<?> assertionValue )
+    {
+        this.assertionValue = assertionValue;
+    }
+
+
+    /**
+     * Get the attribute description
+     * 
+     * @return Returns the attributeDesc.
+     */
+    public String getAttributeDesc()
+    {
+        return attributeDesc;
+    }
+
+
+    /**
+     * Set the attribute description
+     * 
+     * @param attributeDesc The attributeDesc to set.
+     */
+    public void setAttributeDesc( String attributeDesc )
+    {
+        this.attributeDesc = attributeDesc;
+    }
+
+
+    /**
+     * Get a String representation of an AttributeValueAssertion
+     * 
+     * @param tabs The spacing to be put before the string
+     * @return An AttributeValueAssertion String
+     */
+    public String toString( String tabs )
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( tabs ).append( "AttributeValueAssertion\n" );
+        sb.append( tabs ).append( "    Assertion description : '" );
+        sb.append( attributeDesc != null ? attributeDesc : "null" );
+        sb.append( "'\n" );
+        sb.append( tabs ).append( "    Assertion value : '" ).append( dumpObject( assertionValue ) ).append( "'\n" );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Get a String representation of an AttributeValueAssertion, as of RFC
+     * 2254.
+     * 
+     * @param filterType The filter type
+     * @return An AttributeValueAssertion String
+     */
+    public String toStringRFC2254( int filterType )
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( attributeDesc );
+
+        switch ( filterType )
+        {
+            case LdapCodecConstants.EQUALITY_MATCH_FILTER:
+                sb.append( '=' );
+                break;
+
+            case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
+                sb.append( "<=" );
+                break;
+
+            case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
+                sb.append( ">=" );
+                break;
+
+            case LdapCodecConstants.APPROX_MATCH_FILTER:
+                sb.append( "~=" );
+                break;
+
+            default:
+                throw new IllegalStateException( "Unexpected filter type " + filterType );
+        }
+
+        sb.append( dumpObject( assertionValue ) );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Get a String representation of an AttributeValueAssertion
+     * 
+     * @return An AttributeValueAssertion String
+     */
+    public String toString()
+    {
+        return toString( "" );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AttributeValueAssertionFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AttributeValueAssertionFilter.java
new file mode 100644
index 0000000..21f7b28
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/AttributeValueAssertionFilter.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+/**
+ * Object to store the filter. A filter is seen as a tree with a root.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeValueAssertionFilter extends Filter
+{
+    /** The assertion. */
+    private AttributeValueAssertion assertion;
+
+    /** The filter type */
+    private int filterType;
+
+
+    /**
+     * The constructor.
+     * 
+     * @param filterType The filter type
+     */
+    public AttributeValueAssertionFilter( int filterType )
+    {
+        this.filterType = filterType;
+    }
+
+
+    /**
+     * Get the assertion
+     * 
+     * @return Returns the assertion.
+     */
+    public AttributeValueAssertion getAssertion()
+    {
+        return assertion;
+    }
+
+
+    /**
+     * Set the assertion
+     * 
+     * @param assertion The assertion to set.
+     */
+    public void setAssertion( AttributeValueAssertion assertion )
+    {
+        this.assertion = assertion;
+    }
+
+
+    /**
+     * Get the filter type
+     * 
+     * @return Returns the filterType.
+     */
+    public int getFilterType()
+    {
+        return filterType;
+    }
+
+
+    /**
+     * Set the filter type
+     * 
+     * @param filterType The filterType to set.
+     */
+    public void setFilterType( int filterType )
+    {
+        this.filterType = filterType;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing an item filter
+     * 
+     * @return The item filter string
+     */
+    public String toString()
+    {
+        return assertion != null ? assertion.toStringRFC2254( filterType ) : "";
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/BatchRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/BatchRequestDsml.java
new file mode 100644
index 0000000..a7be4a1
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/BatchRequestDsml.java
@@ -0,0 +1,357 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.model.message.Request;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+
+/**
+ * This class represents the Batch Request. It can be used to generate an the XML String of a BatchRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BatchRequestDsml
+{
+    /** The Requests list */
+    private List<DsmlDecorator<? extends Request>> requests;
+
+    /** The ID of the request */
+    private int requestID;
+
+    /** The type of processing of the Batch Request */
+    private Processing processing;
+
+    /** The type of on error handling */
+    private OnError onError;
+
+    /** The response order */
+    private ResponseOrder responseOrder;
+
+    /**
+     * This enum represents the different types of processing for a Batch Request 
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     */
+    public enum Processing
+    {
+        /** Sequential processing. */
+        SEQUENTIAL,
+        /** Parallel processing. */
+        PARALLEL
+    }
+
+    /**
+     * This enum represents the different types of on error handling for a BatchRequest
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+         */
+    public enum OnError
+    {
+        /** Resume on error. */
+        RESUME,
+        /** Exit on error. */
+        EXIT
+    }
+
+    /**
+     * This enum represents the different types of response order for a Batch Request
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+         */
+    public enum ResponseOrder
+    {
+        /** Sequential response order. */
+        SEQUENTIAL,
+        /** Unordered response order. */
+        UNORDERED
+    }
+
+    /**
+     * flag to indicate to store the request objects present in 
+     * this batch request. Default is true
+     */
+    private boolean storeReq = true;
+
+    private DsmlDecorator<? extends Request> currentReq;
+
+
+    /**
+     * Creates a new instance of BatchResponseDsml.
+     */
+    public BatchRequestDsml()
+    {
+        requests = new ArrayList<DsmlDecorator<? extends Request>>();
+        responseOrder = ResponseOrder.SEQUENTIAL;
+        processing = Processing.SEQUENTIAL;
+        onError = OnError.EXIT;
+    }
+
+
+    /**
+     * Gets the current request
+     *
+     * @return
+     *      the current request
+     */
+    public DsmlDecorator<? extends Request> getCurrentRequest()
+    {
+        return currentReq;
+    }
+
+
+    /**
+     * Adds a request to the Batch Request DSML.
+     *
+     * @param request
+     *      the request to add
+     * @return
+     *      true (as per the general contract of the Collection.add method).
+     */
+    public boolean addRequest( DsmlDecorator<? extends Request> request )
+    {
+        currentReq = request;
+
+        if ( storeReq )
+        {
+            return requests.add( request );
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+
+    /**
+     * Removes a request from the Batch Request DSML.
+     *
+     * @param request
+     *      the request to remove
+     * @return
+     *      true if this list contained the specified element.
+     */
+    public boolean removeRequest( DsmlDecorator<? extends Request> request )
+    {
+        return requests.remove( request );
+    }
+
+
+    /**
+     * Gets the ID of the request
+     *
+     * @return
+     *      the ID of the request
+     */
+    public int getRequestID()
+    {
+        return requestID;
+    }
+
+
+    /**
+     * Sets the ID of the request
+     *
+     * @param requestID
+     *      the ID to set
+     */
+    public void setRequestID( int requestID )
+    {
+        this.requestID = requestID;
+    }
+
+
+    /**
+     * Gets the processing type of the request
+     *
+     * @return
+     *      the processing type of the request
+     */
+    public Processing getProcessing()
+    {
+        return processing;
+    }
+
+
+    /**
+     * Sets the processing type of the request
+     *
+     * @param processing
+     *      the processing type to set
+     */
+    public void setProcessing( Processing processing )
+    {
+        this.processing = processing;
+    }
+
+
+    /**
+     * Gets the on error handling type of the request
+     *
+     * @return
+     *      the on error handling type of the request
+     */
+    public OnError getOnError()
+    {
+        return onError;
+    }
+
+
+    /**
+     * Sets the on error handling type of the request
+     *
+     * @param onError
+     *      the on error handling type to set
+     */
+    public void setOnError( OnError onError )
+    {
+        this.onError = onError;
+    }
+
+
+    /**
+     * Gets the response order type of the request
+     *
+     * @return
+     *      the response order type of the request
+     */
+    public ResponseOrder getResponseOrder()
+    {
+        return responseOrder;
+    }
+
+
+    /**
+     * Sets the response order type of the request
+     *
+     * @param responseOrder
+     *      the response order type to set
+     */
+    public void setResponseOrder( ResponseOrder responseOrder )
+    {
+        this.responseOrder = responseOrder;
+    }
+
+
+    /**
+     * Gets the List of all the requests in the Batch Request
+     *
+     * @return the List of all the requests in the Batch Request
+     */
+    public List<DsmlDecorator<? extends Request>> getRequests()
+    {
+        return requests;
+    }
+
+
+    /**
+     * Converts this Batch Request to its XML representation in the DSMLv2 format.
+     * 
+     * @return the XML representation in DSMLv2 format
+     */
+    public String toDsml()
+    {
+        Document document = DocumentHelper.createDocument();
+        Element element = document.addElement( "batchRequest" );
+
+        // RequestID
+        if ( requestID != 0 )
+        {
+            element.addAttribute( "requestID", "" + requestID );
+        }
+
+        // ResponseOrder
+        if ( responseOrder == ResponseOrder.UNORDERED )
+        {
+            element.addAttribute( "responseOrder", "unordered" );
+        }
+
+        // Processing
+        if ( processing == Processing.PARALLEL )
+        {
+            element.addAttribute( "processing", "parallel" );
+        }
+
+        // On Error
+        if ( onError == OnError.RESUME )
+        {
+            element.addAttribute( "onError", "resume" );
+        }
+
+        // Requests
+        for ( DsmlDecorator<? extends Request> request : requests )
+        {
+            request.toDsml( element );
+        }
+
+        return ParserUtils.styleDocument( document ).asXML();
+    }
+
+
+    /**
+     * @return true if the request objects are stored, false otherwise
+     */
+    public boolean isStoringRequests()
+    {
+        return storeReq;
+    }
+
+
+    /**
+     * set the storeReq flag to turn on/off storing of request objects
+     * 
+     * Note: it is better to set this flag to false while processing large DSML 
+     * batch requests
+     *   
+     * @param storeReq
+     */
+    public void setStoreReq( boolean storeReq )
+    {
+        this.storeReq = storeReq;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "[" );
+        sb.append( "processing: " ).append( processing );
+        sb.append( " - " );
+        sb.append( "onError: " ).append( onError );
+        sb.append( " - " );
+        sb.append( "responseOrder: " ).append( responseOrder );
+        sb.append( "]" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/BindRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/BindRequestDsml.java
new file mode 100644
index 0000000..e64fa07
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/BindRequestDsml.java
@@ -0,0 +1,296 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.dom4j.Element;
+
+
+/**
+ * DSML Decorator for BindRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BindRequestDsml
+    extends AbstractResultResponseRequestDsml<BindRequest, BindResponse>
+    implements BindRequest
+{
+    /**
+     * Creates a new getDecoratedMessage() of AuthRequestDsml.
+     */
+    public BindRequestDsml( LdapApiService codec )
+    {
+        super( codec, new BindRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of AuthRequestDsml.
+     *
+     * @param ldapMessage the message to decorate
+     */
+    public BindRequestDsml( LdapApiService codec, BindRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        BindRequest request = getDecorated();
+
+        // Principal
+        Dn dn = request.getDn();
+
+        if ( !Dn.isNullOrEmpty( dn ) )
+        {
+            // A DN has been provided
+
+            element.addAttribute( "principal", dn.getName() );
+        }
+        else
+        {
+            // No DN has been provided, let's use the name as a string instead
+
+            String name = request.getName();
+
+            element.addAttribute( "principal", name );
+        }
+
+        return element;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSimple()
+    {
+        return getDecorated().isSimple();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getSimple()
+    {
+        return getDecorated().getSimple();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setSimple( boolean isSimple )
+    {
+        getDecorated().setSimple( isSimple );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCredentials()
+    {
+        return getDecorated().getCredentials();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setCredentials( String credentials )
+    {
+        getDecorated().setCredentials( credentials );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setCredentials( byte[] credentials )
+    {
+        getDecorated().setCredentials( credentials );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setName( String name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getDn()
+    {
+        return getDecorated().getDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setDn( Dn dn )
+    {
+        getDecorated().setDn( dn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isVersion3()
+    {
+        return getDecorated().isVersion3();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getVersion3()
+    {
+        return getDecorated().getVersion3();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setVersion3( boolean isVersion3 )
+    {
+        getDecorated().setVersion3( isVersion3 );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSaslMechanism()
+    {
+        return getDecorated().getSaslMechanism();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setSaslMechanism( String saslMechanism )
+    {
+        getDecorated().setSaslMechanism( saslMechanism );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest addControl( Control control )
+    {
+        return ( BindRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest addAllControls( Control[] controls )
+    {
+        return ( BindRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest removeControl( Control control )
+    {
+        return ( BindRequest ) super.removeControl( control );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/CompareRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/CompareRequestDsml.java
new file mode 100644
index 0000000..111e681
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/CompareRequestDsml.java
@@ -0,0 +1,263 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareRequestImpl;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.dom4j.Element;
+
+
+/**
+ * DSML Decorator for CompareRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CompareRequestDsml
+    extends AbstractResultResponseRequestDsml<CompareRequest, CompareResponse>
+    implements CompareRequest
+{
+    /**
+     * Creates a new getDecoratedMessage() of CompareRequestDsml.
+     */
+    public CompareRequestDsml( LdapApiService codec )
+    {
+        super( codec, new CompareRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of CompareRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public CompareRequestDsml( LdapApiService codec, CompareRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        CompareRequest request = getDecorated();
+
+        // Dn
+        if ( request.getName() != null )
+        {
+            element.addAttribute( "dn", request.getName().getName() );
+        }
+
+        // Assertion
+        Element assertionElement = element.addElement( "assertion" );
+        if ( request.getAttributeId() != null )
+        {
+            assertionElement.addAttribute( "name", request.getAttributeId() );
+        }
+        if ( request.getAssertionValue() != null )
+        {
+            assertionElement.addElement( "value" ).setText( request.getAssertionValue().getString() );
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Get the entry to be compared
+     * 
+     * @return Returns the entry.
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * Set the entry to be compared
+     * 
+     * @param entry The entry to set.
+     */
+    public CompareRequest setName( Dn entry )
+    {
+        getDecorated().setName( entry );
+
+        return this;
+    }
+
+
+    /**
+     * Set the assertion value
+     * 
+     * @param assertionValue The assertionValue to set.
+     */
+    public void setAssertionValue( Object assertionValue )
+    {
+        if ( assertionValue instanceof String )
+        {
+            getDecorated().setAssertionValue( ( String ) assertionValue );
+        }
+        else
+        {
+            getDecorated().setAssertionValue( ( byte[] ) assertionValue );
+        }
+    }
+
+
+    /**
+     * Get the attribute description
+     * 
+     * @return Returns the attributeDesc.
+     */
+    public String getAttributeDesc()
+    {
+        return getDecorated().getAttributeId();
+    }
+
+
+    /**
+     * Set the attribute description
+     * 
+     * @param attributeDesc The attributeDesc to set.
+     */
+    public void setAttributeDesc( String attributeDesc )
+    {
+        getDecorated().setAttributeId( attributeDesc );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAssertionValue( String value )
+    {
+        getDecorated().setAssertionValue( value );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAssertionValue( byte[] value )
+    {
+        getDecorated().setAssertionValue( value );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getAttributeId()
+    {
+        return getDecorated().getAttributeId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAttributeId( String attrId )
+    {
+        getDecorated().setAttributeId( attrId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> getAssertionValue()
+    {
+        return getDecorated().getAssertionValue();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest addControl( Control control )
+    {
+        return ( CompareRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest addAllControls( Control[] controls )
+    {
+        return ( CompareRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest removeControl( Control control )
+    {
+        return ( CompareRequest ) super.removeControl( control );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ConnectorFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ConnectorFilter.java
new file mode 100644
index 0000000..31f9859
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ConnectorFilter.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+
+
+/**
+ * This Filter abstract class is used to store a set of filters used by
+ * OR/AND/NOT filters.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class ConnectorFilter extends Filter
+{
+    /** The set of filters used by And/Or filters */
+    protected List<Filter> filterSet;
+
+
+    /**
+     * Add a new Filter to the list.
+     * 
+     * @param filter The filter to add
+     */
+    public void addFilter( Filter filter ) throws DecoderException
+    {
+
+        if ( filterSet == null )
+        {
+            filterSet = new ArrayList<Filter>();
+        }
+
+        filterSet.add( filter );
+    }
+
+
+    /**
+     * Get the list of filters stored in the composite filter
+     * 
+     * @return And array of filters
+     */
+    public List<Filter> getFilterSet()
+    {
+        return filterSet;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a composite filter,
+     * one of AND, OR and NOT
+     * 
+     * @return The composite filter string
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        if ( ( filterSet != null ) && ( filterSet.size() != 0 ) )
+        {
+            for ( Filter filter : filterSet )
+            {
+                sb.append( '(' ).append( filter ).append( ')' );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/DelRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/DelRequestDsml.java
new file mode 100644
index 0000000..f05f678
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/DelRequestDsml.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.dom4j.Element;
+
+
+/**
+ * DSML Decorator for DeleteRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DelRequestDsml
+    extends AbstractResultResponseRequestDsml<DeleteRequest, DeleteResponse>
+    implements DeleteRequest
+{
+    /**
+     * Creates a new getDecoratedMessage() of DelRequestDsml.
+     */
+    public DelRequestDsml( LdapApiService codec )
+    {
+        super( codec, new DeleteRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of DelRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public DelRequestDsml( LdapApiService codec, DeleteRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        // Dn
+        if ( getDecorated().getName() != null )
+        {
+            element.addAttribute( "dn", getDecorated().getName().getName() );
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Get the entry to be deleted
+     * 
+     * @return Returns the entry.
+     */
+    public Dn getEntry()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * Set the entry to be deleted
+     * 
+     * @param entry The entry to set.
+     */
+    public void setEntry( Dn entry )
+    {
+        getDecorated().setName( entry );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest setName( Dn name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest addControl( Control control )
+    {
+        return ( DeleteRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest addAllControls( Control[] controls )
+    {
+        return ( DeleteRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest removeControl( Control control )
+    {
+        return ( DeleteRequest ) super.removeControl( control );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Dsmlv2Grammar.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Dsmlv2Grammar.java
new file mode 100644
index 0000000..147530c
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Dsmlv2Grammar.java
@@ -0,0 +1,3025 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.HashMap;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.dsmlv2.AbstractGrammar;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Container;
+import org.apache.directory.api.dsmlv2.Dsmlv2StatesEnum;
+import org.apache.directory.api.dsmlv2.Grammar;
+import org.apache.directory.api.dsmlv2.GrammarAction;
+import org.apache.directory.api.dsmlv2.GrammarTransition;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.dsmlv2.Tag;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.OnError;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.api.ldap.model.message.AddRequestImpl;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareRequestImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedRequestImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl;
+import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
+import org.apache.directory.api.ldap.model.message.Request;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Strings;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * This Class represents the DSMLv2 Request Grammar
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Dsmlv2Grammar extends AbstractGrammar implements Grammar
+{
+    private LdapApiService codec = LdapApiServiceFactory.getSingleton();
+    
+    /** Some literal */
+    private static final String BATCH_REQUEST = "batchRequest";
+    private static final String ABANDON_REQUEST = "abandonRequest";
+    private static final String ADD_REQUEST = "addRequest";
+    private static final String COMPARE_REQUEST = "compareRequest";
+    private static final String DEL_REQUEST = "delRequest";
+    private static final String EXTENDED_REQUEST = "extendedRequest";
+    private static final String MOD_DN_REQUEST = "modDNRequest";
+    private static final String MODIFY_REQUEST = "modifyRequest";
+    private static final String SEARCH_REQUEST = "searchRequest";
+    private static final String CONTROL = "control";
+    private static final String CONTROL_VALUE = "controlValue";
+    private static final String ATTR = "attr";
+    private static final String VALUE = "value";
+    private static final String MODIFICATION = "modification";
+    private static final String SUBSTRINGS = "substrings";
+    private static final String REQUEST_ID = "requestID";
+    private static final String NAME = "name";
+    private static final String TRUE = "true";
+    private static final String FALSE = "false";
+
+
+    /**
+     * Creates a new instance of Dsmlv2Grammar.
+     */
+    @SuppressWarnings("unchecked")
+    public Dsmlv2Grammar()
+    {
+        name = Dsmlv2Grammar.class.getName();
+
+        // Create the transitions table
+        super.transitions = ( HashMap<Tag, GrammarTransition>[] ) Array.newInstance( HashMap.class, 200 );
+
+        //====================================================
+        //  Transitions concerning : BATCH REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.INIT_GRAMMAR_STATE.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // ** OPEN BATCH REQUEST **
+        // State: [INIT_GRAMMAR_STATE] - Tag: <batchRequest>
+        super.transitions[Dsmlv2StatesEnum.INIT_GRAMMAR_STATE.ordinal()].put( new Tag( BATCH_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE, Dsmlv2StatesEnum.BATCHREQUEST_START_TAG,
+                batchRequestCreation ) );
+
+        // ** CLOSE BATCH REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: </batchRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()]
+            .put( new Tag( BATCH_REQUEST, Tag.END ), new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG,
+                Dsmlv2StatesEnum.BATCHREQUEST_END_TAG, null ) );
+        //state: [BATCHREQUEST_LOOP] - Tag: </batchRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( BATCH_REQUEST, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.GRAMMAR_END, null ) );
+
+        // ** ABANDON REQUEST **
+        // State: [BATCHREQUEST_START_TAG] - Tag: <abandonRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put(
+            new Tag( ABANDON_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG, Dsmlv2StatesEnum.ABANDON_REQUEST_START_TAG,
+                abandonRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <abandonRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( ABANDON_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.ABANDON_REQUEST_START_TAG,
+                abandonRequestCreation ) );
+
+        // ** ADD REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <addRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put( new Tag( ADD_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG, Dsmlv2StatesEnum.ADD_REQUEST_START_TAG,
+                addRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <addRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( ADD_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.ADD_REQUEST_START_TAG,
+                addRequestCreation ) );
+
+        // ** AUTH REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <authRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put( new Tag( "authRequest", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG, Dsmlv2StatesEnum.AUTH_REQUEST_START_TAG,
+                authRequestCreation ) );
+
+        // ** COMPARE REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <compareRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put(
+            new Tag( COMPARE_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG, Dsmlv2StatesEnum.COMPARE_REQUEST_START_TAG,
+                compareRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <compareRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( COMPARE_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.COMPARE_REQUEST_START_TAG,
+                compareRequestCreation ) );
+
+        // ** DEL REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <delRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put( new Tag( DEL_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG, Dsmlv2StatesEnum.DEL_REQUEST_START_TAG,
+                delRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <delRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( DEL_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.DEL_REQUEST_START_TAG,
+                delRequestCreation ) );
+
+        // ** EXTENDED REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <extendedRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put(
+            new Tag( EXTENDED_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_START_TAG, extendedRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <extendedRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( EXTENDED_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.EXTENDED_REQUEST_START_TAG,
+                extendedRequestCreation ) );
+
+        // ** MOD Dn REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <modDNRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put( new Tag( MOD_DN_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_DN_REQUEST_START_TAG, modDNRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <modDNRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( MOD_DN_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.MODIFY_DN_REQUEST_START_TAG,
+                modDNRequestCreation ) );
+
+        // ** MODIFY REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <modifyRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put(
+            new Tag( MODIFY_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG, Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG,
+                modifyRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <modifyRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( MODIFY_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG,
+                modifyRequestCreation ) );
+
+        // ** SEARCH REQUEST **
+        // state: [BATCHREQUEST_START_TAG] - Tag: <searchRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_START_TAG.ordinal()].put(
+            new Tag( SEARCH_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_START_TAG, Dsmlv2StatesEnum.SEARCH_REQUEST_START_TAG,
+                searchRequestCreation ) );
+        // state: [BATCHREQUEST_LOOP] - Tag: <searchRequest>
+        super.transitions[Dsmlv2StatesEnum.BATCHREQUEST_LOOP.ordinal()].put( new Tag( SEARCH_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCHREQUEST_LOOP, Dsmlv2StatesEnum.SEARCH_REQUEST_START_TAG,
+                searchRequestCreation ) );
+
+        //====================================================
+        //  Transitions concerning : ABANDON REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [ABANDON_REQUEST_START_TAG] - Tag: </abandonRequest>
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_START_TAG.ordinal()]
+            .put( new Tag( ABANDON_REQUEST, Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.ABANDON_REQUEST_START_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [ABANDON_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ABANDON_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [ABANDON_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_START_TAG.ordinal()].put(
+            new Tag( CONTROL_VALUE, Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [ABANDON_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [ABANDON_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [ABANDON_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [ABANDON_REQUEST_CONTROL_END_TAG] - Tag: </abandonRequest>
+        super.transitions[Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( ABANDON_REQUEST,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ABANDON_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : ADD REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_ATTR_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // state: [ADD_REQUEST_START_TAG] -> Tag: </addRequest>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_START_TAG.ordinal()].put( new Tag( ADD_REQUEST, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_START_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [ADD_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [ADD_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL_VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [ADD_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [ADD_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [ADD_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [ADD_REQUEST_CONTROL_END_TAG] - Tag: </addRequest>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( ADD_REQUEST, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP,
+                null ) );
+
+        // State: [ADD_REQUEST_START_TAG] - Tag: <attr>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_START_TAG.ordinal()].put( new Tag( ATTR, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_START_TAG, Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG,
+                addRequestAddAttribute ) );
+
+        // State: [ADD_REQUEST_CONTROL_END_TAG] - Tag: <attr>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( ATTR, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG, addRequestAddAttribute ) );
+
+        // State: [ADD_REQUEST_ATTR_END_TAG] - Tag: <attr>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_ATTR_END_TAG.ordinal()].put( new Tag( ATTR, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_ATTR_END_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG, addRequestAddAttribute ) );
+
+        // State: [ADD_REQUEST_ATTR_START_TAG] - Tag: </attr>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG.ordinal()].put( new Tag( ATTR, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_ATTR_END_TAG, null ) );
+
+        // State: [ADD_REQUEST_ATTR_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG.ordinal()].put( new Tag( VALUE, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG,
+                Dsmlv2StatesEnum.ADD_REQUEST_ATTR_START_TAG, addRequestAddValue ) );
+
+        // State: [ADD_REQUEST_ATTR_END_TAG] - Tag: </addRequest>
+        super.transitions[Dsmlv2StatesEnum.ADD_REQUEST_ATTR_END_TAG.ordinal()]
+            .put( new Tag( ADD_REQUEST, Tag.END ), new GrammarTransition( Dsmlv2StatesEnum.ADD_REQUEST_ATTR_END_TAG,
+                Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : AUTH REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // state: [AUTH_REQUEST_START_TAG] -> Tag: </authRequest>
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_START_TAG.ordinal()].put( new Tag( "authRequest", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.AUTH_REQUEST_START_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [AUTH_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.AUTH_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [AUTH_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL_VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.AUTH_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [AUTH_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.AUTH_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [AUTH_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_START_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [AUTH_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [AUTH_REQUEST_CONTROL_END_TAG] - Tag: </authRequest>
+        super.transitions[Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( "authRequest", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.AUTH_REQUEST_CONTROL_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP,
+                null ) );
+
+        //====================================================
+        //  Transitions concerning : COMPARE REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_VALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [COMPARE_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [COMPARE_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG.ordinal()].put(
+            new Tag( CONTROL_VALUE, Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [COMPARE_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [COMPARE_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [COMPARE_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [COMPARE_REQUEST_CONTROL_END_TAG] - Tag: </compareRequest>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( COMPARE_REQUEST,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [COMPARE_REQUEST_START_TAG] - Tag: <assertion>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_START_TAG.ordinal()].put( new Tag( "assertion", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_START_TAG, compareRequestAddAssertion ) );
+
+        // State: [COMPARE_REQUEST_CONTROL_END_TAG] - Tag: <assertion>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( "assertion",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_START_TAG, compareRequestAddAssertion ) );
+
+        // State: [COMPARE_REQUEST_ASSERTION_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_START_TAG.ordinal()].put( new Tag( VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_START_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_VALUE_END_TAG, compareRequestAddValue ) );
+
+        //State: [COMPARE_REQUEST_VALUE_END_TAG] - Tag: </assertion>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_VALUE_END_TAG.ordinal()].put(
+            new Tag( "assertion", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.COMPARE_REQUEST_VALUE_END_TAG,
+                Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_END_TAG, null ) );
+
+        // State: [COMPARE_REQUEST_ASSERTION_END_TAG] - Tag: </compareRequest>
+        super.transitions[Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_END_TAG.ordinal()].put(
+            new Tag( COMPARE_REQUEST, Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.COMPARE_REQUEST_ASSERTION_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : DEL REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [DEL_REQUEST_START_TAG] - Tag: </delRequest>
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_START_TAG.ordinal()].put( new Tag( DEL_REQUEST, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.DEL_REQUEST_START_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [DEL_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.DEL_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [DEL_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL_VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.DEL_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [DEL_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.DEL_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [DEL_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [DEL_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [DEL_REQUEST_CONTROL_END_TAG] - Tag: </delRequest>
+        super.transitions[Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( DEL_REQUEST, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.DEL_REQUEST_CONTROL_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP,
+                null ) );
+
+        //====================================================
+        //  Transitions concerning : EXTENDED REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTNAME_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [EXTENDED_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [EXTENDED_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_START_TAG.ordinal()].put(
+            new Tag( CONTROL_VALUE, Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [EXTENDED_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [EXTENDED_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [EXTENDED_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [EXTENDED_REQUEST_CONTROL_END_TAG] - Tag: </extendedRequest>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( EXTENDED_REQUEST, Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [EXTENDED_REQUEST_START_TAG] - Tag: <requestName>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_START_TAG.ordinal()].put(
+            new Tag( "requestName", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTNAME_END_TAG, extendedRequestAddName ) );
+
+        // State: [EXTENDED_REQUEST_CONTROL_END_TAG] - Tag: <requestName>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( "requestName",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTNAME_END_TAG, extendedRequestAddName ) );
+
+        // State: [EXTENDED_REQUEST_REQUESTNAME_END_TAG] - Tag: </extendedRequest>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTNAME_END_TAG.ordinal()].put( new Tag(
+            EXTENDED_REQUEST,
+            Tag.END ), new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTNAME_END_TAG,
+            Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [EXTENDED_REQUEST_REQUESTNAME_END_TAG] - Tag: <requestValue>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTNAME_END_TAG.ordinal()].put( new Tag(
+            "requestValue",
+            Tag.START ), new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTNAME_END_TAG,
+            Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTVALUE_END_TAG, extendedRequestAddValue ) );
+
+        // State: [EXTENDED_REQUEST_REQUESTVALUE_END_TAG] - Tag: </requestRequest>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTVALUE_END_TAG.ordinal()].put( new Tag(
+            EXTENDED_REQUEST,
+            Tag.END ), new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_REQUEST_REQUESTVALUE_END_TAG,
+            Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : MODIFY Dn REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [MODIFY_DN_REQUEST_START_TAG] - Tag: </modDNRequest>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_START_TAG.ordinal()].put(
+            new Tag( MOD_DN_REQUEST, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_DN_REQUEST_START_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP,
+                null ) );
+
+        // State: [MODIFY_DN_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_DN_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [MODIFY_DN_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_START_TAG.ordinal()].put(
+            new Tag( CONTROL_VALUE, Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [MODIFY_DN_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [MODIFY_DN_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [MODIFY_DN_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [MODIFY_DN_REQUEST_CONTROL_END_TAG] - Tag: </modDNRequest>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( MOD_DN_REQUEST,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_DN_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : MODIFY REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_VALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [MODIFY_REQUEST_START_TAG] - Tag: </modifyRequest>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG.ordinal()]
+            .put( new Tag( MODIFY_REQUEST, Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        // State: [MODIFY_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [MODIFY_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL_VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [MODIFY_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [MODIFY_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_START_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [MODIFY_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [MODIFY_REQUEST_CONTROL_END_TAG] - Tag: </modifyRequest>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( MODIFY_REQUEST,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP,
+                null ) );
+
+        // State: [MODIFY_REQUEST_CONTROL_END_TAG] - Tag: <modification>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( MODIFICATION,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG, modifyRequestAddModification ) );
+
+        // State: [MODIFY_REQUEST_START_TAG] - Tag: <modification>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG.ordinal()].put(
+            new Tag( MODIFICATION, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG, modifyRequestAddModification ) );
+
+        // State: [MODIFY_REQUEST_MODIFICATION_END_TAG] - Tag: <modification>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_END_TAG.ordinal()].put(
+            new Tag( MODIFICATION, Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG, modifyRequestAddModification ) );
+
+        // State: [MODIFY_REQUEST_MODIFICATION_START_TAG] - Tag: </modification>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG.ordinal()].put(
+            new Tag( MODIFICATION, Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_END_TAG, null ) );
+
+        // State: [MODIFY_REQUEST_MODIFICATION_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG.ordinal()].put( new Tag( VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_START_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_VALUE_END_TAG, modifyRequestAddValue ) );
+
+        // State: [MODIFY_REQUEST_VALUE_END_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_VALUE_END_TAG.ordinal()].put( new Tag( VALUE, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_VALUE_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_VALUE_END_TAG, modifyRequestAddValue ) );
+
+        // State: [MODIFY_REQUEST_VALUE_END_TAG] - Tag: </modification>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_VALUE_END_TAG.ordinal()].put( new Tag( MODIFICATION,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MODIFY_REQUEST_VALUE_END_TAG,
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_END_TAG, null ) );
+
+        // State: [MODIFY_REQUEST_MODIFICATION_END_TAG] - Tag: </modifyRequest>
+        super.transitions[Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_END_TAG.ordinal()].put(
+            new Tag( MODIFY_REQUEST, Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.MODIFY_REQUEST_MODIFICATION_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : SEARCH REQUEST
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROLVALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_REQUEST_START_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_START_TAG.ordinal()].put( new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [SEARCH_REQUEST_CONTROL_START_TAG] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_START_TAG.ordinal()].put( new Tag( CONTROL_VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROLVALUE_END_TAG, controlValueCreation ) );
+
+        // State: [SEARCH_REQUEST_CONTROLVALUE_END_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROLVALUE_END_TAG.ordinal()].put( new Tag( CONTROL,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROLVALUE_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_CONTROL_START_TAG] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_START_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_CONTROL_END_TAG] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( CONTROL, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_START_TAG, controlCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_END_TAG] - Tag: </searchRequest>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG.ordinal()].put( new Tag( SEARCH_REQUEST,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP,
+                storeFilter ) );
+
+        // State: [SEARCH_REQUEST_ATTRIBUTES_START_TAG] - Tag: </attributes>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_START_TAG.ordinal()].put( new Tag( "attributes",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_END_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_ATTRIBUTES_START_TAG] - Tag: <attribute>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_START_TAG.ordinal()].put( new Tag( "attribute",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_START_TAG, searchRequestAddAttribute ) );
+
+        // State: [SEARCH_REQUEST_ATTRIBUTE_START_TAG] - Tag: </attribute>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_START_TAG.ordinal()].put( new Tag( "attribute",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_END_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_ATTRIBUTE_END_TAG] - Tag: <attribute>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_END_TAG.ordinal()].put( new Tag( "attribute",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_START_TAG, searchRequestAddAttribute ) );
+
+        // State: [SEARCH_REQUEST_ATTRIBUTE_END_TAG] - Tag: </attributes>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_END_TAG.ordinal()].put( new Tag( "attributes",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTE_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_END_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_ATTRIBUTES_END_TAG] - Tag: </searchRequest>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_END_TAG.ordinal()].put( new Tag( SEARCH_REQUEST,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_END_TAG,
+                Dsmlv2StatesEnum.BATCHREQUEST_LOOP, storeFilter ) );
+
+        //====================================================
+        //  Transitions concerning : FILTER
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_EQUALITYMATCH_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_GREATEROREQUAL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_LESSOREQUAL_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_APPROXMATCH_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_PRESENT_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_VALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_REQUEST_START_TAG] - Tag: <filter>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_START_TAG.ordinal()].put( new Tag( "filter", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_CONTROL_END_TAG] - Tag: <filter>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG.ordinal()].put(
+            new Tag( "filter", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_CONTROL_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG, null ) );
+
+        //*** AND ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <and>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( "and", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, andFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <and>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "and", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, andFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: </and>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "and", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, connectorFilterClose ) );
+
+        //*** OR ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <or>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( "or", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, orFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <or>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "or", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, orFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: </or>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "or", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, connectorFilterClose ) );
+
+        //*** NOT ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <not>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( "not", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, notFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <not>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "not", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, notFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: </not>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "not", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, connectorFilterClose ) );
+
+        //*** SUBSTRINGS ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <substrings>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( SUBSTRINGS,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG, substringsFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <substrings>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put(
+            new Tag( SUBSTRINGS, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG, substringsFilterCreation ) );
+
+        //*** EQUALITY MATCH ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <equalityMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( "equalityMatch",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_EQUALITYMATCH_START_TAG, equalityMatchFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <equalityMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "equalityMatch",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_EQUALITYMATCH_START_TAG, equalityMatchFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_EQUALITYMATCH_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_EQUALITYMATCH_START_TAG.ordinal()].put( new Tag( VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_EQUALITYMATCH_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG, filterAddValue ) );
+
+        // State: [SEARCH_REQUEST_VALUE_END_TAG] - Tag: </equalityMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG.ordinal()].put( new Tag( "equalityMatch",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, null ) );
+
+        //*** GREATER OR EQUAL ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <greaterOrEqual>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put(
+            new Tag( "greaterOrEqual", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_GREATEROREQUAL_START_TAG, greaterOrEqualFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <greaterOrEqual>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "greaterOrEqual",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_GREATEROREQUAL_START_TAG, greaterOrEqualFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_GREATEROREQUAL_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_GREATEROREQUAL_START_TAG.ordinal()].put( new Tag( VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_GREATEROREQUAL_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG, filterAddValue ) );
+
+        // State: [SEARCH_REQUEST_VALUE_END_TAG] - Tag: </greaterOrEqual>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG.ordinal()].put( new Tag( "greaterOrEqual",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, null ) );
+
+        //*** LESS OR EQUAL ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <lessOrEqual>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( "lessOrEqual",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_LESSOREQUAL_START_TAG, lessOrEqualFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <lessOrEqual>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put(
+            new Tag( "lessOrEqual", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_LESSOREQUAL_START_TAG, lessOrEqualFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_LESSOREQUAL_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_LESSOREQUAL_START_TAG.ordinal()].put( new Tag( VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_LESSOREQUAL_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG, filterAddValue ) );
+
+        // State: [SEARCH_REQUEST_VALUE_END_TAG] - Tag: </lessOrEqual>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG.ordinal()].put(
+            new Tag( "lessOrEqual", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, null ) );
+
+        //*** LESS OR EQUAL ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <approxMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( "approxMatch",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_APPROXMATCH_START_TAG, approxMatchFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <approxMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put(
+            new Tag( "approxMatch", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_APPROXMATCH_START_TAG, approxMatchFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_APPROXMATCH_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_APPROXMATCH_START_TAG.ordinal()].put( new Tag( VALUE,
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_APPROXMATCH_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG, filterAddValue ) );
+
+        // State: [SEARCH_REQUEST_VALUE_END_TAG] - Tag: </approxMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG.ordinal()].put(
+            new Tag( "approxMatch", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_VALUE_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, null ) );
+
+        //*** PRESENT ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <present>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put( new Tag( "present",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_PRESENT_START_TAG, presentFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <present>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "present", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_PRESENT_START_TAG, presentFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_PRESENT_START_TAG] - Tag: </present>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_PRESENT_START_TAG.ordinal()].put(
+            new Tag( "present", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_PRESENT_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, null ) );
+
+        //*** EXTENSIBLE MATCH ***
+        // State: [SEARCH_REQUEST_FILTER_START_TAG] - Tag: <extensibleMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG.ordinal()].put(
+            new Tag( "extensibleMatch", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_START_TAG, extensibleMatchFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: <extensibleMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "extensibleMatch",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_START_TAG, extensibleMatchFilterCreation ) );
+
+        // State: [SEARCH_REQUEST_EXTENSIBLEMATCH_START_TAG] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_START_TAG.ordinal()].put(
+            new Tag( VALUE, Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_VALUE_END_TAG, extensibleMatchAddValue ) );
+
+        // State: [SEARCH_REQUEST_EXTENSIBLEMATCH_VALUE_END_TAG] - Tag: </extensibleMatch>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_VALUE_END_TAG.ordinal()].put( new Tag(
+            "extensibleMatch", Tag.END ), new GrammarTransition(
+            Dsmlv2StatesEnum.SEARCH_REQUEST_EXTENSIBLEMATCH_VALUE_END_TAG, Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+            null ) );
+
+        //*** Filter (end) ***
+        // State: [SEARCH_REQUEST_FILTER_LOOP] - Tag: </filter>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP.ordinal()].put( new Tag( "filter", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_END_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_FILTER_END_TAG] - Tag: <attributes>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_END_TAG.ordinal()].put( new Tag( "attributes",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ATTRIBUTES_START_TAG, null ) );
+
+        // State: [SEARCH_REQUEST_FILTER_END_TAG] - Tag: </searchRequest>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_END_TAG.ordinal()].put( new Tag( SEARCH_REQUEST,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_END_TAG, Dsmlv2StatesEnum.BATCHREQUEST_LOOP,
+                storeFilter ) );
+
+        //====================================================
+        //  Transitions concerning : SUBSTRING FILTER
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FINAL_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_REQUEST_SUBSTRINGS_START_TAG] - Tag: </substrings>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG.ordinal()].put( new Tag( SUBSTRINGS,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, null ) );
+
+        // State: [SEARCH_REQUEST_SUBSTRINGS_START_TAG] - Tag: <initial>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG.ordinal()].put( new Tag( "initial",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG, substringsFilterSetInitial ) );
+
+        // State: [SEARCH_REQUEST_INITIAL_END_TAG] - Tag: <any>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG.ordinal()].put( new Tag( "any", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG, substringsFilterAddAny ) );
+
+        // State: [SEARCH_REQUEST_INITIAL_END_TAG] - Tag: <final>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG.ordinal()].put(
+            new Tag( "final", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FINAL_END_TAG, substringsFilterSetFinal ) );
+
+        // State: [SEARCH_REQUEST_INITIAL_END_TAG] - Tag: </substrings>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG.ordinal()].put( new Tag( SUBSTRINGS,
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_INITIAL_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, substringsFilterClose ) );
+
+        // State: [SEARCH_REQUEST_SUBSTRINGS_START_TAG] - Tag: <any>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG.ordinal()].put( new Tag( "any",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG, substringsFilterAddAny ) );
+
+        // State: [SEARCH_REQUEST_ANY_END_TAG] - Tag: </any>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG.ordinal()].put( new Tag( "any", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG, substringsFilterAddAny ) );
+
+        // State: [SEARCH_REQUEST_ANY_END_TAG] - Tag: <final>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG.ordinal()].put( new Tag( "final", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FINAL_END_TAG, substringsFilterSetFinal ) );
+
+        // State: [SEARCH_REQUEST_ANY_END_TAG] - Tag: </substrings>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG.ordinal()].put( new Tag( SUBSTRINGS, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_ANY_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, substringsFilterClose ) );
+
+        // State: [SEARCH_REQUEST_SUBSTRINGS_START_TAG] - Tag: <final>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG.ordinal()].put( new Tag( "final",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_SUBSTRINGS_START_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FINAL_END_TAG, substringsFilterSetFinal ) );
+
+        // State: [SEARCH_REQUEST_FINAL_END_TAG] - Tag: </substrings>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_REQUEST_FINAL_END_TAG.ordinal()].put(
+            new Tag( SUBSTRINGS, Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_REQUEST_FINAL_END_TAG,
+                Dsmlv2StatesEnum.SEARCH_REQUEST_FILTER_LOOP, substringsFilterClose ) );
+
+        //------------------------------------------ handle SOAP envelopes --------------------------
+        super.transitions[Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_BODY_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_BODY_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        super.transitions[Dsmlv2StatesEnum.GRAMMAR_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [INIT_GRAMMAR_STATE] - Tag: <envelope>
+        super.transitions[Dsmlv2StatesEnum.INIT_GRAMMAR_STATE.ordinal()].put( new Tag( "envelope", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE, Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG,
+                null ) );
+
+        // state: [SOAP_ENVELOPE_START_TAG] -> Tag: <header>
+        super.transitions[Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG.ordinal()].put( new Tag( "header", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG, Dsmlv2StatesEnum.SOAP_HEADER_START_TAG,
+                ParserUtils.READ_SOAP_HEADER ) );
+
+        // state: [SOAP_HEADER_START_TAG] -> Tag: </header>
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_START_TAG.ordinal()]
+            .put( new Tag( "header", Tag.END ),
+                new GrammarTransition( Dsmlv2StatesEnum.SOAP_HEADER_START_TAG, Dsmlv2StatesEnum.SOAP_HEADER_END_TAG,
+                    null ) );
+
+        // state: [SOAP_HEADER_END_TAG] -> Tag: <body>
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_END_TAG.ordinal()].put( new Tag( "body", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SOAP_HEADER_END_TAG, Dsmlv2StatesEnum.SOAP_BODY_START_TAG, null ) );
+
+        // state: [SOAP_BODY_START_TAG] -> Tag: <batchRequest>
+        super.transitions[Dsmlv2StatesEnum.SOAP_BODY_START_TAG.ordinal()].put( new Tag( BATCH_REQUEST, Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SOAP_BODY_START_TAG, Dsmlv2StatesEnum.BATCHREQUEST_START_TAG,
+                batchRequestCreation ) );
+
+        // the optional transition if no soap header is present
+        // state: [SOAP_ENVELOPE_START_TAG] -> Tag: <body>
+        super.transitions[Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG.ordinal()]
+            .put( new Tag( "body", Tag.START ),
+                new GrammarTransition( Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG, Dsmlv2StatesEnum.SOAP_BODY_START_TAG,
+                    null ) );
+
+        // the below two transitions are a bit unconventional, technically the container's state is set to GRAMMAR_END
+        // when the </batchRequest> tag is encountered by the parser and the corresponding action gets executed but in
+        // a SOAP envelop we still have two more end tags(</body> and </envelope>) are left so we set those corresponding
+        // current and next transition states always to GRAMMAR_END
+        super.transitions[Dsmlv2StatesEnum.GRAMMAR_END.ordinal()].put( new Tag( "body", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.GRAMMAR_END, Dsmlv2StatesEnum.GRAMMAR_END, null ) );
+
+        super.transitions[Dsmlv2StatesEnum.GRAMMAR_END.ordinal()].put( new Tag( "envelope", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.GRAMMAR_END, Dsmlv2StatesEnum.GRAMMAR_END, null ) );
+
+        //------------------------------------------
+
+    } // End of the constructor
+
+
+    /**
+     * @return The LDAP codec service.
+     */
+    public LdapApiService getLdapCodecService()
+    {
+        return codec;
+    }
+
+    //*************************
+    //*    GRAMMAR ACTIONS    *
+    //*************************
+
+    /**
+     * GrammarAction that creates a Batch Request
+     */
+    private final GrammarAction batchRequestCreation = new GrammarAction( "Create Batch Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            BatchRequestDsml batchRequest = new BatchRequestDsml();
+
+            container.setBatchRequest( batchRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                batchRequest.setRequestID( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            // processing
+            attributeValue = xpp.getAttributeValue( "", "processing" );
+
+            if ( attributeValue != null )
+            {
+                if ( "sequential".equals( attributeValue ) )
+                {
+                    batchRequest.setProcessing( Processing.SEQUENTIAL );
+                }
+                else if ( "parallel".equals( attributeValue ) )
+                {
+                    batchRequest.setProcessing( Processing.PARALLEL );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03013 ), xpp, null );
+                }
+            }
+            else
+            {
+                batchRequest.setProcessing( Processing.SEQUENTIAL );
+            }
+
+            // onError
+            attributeValue = xpp.getAttributeValue( "", "onError" );
+
+            if ( attributeValue != null )
+            {
+                if ( "resume".equals( attributeValue ) )
+                {
+                    batchRequest.setOnError( OnError.RESUME );
+                }
+                else if ( "exit".equals( attributeValue ) )
+                {
+                    batchRequest.setOnError( OnError.EXIT );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03014 ), xpp, null );
+                }
+            }
+            else
+            {
+                batchRequest.setOnError( OnError.EXIT );
+            }
+
+            // responseOrder
+            attributeValue = xpp.getAttributeValue( "", "responseOrder" );
+
+            if ( attributeValue != null )
+            {
+                if ( "sequential".equals( attributeValue ) )
+                {
+                    batchRequest.setResponseOrder( ResponseOrder.SEQUENTIAL );
+                }
+                else if ( "unordered".equals( attributeValue ) )
+                {
+                    batchRequest.setResponseOrder( ResponseOrder.UNORDERED );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03015 ), xpp, null );
+                }
+            }
+            else
+            {
+                batchRequest.setResponseOrder( ResponseOrder.SEQUENTIAL );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates an Abandon Request
+     */
+    private final GrammarAction abandonRequestCreation = new GrammarAction( "Create Abandon Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AbandonRequestDsml abandonRequest = new AbandonRequestDsml( codec, new AbandonRequestImpl() );
+            container.getBatchRequest().addRequest( abandonRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+            
+            if ( attributeValue != null )
+            {
+                abandonRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+            
+            // abandonID
+            attributeValue = xpp.getAttributeValue( "", "abandonID" );
+            
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    abandonRequest.setAbandoned( Integer.parseInt( attributeValue ) );
+                }
+                catch ( NumberFormatException nfe )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03017 ), xpp, nfe );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03018 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates an Add Request
+     */
+    private final GrammarAction addRequestCreation = new GrammarAction( "Create Add Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AddRequestDsml addRequest = new AddRequestDsml( codec, new AddRequestImpl() );
+            container.getBatchRequest().addRequest( addRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+            
+            if ( attributeValue != null )
+            {
+                addRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+            
+            // dn
+            attributeValue = xpp.getAttributeValue( "", "dn" );
+            
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    addRequest.setEntryDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03019 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds an attribute to an Add Request
+     */
+    private final GrammarAction addRequestAddAttribute = new GrammarAction( "Add Attribute to Add Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AddRequestDsml addRequest = ( AddRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // name
+            attributeValue = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    addRequest.addAttributeType( attributeValue );
+                }
+                catch ( LdapException le )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03020 ), xpp, le );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to an Attribute of an Add Request
+     */
+    private final GrammarAction addRequestAddValue = new GrammarAction( "Add Value to Attribute" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AddRequestDsml addRequest = ( AddRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+                
+                if ( !nextText.equals( "" ) )
+                {
+                    try
+                    {
+                        if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                        {
+                            addRequest.addAttributeValue( Base64.decode( nextText.trim().toCharArray() ) );
+                        }
+                        else
+                        {
+                            addRequest.addAttributeValue( nextText.trim() );
+                        }
+                    }
+                    catch ( LdapException le )
+                    {
+                        throw new XmlPullParserException( le.getMessage(), xpp, le );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates an Auth Request
+     */
+    private final GrammarAction authRequestCreation = new GrammarAction( "Create Auth Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            BindRequestDsml authRequest = new BindRequestDsml( codec, new BindRequestImpl() );
+            container.getBatchRequest().addRequest( authRequest );
+
+            authRequest.setSimple( true );
+            authRequest.setVersion3( true );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                authRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+            // principal
+            attributeValue = xpp.getAttributeValue( "", "principal" );
+
+            if ( attributeValue != null )
+            {
+                authRequest.setName( attributeValue );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03021 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates an Compare Request
+     */
+    private final GrammarAction compareRequestCreation = new GrammarAction( "Create Compare Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            CompareRequestDsml compareRequest = new CompareRequestDsml( codec, new CompareRequestImpl() );
+            container.getBatchRequest().addRequest( compareRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                compareRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+
+            // dn
+            attributeValue = xpp.getAttributeValue( "", "dn" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    compareRequest.setName( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03019 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds an Assertion to a Compare Request
+     */
+    private final GrammarAction compareRequestAddAssertion = new GrammarAction( "Add Assertion to Compare Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            CompareRequest compareRequest = ( CompareRequest ) container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeId;
+
+            // name
+            attributeId = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeId != null )
+            {
+                compareRequest.setAttributeId( attributeId );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to a Compare Request
+     */
+    private final GrammarAction compareRequestAddValue = new GrammarAction( "Add Value to Compare Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            CompareRequest compareRequest = ( CompareRequest ) container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        compareRequest.setAssertionValue( Base64.decode( nextText.trim().toCharArray() ) );
+                    }
+                    else
+                    {
+                        compareRequest.setAssertionValue( nextText.trim() );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Del Request
+     */
+    private final GrammarAction delRequestCreation = new GrammarAction( "Create Del Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            DelRequestDsml delRequest = new DelRequestDsml( codec, new DeleteRequestImpl() );
+            container.getBatchRequest().addRequest( delRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                delRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+
+            // dn
+            attributeValue = xpp.getAttributeValue( "", "dn" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    delRequest.setName( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( "" + lide.getMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03019 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates an Extended Request
+     */
+    private final GrammarAction extendedRequestCreation = new GrammarAction( "Create Extended Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ExtendedRequestDsml<?, ?> extendedRequest =
+                new ExtendedRequestDsml<ExtendedRequest, ExtendedResponse>( codec,
+                    new ExtendedRequestImpl() );
+            container.getBatchRequest().addRequest( extendedRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                extendedRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Name to an Extended Request
+     */
+    private final GrammarAction extendedRequestAddName = new GrammarAction( "Add Name to Extended Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ExtendedRequestDsml<?, ?> extendedRequest = ( ExtendedRequestDsml<?, ?> )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                String nextText = xpp.nextText();
+
+                if ( nextText.equals( "" ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03022 ), xpp, null );
+                }
+                else
+                {
+                    String oid = nextText.trim();
+
+                    if ( Oid.isOid( oid ) )
+                    {
+                        extendedRequest.setRequestName( nextText.trim() );
+                    }
+                    else
+                    {
+                        throw new XmlPullParserException( "Bad oid : " + oid, xpp, null );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to an Extended Request
+     */
+    private final GrammarAction extendedRequestAddValue = new GrammarAction( "Add Value to Extended Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ExtendedRequestDsml<?, ?> extendedRequest = ( ExtendedRequestDsml<?, ?> )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        extendedRequest.setRequestValue( Base64.decode( nextText.trim().toCharArray() ) );
+                    }
+                    else
+                    {
+                        extendedRequest.setRequestValue( Strings.getBytesUtf8( nextText.trim() ) );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Modify Dn Request
+     */
+    private final GrammarAction modDNRequestCreation = new GrammarAction( "Create Modify Dn Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ModifyDNRequestDsml modifyDNRequest = new ModifyDNRequestDsml( codec, new ModifyDnRequestImpl() );
+            container.getBatchRequest().addRequest( modifyDNRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                modifyDNRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+
+            // dn
+            attributeValue = xpp.getAttributeValue( "", "dn" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    modifyDNRequest.setName( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( "" + lide.getMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03019 ), xpp, null );
+            }
+
+            // newrdn
+            attributeValue = xpp.getAttributeValue( "", "newrdn" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    modifyDNRequest.setNewRdn( new Rdn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( "" + lide.getMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03023 ), xpp, null );
+            }
+
+            // deleteoldrdn
+            attributeValue = xpp.getAttributeValue( "", "deleteoldrdn" );
+
+            if ( attributeValue != null )
+            {
+                if ( ( attributeValue.equalsIgnoreCase( TRUE ) ) || ( attributeValue.equals( "1" ) ) )
+                {
+                    modifyDNRequest.setDeleteOldRdn( true );
+                }
+                else if ( ( attributeValue.equalsIgnoreCase( FALSE ) ) || ( attributeValue.equals( "0" ) ) )
+                {
+                    modifyDNRequest.setDeleteOldRdn( false );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03024 ), xpp, null );
+                }
+            }
+            else
+            {
+                modifyDNRequest.setDeleteOldRdn( true );
+            }
+
+            // newsuperior
+            attributeValue = xpp.getAttributeValue( "", "newSuperior" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    modifyDNRequest.setNewSuperior( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( "" + lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Modify Request
+     */
+    private final GrammarAction modifyRequestCreation = new GrammarAction( "Create Modify Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ModifyRequestDsml modifyRequest = new ModifyRequestDsml( codec, new ModifyRequestImpl() );
+            container.getBatchRequest().addRequest( modifyRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                modifyRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+
+            // dn
+            attributeValue = xpp.getAttributeValue( "", "dn" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    modifyRequest.setName( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( "" + lide.getLocalizedMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( "dn attribute is required", xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Modification to a Modify Request
+     */
+    private final GrammarAction modifyRequestAddModification = new GrammarAction( "Adds Modification to Modify Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ModifyRequestDsml modifyRequest = ( ModifyRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // operation
+            attributeValue = xpp.getAttributeValue( "", "operation" );
+
+            if ( attributeValue != null )
+            {
+                if ( "add".equals( attributeValue ) )
+                {
+                    modifyRequest.setCurrentOperation( LdapCodecConstants.OPERATION_ADD );
+                }
+                else if ( "delete".equals( attributeValue ) )
+                {
+                    modifyRequest.setCurrentOperation( LdapCodecConstants.OPERATION_DELETE );
+                }
+                else if ( "replace".equals( attributeValue ) )
+                {
+                    modifyRequest.setCurrentOperation( LdapCodecConstants.OPERATION_REPLACE );
+                }
+                else
+                {
+                    throw new XmlPullParserException(
+                        "unknown operation. Operation can be 'add', 'delete' or 'replace'.", xpp, null );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03025 ), xpp, null );
+            }
+
+            // name
+            attributeValue = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeValue != null )
+            {
+                modifyRequest.addAttributeTypeAndValues( attributeValue );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to a Modification of a Modify Request
+     */
+    private final GrammarAction modifyRequestAddValue = new GrammarAction(
+        "Add Value to Modification of Modify Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ModifyRequestDsml modifyRequest = ( ModifyRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+                // We are testing if nextText equals "" since a modification can be "".
+
+                try
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        modifyRequest.addAttributeValue( Base64.decode( nextText.trim().toCharArray() ) );
+                    }
+                    else
+                    {
+                        modifyRequest.addAttributeValue( nextText.trim() );
+                    }
+                }
+                catch ( LdapException le )
+                {
+                    throw new XmlPullParserException( le.getMessage(), xpp, le );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Search Request
+     */
+    private final GrammarAction searchRequestCreation = new GrammarAction( "Create Search Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequest = new SearchRequestDsml( codec, new SearchRequestImpl() );
+            container.getBatchRequest().addRequest( searchRequest );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", REQUEST_ID );
+
+            if ( attributeValue != null )
+            {
+                searchRequest.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                if ( ParserUtils.isRequestIdNeeded( container ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03016 ), xpp, null );
+                }
+            }
+
+            // dn
+            attributeValue = xpp.getAttributeValue( "", "dn" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    searchRequest.setBase( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03019 ), xpp, null );
+            }
+
+            // scope
+            attributeValue = xpp.getAttributeValue( "", "scope" );
+
+            if ( attributeValue != null )
+            {
+                if ( "baseObject".equals( attributeValue ) )
+                {
+                    searchRequest.setScope( SearchScope.OBJECT );
+                }
+                else if ( "singleLevel".equals( attributeValue ) )
+                {
+                    searchRequest.setScope( SearchScope.ONELEVEL );
+                }
+                else if ( "wholeSubtree".equals( attributeValue ) )
+                {
+                    searchRequest.setScope( SearchScope.SUBTREE );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03026 ), xpp, null );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03027 ), xpp, null );
+            }
+
+            // derefAliases
+            attributeValue = xpp.getAttributeValue( "", "derefAliases" );
+
+            if ( attributeValue != null )
+            {
+                if ( "neverDerefAliases".equals( attributeValue ) )
+                {
+                    searchRequest.setDerefAliases( AliasDerefMode.NEVER_DEREF_ALIASES );
+                }
+                else if ( "derefInSearching".equals( attributeValue ) )
+                {
+                    searchRequest.setDerefAliases( AliasDerefMode.DEREF_IN_SEARCHING );
+                }
+                else if ( "derefFindingBaseObj".equals( attributeValue ) )
+                {
+                    searchRequest.setDerefAliases( AliasDerefMode.DEREF_FINDING_BASE_OBJ );
+                }
+                else if ( "derefAlways".equals( attributeValue ) )
+                {
+                    searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03028 ), xpp, null );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03029 ), xpp, null );
+            }
+
+            // sizeLimit
+            attributeValue = xpp.getAttributeValue( "", "sizeLimit" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    searchRequest.setSizeLimit( Long.parseLong( attributeValue ) );
+                }
+                catch ( NumberFormatException nfe )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03030 ), xpp, nfe );
+                }
+            }
+            else
+            {
+                searchRequest.setSizeLimit( 0L );
+            }
+
+            // timeLimit
+            attributeValue = xpp.getAttributeValue( "", "timeLimit" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    searchRequest.setTimeLimit( Integer.parseInt( attributeValue ) );
+                }
+                catch ( NumberFormatException nfe )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03031 ), xpp, nfe );
+                }
+            }
+            else
+            {
+                searchRequest.setTimeLimit( 0 );
+            }
+
+            // typesOnly
+            attributeValue = xpp.getAttributeValue( "", "typesOnly" );
+
+            if ( attributeValue != null )
+            {
+                if ( ( attributeValue.equals( TRUE ) ) || ( attributeValue.equals( "1" ) ) )
+                {
+                    searchRequest.setTypesOnly( true );
+                }
+                else if ( ( attributeValue.equals( FALSE ) ) || ( attributeValue.equals( "0" ) ) )
+                {
+                    searchRequest.setTypesOnly( false );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03032 ), xpp, null );
+                }
+            }
+            else
+            {
+                searchRequest.setTypesOnly( false );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds an Attribute to a Search Request
+     */
+    private final GrammarAction searchRequestAddAttribute = new GrammarAction(
+        "Add Value to Modification of Modify Request" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequest searchRequest = ( SearchRequest ) container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attribute name
+            String attributeName = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeName != null )
+            {
+                searchRequest.addAttributes( attributeName );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that create a Substring Filter
+     */
+    private final GrammarAction substringsFilterCreation = new GrammarAction( "Create Substring Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            SubstringFilter filter = new SubstringFilter();
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+
+            searchRequestDecorator.setTerminalFilter( filter );
+
+            // Checking and adding the filter's attributes
+            String attributeValue;
+            // name
+            attributeValue = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeValue != null )
+            {
+                filter.setType( attributeValue );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that sets the Initial value to a Substring Filter
+     */
+    private final GrammarAction substringsFilterSetInitial = new GrammarAction( "Set Initial value to Substring Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            SubstringFilter substringFilter = ( SubstringFilter )
+                searchRequestDecorator.getTerminalFilter();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        substringFilter
+                            .setInitialSubstrings( Strings.utf8ToString( Base64.decode( nextText.trim().toCharArray() ) ) );
+                    }
+                    else
+                    {
+                        substringFilter.setInitialSubstrings( nextText.trim() );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Any value to a Substring Filter
+     */
+    private final GrammarAction substringsFilterAddAny = new GrammarAction( "Add Any value to Substring Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            SubstringFilter substringFilter = ( SubstringFilter ) searchRequestDecorator.getTerminalFilter();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        substringFilter.addAnySubstrings( Strings.utf8ToString( Base64.decode( nextText.trim().toCharArray() ) ) );
+                    }
+                    else
+                    {
+                        substringFilter.addAnySubstrings( nextText.trim() );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that sets the Final value to a Substring Filter
+     */
+    private final GrammarAction substringsFilterSetFinal = new GrammarAction( "Set Final value to Substring Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            SubstringFilter substringFilter = ( SubstringFilter ) searchRequestDecorator.getTerminalFilter();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        substringFilter
+                            .setFinalSubstrings( Strings.utf8ToString( Base64.decode( nextText.trim().toCharArray() ) ) );
+                    }
+                    else
+                    {
+                        substringFilter.setFinalSubstrings( nextText.trim() );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that closes a Substring Filter
+     */
+    private final GrammarAction substringsFilterClose = new GrammarAction( "Close Substring Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            searchRequestDecorator.setTerminalFilter( null );
+        }
+    };
+
+    /**
+     * GrammarAction that create a And Filter
+     */
+    private final GrammarAction andFilterCreation = new GrammarAction( "Create And Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            AndFilter filter = new AndFilter();
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that closes a Connector Filter (And, Or, Not)
+     */
+    private final GrammarAction connectorFilterClose = new GrammarAction( "Close Connector Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            searchRequestDecorator.endCurrentConnectorFilter();
+        }
+    };
+
+    /**
+     * GrammarAction that create a Or Filter
+     */
+    private final GrammarAction orFilterCreation = new GrammarAction( "Create Or Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            OrFilter filter = new OrFilter();
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that create a Not Filter
+     */
+    private final GrammarAction notFilterCreation = new GrammarAction( "Create Not Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            NotFilter filter = new NotFilter();
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that create a Equality Match Filter
+     */
+    private final GrammarAction equalityMatchFilterCreation = new GrammarAction( "Create Equality Match Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            AttributeValueAssertion assertion = new AttributeValueAssertion();
+
+            // Checking and adding the filter's attributes
+            String attributeName = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeName != null )
+            {
+                assertion.setAttributeDesc( attributeName );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+
+            AttributeValueAssertionFilter filter = new AttributeValueAssertionFilter(
+                LdapCodecConstants.EQUALITY_MATCH_FILTER );
+
+            filter.setAssertion( assertion );
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+
+            searchRequestDecorator.setTerminalFilter( filter );
+        }
+    };
+
+    /**
+     * GrammarAction that create a Greater Or Equal Filter
+     */
+    private final GrammarAction greaterOrEqualFilterCreation = new GrammarAction( "Create Greater Or Equal Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            AttributeValueAssertion assertion = new AttributeValueAssertion();
+
+            // Checking and adding the filter's attributes
+            String attributeName = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeName != null )
+            {
+                assertion.setAttributeDesc( attributeName );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+
+            AttributeValueAssertionFilter filter = new AttributeValueAssertionFilter(
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER );
+
+            filter.setAssertion( assertion );
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+
+            searchRequestDecorator.setTerminalFilter( filter );
+        }
+    };
+
+    /**
+     * GrammarAction that create a Less Or Equal Filter
+     */
+    private final GrammarAction lessOrEqualFilterCreation = new GrammarAction( "Create Less Or Equal Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            AttributeValueAssertion assertion = new AttributeValueAssertion();
+
+            // Checking and adding the filter's attributes
+            String attributeValue;
+            // name
+            attributeValue = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeValue != null )
+            {
+                assertion.setAttributeDesc( attributeValue );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+
+            AttributeValueAssertionFilter filter = new AttributeValueAssertionFilter(
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER );
+
+            filter.setAssertion( assertion );
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+
+            searchRequestDecorator.setTerminalFilter( filter );
+        }
+    };
+
+    /**
+     * GrammarAction that create an Approx Match Filter
+     */
+    private final GrammarAction approxMatchFilterCreation = new GrammarAction( "Create Approx Match Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            XmlPullParser xpp = container.getParser();
+
+            AttributeValueAssertion assertion = new AttributeValueAssertion();
+
+            // Checking and adding the filter's attributes
+            String attributeName = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeName != null )
+            {
+                assertion.setAttributeDesc( attributeName );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+
+            AttributeValueAssertionFilter filter = new AttributeValueAssertionFilter(
+                LdapCodecConstants.APPROX_MATCH_FILTER );
+
+            filter.setAssertion( assertion );
+
+            // Adding the filter to the Search Filter
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( filter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+
+            searchRequestDecorator.setTerminalFilter( filter );
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to a Filter
+     */
+    private final GrammarAction filterAddValue = new GrammarAction( "Adds Value to Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+            AttributeValueAssertionFilter filter = ( AttributeValueAssertionFilter ) searchRequestDecorator
+                .getTerminalFilter();
+            AttributeValueAssertion assertion = filter.getAssertion();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        Value<byte[]> value = new BinaryValue( Base64.decode( nextText.trim().toCharArray() ) );
+                        assertion.setAssertionValue( value );
+                    }
+                    else
+                    {
+                        Value<String> value = new StringValue( nextText.trim() );
+                        assertion.setAssertionValue( value );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Present Filter
+     */
+    private final GrammarAction presentFilterCreation = new GrammarAction( "Create Present Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            PresentFilter presentFilter = new PresentFilter();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Adding the filter to the Search Filter
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( presentFilter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+
+            // Checking and adding the filter's attributes
+            String attributeValue;
+            // name
+            attributeValue = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeValue != null )
+            {
+                presentFilter.setAttributeDescription( attributeValue );
+            }
+            else
+            {
+                throw new XmlPullParserException( "name attribute is required", xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that store the Filter into the searchRequest
+     */
+    private final GrammarAction storeFilter = new GrammarAction( "Store Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            // Adding the filter to the Search Filter
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+            SearchRequest searchRequest = searchRequestDecorator.getDecorated();
+
+            if ( searchRequestDecorator.getFilterNode() == null )
+            {
+                throw new IllegalStateException( "No filter element present in the DSML search request" );
+            }
+
+            searchRequest.setFilter( searchRequestDecorator.getFilterNode() );
+        }
+    };
+
+    /**
+     * GrammarAction that creates an Extensible Match Filter
+     */
+    private final GrammarAction extensibleMatchFilterCreation = new GrammarAction( "Create Extensible Match Filter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ExtensibleMatchFilter extensibleMatchFilter = new ExtensibleMatchFilter();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Adding the filter to the Search Filter
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+
+            try
+            {
+                searchRequestDecorator.addCurrentFilter( extensibleMatchFilter );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, de );
+            }
+
+            searchRequestDecorator.setTerminalFilter( extensibleMatchFilter );
+
+            // Checking and adding the filter's attributes
+            String attributeValue;
+            // dnAttributes
+            attributeValue = xpp.getAttributeValue( "", "dnAttributes" );
+
+            if ( attributeValue != null )
+            {
+                if ( ( attributeValue.equals( TRUE ) ) || ( attributeValue.equals( "1" ) ) )
+                {
+                    extensibleMatchFilter.setDnAttributes( true );
+                }
+                else if ( ( attributeValue.equals( FALSE ) ) || ( attributeValue.equals( "0" ) ) )
+                {
+                    extensibleMatchFilter.setDnAttributes( false );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03033 ), xpp, null );
+                }
+            }
+            else
+            {
+                extensibleMatchFilter.setDnAttributes( false );
+            }
+
+            // matchingRule
+            attributeValue = xpp.getAttributeValue( "", "matchingRule" );
+
+            if ( attributeValue != null )
+            {
+                extensibleMatchFilter.setMatchingRule( attributeValue );
+            }
+
+            // name
+            attributeValue = xpp.getAttributeValue( "", NAME );
+
+            if ( attributeValue != null )
+            {
+                extensibleMatchFilter.setType( attributeValue );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to an Extensible Match Filter
+     */
+    private final GrammarAction extensibleMatchAddValue = new GrammarAction( "Adds Value to Extensible MatchFilter" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchRequestDsml searchRequestDecorator = ( SearchRequestDsml )
+                container.getBatchRequest().getCurrentRequest();
+            ExtensibleMatchFilter filter = ( ExtensibleMatchFilter ) searchRequestDecorator.getTerminalFilter();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+                
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        filter.setMatchValue( new BinaryValue( Base64.decode( nextText.trim().toCharArray() ) ) );
+                    }
+                    else
+                    {
+                        filter.setMatchValue( new StringValue( nextText.trim() ) );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Control
+     */
+    private final GrammarAction controlCreation = new GrammarAction( "Create Control" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            XmlPullParser xpp = container.getParser();
+            CodecControl<? extends Control> control;
+
+            // Checking and adding the Control's attributes
+            String attributeValue;
+            // TYPE
+            attributeValue = xpp.getAttributeValue( "", "type" );
+
+            if ( attributeValue != null )
+            {
+                if ( !Oid.isOid( attributeValue ) )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03034 ), xpp, null );
+                }
+
+                control = codec.newControl( codec.newControl( attributeValue ) );
+                ( ( Request ) container.getBatchRequest().getCurrentRequest() ).addControl( control );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03035 ), xpp, null );
+            }
+
+            // CRITICALITY
+            attributeValue = xpp.getAttributeValue( "", "criticality" );
+
+            if ( attributeValue != null )
+            {
+                if ( attributeValue.equals( TRUE ) )
+                {
+                    control.setCritical( true );
+                }
+                else if ( attributeValue.equals( FALSE ) )
+                {
+                    control.setCritical( false );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03007 ), xpp, null );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to a Control
+     */
+    private final GrammarAction controlValueCreation = new GrammarAction( "Add ControlValue to Control" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AbstractRequestDsml<? extends Request> request =
+                ( AbstractRequestDsml<? extends Request> ) container.getBatchRequest().getCurrentRequest();
+            DsmlControl<? extends Control> control = request.getCurrentControl();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        control.setValue( Base64.decode( nextText.trim().toCharArray() ) );
+                    }
+                    else
+                    {
+                        control.setValue( Strings.getBytesUtf8( nextText.trim() ) );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ExtendedRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ExtendedRequestDsml.java
new file mode 100644
index 0000000..ab155ee
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ExtendedRequestDsml.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+
+
+/**
+ * DSML Decorator for ExtendedRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtendedRequestDsml<Q extends ExtendedRequest, P extends ExtendedResponse>
+    extends AbstractResultResponseRequestDsml<Q, P>
+    implements ExtendedRequest
+{
+    private byte[] requestValue;
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ExtendedRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public ExtendedRequestDsml( LdapApiService codec, Q ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        // Request Name
+        if ( getDecorated().getRequestName() != null )
+        {
+            element.addElement( "requestName" ).setText(
+                getDecorated().getRequestName() );
+        }
+
+        // Request Value        
+        Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
+        Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
+        element.getDocument().getRootElement().add( xsdNamespace );
+        element.getDocument().getRootElement().add( xsiNamespace );
+
+        Element valueElement = element.addElement( "requestValue" ).addText(
+            ParserUtils.base64Encode( getRequestValue() ) );
+        valueElement.addAttribute( new QName( "type", xsiNamespace ),
+            "xsd:" + ParserUtils.BASE64BINARY );
+
+        return element;
+    }
+
+
+    /**
+     * Get the extended request name
+     * 
+     * @return Returns the request name.
+     */
+    public String getRequestName()
+    {
+        return getDecorated().getRequestName();
+    }
+
+
+    /**
+     * Set the extended request name
+     * 
+     * @param requestName The request name to set.
+     */
+    public void setRequestName( Oid requestName )
+    {
+        getDecorated().setRequestName( requestName.toString() );
+    }
+
+
+    /**
+     * Get the extended request value
+     * 
+     * @return Returns the request value.
+     */
+    public byte[] getRequestValue()
+    {
+        return this.requestValue;
+    }
+
+
+    /**
+     * Set the extended request value
+     * 
+     * @param requestValue The request value to set.
+     */
+    public void setRequestValue( byte[] requestValue )
+    {
+        this.requestValue = requestValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest setRequestName( String oid )
+    {
+        getDecorated().setRequestName( oid );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addControl( Control control )
+    {
+        return ( ExtendedRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addAllControls( Control[] controls )
+    {
+        return ( ExtendedRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest removeControl( Control control )
+    {
+        return ( ExtendedRequest ) super.removeControl( control );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ExtensibleMatchFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ExtensibleMatchFilter.java
new file mode 100644
index 0000000..b13b842
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ExtensibleMatchFilter.java
@@ -0,0 +1,168 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+/**
+ * The search request filter Matching Rule assertion
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtensibleMatchFilter extends Filter
+{
+    /** Matching rule */
+    private String matchingRule;
+
+    /** Matching rule type */
+    private String type;
+
+    /** Matching rule value */
+    private org.apache.directory.api.ldap.model.entry.Value<?> matchValue;
+
+    /** The dnAttributes flag */
+    private boolean dnAttributes = false;
+
+
+    /**
+     * Get the dnAttributes flag
+     * 
+     * @return Returns the dnAttributes.
+     */
+    public boolean isDnAttributes()
+    {
+        return dnAttributes;
+    }
+
+
+    /**
+     * Set the dnAttributes flag
+     * 
+     * @param dnAttributes The dnAttributes to set.
+     */
+    public void setDnAttributes( boolean dnAttributes )
+    {
+        this.dnAttributes = dnAttributes;
+    }
+
+
+    /**
+     * Get the matchingRule
+     * 
+     * @return Returns the matchingRule.
+     */
+    public String getMatchingRule()
+    {
+        return matchingRule;
+    }
+
+
+    /**
+     * Set the matchingRule
+     * 
+     * @param matchingRule The matchingRule to set.
+     */
+    public void setMatchingRule( String matchingRule )
+    {
+        this.matchingRule = matchingRule;
+    }
+
+
+    /**
+     * Get the matchValue
+     * 
+     * @return Returns the matchValue.
+     */
+    public org.apache.directory.api.ldap.model.entry.Value<?> getMatchValue()
+    {
+        return matchValue;
+    }
+
+
+    /**
+     * Set the matchValue
+     * 
+     * @param matchValue The matchValue to set.
+     */
+    public void setMatchValue( org.apache.directory.api.ldap.model.entry.Value<?> matchValue )
+    {
+        this.matchValue = matchValue;
+    }
+
+
+    /**
+     * Get the type
+     * 
+     * @return Returns the type.
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * Set the type
+     * 
+     * @param type The type to set.
+     */
+    public void setType( String type )
+    {
+        this.type = type;
+    }
+
+
+    /**
+     * Return a String representing an extended filter as of RFC 2254
+     * 
+     * @return An Extened Filter String
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        if ( type != null )
+        {
+            sb.append( type );
+        }
+
+        if ( dnAttributes )
+        {
+            sb.append( ":dn" );
+        }
+
+        if ( matchingRule == null )
+        {
+
+            if ( type == null )
+            {
+                return "Extended Filter wrong syntax";
+            }
+        }
+        else
+        {
+            sb.append( ':' ).append( matchingRule );
+        }
+
+        sb.append( ":=" ).append( matchValue );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Filter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Filter.java
new file mode 100644
index 0000000..813e4e8
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/Filter.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+/**
+ * An abstract Asn1Object used to store the filter. A filter is seen as a tree
+ * with a root. This class does nothing, it's just the root of all the different
+ * filters.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Filter
+{
+    /** The parent Filter */
+    protected Filter parent;
+
+
+    /**
+     * Get the parent
+     * 
+     * @return Returns the parent.
+     */
+    public Filter getParent()
+    {
+        return parent;
+    }
+
+
+    /**
+     * Set the parent
+     * 
+     * @param parent The parent to set.
+     */
+    public void setParent( Filter parent )
+    {
+        this.parent = parent;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyDNRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyDNRequestDsml.java
new file mode 100644
index 0000000..0fe8c7a
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyDNRequestDsml.java
@@ -0,0 +1,302 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.dom4j.Element;
+
+
+/**
+ * DSML Decorator for ModifyDNRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyDNRequestDsml
+    extends AbstractResultResponseRequestDsml<ModifyDnRequest, ModifyDnResponse>
+    implements ModifyDnRequest
+{
+    /**
+     * Creates a new getDecoratedMessage() of ModifyDNRequestDsml.
+     */
+    public ModifyDNRequestDsml( LdapApiService codec )
+    {
+        super( codec, new ModifyDnRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ModifyDNRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public ModifyDNRequestDsml( LdapApiService codec, ModifyDnRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        ModifyDnRequest request = getDecorated();
+
+        // Dn
+        if ( request.getName() != null )
+        {
+            element.addAttribute( "dn", request.getName().getName() );
+        }
+
+        // NewRDN
+        if ( request.getNewRdn() != null )
+        {
+            element.addAttribute( "newrdn", request.getNewRdn().getName() );
+        }
+
+        // DeleteOldRDN
+        element.addAttribute( "deleteoldrdn", ( request.getDeleteOldRdn() ? "true" : "false" ) );
+
+        // NewSuperior
+        if ( request.getNewRdn() != null )
+        {
+            element.addAttribute( "newSuperior", request.getNewSuperior().getName() );
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Get the modification's Dn
+     * 
+     * @return Returns the name.
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * Set the modification Dn.
+     * 
+     * @param name The name to set.
+     */
+    public void setEntry( Dn name )
+    {
+        getDecorated().setName( name );
+    }
+
+
+    /**
+     * Tells if the old Rdn is to be deleted
+     * 
+     * @return Returns the deleteOldRDN.
+     */
+    public boolean isDeleteOldRDN()
+    {
+        return getDecorated().getDeleteOldRdn();
+    }
+
+
+    /**
+     * Set the flag to delete the old Rdn
+     * 
+     * @param deleteOldRDN The deleteOldRDN to set.
+     */
+    public void setDeleteOldRDN( boolean deleteOldRDN )
+    {
+        getDecorated().setDeleteOldRdn( deleteOldRDN );
+    }
+
+
+    /**
+     * Get the new Rdn
+     * 
+     * @return Returns the newRDN.
+     */
+    public Rdn getNewRDN()
+    {
+        return getDecorated().getNewRdn();
+    }
+
+
+    /**
+     * Set the new Rdn
+     * 
+     * @param newRdn The newRdn to set.
+     */
+    public void setNewRDN( Rdn newRdn )
+    {
+        getDecorated().setNewRdn( newRdn );
+    }
+
+
+    /**
+     * Get the newSuperior
+     * 
+     * @return Returns the newSuperior.
+     */
+    public Dn getNewSuperior()
+    {
+        return getDecorated().getNewSuperior();
+    }
+
+
+    /**
+     * Set the new superior
+     * 
+     * @param newSuperior The newSuperior to set.
+     */
+    public ModifyDnRequest setNewSuperior( Dn newSuperior )
+    {
+        getDecorated().setNewSuperior( newSuperior );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setName( Dn name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Rdn getNewRdn()
+    {
+        return getDecorated().getNewRdn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setNewRdn( Rdn newRdn )
+    {
+        getDecorated().setNewRdn( newRdn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getDeleteOldRdn()
+    {
+        return getDecorated().getDeleteOldRdn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setDeleteOldRdn( boolean deleteOldRdn )
+    {
+        getDecorated().setDeleteOldRdn( deleteOldRdn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isMove()
+    {
+        return getDecorated().isMove();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest addControl( Control control )
+    {
+        return ( ModifyDnRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest addAllControls( Control[] controls )
+    {
+        return ( ModifyDnRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest removeControl( Control control )
+    {
+        return ( ModifyDnRequest ) super.removeControl( control );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyRequestDsml.java
new file mode 100644
index 0000000..3e3edd7
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/ModifyRequestDsml.java
@@ -0,0 +1,441 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.util.Collection;
+
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+
+
+/**
+ * DSML Decorator for ModifyRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyRequestDsml
+    extends AbstractResultResponseRequestDsml<ModifyRequest, ModifyResponse>
+    implements ModifyRequest
+{
+
+    /** The current attribute being decoded */
+    private Attribute currentAttribute;
+
+    /** A local storage for the operation */
+    private ModificationOperation currentOperation;
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ModifyRequestDsml.
+     */
+    public ModifyRequestDsml( LdapApiService codec )
+    {
+        super( codec, new ModifyRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ModifyRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public ModifyRequestDsml( LdapApiService codec, ModifyRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * Return the current attribute's type
+     */
+    public String getCurrentAttributeType()
+    {
+        return currentAttribute.getId();
+    }
+
+
+    /**
+     * Store the current operation
+     * 
+     * @param currentOperation The currentOperation to set.
+     */
+    public void setCurrentOperation( int currentOperation )
+    {
+        this.currentOperation = ModificationOperation.getOperation( currentOperation );
+    }
+
+
+    /**
+     * Add a new attributeTypeAndValue
+     * 
+     * @param type The attribute's name
+     */
+    public void addAttributeTypeAndValues( String type )
+    {
+        currentAttribute = new DefaultAttribute( type );
+
+        Modification modification = new DefaultModification( currentOperation, currentAttribute );
+        getDecorated().addModification( modification );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( byte[] value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( String value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        ModifyRequest request = getDecorated();
+
+        // Dn
+        if ( request.getName() != null )
+        {
+            element.addAttribute( "dn", request.getName().getName() );
+        }
+
+        // Modifications
+        Collection<Modification> modifications = request.getModifications();
+
+        for ( Modification modification : modifications )
+        {
+            Element modElement = element.addElement( "modification" );
+
+            if ( modification.getAttribute() != null )
+            {
+                modElement.addAttribute( "name", modification.getAttribute().getId() );
+
+                for ( Value<?> value : modification.getAttribute() )
+                {
+                    if ( value.getValue() != null )
+                    {
+                        if ( ParserUtils.needsBase64Encoding( value.getValue() ) )
+                        {
+                            Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
+                            Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
+                            element.getDocument().getRootElement().add( xsdNamespace );
+                            element.getDocument().getRootElement().add( xsiNamespace );
+
+                            Element valueElement = modElement.addElement( "value" ).addText(
+                                ParserUtils.base64Encode( value.getValue() ) );
+                            valueElement.addAttribute( new QName( "type", xsiNamespace ), "xsd:"
+                                + ParserUtils.BASE64BINARY );
+                        }
+                        else
+                        {
+                            modElement.addElement( "value" ).setText( value.getString() );
+                        }
+                    }
+                }
+            }
+
+            ModificationOperation operation = modification.getOperation();
+
+            if ( operation == ModificationOperation.ADD_ATTRIBUTE )
+            {
+                modElement.addAttribute( "operation", "add" );
+            }
+            else if ( operation == ModificationOperation.REPLACE_ATTRIBUTE )
+            {
+                modElement.addAttribute( "operation", "replace" );
+            }
+            else if ( operation == ModificationOperation.REMOVE_ATTRIBUTE )
+            {
+                modElement.addAttribute( "operation", "delete" );
+            }
+        }
+
+        return element;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The ModifyRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest setName( Dn name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<Modification> getModifications()
+    {
+        return getDecorated().getModifications();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addModification( Modification mod )
+    {
+        getDecorated().addModification( mod );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest removeModification( Modification mod )
+    {
+        getDecorated().removeModification( mod );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName, String... attributeValue )
+    {
+        getDecorated().remove( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName, byte[]... attributeValue )
+    {
+        getDecorated().remove( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( Attribute attr )
+    {
+        getDecorated().remove( attr );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName )
+    {
+        getDecorated().remove( attributeName );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addModification( Attribute attr, ModificationOperation modOp )
+    {
+        getDecorated().addModification( attr, modOp );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest add( String attributeName, String... attributeValue )
+    {
+        getDecorated().add( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest add( String attributeName, byte[]... attributeValue )
+    {
+        getDecorated().add( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest add( Attribute attr )
+    {
+        getDecorated().add( attr );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( String attributeName )
+    {
+        getDecorated().replace( attributeName );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( String attributeName, String... attributeValue )
+    {
+        getDecorated().replace( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( String attributeName, byte[]... attributeValue )
+    {
+        getDecorated().replace( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( Attribute attr )
+    {
+        getDecorated().replace( attr );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addControl( Control control )
+    {
+        return ( ModifyRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addAllControls( Control[] controls )
+    {
+        return ( ModifyRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest removeControl( Control control )
+    {
+        return ( ModifyRequest ) super.removeControl( control );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/NotFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/NotFilter.java
new file mode 100644
index 0000000..c09ceee
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/NotFilter.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Not Filter Object to store the Not filter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NotFilter extends ConnectorFilter
+{
+    /**
+     * Subclass the addFilterMethod, as this is specific for a NotFilter (we
+     * cannot have more than one elements).
+     * 
+     * @param filter The Filter to add
+     */
+    public void addFilter( Filter filter ) throws DecoderException
+    {
+        if ( filterSet != null )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_04057 ) );
+        }
+
+        super.addFilter( filter );
+    }
+
+
+    /**
+     * Get the NotFilter
+     * 
+     * @return Returns the notFilter.
+     */
+    public Filter getNotFilter()
+    {
+        return filterSet.get( 0 );
+    }
+
+
+    /**
+     * Set the NotFilter
+     * 
+     * @param notFilter The notFilter to set.
+     */
+    public void setNotFilter( Filter notFilter ) throws DecoderException
+    {
+        if ( filterSet != null )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_04057 ) );
+        }
+
+        super.addFilter( notFilter );
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a NOT filter
+     * 
+     * @return The NOT filter string
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( '!' ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/OrFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/OrFilter.java
new file mode 100644
index 0000000..8596b19
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/OrFilter.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.util.List;
+
+
+/**
+ * Or Filter Object to store the Or filter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OrFilter extends ConnectorFilter
+{
+    /**
+     * Get the OrFilter
+     * 
+     * @return Returns the orFilter.
+     */
+    public List<Filter> getOrFilter()
+    {
+        return filterSet;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing an OR filter
+     * 
+     * @return The OR filter string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( '|' ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/PresentFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/PresentFilter.java
new file mode 100644
index 0000000..8522bcc
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/PresentFilter.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+/**
+ * Object to store the filter. A filter is seen as a tree with a root.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PresentFilter extends Filter
+{
+    /** The attribute description. */
+    private String attributeDescription;
+
+
+    /**
+     * Get the attribute
+     * 
+     * @return Returns the attributeDescription.
+     */
+    public String getAttributeDescription()
+    {
+        return attributeDescription;
+    }
+
+
+    /**
+     * Set the attributeDescription
+     * 
+     * @param attributeDescription The attributeDescription to set.
+     */
+    public void setAttributeDescription( String attributeDescription )
+    {
+        this.attributeDescription = attributeDescription;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a Present filter
+     * 
+     * @return The Present filter string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( attributeDescription ).append( "=*" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/SearchRequestDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/SearchRequestDsml.java
new file mode 100644
index 0000000..b6d42f3
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/SearchRequestDsml.java
@@ -0,0 +1,871 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.ApproximateNode;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.api.ldap.model.filter.LeafNode;
+import org.apache.directory.api.ldap.model.filter.LessEqNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.apache.directory.api.ldap.model.filter.SimpleNode;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+
+
+/**
+ * DSML Decorator for SearchRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchRequestDsml
+    extends AbstractResultResponseRequestDsml<SearchRequest, SearchResultDone>
+    implements SearchRequest
+{
+    /** Some string constants */
+    private static final String DEREF_ALIASES = "derefAliases";
+    private static final String NAME = "name";
+    private static final String VALUE = "value";
+    
+    /** A temporary storage for a terminal Filter */
+    private Filter terminalFilter;
+
+    /** The current filter. This is used while decoding a PDU */
+    private Filter currentFilter;
+
+    /** The global filter. This is used while decoding a PDU */
+    private Filter topFilter;
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchRequestDsml.
+     */
+    public SearchRequestDsml( LdapApiService codec )
+    {
+        super( codec, new SearchRequestImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchRequestDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public SearchRequestDsml( LdapApiService codec, SearchRequest ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * Gets the search filter associated with this search request.
+     *
+     * @return the expression node for the root of the filter expression tree.
+     */
+    public Filter getCodecFilter()
+    {
+        return topFilter;
+    }
+
+
+    /**
+     * Gets the search filter associated with this search request.
+     *
+     * @return the expression node for the root of the filter expression tree.
+     */
+    public ExprNode getFilterNode()
+    {
+        return transform( topFilter );
+    }
+
+
+    /**
+     * Get the terminal filter
+     *
+     * @return Returns the terminal filter.
+     */
+    public Filter getTerminalFilter()
+    {
+        return terminalFilter;
+    }
+
+
+    /**
+     * Set the terminal filter
+     *
+     * @param terminalFilter the teminalFilter.
+     */
+    public void setTerminalFilter( Filter terminalFilter )
+    {
+        this.terminalFilter = terminalFilter;
+    }
+
+
+    /**
+     * set the currentFilter to its parent
+     */
+    public void endCurrentConnectorFilter()
+    {
+        currentFilter = currentFilter.getParent();
+    }
+
+
+    /**
+     * Add a current filter. We have two cases :
+     * - there is no previous current filter : the filter
+     * is the top level filter
+     * - there is a previous current filter : the filter is added
+     * to the currentFilter set, and the current filter is changed
+     *
+     * In any case, the previous current filter will always be a
+     * ConnectorFilter when this method is called.
+     *
+     * @param localFilter The filter to set.
+     */
+    public void addCurrentFilter( Filter localFilter ) throws DecoderException
+    {
+        if ( currentFilter != null )
+        {
+            // Ok, we have a parent. The new Filter will be added to
+            // this parent, and will become the currentFilter if it's a connector.
+            ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter );
+            localFilter.setParent( currentFilter );
+
+            if ( localFilter instanceof ConnectorFilter )
+            {
+                currentFilter = localFilter;
+            }
+        }
+        else
+        {
+            // No parent. This Filter will become the root.
+            currentFilter = localFilter;
+            currentFilter.setParent( null );
+            topFilter = localFilter;
+        }
+    }
+
+
+    /**
+     * Transform the Filter part of a SearchRequest to an ExprNode
+     *
+     * @param filter The filter to be transformed
+     * @return An ExprNode
+     */
+    @SuppressWarnings(
+        { "unchecked", "rawtypes" })
+    private ExprNode transform( Filter filter )
+    {
+        if ( filter != null )
+        {
+            // Transform OR, AND or NOT leaves
+            if ( filter instanceof ConnectorFilter )
+            {
+                BranchNode branch = null;
+
+                if ( filter instanceof AndFilter )
+                {
+                    branch = new AndNode();
+                }
+                else if ( filter instanceof OrFilter )
+                {
+                    branch = new OrNode();
+                }
+                else if ( filter instanceof NotFilter )
+                {
+                    branch = new NotNode();
+                }
+
+                List<Filter> filtersSet = ( ( ConnectorFilter ) filter ).getFilterSet();
+
+                // Loop on all AND/OR children
+                if ( filtersSet != null )
+                {
+                    for ( Filter node : filtersSet )
+                    {
+                        branch.addNode( transform( node ) );
+                    }
+                }
+
+                return branch;
+            }
+            else
+            {
+                // Transform PRESENT or ATTRIBUTE_VALUE_ASSERTION
+                LeafNode branch = null;
+
+                if ( filter instanceof PresentFilter )
+                {
+                    branch = new PresenceNode( ( ( PresentFilter ) filter ).getAttributeDescription() );
+                }
+                else if ( filter instanceof AttributeValueAssertionFilter )
+                {
+                    AttributeValueAssertionFilter avaFilter = ( AttributeValueAssertionFilter ) filter;
+
+                    AttributeValueAssertion ava = avaFilter.getAssertion();
+
+                    // Transform =, >=, <=, ~= filters
+                    int filterType = avaFilter.getFilterType();
+                    switch ( filterType )
+                    {
+                        case LdapCodecConstants.EQUALITY_MATCH_FILTER:
+                            branch = new EqualityNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
+                            branch = new GreaterEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
+                            branch = new LessEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        case LdapCodecConstants.APPROX_MATCH_FILTER:
+                            branch = new ApproximateNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        default:
+                            throw new IllegalStateException( "Unexpected filter type " + filterType );
+                    }
+
+                }
+                else if ( filter instanceof SubstringFilter )
+                {
+                    // Transform Substring filters
+                    SubstringFilter substrFilter = ( SubstringFilter ) filter;
+                    String initialString = null;
+                    String finalString = null;
+                    List<String> anyString = null;
+
+                    if ( substrFilter.getInitialSubstrings() != null )
+                    {
+                        initialString = substrFilter.getInitialSubstrings();
+                    }
+
+                    if ( substrFilter.getFinalSubstrings() != null )
+                    {
+                        finalString = substrFilter.getFinalSubstrings();
+                    }
+
+                    if ( substrFilter.getAnySubstrings() != null )
+                    {
+                        anyString = new ArrayList<String>();
+
+                        for ( String any : substrFilter.getAnySubstrings() )
+                        {
+                            anyString.add( any );
+                        }
+                    }
+
+                    branch = new SubstringNode( anyString, substrFilter.getType(), initialString, finalString );
+                }
+                else if ( filter instanceof ExtensibleMatchFilter )
+                {
+                    // Transform Extensible Match Filter
+                    ExtensibleMatchFilter extFilter = ( ExtensibleMatchFilter ) filter;
+                    String matchingRule = null;
+
+                    Value<?> value = extFilter.getMatchValue();
+
+                    if ( extFilter.getMatchingRule() != null )
+                    {
+                        matchingRule = extFilter.getMatchingRule();
+                    }
+
+                    branch = new ExtensibleNode( extFilter.getType(), value, matchingRule, extFilter.isDnAttributes() );
+                }
+
+                return branch;
+            }
+        }
+        else
+        {
+            // We have found nothing to transform. Return null then.
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = super.toDsml( root );
+
+        SearchRequest request = getDecorated();
+
+        // Dn
+        if ( request.getBase() != null )
+        {
+            element.addAttribute( "dn", request.getBase().getName() );
+        }
+
+        // Scope
+        SearchScope scope = request.getScope();
+        if ( scope != null )
+        {
+            if ( scope == SearchScope.OBJECT )
+            {
+                element.addAttribute( "scope", "baseObject" );
+            }
+            else if ( scope == SearchScope.ONELEVEL )
+            {
+                element.addAttribute( "scope", "singleLevel" );
+            }
+            else if ( scope == SearchScope.SUBTREE )
+            {
+                element.addAttribute( "scope", "wholeSubtree" );
+            }
+        }
+
+        // DerefAliases
+        AliasDerefMode derefAliases = request.getDerefAliases();
+
+        switch ( derefAliases )
+        {
+            case NEVER_DEREF_ALIASES:
+                element.addAttribute( DEREF_ALIASES, "neverDerefAliases" );
+                break;
+
+            case DEREF_ALWAYS:
+                element.addAttribute( DEREF_ALIASES, "derefAlways" );
+                break;
+
+            case DEREF_FINDING_BASE_OBJ:
+                element.addAttribute( DEREF_ALIASES, "derefFindingBaseObj" );
+                break;
+
+            case DEREF_IN_SEARCHING:
+                element.addAttribute( DEREF_ALIASES, "derefInSearching" );
+                break;
+
+            default:
+                throw new IllegalStateException( "Unexpected deref alias mode " + derefAliases );
+        }
+
+        // SizeLimit
+        if ( request.getSizeLimit() != 0L )
+        {
+            element.addAttribute( "sizeLimit", "" + request.getSizeLimit() );
+        }
+
+        // TimeLimit
+        if ( request.getTimeLimit() != 0 )
+        {
+            element.addAttribute( "timeLimit", "" + request.getTimeLimit() );
+        }
+
+        // TypesOnly
+        if ( request.getTypesOnly() )
+        {
+            element.addAttribute( "typesOnly", "true" );
+        }
+
+        // Filter
+        Element filterElement = element.addElement( "filter" );
+        toDsml( filterElement, request.getFilter() );
+
+        // Attributes
+        List<String> attributes = request.getAttributes();
+
+        if ( attributes.size() > 0 )
+        {
+            Element attributesElement = element.addElement( "attributes" );
+
+            for ( String entryAttribute : attributes )
+            {
+                attributesElement.addElement( "attribute" ).addAttribute( NAME, entryAttribute );
+            }
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Recursively converts the filter of the Search Request into a DSML representation and adds 
+     * it to the XML Element corresponding to the Search Request
+     *
+     * @param element
+     *      the parent Element
+     * @param filter
+     *      the filter to convert
+     */
+    private void toDsml( Element element, ExprNode filter )
+    {
+        // AND FILTER
+        if ( filter instanceof AndNode )
+        {
+            Element newElement = element.addElement( "and" );
+
+            List<ExprNode> filterList = ( ( AndNode ) filter ).getChildren();
+
+            for ( int i = 0; i < filterList.size(); i++ )
+            {
+                toDsml( newElement, filterList.get( i ) );
+            }
+        }
+
+        // OR FILTER
+        else if ( filter instanceof OrNode )
+        {
+            Element newElement = element.addElement( "or" );
+
+            List<ExprNode> filterList = ( ( OrNode ) filter ).getChildren();
+
+            for ( int i = 0; i < filterList.size(); i++ )
+            {
+                toDsml( newElement, filterList.get( i ) );
+            }
+        }
+
+        // NOT FILTER
+        else if ( filter instanceof NotNode )
+        {
+            Element newElement = element.addElement( "not" );
+
+            toDsml( newElement, ( ( NotNode ) filter ).getFirstChild() );
+        }
+
+        // SUBSTRING FILTER
+        else if ( filter instanceof SubstringNode )
+        {
+            Element newElement = element.addElement( "substrings" );
+
+            SubstringNode substringFilter = ( SubstringNode ) filter;
+
+            newElement.addAttribute( NAME, substringFilter.getAttribute() );
+
+            String initial = substringFilter.getInitial();
+
+            if ( ( initial != null ) && ( !"".equals( initial ) ) )
+            {
+                newElement.addElement( "initial" ).setText( initial );
+            }
+
+            List<String> anyList = substringFilter.getAny();
+
+            for ( int i = 0; i < anyList.size(); i++ )
+            {
+                newElement.addElement( "any" ).setText( anyList.get( i ) );
+            }
+
+            String finalString = substringFilter.getFinal();
+
+            if ( ( finalString != null ) && ( !"".equals( finalString ) ) )
+            {
+                newElement.addElement( "final" ).setText( finalString );
+            }
+        }
+
+        // APPROXMATCH, EQUALITYMATCH, GREATEROREQUALS & LESSOREQUAL FILTERS
+        else if ( filter instanceof SimpleNode )
+        {
+            Element newElement = null;
+
+            if ( filter instanceof ApproximateNode )
+            {
+                newElement = element.addElement( "approxMatch" );
+            }
+            else if ( filter instanceof EqualityNode )
+            {
+                newElement = element.addElement( "equalityMatch" );
+            }
+            else if ( filter instanceof GreaterEqNode )
+            {
+                newElement = element.addElement( "greaterOrEqual" );
+            }
+            else
+            // it is a LessEqNode )
+            {
+                newElement = element.addElement( "lessOrEqual" );
+            }
+
+            String attributeName = ( ( SimpleNode<?> ) filter ).getAttribute();
+            newElement.addAttribute( NAME, attributeName );
+
+            Value<?> value = ( ( SimpleNode<?> ) filter ).getValue();
+            if ( value != null )
+            {
+                if ( ParserUtils.needsBase64Encoding( value ) )
+                {
+                    Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
+                    Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
+                    element.getDocument().getRootElement().add( xsdNamespace );
+                    element.getDocument().getRootElement().add( xsiNamespace );
+
+                    Element valueElement = newElement.addElement( VALUE ).addText(
+                        ParserUtils.base64Encode( value ) );
+                    valueElement
+                        .addAttribute( new QName( "type", xsiNamespace ), "xsd:" + ParserUtils.BASE64BINARY );
+                }
+                else
+                {
+                    newElement.addElement( VALUE ).setText( value.getString() );
+                }
+            }
+        }
+
+        // PRESENT FILTER
+        else if ( filter instanceof PresenceNode )
+        {
+            Element newElement = element.addElement( "present" );
+
+            newElement.addAttribute( NAME, ( ( PresenceNode ) filter ).getAttribute() );
+        }
+
+        // EXTENSIBLEMATCH
+        else if ( filter instanceof ExtensibleNode )
+        {
+            Element newElement = element.addElement( "extensibleMatch" );
+
+            Value<?> value = ( ( ExtensibleNode ) filter ).getValue();
+            if ( value != null )
+            {
+                if ( ParserUtils.needsBase64Encoding( value ) )
+                {
+                    Namespace xsdNamespace = new Namespace( "xsd", ParserUtils.XML_SCHEMA_URI );
+                    Namespace xsiNamespace = new Namespace( "xsi", ParserUtils.XML_SCHEMA_INSTANCE_URI );
+                    element.getDocument().getRootElement().add( xsdNamespace );
+                    element.getDocument().getRootElement().add( xsiNamespace );
+
+                    Element valueElement = newElement.addElement( VALUE ).addText(
+                        ParserUtils.base64Encode( value.getValue() ) );
+                    valueElement.addAttribute( new QName( "type", xsiNamespace ), "xsd:" + ParserUtils.BASE64BINARY );
+                }
+                else
+                {
+                    newElement.addElement( VALUE ).setText( value.getString() );
+                }
+            }
+
+            if ( ( ( ExtensibleNode ) filter ).hasDnAttributes() )
+            {
+                newElement.addAttribute( "dnAttributes", "true" );
+            }
+
+            String matchingRule = ( ( ExtensibleNode ) filter ).getMatchingRuleId();
+            if ( ( matchingRule != null ) && ( "".equals( matchingRule ) ) )
+            {
+                newElement.addAttribute( "matchingRule", matchingRule );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum[] getResponseTypes()
+    {
+        return getDecorated().getResponseTypes();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getBase()
+    {
+        return getDecorated().getBase();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setBase( Dn baseDn )
+    {
+        getDecorated().setBase( baseDn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchScope getScope()
+    {
+        return getDecorated().getScope();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setScope( SearchScope scope )
+    {
+        getDecorated().setScope( scope );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AliasDerefMode getDerefAliases()
+    {
+        return getDecorated().getDerefAliases();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
+    {
+        getDecorated().setDerefAliases( aliasDerefAliases );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getSizeLimit()
+    {
+        return getDecorated().getSizeLimit();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setSizeLimit( long entriesMax )
+    {
+        getDecorated().setSizeLimit( entriesMax );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeLimit()
+    {
+        return getDecorated().getTimeLimit();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setTimeLimit( int secondsMax )
+    {
+        getDecorated().setTimeLimit( secondsMax );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getTypesOnly()
+    {
+        return getDecorated().getTypesOnly();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setTypesOnly( boolean typesOnly )
+    {
+        getDecorated().setTypesOnly( typesOnly );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExprNode getFilter()
+    {
+        return getDecorated().getFilter();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setFilter( ExprNode filter )
+    {
+        getDecorated().setFilter( filter );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setFilter( String filter ) throws LdapException
+    {
+        getDecorated().setFilter( filter );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getAttributes()
+    {
+        return getDecorated().getAttributes();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addAttributes( String... attributes )
+    {
+        getDecorated().addAttributes( attributes );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest removeAttribute( String attribute )
+    {
+        getDecorated().removeAttribute( attribute );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setMessageId( int messageId )
+    {
+        return ( SearchRequest ) super.setMessageId( messageId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addControl( Control control )
+    {
+        return ( SearchRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addAllControls( Control[] controls )
+    {
+        return ( SearchRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest removeControl( Control control )
+    {
+        return ( SearchRequest ) super.removeControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isFollowReferrals()
+    {
+        return getDecorated().isFollowReferrals();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest followReferrals()
+    {
+        return getDecorated().followReferrals();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isIgnoreReferrals()
+    {
+        return getDecorated().isIgnoreReferrals();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest ignoreReferrals()
+    {
+        return getDecorated().ignoreReferrals();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/SubstringFilter.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/SubstringFilter.java
new file mode 100644
index 0000000..453b1d4
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/request/SubstringFilter.java
@@ -0,0 +1,178 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.request;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * A Object that stores the substring filter. 
+ * 
+ * A substring filter follow this
+ * grammar : 
+ * 
+ * substring = attr "=" ( ([initial] any [final] | 
+ *                        (initial [any] [final) | 
+ *                        ([initial] [any] final) ) 
+ *                       
+ * initial = value 
+ * any = "*" *(value "*")
+ * final = value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubstringFilter extends Filter
+{
+    /** The substring filter type (an attributeDescription) */
+    private String type;
+
+    /** The initial filter */
+    private String initialSubstrings;
+
+    /** The any filter. It's a list of LdapString */
+    private List<String> anySubstrings = new ArrayList<String>( 1 );
+
+    /** The final filter */
+    private String finalSubstrings;
+
+
+    /**
+     * Get the internal substrings
+     * 
+     * @return Returns the anySubstrings.
+     */
+    public List<String> getAnySubstrings()
+    {
+        return anySubstrings;
+    }
+
+
+    /**
+     * Add a internal substring
+     * 
+     * @param any The anySubstrings to set.
+     */
+    public void addAnySubstrings( String any )
+    {
+        this.anySubstrings.add( any );
+    }
+
+
+    /**
+     * Get the final substring
+     * 
+     * @return Returns the finalSubstrings.
+     */
+    public String getFinalSubstrings()
+    {
+        return finalSubstrings;
+    }
+
+
+    /**
+     * Set the final substring
+     * 
+     * @param finalSubstrings The finalSubstrings to set.
+     */
+    public void setFinalSubstrings( String finalSubstrings )
+    {
+        this.finalSubstrings = finalSubstrings;
+    }
+
+
+    /**
+     * Get the initial substring
+     * 
+     * @return Returns the initialSubstrings.
+     */
+    public String getInitialSubstrings()
+    {
+        return initialSubstrings;
+    }
+
+
+    /**
+     * Set the initial substring
+     * 
+     * @param initialSubstrings The initialSubstrings to set.
+     */
+    public void setInitialSubstrings( String initialSubstrings )
+    {
+        this.initialSubstrings = initialSubstrings;
+    }
+
+
+    /**
+     * Get the attribute
+     * 
+     * @return Returns the type.
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * Set the attribute to match
+     * 
+     * @param type The type to set.
+     */
+    public void setType( String type )
+    {
+        this.type = type;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a Substring filter
+     * 
+     * @return The substring filter string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        if ( initialSubstrings != null )
+        {
+            sb.append( initialSubstrings );
+        }
+
+        sb.append( '*' );
+
+        if ( anySubstrings != null )
+        {
+            for ( String any : anySubstrings )
+            {
+                sb.append( any ).append( '*' );
+            }
+        }
+
+        if ( finalSubstrings != null )
+        {
+            sb.append( finalSubstrings );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AbstractResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AbstractResponseDsml.java
new file mode 100644
index 0000000..fb91ba7
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AbstractResponseDsml.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.dsmlv2.AbstractDsmlMessageDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Response;
+
+
+/**
+ * Base class for all DSML responses.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractResponseDsml<E extends Response>
+    extends AbstractDsmlMessageDecorator<E> implements Response
+{
+    /**
+     * Instantiates a new abstract DSML response.
+     *
+     * @param response the LDAP response message to decorate
+     */
+    public AbstractResponseDsml( LdapApiService codec, E response )
+    {
+        super( codec, response );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AbstractResultResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AbstractResultResponseDsml.java
new file mode 100644
index 0000000..f687614
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AbstractResultResponseDsml.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.dom4j.Element;
+
+
+/**
+ * Base class for all DSML responses.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractResultResponseDsml<E extends ResultResponse>
+    extends AbstractResponseDsml<E> implements ResultResponse
+{
+    /**
+     * Instantiates a new abstract DSML response.
+     *
+     * @param ldapMessage the LDAP message to decorate
+     */
+    public AbstractResultResponseDsml( LdapApiService codec, E resultResponse )
+    {
+        super( codec, resultResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public abstract Element toDsml( Element root );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapResult getLdapResult()
+    {
+        return getDecorated().getLdapResult();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AddResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AddResponseDsml.java
new file mode 100644
index 0000000..0b7cf60
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/AddResponseDsml.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.AddResponseImpl;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for AddResponse
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddResponseDsml extends AbstractResultResponseDsml<AddResponse>
+    implements AddResponse
+{
+    private static final String ADD_RESPONSE_TAG = "addResponse";
+
+
+    /**
+     * Creates a new getDecoratedMessage() of AddResponseDsml.
+     */
+    public AddResponseDsml( LdapApiService codec )
+    {
+        super( codec, new AddResponseImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of AddResponseDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public AddResponseDsml( LdapApiService codec, AddResponse ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( ADD_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( ADD_RESPONSE_TAG );
+        }
+
+        LdapResultDsml ldapResultDsml = new LdapResultDsml( getCodecService(),
+            getDecorated().getLdapResult(), getDecorated() );
+        ldapResultDsml.toDsml( element );
+        return element;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/BatchResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/BatchResponseDsml.java
new file mode 100644
index 0000000..26f4da2
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/BatchResponseDsml.java
@@ -0,0 +1,179 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+
+/**
+ * This class represents the Batch Response. It can be used to generate an the XML String of a BatchResponse.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BatchResponseDsml
+{
+    /** The Responses list */
+    private List<DsmlDecorator<? extends Response>> responses;
+
+    /** The ID of the response */
+    private int requestID;
+
+
+    /**
+     * Creates a new instance of BatchResponseDsml.
+     */
+    public BatchResponseDsml()
+    {
+        responses = new ArrayList<DsmlDecorator<? extends Response>>();
+    }
+
+
+    /**
+     * Gets the current response
+     *
+     * @return
+     *      the current response
+     */
+    public DsmlDecorator<? extends Response> getCurrentResponse()
+    {
+        return responses.get( responses.size() - 1 );
+    }
+
+
+    /**
+     * Adds a request to the Batch Response DSML.
+     *
+     * @param response
+     *      the request to add
+     * @return
+     *      true (as per the general contract of the Collection.add method).
+     */
+    public boolean addResponse( DsmlDecorator<? extends Response> response )
+    {
+        return responses.add( response );
+    }
+
+
+    /**
+     * Removes a request from the Batch Response DSML.
+     *
+     * @param response
+     *      the request to remove
+     * @return
+     *      true if this list contained the specified element.
+     */
+    public boolean removeResponse( DsmlDecorator<Response> response )
+    {
+        return responses.remove( response );
+    }
+
+
+    /**
+     * Gets the ID of the response
+     * @return
+     *      the ID of the response
+     */
+    public int getRequestID()
+    {
+        return requestID;
+    }
+
+
+    /**
+     * Sets the ID of the response
+     *
+     * @param requestID
+     *      the ID to set
+     */
+    public void setRequestID( int requestID )
+    {
+        this.requestID = requestID;
+    }
+
+
+    /**
+     * Gets the List of all the responses
+     *
+     * @return
+     *      the List of all the responses
+     */
+    public List<DsmlDecorator<? extends Response>> getResponses()
+    {
+        return responses;
+    }
+
+
+    /**
+     * Converts this Batch Response to its XML representation in the DSMLv2 format.
+     * The XML document will be formatted for pretty printing by default. 
+     * 
+     * @see {@link #toDsml(boolean)}
+     * 
+     * @return the XML representation in DSMLv2 format
+     */
+    public String toDsml()
+    {
+       return toDsml( true ); 
+    }
+    
+    
+    /**
+     * Converts this Batch Response to its XML representation in the DSMLv2 format.
+     * 
+     * @param prettyPrint if true, formats the document for pretty printing
+     * @return the XML representation in DSMLv2 format
+     */
+    public String toDsml( boolean prettyPrint )
+    {
+        Document document = DocumentHelper.createDocument();
+        Element element = document.addElement( "batchResponse" );
+
+        element.add( ParserUtils.DSML_NAMESPACE );
+        element.add( ParserUtils.XSD_NAMESPACE );
+        element.add( ParserUtils.XSI_NAMESPACE );
+
+        // RequestID
+        if ( requestID != 0 )
+        {
+            element.addAttribute( "requestID", "" + requestID );
+        }
+
+        for ( DsmlDecorator<? extends Response> response : responses )
+        {
+            response.toDsml( element );
+        }
+
+        if ( prettyPrint )
+        {
+            document = ParserUtils.styleDocument( document );
+        }
+        
+        return document.asXML();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/BindResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/BindResponseDsml.java
new file mode 100644
index 0000000..f73a957
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/BindResponseDsml.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+import org.dom4j.Element;
+
+
+/**
+ * DSML Decorator for AuthResponse
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BindResponseDsml extends AbstractResultResponseDsml<BindResponse> implements BindResponse
+{
+    /**
+     * Creates a new getDecoratedMessage() of AuthResponseDsml.
+     */
+    public BindResponseDsml( LdapApiService codec )
+    {
+        super( codec, new BindResponseImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of AuthResponseDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public BindResponseDsml( LdapApiService codec, BindResponse ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = root.addElement( "authResponse" );
+
+        LdapResultDsml ldapResultDsml = new LdapResultDsml( getCodecService(),
+            getDecorated().getLdapResult(), getDecorated() );
+        ldapResultDsml.toDsml( element );
+        return element;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getServerSaslCreds()
+    {
+        return getDecorated().getServerSaslCreds();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setServerSaslCreds( byte[] serverSaslCreds )
+    {
+        getDecorated().setServerSaslCreds( serverSaslCreds );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/CompareResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/CompareResponseDsml.java
new file mode 100644
index 0000000..3063ae4
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/CompareResponseDsml.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for CompareResponse
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CompareResponseDsml extends AbstractResultResponseDsml<CompareResponse> implements CompareResponse
+{
+    private static final String COMPARE_RESPONSE_TAG = "compareResponse";
+
+
+    /**
+     * Creates a new getDecoratedMessage() of CompareResponseDsml.
+     */
+    public CompareResponseDsml( LdapApiService codec )
+    {
+        super( codec, new CompareResponseImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of CompareResponseDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public CompareResponseDsml( LdapApiService codec, CompareResponse ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( COMPARE_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( COMPARE_RESPONSE_TAG );
+        }
+
+        LdapResultDsml ldapResultDsml = new LdapResultDsml( getCodecService(),
+            getDecorated().getLdapResult(), getDecorated() );
+        ldapResultDsml.toDsml( element );
+        return element;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isTrue()
+    {
+        return getDecorated().isTrue();
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/DelResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/DelResponseDsml.java
new file mode 100644
index 0000000..33cf0c1
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/DelResponseDsml.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.DeleteResponseImpl;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for DelResponse
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DelResponseDsml extends AbstractResultResponseDsml<DeleteResponse>
+    implements DeleteResponse
+{
+    private static final String DEL_RESPONSE_TAG = "delResponse";
+
+
+    /**
+     * Creates a new getDecoratedMessage() of DelResponseDsml.
+     */
+    public DelResponseDsml( LdapApiService codec )
+    {
+        super( codec, new DeleteResponseImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of DelResponseDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public DelResponseDsml( LdapApiService codec, DeleteResponse ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( DEL_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( DEL_RESPONSE_TAG );
+        }
+
+        LdapResultDsml ldapResultDsml = new LdapResultDsml( getCodecService(),
+            getDecorated().getLdapResult(), getDecorated() );
+        ldapResultDsml.toDsml( element );
+        return element;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/Dsmlv2ResponseGrammar.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/Dsmlv2ResponseGrammar.java
new file mode 100644
index 0000000..0d9df4b
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/Dsmlv2ResponseGrammar.java
@@ -0,0 +1,2030 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.dsmlv2.AbstractDsmlMessageDecorator;
+import org.apache.directory.api.dsmlv2.AbstractGrammar;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.dsmlv2.Dsmlv2Container;
+import org.apache.directory.api.dsmlv2.Dsmlv2StatesEnum;
+import org.apache.directory.api.dsmlv2.Grammar;
+import org.apache.directory.api.dsmlv2.GrammarAction;
+import org.apache.directory.api.dsmlv2.GrammarTransition;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.dsmlv2.Tag;
+import org.apache.directory.api.dsmlv2.response.ErrorResponse.ErrorResponseType;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.AddResponseImpl;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.message.SearchResultDoneImpl;
+import org.apache.directory.api.ldap.model.message.SearchResultEntryImpl;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.ldap.model.message.SearchResultReferenceImpl;
+import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Strings;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * This Class represents the DSMLv2 Response Grammar
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Dsmlv2ResponseGrammar extends AbstractGrammar implements Grammar
+{
+    /** The instance of grammar. Dsmlv2ResponseGrammar is a singleton */
+    private static Dsmlv2ResponseGrammar instance = new Dsmlv2ResponseGrammar();
+
+    /** The DSMLv2 description tags */
+    private static final Set<String> DSMLV2_DESCR_TAGS;
+    static
+    {
+        DSMLV2_DESCR_TAGS = new HashSet<String>();
+        DSMLV2_DESCR_TAGS.add( "success" );
+        DSMLV2_DESCR_TAGS.add( "operationsError" );
+        DSMLV2_DESCR_TAGS.add( "protocolError" );
+        DSMLV2_DESCR_TAGS.add( "timeLimitExceeded" );
+        DSMLV2_DESCR_TAGS.add( "sizeLimitExceeded" );
+        DSMLV2_DESCR_TAGS.add( "compareFalse" );
+        DSMLV2_DESCR_TAGS.add( "compareTrue" );
+        DSMLV2_DESCR_TAGS.add( "authMethodNotSupported" );
+        DSMLV2_DESCR_TAGS.add( "strongAuthRequired" );
+        DSMLV2_DESCR_TAGS.add( "referral" );
+        DSMLV2_DESCR_TAGS.add( "adminLimitExceeded" );
+        DSMLV2_DESCR_TAGS.add( "unavailableCriticalExtension" );
+        DSMLV2_DESCR_TAGS.add( "confidentialityRequired" );
+        DSMLV2_DESCR_TAGS.add( "saslBindInProgress" );
+        DSMLV2_DESCR_TAGS.add( "noSuchAttribute" );
+        DSMLV2_DESCR_TAGS.add( "undefinedAttributeType" );
+        DSMLV2_DESCR_TAGS.add( "inappropriateMatching" );
+        DSMLV2_DESCR_TAGS.add( "constraintViolation" );
+        DSMLV2_DESCR_TAGS.add( "attributeOrValueExists" );
+        DSMLV2_DESCR_TAGS.add( "invalidAttributeSyntax" );
+        DSMLV2_DESCR_TAGS.add( "noSuchObject" );
+        DSMLV2_DESCR_TAGS.add( "aliasProblem" );
+        DSMLV2_DESCR_TAGS.add( "invalidDNSyntax" );
+        DSMLV2_DESCR_TAGS.add( "aliasDereferencingProblem" );
+        DSMLV2_DESCR_TAGS.add( "inappropriateAuthentication" );
+        DSMLV2_DESCR_TAGS.add( "invalidCredentials" );
+        DSMLV2_DESCR_TAGS.add( "insufficientAccessRights" );
+        DSMLV2_DESCR_TAGS.add( "busy" );
+        DSMLV2_DESCR_TAGS.add( "unavailable" );
+        DSMLV2_DESCR_TAGS.add( "unwillingToPerform" );
+        DSMLV2_DESCR_TAGS.add( "loopDetect" );
+        DSMLV2_DESCR_TAGS.add( "namingViolation" );
+        DSMLV2_DESCR_TAGS.add( "objectClassViolation" );
+        DSMLV2_DESCR_TAGS.add( "notAllowedOnNonLeaf" );
+        DSMLV2_DESCR_TAGS.add( "notAllowedOnRDN" );
+        DSMLV2_DESCR_TAGS.add( "entryAlreadyExists" );
+        DSMLV2_DESCR_TAGS.add( "objectClassModsProhibited" );
+        DSMLV2_DESCR_TAGS.add( "affectMultipleDSAs" );
+        DSMLV2_DESCR_TAGS.add( "other" );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    private Dsmlv2ResponseGrammar()
+    {
+        name = Dsmlv2ResponseGrammar.class.getName();
+
+        // Create the transitions table
+        super.transitions = ( HashMap<Tag, GrammarTransition>[] ) Array.newInstance( HashMap.class, 300 );
+
+        //====================================================
+        //  Transitions concerning : BATCH RESPONSE
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.INIT_GRAMMAR_STATE.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // ** OPEN BATCH Reponse **
+        // State: [INIT_GRAMMAR_STATE] - Tag: <batchResponse>
+        super.transitions[Dsmlv2StatesEnum.INIT_GRAMMAR_STATE.ordinal()].put( new Tag( "batchResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                batchResponseCreation ) );
+
+        //====================================================
+        //  Transitions concerning : BATCH RESPONSE LOOP
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <addResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "addResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                addResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <authResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "authResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                authResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <compareResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "compareResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                compareResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <delResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "delResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                delResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <modifyResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "modifyResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                modifyResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <modDNResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "modDNResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                modDNResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <extendedResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put(
+            new Tag( "extendedResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.EXTENDED_RESPONSE,
+                extendedResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <errorResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "errorResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.ERROR_RESPONSE,
+                errorResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: <searchReponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "searchResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.SEARCH_RESPONSE,
+                searchResponseCreation ) );
+
+        // State: [BATCH_RESPONSE_LOOP] - Tag: </batchResponse>
+        super.transitions[Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP.ordinal()].put( new Tag( "batchResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, Dsmlv2StatesEnum.GRAMMAR_END, null ) );
+
+        //====================================================
+        //  Transitions concerning : ERROR RESPONSE
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.ERROR_RESPONSE.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.MESSAGE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.DETAIL_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.DETAIL_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [ERROR_RESPONSE] - Tag: <message>
+        super.transitions[Dsmlv2StatesEnum.ERROR_RESPONSE.ordinal()].put( new Tag( "message", Tag.START ),
+            new GrammarTransition(
+                Dsmlv2StatesEnum.ERROR_RESPONSE, Dsmlv2StatesEnum.MESSAGE_END, errorResponseAddMessage ) );
+
+        // State: [ERROR_RESPONSE] - Tag: <detail>
+        super.transitions[Dsmlv2StatesEnum.ERROR_RESPONSE.ordinal()].put( new Tag( "detail", Tag.START ),
+            new GrammarTransition(
+                Dsmlv2StatesEnum.ERROR_RESPONSE, Dsmlv2StatesEnum.DETAIL_START, ERROR_RESPONSE_ADD_DETAIL ) );
+
+        // State: [MESSAGE_END] - Tag: </errorResponse>
+        super.transitions[Dsmlv2StatesEnum.MESSAGE_END.ordinal()].put( new Tag( "errorResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.MESSAGE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [MESSAGE_END] - Tag: <detail>
+        super.transitions[Dsmlv2StatesEnum.MESSAGE_END.ordinal()].put( new Tag( "detail", Tag.START ),
+            new GrammarTransition(
+                Dsmlv2StatesEnum.MESSAGE_END, Dsmlv2StatesEnum.DETAIL_START, ERROR_RESPONSE_ADD_DETAIL ) );
+
+        // State: [DETAIL_START] - Tag: </detail>
+        super.transitions[Dsmlv2StatesEnum.DETAIL_START.ordinal()].put( new Tag( "detail", Tag.END ),
+            new GrammarTransition(
+                Dsmlv2StatesEnum.DETAIL_START, Dsmlv2StatesEnum.DETAIL_END, null ) );
+
+        // State: [DETAIL_END] - Tag: <detail>
+        super.transitions[Dsmlv2StatesEnum.DETAIL_END.ordinal()].put( new Tag( "detail", Tag.END ),
+            new GrammarTransition(
+                Dsmlv2StatesEnum.DETAIL_END, Dsmlv2StatesEnum.DETAIL_END, ERROR_RESPONSE_ADD_DETAIL ) );
+
+        // State: [ERROR_RESPONSE] - Tag: </errorResponse>
+        super.transitions[Dsmlv2StatesEnum.ERROR_RESPONSE.ordinal()].put( new Tag( "errorResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.ERROR_RESPONSE, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : EXTENDED RESPONSE
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_VALUE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.RESPONSE_NAME_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.RESPONSE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [EXTENDED_RESPONSE] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE.ordinal()].put( new Tag( "control", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_START, ldapResultControlCreation ) );
+
+        // State: [EXTENDED_RESPONSE_CONTROL_START] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_START.ordinal()].put( new Tag( "controlValue",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_START,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_VALUE_END, ldapResultControlValueCreation ) );
+
+        // State: [EXTENDED_RESPONSE_CONTROL_VALUE_END] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_VALUE_END.ordinal()].put( new Tag( "control",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_VALUE_END,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_END, null ) );
+
+        // State: [EXTENDED_RESPONSE_CONTROL_START] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_START.ordinal()].put(
+            new Tag( "control", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_START,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_END, null ) );
+
+        // State: [EXTENDED_RESPONSE_CONTROL_END] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_END.ordinal()].put(
+            new Tag( "control", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_END,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_START, ldapResultControlCreation ) );
+
+        // State: [EXTENDED_RESPONSE_CONTROL_END] - Tag: <resultCode>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_END.ordinal()].put( new Tag( "resultCode",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_CONTROL_END,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_START, extendedResponseAddResultCode ) );
+
+        // State: [EXTENDED_RESPONSE] - Tag: <resultCode>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE.ordinal()].put( new Tag( "resultCode", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_START, extendedResponseAddResultCode ) );
+
+        // State: [EXTENDED_RESPONSE_RESULT_CODE_START] - Tag: </resultCode>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_START.ordinal()].put( new Tag( "resultCode",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_START,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END, null ) );
+
+        // State: [EXTENDED_RESPONSE_RESULT_CODE_END] - Tag: <errorMessage>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END.ordinal()].put(
+            new Tag( "errorMessage", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END, extendedResponseAddErrorMessage ) );
+
+        // State: [EXTENDED_RESPONSE_RESULT_CODE_END] - Tag: <referral>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END.ordinal()].put( new Tag( "referral",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END, extendedResponseAddReferral ) );
+
+        // State: [EXTENDED_RESPONSE_RESULT_CODE_END] - Tag: <responseName>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END.ordinal()].put(
+            new Tag( "responseName", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END, Dsmlv2StatesEnum.RESPONSE_NAME_END,
+                extendedResponseAddResponseName ) );
+
+        // State: [EXTENDED_RESPONSE_RESULT_CODE_END] - Tag: <response>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END.ordinal()].put( new Tag( "response",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END, Dsmlv2StatesEnum.RESPONSE_END,
+                extendedResponseAddResponse ) );
+
+        // State: [EXTENDED_RESPONSE_RESULT_CODE_END] - Tag: </extendedResponse>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END.ordinal()].put(
+            new Tag( "extendedResponse", Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_RESULT_CODE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [EXTENDED_RESPONSE_ERROR_MESSAGE_END] - Tag: <referral>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END.ordinal()].put( new Tag( "referral",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END, extendedResponseAddReferral ) );
+
+        // State: [EXTENDED_RESPONSE_ERROR_MESSAGE_END] - Tag: <responseName>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END.ordinal()].put(
+            new Tag( "responseName", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END, Dsmlv2StatesEnum.RESPONSE_NAME_END,
+                extendedResponseAddResponseName ) );
+
+        // State: [EXTENDED_RESPONSE_ERROR_MESSAGE_END] - Tag: <response>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END.ordinal()].put( new Tag( "response",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END, Dsmlv2StatesEnum.RESPONSE_END,
+                extendedResponseAddResponse ) );
+
+        // State: [EXTENDED_RESPONSE_ERROR_MESSAGE_END] - Tag: </extendedResponse>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END.ordinal()].put( new Tag(
+            "extendedResponse",
+            Tag.END ), new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_ERROR_MESSAGE_END,
+            Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [EXTENDED_RESPONSE_REFERRAL_END] - Tag: <referral>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END.ordinal()].put( new Tag( "referral",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END,
+                Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END, extendedResponseAddReferral ) );
+
+        // State: [EXTENDED_RESPONSE_REFERRAL_END] - Tag: <responseName>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END.ordinal()].put( new Tag( "responseName",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END, Dsmlv2StatesEnum.RESPONSE_NAME_END,
+                extendedResponseAddResponseName ) );
+
+        // State: [EXTENDED_RESPONSE_REFERRAL_END] - Tag: <reponse>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END.ordinal()].put(
+            new Tag( "reponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END, Dsmlv2StatesEnum.RESPONSE_END,
+                extendedResponseAddResponse ) );
+
+        // State: [EXTENDED_RESPONSE_REFERRAL_END] - Tag: </extendedResponse>
+        super.transitions[Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END.ordinal()].put( new Tag( "extendedResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.EXTENDED_RESPONSE_REFERRAL_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [RESPONSE_NAME_END] - Tag: <response>
+        super.transitions[Dsmlv2StatesEnum.RESPONSE_NAME_END.ordinal()].put( new Tag( "response", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.RESPONSE_NAME_END, Dsmlv2StatesEnum.RESPONSE_END,
+                extendedResponseAddResponse ) );
+
+        // State: [RESPONSE_NAME_END] - Tag: </extendedResponse>
+        super.transitions[Dsmlv2StatesEnum.RESPONSE_NAME_END.ordinal()].put( new Tag( "extendedResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.RESPONSE_NAME_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [RESPONSE_END] - Tag: </extendedResponse>
+        super.transitions[Dsmlv2StatesEnum.RESPONSE_END.ordinal()].put( new Tag( "extendedResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.RESPONSE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        //====================================================
+        //  Transitions concerning : LDAP RESULT
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_VALUE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_DONE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [LDAP_RESULT] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT.ordinal()].put( new Tag( "control", Tag.START ),
+            new GrammarTransition(
+                Dsmlv2StatesEnum.LDAP_RESULT, Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_START, ldapResultControlCreation ) );
+
+        // State: [LDAP_RESULT] - Tag: <resultCode>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT.ordinal()]
+            .put( new Tag( "resultCode", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.LDAP_RESULT, Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_START, ldapResultAddResultCode ) );
+
+        // State: [LDAP_RESULT_CONTROL_START] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_START.ordinal()].put(
+            new Tag( "controlValue", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_START,
+                Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_VALUE_END, ldapResultControlValueCreation ) );
+
+        // State: [LDAP_RESULT_CONTROL_VALUE_END] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_VALUE_END.ordinal()].put( new Tag( "control", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_VALUE_END,
+                Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_END, null ) );
+
+        // State: [LDAP_RESULT_CONTROL_START] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_START.ordinal()].put( new Tag( "control", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_START,
+                Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_END, null ) );
+
+        // State: [LDAP_RESULT_CONTROL_END] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_END.ordinal()].put( new Tag( "control", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_END,
+                Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_START, ldapResultControlCreation ) );
+
+        // State: [LDAP_RESULT_CONTROL_END] - Tag: <resultCode>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_END.ordinal()].put( new Tag( "resultCode", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_CONTROL_END,
+                Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_START, ldapResultAddResultCode ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_START] - Tag: </resultCode>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_START.ordinal()].put(
+            new Tag( "resultCode", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_START,
+                Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END, null ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: <errorMessage>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put( new Tag( "errorMessage",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END,
+                Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END, ldapResultAddErrorMessage ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: <referral>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put(
+            new Tag( "referral", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END,
+                Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, ldapResultAddReferral ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: </addResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put(
+            new Tag( "addResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: </authResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put(
+            new Tag( "authResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: </compareResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put( new Tag( "compareResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: </delResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put(
+            new Tag( "delResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: </modifyResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put( new Tag( "modifyResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: </modDNResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put( new Tag( "modDNResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_RESULT_CODE_END] - Tag: </searchResultDone>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END.ordinal()].put( new Tag( "searchResultDone",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_RESULT_CODE_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_DONE_END, null ) );
+
+        // State: [SEARCH_RESULT_DONE_END] - Tag: </searchResponse>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_DONE_END.ordinal()]
+            .put( new Tag( "searchResponse", Tag.END ), new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_DONE_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: <referral>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put(
+            new Tag( "referral", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, ldapResultAddReferral ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: </addResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put( new Tag( "addResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: </authResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put( new Tag( "authResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: </compareResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put( new Tag( "compareResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: </delResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put( new Tag( "delResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: </modifyResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put( new Tag( "modifyResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: </modDNResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put( new Tag( "modDNResponse",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP, null ) );
+
+        // State: [LDAP_RESULT_ERROR_MESSAGE_END] - Tag: </searchResultDone>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END.ordinal()].put( new Tag( "searchResultDone",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_ERROR_MESSAGE_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_DONE_END, null ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: <referral>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put( new Tag( "referral", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END,
+                Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, ldapResultAddReferral ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: </addResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put( new Tag( "addResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: </authResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put( new Tag( "authResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: </compareResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put(
+            new Tag( "compareResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: </delResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put( new Tag( "delResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: </modifyResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put(
+            new Tag( "modifyResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: </modDNResponse>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put(
+            new Tag( "modDNResponse", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                null ) );
+
+        // State: [LDAP_RESULT_REFERRAL_END] - Tag: </searchResultDone>
+        super.transitions[Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END.ordinal()].put( new Tag( "searchResultDone",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.LDAP_RESULT_REFERRAL_END, Dsmlv2StatesEnum.SEARCH_RESULT_DONE_END,
+                null ) );
+
+        //====================================================
+        //  Transitions concerning : SEARCH RESPONSE
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESPONSE.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_REPONSE] - Tag: <searchResultEntry>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESPONSE.ordinal()].put( new Tag( "searchResultEntry", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESPONSE, Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY,
+                searchResultEntryCreation ) );
+
+        // State: [SEARCH_REPONSE] - Tag: <searchResultReference>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESPONSE.ordinal()].put(
+            new Tag( "searchResultReference", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESPONSE, Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE,
+                searchResultReferenceCreation ) );
+
+        // State: [SEARCH_REPONSE] - Tag: <searchResultDone>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESPONSE.ordinal()].put( new Tag( "searchResultDone", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESPONSE, Dsmlv2StatesEnum.LDAP_RESULT,
+                searchResultDoneCreation ) );
+
+        //====================================================
+        //  Transitions concerning : SEARCH RESULT ENTRY
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_VALUE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_VALUE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_RESULT_ENTRY] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY.ordinal()].put( new Tag( "control", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_START, searchResultEntryControlCreation ) );
+
+        // State: [SEARCH_RESULT_ENTRY] - Tag: <attr>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY.ordinal()].put( new Tag( "attr", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START, searchResultEntryAddAttr ) );
+
+        // State: [SEARCH_RESULT_ENTRY] - Tag: </searchResultEntry>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY.ordinal()].put( new Tag( "searchResultEntry", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY, Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP,
+                null ) );
+
+        // State: [SEARCH_RESULT_ENTRY_CONTROL_START] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_START.ordinal()].put(
+            new Tag( "controlValue", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_START,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_VALUE_END, searchResultEntryControlValueCreation ) );
+
+        // State: [SEARCH_RESULT_ENTRY_CONTROL_VALUE_END] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_VALUE_END.ordinal()].put( new Tag( "control",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_VALUE_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END, null ) );
+
+        // State: [SEARCH_RESULT_ENTRY_CONTROL_START] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_START.ordinal()].put( new Tag( "control",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_START,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END, null ) );
+
+        // State: [SEARCH_RESULT_ENTRY_CONTROL_END] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END.ordinal()].put( new Tag( "control",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_START, searchResultEntryControlCreation ) );
+
+        // State: [SEARCH_RESULT_ENTRY_CONTROL_END] - Tag: </searchResultEntry>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END.ordinal()].put(
+            new Tag( "searchResultEntry", Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END, Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP, null ) );
+
+        // State: [SEARCH_RESULT_ENTRY_CONTROL_END] - Tag: <attr>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END.ordinal()].put(
+            new Tag( "attr", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_CONTROL_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START, null ) );
+
+        // State: [SEARCH_RESULT_ENTRY_ATTR_START] - Tag: </attr>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START.ordinal()].put( new Tag( "attr", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_END, null ) );
+
+        // State: [SEARCH_RESULT_ENTRY_ATTR_START] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START.ordinal()].put(
+            new Tag( "value", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_VALUE_END, searchResultEntryAddValue ) );
+
+        // State: [SEARCH_RESULT_ENTRY_ATTR_END] - Tag: <attr>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_END.ordinal()].put( new Tag( "attr", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_START, searchResultEntryAddAttr ) );
+
+        // State: [SEARCH_RESULT_ENTRY_ATTR_END] - Tag: </searchResultEntry>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_END.ordinal()].put( new Tag( "searchResultEntry",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP, null ) );
+
+        // State: [SEARCH_RESULT_ENTRY_VALUE_END] - Tag: <value>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_VALUE_END.ordinal()].put( new Tag( "value", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_VALUE_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_VALUE_END, searchResultEntryAddValue ) );
+
+        // State: [SEARCH_RESULT_ENTRY_VALUE_END] - Tag: </attr>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_VALUE_END.ordinal()].put( new Tag( "attr", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_VALUE_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_ATTR_END, null ) );
+
+        //====================================================
+        //  Transitions concerning : SEARCH RESULT ENTRY LOOP
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_RESULT_ENTRY_LOOP] - Tag: <searchResultEntry>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP.ordinal()].put( new Tag( "searchResultEntry",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP, Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY,
+                searchResultEntryCreation ) );
+
+        // State: [SEARCH_RESULT_ENTRY_LOOP] - Tag: <searchResultReference>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP.ordinal()].put(
+            new Tag( "searchResultReference", Tag.START ), new GrammarTransition(
+                Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP, Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE,
+                searchResultReferenceCreation ) );
+
+        // State: [SEARCH_RESULT_ENTRY_LOOP] - Tag: <searchResultDone>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP.ordinal()].put( new Tag( "searchResultDone",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_ENTRY_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                searchResultDoneCreation ) );
+
+        //====================================================
+        //  Transitions concerning : SEARCH RESULT REFERENCE
+        //====================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_START.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_VALUE_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_RESULT_REFERENCE] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE.ordinal()].put( new Tag( "control", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE,
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_START, searchResultReferenceControlCreation ) );
+
+        // State: [SEARCH_RESULT_REFERENCE] - Tag: <ref>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE.ordinal()].put( new Tag( "ref", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE,
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END, searchResultReferenceAddRef ) );
+
+        // State: [SEARCH_RESULT_REFERENCE_CONTROL_START] - Tag: <controlValue>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_START.ordinal()].put( new Tag(
+            "controlValue",
+            Tag.START ), new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_START,
+            Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_VALUE_END, searchResultReferenceControlValueCreation ) );
+
+        // State: [sEARCH_RESULT_REFERENCE_CONTROL_VALUE_END] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_VALUE_END.ordinal()].put(
+            new Tag( "control", Tag.END ), new GrammarTransition(
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_VALUE_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_END, null ) );
+
+        // State: [SEARCH_RESULT_REFERENCE_CONTROL_START] - Tag: </control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_START.ordinal()].put( new Tag( "control",
+            Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_START,
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_END, null ) );
+
+        // State: [SEARCH_RESULT_REFERENCE_CONTROL_END] - Tag: <control>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_END.ordinal()].put( new Tag( "control",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_START, searchResultReferenceControlCreation ) );
+
+        // State: [SEARCH_RESULT_REFERENCE_CONTROL_END] - Tag: <ref>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_END.ordinal()].put( new Tag( "ref",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_CONTROL_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END, searchResultReferenceAddRef ) );
+
+        // State: [SEARCH_RESULT_REFERENCE_REF_END] - Tag: <ref>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END.ordinal()].put( new Tag( "ref", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END,
+                Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END, searchResultReferenceAddRef ) );
+
+        // State: [SEARCH_RESULT_REFERENCE_REF_END] - Tag: </searchResultReference>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END.ordinal()].put( new Tag(
+            "searchResultReference",
+            Tag.END ), new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_REF_END,
+            Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_LOOP, null ) );
+
+        //==========================================================
+        //  Transitions concerning : SEARCH RESULT REFERENCE LOOP
+        //==========================================================
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_LOOP.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [SEARCH_RESULT_REFERENCE_LOOP] - Tag: <searchResultReference>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_LOOP.ordinal()].put( new Tag(
+            "searchResultReference",
+            Tag.START ), new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_LOOP,
+            Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE, searchResultReferenceCreation ) );
+
+        // State: [SEARCH_RESULT_REFERENCE_LOOP] - Tag: <searchResultDone>
+        super.transitions[Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_LOOP.ordinal()].put( new Tag( "searchResultDone",
+            Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SEARCH_RESULT_REFERENCE_LOOP, Dsmlv2StatesEnum.LDAP_RESULT,
+                searchResultDoneCreation ) );
+
+        //------------------------------------------ handle SOAP envelopes --------------------------
+        super.transitions[Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_BODY_START_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+        super.transitions[Dsmlv2StatesEnum.SOAP_BODY_END_TAG.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        super.transitions[Dsmlv2StatesEnum.GRAMMAR_END.ordinal()] = new HashMap<Tag, GrammarTransition>();
+
+        // State: [INIT_GRAMMAR_STATE] - Tag: <envelope>
+        super.transitions[Dsmlv2StatesEnum.INIT_GRAMMAR_STATE.ordinal()].put( new Tag( "envelope", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE, Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG,
+                null ) );
+
+        // state: [SOAP_ENVELOPE_START_TAG] -> Tag: <header>
+        super.transitions[Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG.ordinal()].put( new Tag( "header", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG, Dsmlv2StatesEnum.SOAP_HEADER_START_TAG,
+                ParserUtils.READ_SOAP_HEADER ) );
+
+        // state: [SOAP_HEADER_START_TAG] -> Tag: </header>
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_START_TAG.ordinal()]
+            .put( new Tag( "header", Tag.END ),
+                new GrammarTransition( Dsmlv2StatesEnum.SOAP_HEADER_START_TAG, Dsmlv2StatesEnum.SOAP_HEADER_END_TAG,
+                    null ) );
+
+        // state: [SOAP_HEADER_END_TAG] -> Tag: <body>
+        super.transitions[Dsmlv2StatesEnum.SOAP_HEADER_END_TAG.ordinal()].put( new Tag( "body", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SOAP_HEADER_END_TAG, Dsmlv2StatesEnum.SOAP_BODY_START_TAG, null ) );
+
+        // state: [SOAP_BODY_START_TAG] -> Tag: <batchResponse>
+        super.transitions[Dsmlv2StatesEnum.SOAP_BODY_START_TAG.ordinal()].put( new Tag( "batchResponse", Tag.START ),
+            new GrammarTransition( Dsmlv2StatesEnum.SOAP_BODY_START_TAG, Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP,
+                batchResponseCreation ) );
+
+        // the optional transition if no soap header is present
+        // state: [SOAP_ENVELOPE_START_TAG] -> Tag: <body>
+        super.transitions[Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG.ordinal()]
+            .put( new Tag( "body", Tag.START ),
+                new GrammarTransition( Dsmlv2StatesEnum.SOAP_ENVELOPE_START_TAG, Dsmlv2StatesEnum.SOAP_BODY_START_TAG,
+                    null ) );
+
+        // the below two transitions are a bit unconventional, technically the container's state is set to GRAMMAR_END
+        // when the </batchRequest> tag is encountered by the parser and the corresponding action gets executed but in
+        // a SOAP envelop we still have two more end tags(</body> and </envelope>) are left so we set those corresponding
+        // current and next transition states always to GRAMMAR_END
+        super.transitions[Dsmlv2StatesEnum.GRAMMAR_END.ordinal()].put( new Tag( "body", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.GRAMMAR_END, Dsmlv2StatesEnum.GRAMMAR_END, null ) );
+
+        super.transitions[Dsmlv2StatesEnum.GRAMMAR_END.ordinal()].put( new Tag( "envelope", Tag.END ),
+            new GrammarTransition( Dsmlv2StatesEnum.GRAMMAR_END, Dsmlv2StatesEnum.GRAMMAR_END, null ) );
+
+        //------------------------------------------
+    }
+
+    /**
+     * GrammarAction that creates the Batch Response
+     */
+    private final GrammarAction batchResponseCreation = new GrammarAction( "Create Batch Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            BatchResponseDsml batchResponse = new BatchResponseDsml();
+
+            container.setBatchResponse( batchResponse );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                batchResponse.setRequestID( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Add Response
+     */
+    private final GrammarAction addResponseCreation = new GrammarAction( "Create Add Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AddResponseDsml addResponse = new AddResponseDsml(
+                container.getLdapCodecService(), new AddResponseImpl() );
+            container.getBatchResponse().addResponse( addResponse );
+
+            LdapResult ldapResult = addResponse.getLdapResult();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                addResponse.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Auth Response
+     */
+    private final GrammarAction authResponseCreation = new GrammarAction( "Create Auth Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            BindResponseDsml bindResponse = new BindResponseDsml(
+                container.getLdapCodecService(), new BindResponseImpl() );
+            container.getBatchResponse().addResponse( bindResponse );
+
+            LdapResult ldapResult = bindResponse.getLdapResult();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                bindResponse.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+
+            }
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Compare Response
+     */
+    private final GrammarAction compareResponseCreation = new GrammarAction( "Create Compare Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            CompareResponseDsml compareResponse = new CompareResponseDsml(
+                container.getLdapCodecService(), new CompareResponseImpl() );
+            container.getBatchResponse().addResponse( compareResponse );
+
+            LdapResult ldapResult = compareResponse.getLdapResult();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                compareResponse.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Del Response
+     */
+    private final GrammarAction delResponseCreation = new GrammarAction( "Create Del Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            DelResponseDsml delResponse = new DelResponseDsml(
+                container.getLdapCodecService(), new DeleteResponseImpl() );
+            container.getBatchResponse().addResponse( delResponse );
+
+            LdapResult ldapResult = delResponse.getLdapResult();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                delResponse.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Modify Response
+     */
+    private final GrammarAction modifyResponseCreation = new GrammarAction( "Create Modify Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ModifyResponseDsml modifyResponse = new ModifyResponseDsml(
+                container.getLdapCodecService(), new ModifyResponseImpl() );
+            container.getBatchResponse().addResponse( modifyResponse );
+
+            LdapResult ldapResult = modifyResponse.getLdapResult();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                modifyResponse.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Mod Dn Response
+     */
+    private final GrammarAction modDNResponseCreation = new GrammarAction( "Create Mod Dn Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ModDNResponseDsml modDNResponse = new ModDNResponseDsml(
+                container.getLdapCodecService(), new ModifyDnResponseImpl() );
+            container.getBatchResponse().addResponse( modDNResponse );
+
+            LdapResult ldapResult = modDNResponse.getLdapResult();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                modDNResponse.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Extended Response
+     */
+    private final GrammarAction extendedResponseCreation = new GrammarAction( "Create Extended Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ExtendedResponseDsml extendedResponse = null;
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+
+            XmlPullParser xpp = container.getParser();
+
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                extendedResponse = new ExtendedResponseDsml(
+                    container.getLdapCodecService(), new ExtendedResponseImpl(
+                        ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) ) );
+            }
+            else
+            {
+                extendedResponse = new ExtendedResponseDsml(
+                    container.getLdapCodecService(), new ExtendedResponseImpl( -1 ) );
+            }
+
+            container.getBatchResponse().addResponse( extendedResponse );
+
+            LdapResult ldapResult = extendedResponse.getLdapResult();
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Error Response
+     */
+    private final GrammarAction errorResponseCreation = new GrammarAction( "Create Error Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ErrorResponse errorResponse = null;
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                errorResponse = new ErrorResponse( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ), null );
+
+                container.getBatchResponse().addResponse( errorResponse );
+            }
+            // type
+            attributeValue = xpp.getAttributeValue( "", "type" );
+            if ( attributeValue != null )
+            {
+                if ( attributeValue.equals( errorResponse.getTypeDescr( ErrorResponseType.NOT_ATTEMPTED ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.NOT_ATTEMPTED );
+                }
+                else if ( attributeValue.equals( errorResponse.getTypeDescr( ErrorResponseType.COULD_NOT_CONNECT ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.COULD_NOT_CONNECT );
+                }
+                else if ( attributeValue.equals( errorResponse.getTypeDescr( ErrorResponseType.CONNECTION_CLOSED ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.CONNECTION_CLOSED );
+                }
+                else if ( attributeValue.equals( errorResponse.getTypeDescr( ErrorResponseType.MALFORMED_REQUEST ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.MALFORMED_REQUEST );
+                }
+                else if ( attributeValue
+                    .equals( errorResponse.getTypeDescr( ErrorResponseType.GATEWAY_INTERNAL_ERROR ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.GATEWAY_INTERNAL_ERROR );
+                }
+                else if ( attributeValue.equals( errorResponse.getTypeDescr( ErrorResponseType.AUTHENTICATION_FAILED ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.AUTHENTICATION_FAILED );
+                }
+                else if ( attributeValue.equals( errorResponse.getTypeDescr( ErrorResponseType.UNRESOLVABLE_URI ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.UNRESOLVABLE_URI );
+                }
+                else if ( attributeValue.equals( errorResponse.getTypeDescr( ErrorResponseType.OTHER ) ) )
+                {
+                    errorResponse.setErrorType( ErrorResponseType.OTHER );
+                }
+                else
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03004 ), xpp, null );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03005 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds Message to an Error Response
+     */
+    private final GrammarAction errorResponseAddMessage = new GrammarAction( "Add Message to Error Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ErrorResponse errorResponse = ( ErrorResponse ) container.getBatchResponse().getCurrentResponse();
+
+            XmlPullParser xpp = container.getParser();
+            try
+            {
+                String nextText = xpp.nextText();
+                if ( !nextText.equals( "" ) )
+                {
+                    errorResponse.setMessage( nextText.trim() );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( ioe.getMessage(), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds Detail to an Error Response
+     */
+    // TODO Look for documentation about this Detail element (the DSML documentation doesn't give enough information)
+    private static final GrammarAction ERROR_RESPONSE_ADD_DETAIL = null;
+
+
+    /**
+     * Creates a Control parsing the current node and adds it to the given parent 
+     * @param container the DSMLv2Container
+     * @param parent the parent 
+     * @throws XmlPullParserException
+     */
+    private void createAndAddControl( Dsmlv2Container container,
+        AbstractDsmlMessageDecorator<? extends Message> parent ) throws XmlPullParserException
+    {
+        CodecControl<? extends Control> control = null;
+
+        XmlPullParser xpp = container.getParser();
+
+        // Checking and adding the Control's attributes
+        String attributeValue;
+        // TYPE
+        attributeValue = xpp.getAttributeValue( "", "type" );
+
+        if ( attributeValue != null )
+        {
+            if ( !Oid.isOid( attributeValue ) )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03006 ), xpp, null );
+            }
+
+            control = container.getLdapCodecService().newControl( new OpaqueControl( attributeValue ) );
+            parent.addControl( control );
+        }
+        else
+        {
+            throw new XmlPullParserException( I18n.err( I18n.ERR_03005 ), xpp, null );
+        }
+        // CRITICALITY
+        attributeValue = xpp.getAttributeValue( "", "criticality" );
+
+        if ( attributeValue != null )
+        {
+            if ( attributeValue.equals( "true" ) )
+            {
+                control.setCritical( true );
+            }
+            else if ( attributeValue.equals( "false" ) )
+            {
+                control.setCritical( false );
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03007 ), xpp, null );
+            }
+        }
+    }
+
+    /**
+     * GrammarAction that creates a Control for LDAP Result
+     */
+    private final GrammarAction ldapResultControlCreation = new GrammarAction( "Create Control for LDAP Result" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AbstractDsmlMessageDecorator<? extends Message> message =
+                ( AbstractDsmlMessageDecorator<? extends Message> )
+                container.getBatchResponse().getCurrentResponse();
+
+            if ( message instanceof SearchResponseDsml )
+            {
+                createAndAddControl( container,
+                    ( ( SearchResponse ) ( ( SearchResponseDsml ) message ).getDecorated() ).getSearchResultDone() );
+            }
+            else
+            {
+                createAndAddControl( container, message );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Control for Search Result Entry
+     */
+    private final GrammarAction searchResultEntryControlCreation = new GrammarAction(
+        "Create Control for Search Result Entry" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResponse response = ( SearchResponse )
+                ( ( SearchResponseDsml ) container.getBatchResponse()
+                    .getCurrentResponse() ).getDecorated();
+
+            createAndAddControl( container, response.getCurrentSearchResultEntry() );
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Control for Search Result Entry
+     */
+    private final GrammarAction searchResultReferenceControlCreation = new GrammarAction(
+        "Create Control for Search Result Reference" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResponse response = ( SearchResponse )
+                ( ( SearchResponseDsml ) container.getBatchResponse()
+                    .getCurrentResponse() ).getDecorated();
+
+            createAndAddControl( container, response.getCurrentSearchResultReference() );
+        }
+    };
+
+
+    /**
+     * Creates a Control Value parsing the current node and adds it to the given parent 
+     * @param container the DSMLv2Container
+     * @param parent the parent 
+     * @throws XmlPullParserException
+     */
+    private void createAndAddControlValue( Dsmlv2Container container,
+        AbstractDsmlMessageDecorator<? extends Message> parent )
+        throws XmlPullParserException
+    {
+        DsmlControl<? extends Control> control =
+            ( ( AbstractDsmlMessageDecorator<?> ) parent ).getCurrentControl();
+
+        XmlPullParser xpp = container.getParser();
+        try
+        {
+            // We have to catch the type Attribute Value before going to the next Text node
+            String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+            // Getting the value
+            String nextText = xpp.nextText();
+
+            if ( !nextText.equals( "" ) )
+            {
+                if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                {
+                    control.setValue( Base64.decode( nextText.trim().toCharArray() ) );
+                }
+                else
+                {
+                    control.setValue( Strings.getBytesUtf8( nextText.trim() ) );
+                }
+            }
+        }
+        catch ( IOException ioe )
+        {
+            throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+        }
+    }
+
+    /**
+     * GrammarAction that creates a Control Value for LDAP Result
+     */
+    private final GrammarAction ldapResultControlValueCreation = new GrammarAction(
+        "Add ControlValue to Control for LDAP Result" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            AbstractDsmlMessageDecorator<? extends Response> response
+            = ( AbstractDsmlMessageDecorator<? extends Response> )
+                container.getBatchResponse().getCurrentResponse();
+
+            if ( response instanceof SearchResponseDsml )
+            {
+                SearchResponse searchResponse = ( SearchResponse )
+                    response.getDecorated();
+                createAndAddControlValue( container,
+                    searchResponse.getSearchResultDone() );
+            }
+            else
+            {
+                createAndAddControlValue( container, response );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Control Value for Search Result Entry
+     */
+    private final GrammarAction searchResultEntryControlValueCreation = new GrammarAction(
+        "Add ControlValue to Control for Search Result Entry" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResponse response = ( SearchResponse )
+                container.getBatchResponse().getCurrentResponse().getDecorated();
+            createAndAddControlValue( container,
+                response.getCurrentSearchResultEntry() );
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Control Value for Search Result Reference
+     */
+    private final GrammarAction searchResultReferenceControlValueCreation = new GrammarAction(
+        "Add ControlValue to Control for Search Result Entry" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResponseDsml response = ( SearchResponseDsml )
+                container.getBatchResponse().getCurrentResponse();
+            createAndAddControlValue( container,
+                ( ( SearchResponse ) response.getDecorated() ).getCurrentSearchResultReference() );
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Result Code to a LDAP Result
+     */
+    private final GrammarAction ldapResultAddResultCode = new GrammarAction( "Add ResultCode to LDAP Result" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            DsmlDecorator<? extends Response> ldapResponse =
+                container.getBatchResponse().getCurrentResponse();
+
+            LdapResult ldapResult = null;
+
+            // Search Response is a special case
+            // ResultCode can only occur in a case of Search Result Done in a Search Response
+            if ( ldapResponse.getDecorated() instanceof SearchResponse )
+            {
+                SearchResponse searchResponse = ( SearchResponse ) ldapResponse.getDecorated();
+                ldapResult = searchResponse.getSearchResultDone().getLdapResult();
+            }
+            else
+            {
+                ldapResult = ( ( ResultResponse ) ldapResponse.getDecorated() ).getLdapResult();
+            }
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // code
+            attributeValue = xpp.getAttributeValue( "", "code" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    ldapResult.setResultCode( ResultCodeEnum.getResultCode( Integer.parseInt( attributeValue ) ) );
+                }
+                catch ( NumberFormatException nfe )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03009 ), xpp, nfe );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03010 ), xpp, null );
+            }
+
+            // descr
+            attributeValue = xpp.getAttributeValue( "", "descr" );
+
+            if ( ( attributeValue != null ) && !DSMLV2_DESCR_TAGS.contains( attributeValue ) )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03011, attributeValue ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Error Message to a LDAP Result
+     */
+    private final GrammarAction ldapResultAddErrorMessage = new GrammarAction( "Add Error Message to LDAP Result" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            DsmlDecorator<? extends Response> ldapResponse =
+                container.getBatchResponse().getCurrentResponse();
+
+            LdapResult ldapResult = null;
+
+            // Search Response is a special case
+            // ResultCode can only occur in a case of Search Result Done in a Search Response
+            if ( ldapResponse.getDecorated() instanceof SearchResponse )
+            {
+                SearchResponse searchResponse = ( SearchResponse ) ldapResponse.getDecorated();
+                ldapResult = searchResponse.getSearchResultDone().getLdapResult();
+            }
+            else
+            {
+                ldapResult = ( ( ResultResponse ) ldapResponse.getDecorated() ).getLdapResult();
+            }
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    ldapResult.setDiagnosticMessage( nextText.trim() );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Referral to a LDAP Result
+     */
+    private final GrammarAction ldapResultAddReferral = new GrammarAction( "Add Referral to LDAP Result" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            DsmlDecorator<? extends Response> ldapResponse =
+                container.getBatchResponse().getCurrentResponse();
+
+            LdapResult ldapResult = null;
+
+            // Search Response is a special case
+            // ResultCode can only occur in a case of Search Result Done in a Search Response
+            if ( ldapResponse.getDecorated() instanceof SearchResponse )
+            {
+                SearchResponse searchResponse = ( SearchResponse ) ldapResponse.getDecorated();
+                ldapResult = searchResponse.getSearchResultDone().getLdapResult();
+            }
+            else
+            {
+                ldapResult = ( ( ResultResponse ) ldapResponse.getDecorated() ).getLdapResult();
+            }
+
+            // Initialization of the Referrals if needed
+            if ( ldapResult.getReferral() == null )
+            {
+                ldapResult.setReferral( new ReferralImpl() );
+            }
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    try
+                    {
+                        String urlStr = nextText.trim();
+                        LdapUrl ldapUrl = new LdapUrl( urlStr );
+                        ldapResult.getReferral().addLdapUrl( ldapUrl.toString() );
+                    }
+                    catch ( LdapURLEncodingException luee )
+                    {
+                        throw new XmlPullParserException( luee.getMessage(), xpp, luee );
+                    }
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates the Search Response
+     */
+    private final GrammarAction searchResponseCreation = new GrammarAction( "Create Search Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            XmlPullParser xpp = container.getParser();
+            SearchResponse searchResponse = null;
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                searchResponse = new SearchResponse(
+                    ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+            else
+            {
+                searchResponse = new SearchResponse();
+            }
+
+            container.getBatchResponse().addResponse( new SearchResponseDsml(
+                container.getLdapCodecService(), searchResponse ) );
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Search Result Entry
+     */
+    private final GrammarAction searchResultEntryCreation = new GrammarAction(
+        "Add Search Result Entry to Search Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResultEntryDsml searchResultEntry =
+                new SearchResultEntryDsml( container.getLdapCodecService(),
+                    new SearchResultEntryImpl() );
+            SearchResponseDsml searchResponse = ( SearchResponseDsml )
+                container.getBatchResponse().getCurrentResponse();
+            searchResponse.addResponse( searchResultEntry );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                searchResultEntry.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+
+            // dn
+            attributeValue = xpp.getAttributeValue( "", "dn" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    searchResultEntry.setObjectName( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( "dn attribute is required", xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Search Result Reference
+     */
+    private final GrammarAction searchResultReferenceCreation = new GrammarAction(
+        "Add Search Result Reference to Search Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResultReferenceDsml searchResultReference =
+                new SearchResultReferenceDsml(
+                    container.getLdapCodecService(),
+                    new SearchResultReferenceImpl() );
+
+            SearchResponseDsml searchResponseDsml = ( SearchResponseDsml )
+                container.getBatchResponse().getCurrentResponse();
+
+            searchResponseDsml.addResponse( searchResultReference );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                searchResultReference.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that creates a Search Result Done
+     */
+    private final GrammarAction searchResultDoneCreation = new GrammarAction(
+        "Add Search Result Done to Search Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResultDoneDsml searchResultDone =
+                new SearchResultDoneDsml( container.getLdapCodecService(),
+                    new SearchResultDoneImpl() );
+
+            SearchResponseDsml searchResponseDsml = ( SearchResponseDsml )
+                container.getBatchResponse().getCurrentResponse();
+            searchResponseDsml.addResponse( searchResultDone );
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the batchRequest's attributes
+            String attributeValue;
+            // requestID
+            attributeValue = xpp.getAttributeValue( "", "requestID" );
+
+            if ( attributeValue != null )
+            {
+                searchResultDone.setMessageId( ParserUtils.parseAndVerifyRequestID( attributeValue, xpp ) );
+            }
+
+            // MatchedDN
+            attributeValue = xpp.getAttributeValue( "", "matchedDN" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    searchResultDone.getLdapResult().setMatchedDn( new Dn( attributeValue ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    throw new XmlPullParserException( lide.getMessage(), xpp, lide );
+                }
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds an Attr to a Search Result Entry
+     */
+    private final GrammarAction searchResultEntryAddAttr = new GrammarAction( "Add Attr to Search Result Entry" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResponse searchResponse = ( SearchResponse )
+                container.getBatchResponse().getCurrentResponse().getDecorated();
+
+            SearchResultEntryDsml searchResultEntry = ( SearchResultEntryDsml )
+                searchResponse.getCurrentSearchResultEntry();
+
+            XmlPullParser xpp = container.getParser();
+
+            // Checking and adding the request's attributes
+            String attributeValue;
+            // name
+            attributeValue = xpp.getAttributeValue( "", "name" );
+
+            if ( attributeValue != null )
+            {
+                try
+                {
+                    searchResultEntry.addAttribute( attributeValue );
+                }
+                catch ( LdapException le )
+                {
+                    throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, le );
+                }
+            }
+            else
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03012 ), xpp, null );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Value to an Attr of a Search Result Entry
+     */
+    private final GrammarAction searchResultEntryAddValue = new GrammarAction(
+        "Add a Value to an Attr of a Search Result Entry" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResponse searchResponse = ( SearchResponse )
+                container.getBatchResponse().getCurrentResponse().getDecorated();
+            SearchResultEntryDsml searchResultEntry = ( SearchResultEntryDsml )
+                searchResponse.getCurrentSearchResultEntry();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                try
+                {
+                    if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                    {
+                        searchResultEntry.addAttributeValue( Base64.decode( nextText.toCharArray() ) );
+                    }
+                    else
+                    {
+                        searchResultEntry.addAttributeValue( nextText );
+                    }
+                }
+                catch ( LdapException le )
+                {
+                    throw new XmlPullParserException( le.getMessage(), xpp, le );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Ref to a Search Result Reference
+     */
+    private final GrammarAction searchResultReferenceAddRef = new GrammarAction(
+        "Add a Ref to a Search Result Reference" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            SearchResponse searchResponse = ( SearchResponse )
+                container.getBatchResponse().getCurrentResponse().getDecorated();
+            SearchResultReference searchResultReference = searchResponse.getCurrentSearchResultReference();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    LdapUrl ldapUrl = new LdapUrl( nextText );
+
+                    searchResultReference.getReferral().addLdapUrl( ldapUrl.toString() );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+            catch ( LdapURLEncodingException luee )
+            {
+                throw new XmlPullParserException( luee.getMessage(), xpp, luee );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds Result Code to an Extended Response
+     */
+    private final GrammarAction extendedResponseAddResultCode = ldapResultAddResultCode;
+
+    /**
+     * GrammarAction that creates the Search Response
+     */
+    private final GrammarAction extendedResponseAddErrorMessage = ldapResultAddErrorMessage;
+
+    /**
+     * GrammarAction that adds a Referral to an Extended Response
+     */
+    private final GrammarAction extendedResponseAddReferral = ldapResultAddReferral;
+
+    /**
+     * GrammarAction that adds a Response Name to an Extended Response
+     */
+    private final GrammarAction extendedResponseAddResponseName = new GrammarAction(
+        "Add Response Name to Extended Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ExtendedResponse extendedResponse = ( ExtendedResponse ) container.getBatchResponse().getCurrentResponse();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                String nextText = xpp.nextText();
+
+                if ( !nextText.equals( "" ) )
+                {
+                    extendedResponse.setResponseName( Oid.fromString( nextText.trim() ).toString() );
+                }
+
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+            catch ( DecoderException de )
+            {
+                throw new XmlPullParserException( de.getMessage(), xpp, de );
+            }
+        }
+    };
+
+    /**
+     * GrammarAction that adds a Response to an Extended Response
+     */
+    private final GrammarAction extendedResponseAddResponse = new GrammarAction( "Add Response to Extended Response" )
+    {
+        public void action( Dsmlv2Container container ) throws XmlPullParserException
+        {
+            ExtendedResponseDsml extendedResponse = ( ExtendedResponseDsml ) container.getBatchResponse()
+                .getCurrentResponse();
+
+            XmlPullParser xpp = container.getParser();
+
+            try
+            {
+                // We have to catch the type Attribute Value before going to the next Text node
+                String typeValue = ParserUtils.getXsiTypeAttributeValue( xpp );
+
+                // Getting the value
+                String nextText = xpp.nextText();
+
+                if ( ParserUtils.isBase64BinaryValue( xpp, typeValue ) )
+                {
+                    extendedResponse.setResponseValue( Base64.decode( nextText.trim().toCharArray() ) );
+                }
+                else
+                {
+                    extendedResponse.setResponseValue( Strings.getBytesUtf8( nextText.trim() ) );
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw new XmlPullParserException( I18n.err( I18n.ERR_03008, ioe.getMessage() ), xpp, ioe );
+            }
+        }
+    };
+
+
+    /**
+     * Get the instance of this grammar
+     * 
+     * @return
+     *      an instance on this grammar
+     */
+    public static Dsmlv2ResponseGrammar getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ErrorResponse.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ErrorResponse.java
new file mode 100644
index 0000000..24ed1b7
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ErrorResponse.java
@@ -0,0 +1,290 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.AbstractResponse;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * Class representing Error Response.
+ * <br/>
+ * An Error Response has a requestID, a message, and a type which can be :
+ * <ul>
+ *     <li>NOT_ATTEMPTED,</li>
+ *     <li>COULD_NOT_CONNECT,</li>
+ *     <li>CONNECTION_CLOSED,</li>
+ *     <li>MALFORMED_REQUEST,</li>
+ *     <li>GATEWAY_INTERNAL_ERROR,</li>
+ *     <li>AUTHENTICATION_FAILED,</li>
+ *     <li>UNRESOLVABLE_URI,</li>
+ *     <li>OTHER</li>
+ * </ul>
+ * 
+ * @TODO review this class - maybe it should not be decorated and if it is
+ * it should extend AbstractResultResponseDsml - by Alex
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ErrorResponse extends AbstractResponse implements Response, DsmlDecorator<Response>
+{
+    private static final String ERROR_RESPONSE_TAG = "errorResponse";
+
+    /**
+     * This enum represents the different types of error response
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     */
+    public enum ErrorResponseType
+    {
+        /** Not attempted error response type. */
+        NOT_ATTEMPTED,
+        /** Could not connect error response type. */
+        COULD_NOT_CONNECT,
+        /**  error response type. */
+        CONNECTION_CLOSED,
+        /** Malformed request error response type. */
+        MALFORMED_REQUEST,
+        /** Gateway internal error error response type. */
+        GATEWAY_INTERNAL_ERROR,
+        /** Authentication failed error response type. */
+        AUTHENTICATION_FAILED,
+        /** Unresolveable URI error response type. */
+        UNRESOLVABLE_URI,
+        /** Other error response type. */
+        OTHER
+    }
+
+    /** The type of error response */
+    private ErrorResponseType errorType;
+
+    /** The associated message */
+    private String message;
+
+    /** The request ID */
+    private int requestID;
+
+
+    /**
+     * Creates a new instance of ErrorResponse.
+     *
+     * @param id the response eliciting this Request
+     * @param type the message type of the response
+     */
+    public ErrorResponse( int id, MessageTypeEnum type )
+    {
+        super( id, type );
+    }
+
+
+    /**
+     * Creates a new instance of ErrorResponse.
+     *
+     * @param requestID
+     *      the requestID of the response
+     * @param type
+     *      the type of the response
+     * @param message
+     *      the associated message
+     */
+    public ErrorResponse( int requestID, ErrorResponseType type, String message )
+    {
+        super( requestID, null );
+        this.requestID = requestID;
+        this.errorType = type;
+        this.message = message;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( ERROR_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( ERROR_RESPONSE_TAG );
+        }
+
+        // RequestID
+        if ( requestID != 0 )
+        {
+            element.addAttribute( "requestID", "" + requestID );
+        }
+
+        // Type
+        element.addAttribute( "type", getTypeDescr( errorType ) );
+
+        // TODO Add Detail
+
+        if ( ( message != null ) && ( !"".equals( message ) ) )
+        {
+            Element messageElement = element.addElement( "message" );
+            messageElement.addText( message );
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Returns the String associated to the error response type
+     * 
+     * @param type
+     *      the error response type
+     * @return
+     *      the corresponding String
+     */
+    public String getTypeDescr( ErrorResponseType type )
+    {
+        if ( type.equals( ErrorResponseType.NOT_ATTEMPTED ) )
+        {
+            return "notAttempted";
+        }
+        else if ( type.equals( ErrorResponseType.COULD_NOT_CONNECT ) )
+        {
+            return "couldNotConnect";
+        }
+        else if ( type.equals( ErrorResponseType.CONNECTION_CLOSED ) )
+        {
+            return "connectionClosed";
+        }
+        else if ( type.equals( ErrorResponseType.MALFORMED_REQUEST ) )
+        {
+            return "malformedRequest";
+        }
+        else if ( type.equals( ErrorResponseType.GATEWAY_INTERNAL_ERROR ) )
+        {
+            return "gatewayInternalError";
+        }
+        else if ( type.equals( ErrorResponseType.AUTHENTICATION_FAILED ) )
+        {
+            return "authenticationFailed";
+        }
+        else if ( type.equals( ErrorResponseType.UNRESOLVABLE_URI ) )
+        {
+            return "unresolvableURI";
+        }
+        else if ( type.equals( ErrorResponseType.OTHER ) )
+        {
+            return "other";
+        }
+        else
+        {
+            return "unknown";
+        }
+    }
+
+
+    /**
+     * Gets the message
+     *
+     * @return
+     *      the message
+     */
+    public String getMessage()
+    {
+        return message;
+    }
+
+
+    /**
+     * Sets the message
+     *
+     * @param message
+     *      the message to set
+     */
+    public void setMessage( String message )
+    {
+        this.message = message;
+    }
+
+
+    /**
+     * Gets the request ID
+     *
+     * @return
+     *      the request ID
+     */
+    public int getRequestID()
+    {
+        return requestID;
+    }
+
+
+    /**
+     * Sets the request ID
+     *
+     * @param requestID
+     *      the request ID to set
+     */
+    public void setRequestID( int requestID )
+    {
+        this.requestID = requestID;
+    }
+
+
+    /**
+     * Gets the type of error response
+     *
+     * @return the type of error response
+     */
+    public ErrorResponseType getErrorType()
+    {
+        return errorType;
+    }
+
+
+    /**
+     * Sets the type of error response
+     *
+     * @param errorType the type of error response to set
+     */
+    public void setErrorType( ErrorResponseType errorType )
+    {
+        this.errorType = errorType;
+    }
+
+
+    public LdapApiService getCodecService()
+    {
+        throw new IllegalArgumentException( "This should not be a decorator "
+            + "but seems it was made into one. We need to do something about"
+            + "this if this exception is being raise." );
+    }
+
+
+    public Response getDecorated()
+    {
+        return this;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ExtendedResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ExtendedResponseDsml.java
new file mode 100644
index 0000000..86b1de9
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ExtendedResponseDsml.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.util.Strings;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for ExtendedResponse
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtendedResponseDsml extends AbstractResultResponseDsml<ExtendedResponse>
+    implements ExtendedResponse
+{
+    private static final String EXTENDED_RESPONSE_TAG = "extendedResponse";
+    private byte[] response;
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ExtendedResponseDsml.
+     */
+    public ExtendedResponseDsml( LdapApiService codec )
+    {
+        super( codec, new ExtendedResponseImpl( "" ) );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ExtendedResponseDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public ExtendedResponseDsml( LdapApiService codec, ExtendedResponse ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( EXTENDED_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( EXTENDED_RESPONSE_TAG );
+        }
+
+        ExtendedResponse extendedResponse = getDecorated();
+
+        // LDAP Result
+        LdapResultDsml ldapResultDsml = new LdapResultDsml( getCodecService(),
+            getDecorated().getLdapResult(), getDecorated() );
+        ldapResultDsml.toDsml( element );
+
+        // ResponseName
+        String responseName = extendedResponse.getResponseName();
+        if ( responseName != null )
+        {
+            element.addElement( "responseName" ).addText( responseName );
+        }
+
+        // Response
+        Object responseValue = getResponseValue();
+
+        if ( responseValue != null )
+        {
+            if ( ParserUtils.needsBase64Encoding( responseValue ) )
+            {
+                Namespace xsdNamespace = new Namespace( ParserUtils.XSD, ParserUtils.XML_SCHEMA_URI );
+                Namespace xsiNamespace = new Namespace( ParserUtils.XSI, ParserUtils.XML_SCHEMA_INSTANCE_URI );
+                element.getDocument().getRootElement().add( xsdNamespace );
+                element.getDocument().getRootElement().add( xsiNamespace );
+
+                Element responseElement = element.addElement( "response" )
+                    .addText( ParserUtils.base64Encode( responseValue ) );
+                responseElement.addAttribute( new QName( "type", xsiNamespace ), ParserUtils.XSD + ":"
+                    + ParserUtils.BASE64BINARY );
+            }
+            else
+            {
+                element.addElement( "response" ).addText( Strings.utf8ToString( ( byte[] ) responseValue ) );
+            }
+        }
+
+        return element;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setResponseName( String oid )
+    {
+        getDecorated().setResponseName( oid );
+    }
+
+
+    /**
+     * Get the extended response name
+     * 
+     * @return Returns the name.
+     */
+    public String getResponseName()
+    {
+        return getDecorated().getResponseName();
+    }
+
+
+    /**
+     * Set the extended response name
+     * 
+     * @param responseName The name to set.
+     */
+    public void setResponseName( Oid responseName )
+    {
+        getDecorated().setResponseName( responseName.toString() );
+    }
+
+
+    /**
+     * Get the extended response
+     * 
+     * @return Returns the response.
+     */
+    public byte[] getResponseValue()
+    {
+        return this.response;
+    }
+
+
+    /**
+     * Set the extended response
+     * 
+     * @param responseValue The response to set.
+     */
+    public void setResponseValue( byte[] responseValue )
+    {
+        this.response = responseValue;
+    }
+}
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/LdapResultDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/LdapResultDsml.java
new file mode 100644
index 0000000..767e463
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/LdapResultDsml.java
@@ -0,0 +1,255 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.dom4j.Element;
+
+
+/**
+ * DSML Decorator for the LdapResult class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapResultDsml implements DsmlDecorator<LdapResult>, LdapResult
+{
+    /** The LDAP Result to decorate */
+    private LdapResult result;
+
+    /** The associated LDAP Message */
+    private Message message;
+
+    /** The ldap codec service */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of LdapResultDsml.
+     *
+     * @param result
+     *      the LdapResult to decorate
+     * @param message
+     *      the associated message
+     * @param the ldap codec service 
+     */
+    public LdapResultDsml( LdapApiService codec, LdapResult result, Message message )
+    {
+        this.codec = codec;
+        this.result = result;
+        this.message = message;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+
+        // RequestID
+        int requestID = message.getMessageId();
+        if ( requestID > 0 )
+        {
+            root.addAttribute( "requestID", "" + requestID );
+        }
+
+        // Matched Dn
+        Dn matchedDn = result.getMatchedDn();
+
+        if ( !Dn.isNullOrEmpty( matchedDn ) )
+        {
+            root.addAttribute( "matchedDn", matchedDn.getName() );
+        }
+
+        // Controls
+        ParserUtils.addControls( codec, root, message.getControls().values() );
+
+        // ResultCode
+        Element resultCodeElement = root.addElement( "resultCode" );
+        resultCodeElement.addAttribute( "code", "" + result.getResultCode().getResultCode() );
+        resultCodeElement.addAttribute( "descr", result.getResultCode().getMessage() );
+
+        // ErrorMessage
+        String errorMessage = ( result.getDiagnosticMessage() );
+        if ( ( errorMessage != null ) && ( !errorMessage.equals( "" ) ) )
+        {
+            Element errorMessageElement = root.addElement( "errorMessage" );
+            errorMessageElement.addText( errorMessage );
+        }
+
+        // Referrals
+        Referral referral = result.getReferral();
+        if ( referral != null )
+        {
+            Collection<String> ldapUrls = referral.getLdapUrls();
+            if ( ldapUrls != null )
+            {
+                for ( String ldapUrl : ldapUrls )
+                {
+                    Element referalElement = root.addElement( "referal" );
+                    referalElement.addText( ldapUrl );
+                }
+            }
+        }
+
+        return root;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDiagnosticMessage()
+    {
+        return result.getDiagnosticMessage();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDiagnosticMessage( String diagnosticMessage )
+    {
+        result.setDiagnosticMessage( diagnosticMessage );
+    }
+
+
+    /**
+     * Get the matched Dn
+     * 
+     * @return Returns the matchedDN.
+     */
+    public Dn getMatchedDn()
+    {
+        return result.getMatchedDn();
+    }
+
+
+    /**
+     * Set the Matched Dn
+     * 
+     * @param matchedDn The matchedDn to set.
+     */
+    public void setMatchedDn( Dn matchedDn )
+    {
+        result.setMatchedDn( matchedDn );
+    }
+
+
+    /**
+     * Get the referrals
+     * 
+     * @return Returns the referrals.
+     */
+    public List<String> getReferrals()
+    {
+        return ( List<String> ) result.getReferral().getLdapUrls();
+    }
+
+
+    /**
+     * Add a referral
+     * 
+     * @param referral The referral to add.
+     */
+    public void addReferral( LdapUrl referral )
+    {
+        result.getReferral().addLdapUrl( referral.toString() );
+    }
+
+
+    /**
+     * Get the result code
+     * 
+     * @return Returns the resultCode.
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return result.getResultCode();
+    }
+
+
+    /**
+     * Set the result code
+     * 
+     * @param resultCode The resultCode to set.
+     */
+    public void setResultCode( ResultCodeEnum resultCode )
+    {
+        result.setResultCode( resultCode );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapResult getDecorated()
+    {
+        return result;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isReferral()
+    {
+        return getDecorated().isReferral();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Referral getReferral()
+    {
+        return getDecorated().getReferral();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReferral( Referral referral )
+    {
+        getDecorated().setReferral( referral );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDefaultSuccess()
+    {
+        return false;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ModDNResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ModDNResponseDsml.java
new file mode 100644
index 0000000..4bfca99
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ModDNResponseDsml.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for ModDNResponse
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModDNResponseDsml extends AbstractResultResponseDsml<ModifyDnResponse>
+    implements ModifyDnResponse
+{
+    private static final String MOD_DN_RESPONSE_TAG = "modDNResponse";
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ModDNResponseDsml.
+     */
+    public ModDNResponseDsml( LdapApiService codec )
+    {
+        super( codec, new ModifyDnResponseImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ModDNResponseDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public ModDNResponseDsml( LdapApiService codec, ModifyDnResponse ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( MOD_DN_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( MOD_DN_RESPONSE_TAG );
+        }
+
+        LdapResultDsml ldapResultDsml = new LdapResultDsml( getCodecService(),
+            getDecorated().getLdapResult(), getDecorated() );
+        ldapResultDsml.toDsml( element );
+        return element;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ModifyResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ModifyResponseDsml.java
new file mode 100644
index 0000000..7f4bec2
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/ModifyResponseDsml.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for ModifyResponse
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyResponseDsml extends AbstractResultResponseDsml<ModifyResponse>
+    implements ModifyResponse
+{
+    private static final String MODIFY_RESPONSE_TAG = "modifyResponse";
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ModifyResponseDsml.
+     */
+    public ModifyResponseDsml( LdapApiService codec )
+    {
+        super( codec, new ModifyResponseImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of ModifyResponseDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public ModifyResponseDsml( LdapApiService codec, ModifyResponse ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( MODIFY_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( MODIFY_RESPONSE_TAG );
+        }
+
+        LdapResultDsml ldapResultDsml = new LdapResultDsml( getCodecService(),
+            getDecorated().getLdapResult(), getDecorated() );
+        ldapResultDsml.toDsml( element );
+        return element;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResponse.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResponse.java
new file mode 100644
index 0000000..8d1adab
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResponse.java
@@ -0,0 +1,214 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.message.AbstractResponse;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+
+
+/**
+ * This class represents the DSML Search Response
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResponse extends AbstractResponse
+{
+    /** The List of contained Search Result Entries */
+    private List<SearchResultEntryDsml> searchResultEntryList = new ArrayList<SearchResultEntryDsml>();
+
+    /** The List of contained Search Result References */
+    private List<SearchResultReferenceDsml> searchResultReferenceList = new ArrayList<SearchResultReferenceDsml>();
+
+    /** The Search Result Done object */
+    private SearchResultDoneDsml searchResultDone;
+
+
+    /**
+     * Creates a new instance of SearchResponse.
+     */
+    public SearchResponse()
+    {
+        super( -1, null );
+    }
+
+
+    /**
+     * Creates a new instance of SearchResponse.
+     *
+     * @param messageId the response eliciting this Request
+     */
+    public SearchResponse( int messageId )
+    {
+        super( messageId, null );
+    }
+
+
+    /**
+     * Adds a Search Result Entry
+     *
+     * @param searchResultEntry
+     *      the Search Result Entry to add
+     * @return
+     *      true (as per the general contract of the Collection.add method)
+     */
+    public boolean addSearchResultEntry( SearchResultEntryDsml searchResultEntry )
+    {
+        return searchResultEntryList.add( searchResultEntry );
+    }
+
+
+    /**
+     * Removes a Search Result Entry
+     *
+     * @param searchResultEntry
+     *      the Search Result Entry to remove
+     * @return
+     *      true (as per the general contract of the Collection.remove method)
+     */
+    public boolean removeSearchResultEntry( SearchResultEntryDsml searchResultEntry )
+    {
+        return searchResultEntryList.remove( searchResultEntry );
+    }
+
+
+    /**
+     * Gets the Current Search Result Entry
+     * 
+     * @return
+     *      the current Searche Result Entry
+     */
+    public SearchResultEntryDsml getCurrentSearchResultEntry()
+    {
+        if ( searchResultEntryList.size() > 0 )
+        {
+            return searchResultEntryList.get( searchResultEntryList.size() - 1 );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Gets the Search Result Entry List
+     *
+     * @return
+     *      the Search Result Entry List
+     */
+    public List<SearchResultEntryDsml> getSearchResultEntryList()
+    {
+        return searchResultEntryList;
+    }
+
+
+    /**
+     * Adds a Search Result Reference
+     *
+     * @param searchResultReference
+     *      the Search Result Reference to add
+     * @return
+     *      true (as per the general contract of the Collection.add method)
+     */
+    public boolean addSearchResultReference( SearchResultReferenceDsml searchResultReference )
+    {
+        return searchResultReferenceList.add( searchResultReference );
+    }
+
+
+    /**
+     * Removes a Search Result Reference
+     *
+     * @param searchResultReference
+     *      the Search Result Reference to remove
+     * @return
+     *      true (as per the general contract of the Collection.remove method)
+     */
+    public boolean removeSearchResultReference( SearchResultReferenceDsml searchResultReference )
+    {
+        return searchResultReferenceList.remove( searchResultReference );
+    }
+
+
+    /**
+     * Gets the current Search Result Reference
+     *
+     * @return
+     *      the current Search Result Reference
+     */
+    public SearchResultReferenceDsml getCurrentSearchResultReference()
+    {
+        if ( searchResultReferenceList.size() > 0 )
+        {
+            return searchResultReferenceList.get( searchResultReferenceList.size() - 1 );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Gets the Search Result Reference List
+     *
+     * @return
+     *      the Search Result Reference List
+     */
+    public List<SearchResultReferenceDsml> getSearchResultReferenceList()
+    {
+        return searchResultReferenceList;
+    }
+
+
+    /**
+     * Gets the Search Result Entry
+     * 
+     * @return
+     *      the Search Result Entry
+     */
+    public SearchResultDoneDsml getSearchResultDone()
+    {
+        return searchResultDone;
+    }
+
+
+    /**
+     * Sets the Search Result Entry
+     *
+     * @param searchResultDone
+     *      the Search Result Entry to set
+     */
+    public void setSearchResultDone( SearchResultDoneDsml searchResultDone )
+    {
+        this.searchResultDone = searchResultDone;
+    }
+
+
+    @Override
+    public MessageTypeEnum getType()
+    {
+        return null;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResponseDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResponseDsml.java
new file mode 100644
index 0000000..3609fbf
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResponseDsml.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * This class represents the Search Response Dsml Container. 
+ * It is used to store Search Responses (Search Result Entry, 
+ * Search Result Reference and SearchResultDone).
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResponseDsml extends AbstractResponseDsml<Response>
+{
+    private static final String SEARCH_RESPONSE_TAG = "searchResponse";
+
+    /** The responses */
+    private List<DsmlDecorator<? extends Response>> responses =
+        new ArrayList<DsmlDecorator<? extends Response>>();
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResponseDsml.
+     */
+    public SearchResponseDsml( LdapApiService codec )
+    {
+        super( codec, new SearchResponse() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResponseDsml.
+     *
+     * @param response the LDAP response message to decorate
+     */
+    public SearchResponseDsml( LdapApiService codec, Message response )
+    {
+        super( codec, ( Response ) response );
+    }
+
+
+    /**
+     * Adds a response.
+     *
+     * @param response
+     *      the response to add
+     * @return
+     *      true (as per the general contract of the Collection.add method).
+     */
+    public boolean addResponse( DsmlDecorator<? extends Response> response )
+    {
+        if ( response instanceof SearchResultEntry )
+        {
+            ( ( SearchResponse ) getDecorated() ).addSearchResultEntry(
+                ( SearchResultEntryDsml ) response );
+        }
+        else if ( response instanceof SearchResultReference )
+        {
+            ( ( SearchResponse ) getDecorated() ).addSearchResultReference(
+                ( SearchResultReferenceDsml ) response );
+        }
+        else if ( response instanceof SearchResultDone )
+        {
+            ( ( SearchResponse ) getDecorated() ).setSearchResultDone(
+                ( SearchResultDoneDsml ) response );
+        }
+        else
+        {
+            throw new IllegalArgumentException( "Unidentified search resp type" );
+        }
+
+        return responses.add( response );
+    }
+
+
+    /**
+     * Removes a response.
+     *
+     * @param response
+     *      the response to remove
+     * @return
+     *      true if this list contained the specified element.
+     */
+    public boolean removeResponse( DsmlDecorator<? extends Response> response )
+    {
+        if ( response instanceof SearchResultEntry )
+        {
+            ( ( SearchResponse ) getDecorated() ).removeSearchResultEntry(
+                ( SearchResultEntryDsml ) response );
+        }
+        else if ( response instanceof SearchResultReference )
+        {
+            ( ( SearchResponse ) getDecorated() ).removeSearchResultReference(
+                ( SearchResultReferenceDsml ) response );
+        }
+        else if ( response instanceof SearchResultDone )
+        {
+            if ( response.equals( ( ( SearchResponse ) getDecorated() ).getSearchResultDone() ) )
+            {
+                ( ( SearchResponse ) getDecorated() ).setSearchResultDone( null );
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException( "Unidentified search resp type" );
+        }
+
+        return responses.remove( response );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( SEARCH_RESPONSE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( SEARCH_RESPONSE_TAG );
+        }
+
+        // RequestID
+        if ( getDecorated() != null )
+        {
+            int requestID = getDecorated().getMessageId();
+            if ( requestID > 0 )
+            {
+                element.addAttribute( "requestID", "" + requestID );
+            }
+        }
+
+        for ( DsmlDecorator<? extends Response> response : responses )
+        {
+            response.toDsml( element );
+        }
+
+        return element;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultDoneDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultDoneDsml.java
new file mode 100644
index 0000000..a70d356
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultDoneDsml.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchResultDoneImpl;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for SearchResultDone
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultDoneDsml extends AbstractResultResponseDsml<SearchResultDone>
+    implements SearchResultDone
+{
+    private static final String SEARCH_RESULT_DONE_TAG = "searchResultDone";
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResultDoneDsml.
+     */
+    public SearchResultDoneDsml( LdapApiService codec )
+    {
+        super( codec, new SearchResultDoneImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResultDoneDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public SearchResultDoneDsml( LdapApiService codec, SearchResultDone ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( SEARCH_RESULT_DONE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( SEARCH_RESULT_DONE_TAG );
+        }
+
+        LdapResultDsml ldapResultDsml =
+            new LdapResultDsml( getCodecService(), getDecorated().getLdapResult(), getDecorated() );
+        if ( ldapResultDsml != null )
+        {
+            ldapResultDsml.toDsml( element );
+        }
+
+        return element;
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultEntryDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultEntryDsml.java
new file mode 100644
index 0000000..c603d6e
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultEntryDsml.java
@@ -0,0 +1,223 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchResultEntryImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for SearchResultEntry
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultEntryDsml
+    extends AbstractResponseDsml<SearchResultEntry>
+    implements SearchResultEntry
+{
+
+    private static final String SEARCH_RESULT_ENTRY_TAG = "searchResultEntry";
+
+    /** The current attribute being processed */
+    private Attribute currentAttribute;
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResultEntryDsml.
+     */
+    public SearchResultEntryDsml( LdapApiService codec )
+    {
+        super( codec, new SearchResultEntryImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResultEntryDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public SearchResultEntryDsml( LdapApiService codec, SearchResultEntry ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    public Attribute getCurrentAttribute()
+    {
+        return currentAttribute;
+    }
+
+
+    /**
+     * Create a new attribute
+     * 
+     * @param type The attribute's type
+     */
+    public void addAttribute( String type ) throws LdapException
+    {
+        currentAttribute = new DefaultAttribute( type );
+
+        getDecorated().getEntry().put( currentAttribute );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The added value
+     */
+    public void addAttributeValue( Object value ) throws LdapException
+    {
+        if ( value instanceof String )
+        {
+            currentAttribute.add( ( String ) value );
+        }
+        else
+        {
+            currentAttribute.add( ( byte[] ) value );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( SEARCH_RESULT_ENTRY_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( SEARCH_RESULT_ENTRY_TAG );
+        }
+
+        SearchResultEntry searchResultEntry = ( SearchResultEntry ) getDecorated();
+        element.addAttribute( "dn", searchResultEntry.getObjectName().getName() );
+
+        Entry entry = searchResultEntry.getEntry();
+        for ( Attribute attribute : entry )
+        {
+
+            Element attributeElement = element.addElement( "attr" );
+            attributeElement.addAttribute( "name", attribute.getUpId() );
+
+            for ( Value<?> value : attribute )
+            {
+                if ( ParserUtils.needsBase64Encoding( value.getValue() ) )
+                {
+                    Namespace xsdNamespace = new Namespace( ParserUtils.XSD, ParserUtils.XML_SCHEMA_URI );
+                    Namespace xsiNamespace = new Namespace( ParserUtils.XSI, ParserUtils.XML_SCHEMA_INSTANCE_URI );
+                    Document doc = attributeElement.getDocument();
+
+                    if ( doc != null )
+                    {
+                        Element docRoot = doc.getRootElement();
+                        docRoot.add( xsdNamespace );
+                        docRoot.add( xsiNamespace );
+                    }
+
+                    Element valueElement = attributeElement.addElement( "value" ).addText(
+                        ParserUtils.base64Encode( value.getValue() ) );
+                    valueElement.addAttribute( new QName( "type", xsiNamespace ), ParserUtils.XSD + ":"
+                        + ParserUtils.BASE64BINARY );
+                }
+                else
+                {
+                    attributeElement.addElement( "value" ).addText( value.getString() );
+                }
+            }
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Get the entry Dn
+     * 
+     * @return Returns the objectName.
+     */
+    public Dn getObjectName()
+    {
+        return getDecorated().getObjectName();
+    }
+
+
+    /**
+     * Set the entry Dn
+     * 
+     * @param objectName The objectName to set.
+     */
+    public void setObjectName( Dn objectName )
+    {
+        getDecorated().setObjectName( objectName );
+    }
+
+
+    /**
+     * Get the entry.
+     * 
+     * @return Returns the entry.
+     */
+    public Entry getEntry()
+    {
+        return getDecorated().getEntry();
+    }
+
+
+    /**
+     * Initialize the entry.
+     * 
+     * @param entry the entry
+     */
+    public void setEntry( Entry entry )
+    {
+        getDecorated().setEntry( entry );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultReferenceDsml.java b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultReferenceDsml.java
new file mode 100644
index 0000000..51f9a95
--- /dev/null
+++ b/trunk/dsml/parser/src/main/java/org/apache/directory/api/dsmlv2/response/SearchResultReferenceDsml.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.response;
+
+
+import java.util.Collection;
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.ldap.model.message.SearchResultReferenceImpl;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.dom4j.Element;
+import org.dom4j.tree.DefaultElement;
+
+
+/**
+ * DSML Decorator for SearchResultReference
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultReferenceDsml
+    extends AbstractResponseDsml<SearchResultReference>
+    implements SearchResultReference
+{
+    private static final String SEARCH_RESULT_REFERENCE_TAG = "searchResultReference";
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResultReferenceDsml.
+     */
+    public SearchResultReferenceDsml( LdapApiService codec )
+    {
+        super( codec, new SearchResultReferenceImpl() );
+    }
+
+
+    /**
+     * Creates a new getDecoratedMessage() of SearchResultReferenceDsml.
+     *
+     * @param ldapMessage
+     *      the message to decorate
+     */
+    public SearchResultReferenceDsml( LdapApiService codec, SearchResultReference ldapMessage )
+    {
+        super( codec, ldapMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Element toDsml( Element root )
+    {
+        Element element = null;
+
+        if ( root != null )
+        {
+            element = root.addElement( SEARCH_RESULT_REFERENCE_TAG );
+        }
+        else
+        {
+            element = new DefaultElement( SEARCH_RESULT_REFERENCE_TAG );
+        }
+
+        // Adding References
+        for ( String url : getDecorated().getReferral().getLdapUrls() )
+        {
+            element.addElement( "ref" ).addText( url );
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Add a new reference to the list.
+     * 
+     * @param searchResultReference The search result reference
+     */
+    public void addSearchResultReference( LdapUrl searchResultReference )
+    {
+        getDecorated().getReferral().addLdapUrl( searchResultReference.toString() );
+    }
+
+
+    /**
+     * Get the list of references
+     * 
+     * @return An ArrayList of SearchResultReferences
+     */
+    public Collection<String> getSearchResultReferences()
+    {
+        return getDecorated().getReferral().getLdapUrls();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Referral getReferral()
+    {
+        return getDecorated().getReferral();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReferral( Referral referral )
+    {
+        getDecorated().setReferral( referral );
+    }
+}
diff --git a/trunk/dsml/parser/src/main/resources/org/apache/directory/shared/dsmlv2/DSMLv2.xslt b/trunk/dsml/parser/src/main/resources/org/apache/directory/shared/dsmlv2/DSMLv2.xslt
new file mode 100644
index 0000000..f017c72
--- /dev/null
+++ b/trunk/dsml/parser/src/main/resources/org/apache/directory/shared/dsmlv2/DSMLv2.xslt
@@ -0,0 +1,48 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<xsl:stylesheet version="1.0" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output method="xml"/>
+   <xsl:param name="indent-increment" select="'   '" />
+
+   <xsl:template match="*">
+      <xsl:param name="indent" select="'&#xA;'"/>
+
+      <xsl:value-of select="$indent"/>
+      <xsl:copy>
+        <xsl:copy-of select="@*" />
+        <xsl:apply-templates>
+          <xsl:with-param name="indent"
+               select="concat($indent, $indent-increment)"/>
+        </xsl:apply-templates>
+        <xsl:if test="*">
+          <xsl:value-of select="$indent"/>
+        </xsl:if>
+      </xsl:copy>
+   </xsl:template>
+
+   <xsl:template match="comment()|processing-instruction()">
+      <xsl:copy />
+   </xsl:template>
+
+   <!-- WARNING: this is dangerous. Handle with care -->
+   <!-- <xsl:template match="text()[normalize-space(.)='']"/> -->
+
+</xsl:stylesheet>
diff --git a/trunk/dsml/parser/src/site/site.xml b/trunk/dsml/parser/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/dsml/parser/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AbstractResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AbstractResponseTest.java
new file mode 100644
index 0000000..d8abb43
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AbstractResponseTest.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.dsmlv2;
+
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * This class had to be used to create a Response TestCase
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractResponseTest extends AbstractTest
+{
+    /**
+     * Asserts that parsing throws a correct XmlPullParserException due to an incorrect file
+     *
+     * @param testClass
+     *      the Class of the TestCase
+     * @param filename
+     *      the path of the xml file to parse 
+     */
+    public void testParsingFail( Class<?> testClass, String filename )
+    {
+        try
+        {
+            Dsmlv2ResponseParser parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( testClass.getResource( filename ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( XmlPullParserException e )
+        {
+            assertTrue( e.getMessage(), true );
+            return;
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+        fail();
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AbstractTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AbstractTest.java
new file mode 100644
index 0000000..49dad1f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AbstractTest.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.dsmlv2;
+
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.xmlpull.v1.XmlPullParserException;
+
+
+/**
+ * This class had to be used to create a Request TestCase
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractTest
+{
+    /** The LDAP encoder decoder service */
+    private LdapApiService codec = LdapApiServiceFactory.getSingleton();
+
+    private Dsmlv2Grammar grammar = new Dsmlv2Grammar();
+
+
+    public Dsmlv2Parser newParser() throws Exception
+    {
+        return new Dsmlv2Parser( grammar );
+    }
+
+
+    public LdapApiService getCodec()
+    {
+        return codec;
+    }
+
+
+    /**
+     * Asserts that parsing throws a correct XmlPullParserException due to an incorrect file
+     *
+     * @param testClass
+     *      the Class of the TestCase
+     * @param filename
+     *      the path of the xml file to parse 
+     */
+    public void testParsingFail( Class<?> testClass, String filename )
+    {
+        try
+        {
+            Dsmlv2Parser parser = new Dsmlv2Parser( grammar );
+
+            parser.setInput( testClass.getResource( filename ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( XmlPullParserException e )
+        {
+            assertTrue( e.getMessage(), true );
+            return;
+        }
+        catch ( IllegalStateException e )
+        {
+            assertTrue( e.getMessage(), true );
+            return;
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+        fail();
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AllTests.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AllTests.java
new file mode 100644
index 0000000..ce40700
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/AllTests.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.dsmlv2;
+
+
+import org.apache.directory.api.dsmlv2.abandonRequest.AbandonRequestTest;
+import org.apache.directory.api.dsmlv2.addRequest.AddRequestTest;
+import org.apache.directory.api.dsmlv2.addResponse.AddResponseTest;
+import org.apache.directory.api.dsmlv2.authRequest.AuthRequestTest;
+import org.apache.directory.api.dsmlv2.authResponse.AuthResponseTest;
+import org.apache.directory.api.dsmlv2.batchRequest.BatchRequestTest;
+import org.apache.directory.api.dsmlv2.batchResponse.BatchResponseTest;
+import org.apache.directory.api.dsmlv2.compareRequest.CompareRequestTest;
+import org.apache.directory.api.dsmlv2.compareResponse.CompareResponseTest;
+import org.apache.directory.api.dsmlv2.delRequest.DelRequestTest;
+import org.apache.directory.api.dsmlv2.delResponse.DelResponseTest;
+import org.apache.directory.api.dsmlv2.errorResponse.ErrorResponseTest;
+import org.apache.directory.api.dsmlv2.extendedRequest.ExtendedRequestTest;
+import org.apache.directory.api.dsmlv2.extendedResponse.ExtendedResponseTest;
+import org.apache.directory.api.dsmlv2.modDNRequest.ModifyDNRequestTest;
+import org.apache.directory.api.dsmlv2.modDNResponse.ModifyDNResponseTest;
+import org.apache.directory.api.dsmlv2.modifyRequest.ModifyRequestTest;
+import org.apache.directory.api.dsmlv2.modifyResponse.ModifyResponseTest;
+import org.apache.directory.api.dsmlv2.searchRequest.SearchRequestTest;
+import org.apache.directory.api.dsmlv2.searchResponse.SearchResponseTest;
+import org.apache.directory.api.dsmlv2.searchResponse.searchResultDone.SearchResultDoneTest;
+import org.apache.directory.api.dsmlv2.searchResponse.searchResultEntry.SearchResultEntryTest;
+import org.apache.directory.api.dsmlv2.searchResponse.searchResultReference.SearchResultReferenceTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+import com.mycila.junit.concurrent.ConcurrentSuite;
+
+
+/**
+ * This is the complete Test Suite for DSMLv2 Parser (Request and Response)
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentSuite.class)
+@Suite.SuiteClasses(
+    {
+        AbandonRequestTest.class,
+        AddRequestTest.class,
+        AddResponseTest.class,
+        AuthRequestTest.class,
+        AuthResponseTest.class,
+        BatchRequestTest.class,
+        BatchResponseTest.class,
+        CompareRequestTest.class,
+        CompareResponseTest.class,
+        DelRequestTest.class,
+        DelResponseTest.class,
+        ErrorResponseTest.class,
+        ExtendedRequestTest.class,
+        ExtendedResponseTest.class,
+        ModifyDNRequestTest.class,
+        ModifyDNResponseTest.class,
+        ModifyRequestTest.class,
+        ModifyResponseTest.class,
+        SearchRequestTest.class,
+        SearchResponseTest.class,
+        SearchResultDoneTest.class,
+        SearchResultEntryTest.class,
+        SearchResultReferenceTest.class
+})
+public class AllTests
+{
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/ParserUtilsTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/ParserUtilsTest.java
new file mode 100644
index 0000000..2398c0d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/ParserUtilsTest.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.dsmlv2.batchRequest.BatchRequestTest;
+import org.apache.directory.api.dsmlv2.batchResponse.BatchResponseTest;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
+import org.junit.Test;
+
+
+/**
+ * Tests for ParserUtils.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ParserUtilsTest extends AbstractTest
+{
+
+    private static final Pattern NEW_LINE_PATTERN = Pattern.compile( "\n", Pattern.DOTALL );
+    private static final Pattern INDENTION_PATTERN = Pattern.compile( "   ", Pattern.DOTALL );
+
+
+    /**
+     * Test for DIRAPI-238: DSML pretty print does not work, prints error.
+     * 
+     * Indirect test of ParserUtils.styleDocument() via BatchRequestDsml.toDsml().
+     */
+    @Test
+    public void testStyleDocumentWithBatchRequest() throws Exception
+    {
+        Dsmlv2Parser parser = newParser();
+        parser.setInput( BatchRequestTest.class.getResource( "request_with_2_AddRequest.xml" ).openStream(), "UTF-8" );
+        parser.parse();
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        String dsml = batchRequest.toDsml();
+        assertNotNull( dsml );
+
+        assertEquals( "Pretty printed DSML should contain newlines", 20, countNewlines( dsml ) );
+        assertEquals( "Pretty printed DSML should contain indention", 38, countIndention( dsml ) );
+    }
+
+
+    /**
+     * Test for DIRAPI-238: DSML pretty print does not work, prints error.
+     * 
+     * Indirect test of ParserUtils.styleDocument() via BatchResponseDsml.toDsml() 
+     */
+    @Test
+    public void testStyleDocumentWithBatchResponse() throws Exception
+    {
+        Dsmlv2ResponseParser parser = new Dsmlv2ResponseParser( getCodec() );
+        parser.setInput( BatchResponseTest.class.getResource( "response_with_2_SearchResponse.xml" ).openStream(),
+            "UTF-8" );
+        parser.parse();
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        String dsml = batchResponse.toDsml();
+        assertNotNull( dsml );
+
+        assertEquals( "Pretty printed DSML should contain newlines", 12, countNewlines( dsml ) );
+        assertEquals( "Pretty printed DSML should contain indention", 18, countIndention( dsml ) );
+    }
+
+
+    private int countNewlines( String dsml )
+    {
+        return count( NEW_LINE_PATTERN, dsml );
+    }
+
+
+    private int countIndention( String dsml )
+    {
+        return count( INDENTION_PATTERN, dsml );
+    }
+
+
+    private int count( Pattern p, String dsml )
+    {
+        Matcher matcher = p.matcher( dsml );
+        int count = 0;
+        while ( matcher.find() )
+        {
+            count++;
+        }
+        return count;
+    }
+
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/abandonRequest/AbandonRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/abandonRequest/AbandonRequestTest.java
new file mode 100644
index 0000000..f185e73
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/abandonRequest/AbandonRequestTest.java
@@ -0,0 +1,347 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.abandonRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Abandon Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AbandonRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request without the abandonID attribute
+     */
+    @Test
+    public void testRequestWithoutAbandonId()
+    {
+        testParsingFail( AbandonRequestTest.class, "request_without_abandonID_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the abandonID attribute
+     */
+    @Test
+    public void testRequestWithAbandonId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AbandonRequestTest.class.getResource( "request_with_abandonID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AbandonRequest abandonRequest = ( AbandonRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 123, abandonRequest.getAbandoned() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( AbandonRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AbandonRequestTest.class.getResource( "request_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AbandonRequest abandonRequest = ( AbandonRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, abandonRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+
+        try
+        {
+            parser = newParser();
+
+            parser
+                .setInput( AbandonRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AbandonRequest abandonRequest = ( AbandonRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 1, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AbandonRequestTest.class.getResource( "request_with_1_control_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AbandonRequest abandonRequest = ( AbandonRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 1, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AbandonRequestTest.class.getResource( "request_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AbandonRequest abandonRequest = ( AbandonRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 1, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AbandonRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AbandonRequest abandonRequest = ( AbandonRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 2, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AbandonRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AbandonRequest abandonRequest = ( AbandonRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 3, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( AbandonRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+    
+    
+    /**
+     * Test parsing of a request without the abandonID attribute with a value of 0
+     */
+    @Test
+    public void testRequestWithoutAbandonId0()
+    {
+        Dsmlv2Parser parser = null;
+
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AbandonRequestTest.class.getResource( "request_with_0_abandonID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+        assertEquals( 0, batchRequest.getRequestID() );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/addRequest/AddRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/addRequest/AddRequestTest.java
new file mode 100644
index 0000000..d88c828
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/addRequest/AddRequestTest.java
@@ -0,0 +1,564 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.addRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Add Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AddRequestTest extends AbstractTest
+{
+
+    /**
+     * Test parsing of a request without the dn attribute
+     */
+    @Test
+    public void testRequestWithoutDn()
+    {
+        testParsingFail( AddRequestTest.class, "request_without_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the dn attribute
+     */
+    @Test
+    public void testRequestWithDn()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_dn_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", addRequest.getEntryDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_requestID_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, addRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdEquals0()
+    {
+        testParsingFail( AddRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = addRequest.getControls();
+
+        assertEquals( 1, addRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                AddRequestTest.class.getResource( "request_with_1_control_base64_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = addRequest.getControls();
+
+        assertEquals( 1, addRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_1_control_empty_value.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = addRequest.getControls();
+
+        assertEquals( 1, addRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = addRequest.getControls();
+
+        assertEquals( 2, addRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = addRequest.getControls();
+
+        assertEquals( 3, addRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attr elements with value
+     */
+    @Test
+    public void testRequestWith1AttrWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_1_attr_without_value.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Entry entry = addRequest.getEntry();
+        assertEquals( 1, entry.size() );
+
+        // Getting the Attribute
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "objectclass", attribute.getUpId() );
+
+        // Getting the Value
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertFalse( valueIterator.hasNext() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attr elements with empty value
+     */
+    @Test
+    public void testRequestWith1AttrEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_1_attr_empty_value.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Entry entry = addRequest.getEntry();
+        assertEquals( 1, entry.size() );
+
+        // Getting the Attribute
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "objectclass", attribute.getUpId() );
+
+        // Getting the Value
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertFalse( valueIterator.hasNext() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attr elements with value
+     */
+    @Test
+    public void testRequestWith1AttrWithValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_1_attr_with_value.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Entry entry = addRequest.getEntry();
+        assertEquals( 1, entry.size() );
+
+        // Getting the Attribute
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "objectclass", attribute.getUpId() );
+
+        // Getting the Value
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertEquals( "top", value.getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attr elements with value
+     */
+    @Test
+    public void testRequestWith1AttrWithBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_1_attr_with_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Entry entry = addRequest.getEntry();
+        assertEquals( 1, entry.size() );
+
+        // Getting the Attribute
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "objectclass", attribute.getUpId() );
+
+        // Getting the Value
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertFalse( value.isHumanReadable() );
+        assertEquals( "DSMLv2.0 rocks!!", value.getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 Attr elements with value
+     */
+    @Test
+    public void testRequestWith2AttrWithValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_2_attr_with_value.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Entry entry = addRequest.getEntry();
+        assertEquals( 1, entry.size() );
+
+        // Getting the Attribute
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "objectclass", attribute.getUpId() );
+
+        // Getting the Value
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertEquals( "top", value.getString() );
+        assertTrue( valueIterator.hasNext() );
+        value = valueIterator.next();
+        assertEquals( "person", value.getString() );
+        assertFalse( valueIterator.hasNext() );
+    }
+
+
+    /**
+     * Test parsing of a request with 1 Attr element without attribute value
+     */
+    @Test
+    public void testRequestWith1AttrWithoutNameAttribute()
+    {
+        testParsingFail( AddRequestTest.class, "request_with_1_attr_without_name_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with 1 Attr element with 2 Values
+     */
+    @Test
+    public void testRequestWith1AttrWith2Values()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AddRequestTest.class.getResource( "request_with_1_attr_with_2_values.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddRequest addRequest = ( AddRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Entry entry = addRequest.getEntry();
+        assertEquals( 1, entry.size() );
+
+        // Getting the Attribute
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "objectclass", attribute.getUpId() );
+
+        // Getting the Value
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertEquals( "top", value.getString() );
+        assertTrue( valueIterator.hasNext() );
+        value = valueIterator.next();
+        assertEquals( "person", value.getString() );
+        assertFalse( valueIterator.hasNext() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( AddRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/addResponse/AddResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/addResponse/AddResponseTest.java
new file mode 100644
index 0000000..3d31834
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/addResponse/AddResponseTest.java
@@ -0,0 +1,529 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.addResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Add Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AddResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_requestID_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, addResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( AddResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = addResponse.getControls();
+
+        assertEquals( 1, addResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with emptyValue
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = addResponse.getControls();
+
+        assertEquals( 1, addResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = addResponse.getControls();
+
+        assertEquals( 2, addResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = addResponse.getControls();
+
+        assertEquals( 3, addResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( AddResponseTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( AddResponseTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser
+                .setInput( AddResponseTest.class.getResource( "response_with_result_code.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_empty_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_1_referral.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        assertTrue( referrals.contains( "ldap://www.apache.org/" ) );
+    }
+
+
+    /**
+     * Test parsing of a response with an empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_1_empty_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser
+                .setInput( AddResponseTest.class.getResource( "response_with_2_referrals.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        assertTrue( referrals.contains( "ldap://www.apache.org/" ) );
+        assertTrue( referrals.contains( "ldap://www.apple.com/" ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AddResponseTest.class.getResource( "response_with_matchedDN_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        AddResponse addResponse = ( AddResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = addResponse.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( AddResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( AddResponseTest.class, "response_with_wrong_descr.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/authRequest/AuthRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/authRequest/AuthRequestTest.java
new file mode 100644
index 0000000..5145dea
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/authRequest/AuthRequestTest.java
@@ -0,0 +1,311 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.authRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Auth Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AuthRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request without the principal attribute
+     */
+    @Test
+    public void testRequestWithoutPrincipal()
+    {
+        testParsingFail( AuthRequestTest.class, "request_without_principal_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the principal attribute
+     */
+    @Test
+    public void testRequestWithPrincipal()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AuthRequestTest.class.getResource( "request_with_principal_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindRequest bindRequest = ( BindRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "CN=Bob Rush,OU=Dev,DC=Example,DC=COM", bindRequest.getName() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AuthRequestTest.class.getResource( "request_with_requestID_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindRequest abandonRequest = ( BindRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, abandonRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( AuthRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AuthRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindRequest abandonRequest = ( BindRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 1, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AuthRequestTest.class.getResource( "request_with_1_control_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindRequest abandonRequest = ( BindRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 1, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                AuthRequestTest.class.getResource( "request_with_1_control_empty_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindRequest abandonRequest = ( BindRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 1, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AuthRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindRequest abandonRequest = ( BindRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 2, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( AuthRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindRequest abandonRequest = ( BindRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 3, abandonRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( AuthRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/authResponse/AuthResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/authResponse/AuthResponseTest.java
new file mode 100644
index 0000000..d157406
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/authResponse/AuthResponseTest.java
@@ -0,0 +1,552 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.authResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Auth Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AuthResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                AuthResponseTest.class.getResource( "response_with_requestID_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, bindResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( AuthResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = bindResponse.getControls();
+
+        assertEquals( 1, bindResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = bindResponse.getControls();
+
+        assertEquals( 1, bindResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser
+                .setInput( AuthResponseTest.class.getResource( "response_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = bindResponse.getControls();
+
+        assertEquals( 2, bindResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = bindResponse.getControls();
+
+        assertEquals( 3, bindResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( AuthResponseTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( AuthResponseTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_result_code.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with Empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                AuthResponseTest.class.getResource( "response_with_empty_error_message.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser
+                .setInput( AuthResponseTest.class.getResource( "response_with_1_referral.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with an empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_1_empty_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_2_referrals.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apple.com/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( AuthResponseTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                AuthResponseTest.class.getResource( "response_with_matchedDN_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BindResponse bindResponse = ( BindResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = bindResponse.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( AuthResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( AuthResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/batchRequest/BatchRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/batchRequest/BatchRequestTest.java
new file mode 100644
index 0000000..d8e50d1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/batchRequest/BatchRequestTest.java
@@ -0,0 +1,792 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.batchRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.Request;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Compare Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BatchRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a Request with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_requestID_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1234567890, batchRequest.getRequestID() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( BatchRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a Request with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWith0Request()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_requestID_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 0, batchRequest.getRequests().size() );
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 AuthRequest
+     */
+    @Test
+    public void testResponseWith1AuthRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_AuthRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof BindRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 AddRequest
+     */
+    @Test
+    public void testResponseWith1AddRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_AddRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof AddRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 CompareRequest
+     */
+    @Test
+    public void testResponseWith1CompareRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_CompareRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof CompareRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 AbandonRequest
+     */
+    @Test
+    public void testResponseWith1AbandonRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_AbandonRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof AbandonRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 DelRequest
+     */
+    @Test
+    public void testResponseWith1DelRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_DelRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof DeleteRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 ExtendedRequest
+     */
+    @Test
+    public void testResponseWith1ExtendedRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_ExtendedRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof ExtendedRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 ModDNRequest
+     */
+    @Test
+    public void testResponseWith1ModDNRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_ModDNRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof ModifyDnRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 ModifyRequest
+     */
+    @Test
+    public void testResponseWith1ModifyRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_ModifyRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof ModifyRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 SearchRequest
+     */
+    @Test
+    public void testResponseWith1SearchRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_SearchRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 1, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof SearchRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 AddRequest
+     */
+    @Test
+    public void testResponseWith2AddRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_AddRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof AddRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 CompareRequest
+     */
+    @Test
+    public void testResponseWith2CompareRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_CompareRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof CompareRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 AbandonRequest
+     */
+    @Test
+    public void testResponseWith2AbandonRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_AbandonRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof AbandonRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 DelRequest
+     */
+    @Test
+    public void testResponseWith2DelRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_DelRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof DeleteRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 ExtendedRequest
+     */
+    @Test
+    public void testResponseWith2ExtendedRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_ExtendedRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof ExtendedRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 ModDNRequest
+     */
+    @Test
+    public void testResponseWith2ModDNRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_ModDNRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof ModifyDnRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 ModifyRequest
+     */
+    @Test
+    public void testResponseWith2ModifyRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_ModifyRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof ModifyRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 2 SearchRequest
+     */
+    @Test
+    public void testResponseWith2SearchRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_2_SearchRequest.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        assertEquals( 2, batchRequest.getRequests().size() );
+
+        if ( batchRequest.getCurrentRequest() instanceof SearchRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Request with 1 AuthRequest and 1 AddRequest
+     */
+    @Test
+    public void testResponseWith1AuthRequestAnd1AddRequest()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( BatchRequestTest.class.getResource( "request_with_1_AuthRequest_1_AddRequest.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchRequestDsml batchRequest = parser.getBatchRequest();
+
+        List<DsmlDecorator<? extends Request>> requests =
+            batchRequest.getRequests();
+
+        assertEquals( 2, requests.size() );
+
+        if ( requests.get( 0 ) instanceof BindRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+
+        if ( requests.get( 1 ) instanceof AddRequest )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a request with 1 wrong placed AuthRequest
+     */
+    @Test
+    public void testRequestWithWrongPlacedAuthRequest()
+    {
+        testParsingFail( BatchRequestTest.class, "request_with_wrong_placed_AuthRequest.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/batchResponse/BatchResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/batchResponse/BatchResponseTest.java
new file mode 100644
index 0000000..2f76952
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/batchResponse/BatchResponseTest.java
@@ -0,0 +1,804 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.batchResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlDecorator;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
+import org.apache.directory.api.dsmlv2.response.ErrorResponse;
+import org.apache.directory.api.dsmlv2.response.SearchResponse;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Compare Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BatchResponseTest extends AbstractResponseTest
+{
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1234567890, batchResponse.getRequestID() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( BatchResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a Response with 0 Response
+     */
+    @Test
+    public void testResponseWith0Reponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_0_response.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 0, batchResponse.getResponses().size() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 AddResponse
+     */
+    @Test
+    public void testResponseWith1AddResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_AddResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof AddResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 AuthResponse
+     */
+    @Test
+    public void testResponseWith1AuthResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_AuthResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof BindResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 CompareResponse
+     */
+    @Test
+    public void testResponseWith1CompareResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_CompareResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof CompareResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 DelResponse
+     */
+    @Test
+    public void testResponseWith1DelResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_DelResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof DeleteResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 ErrorResponse
+     */
+    @Test
+    public void testResponseWith1ErrorResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_ErrorResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ErrorResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 ExtendedResponse
+     */
+    @Test
+    public void testResponseWith1ExtendedResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                BatchResponseTest.class.getResource( "response_with_1_ExtendedResponse.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ExtendedResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 ModDNResponse
+     */
+    @Test
+    public void testResponseWith1ModDNResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_ModDNResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ModifyDnResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 ModifyResponse
+     */
+    @Test
+    public void testResponseWith1ModifyResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_ModifyResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ModifyResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 1 SearchResponse
+     */
+    @Test
+    public void testResponseWith1SearchResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_1_SearchResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 1, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response.getDecorated() instanceof SearchResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 AddResponse
+     */
+    @Test
+    public void testResponseWith2AddResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_AddResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof AddResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 AuthResponse
+     */
+    @Test
+    public void testResponseWith2AuthResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_AuthResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof BindResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 CompareResponse
+     */
+    @Test
+    public void testResponseWith2CompareResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_CompareResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof CompareResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 DelResponse
+     */
+    @Test
+    public void testResponseWith2DelResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_DelResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof DeleteResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 ErrorResponse
+     */
+    @Test
+    public void testResponseWith2ErrorResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_ErrorResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ErrorResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 ExtendedResponse
+     */
+    @Test
+    public void testResponseWith2ExtendedResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                BatchResponseTest.class.getResource( "response_with_2_ExtendedResponse.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ExtendedResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 ModDNResponse
+     */
+    @Test
+    public void testResponseWith2ModDNResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_ModDNResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ModifyDnResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 ModifyResponse
+     */
+    @Test
+    public void testResponseWith2ModifyResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_ModifyResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response instanceof ModifyResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with the 2 SearchResponse
+     */
+    @Test
+    public void testResponseWith2SearchResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( BatchResponseTest.class.getResource( "response_with_2_SearchResponse.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        BatchResponseDsml batchResponse = parser.getBatchResponse();
+
+        assertEquals( 2, batchResponse.getResponses().size() );
+
+        DsmlDecorator<? extends Response> response = batchResponse.getCurrentResponse();
+
+        if ( response.getDecorated() instanceof SearchResponse )
+        {
+            assertTrue( true );
+        }
+        else
+        {
+            fail();
+        }
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/compareRequest/CompareRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/compareRequest/CompareRequestTest.java
new file mode 100644
index 0000000..6566adc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/compareRequest/CompareRequestTest.java
@@ -0,0 +1,457 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.compareRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Compare Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CompareRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request without the dn attribute
+     */
+    @Test
+    public void testRequestWithoutDn()
+    {
+        testParsingFail( CompareRequestTest.class, "request_without_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the dn attribute
+     */
+    @Test
+    public void testRequestWithDn()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class.getResource( "request_with_dn_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", compareRequest.getName().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class.getResource( "request_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, compareRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( CompareRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser
+                .setInput( CompareRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = compareRequest.getControls();
+
+        assertEquals( 1, compareRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser
+                .setInput( CompareRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = compareRequest.getControls();
+
+        assertEquals( 1, compareRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class.getResource( "request_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = compareRequest.getControls();
+
+        assertEquals( 1, compareRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = compareRequest.getControls();
+
+        assertEquals( 2, compareRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = compareRequest.getControls();
+
+        assertEquals( 3, compareRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attr elements with value
+     */
+    @Test
+    public void testRequestWith1CompleteAssertion()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class.getResource( "request_with_1_complete_assertion.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", compareRequest.getName().getNormName() );
+
+        assertEquals( "sn", compareRequest.getAttributeId() );
+
+        assertEquals( "Johnson", compareRequest.getAssertionValue().getValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with a complete assertion with base64 value
+     */
+    @Test
+    public void testRequestWith1CompleteAssertionBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class
+                .getResource( "request_with_1_complete_assertion_base64_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", compareRequest.getName().getNormName() );
+
+        assertEquals( "sn", compareRequest.getAttributeId() );
+
+        assertEquals( "DSMLv2.0 rocks!!", new String( compareRequest.getAssertionValue().getBytes() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attr elements with empty value
+     */
+    @Test
+    public void testRequestWith1AssertionEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( CompareRequestTest.class.getResource( "request_with_1_assertion_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareRequest compareRequest = ( CompareRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", compareRequest.getName().getNormName() );
+
+        assertEquals( "sn", compareRequest.getAttributeId() );
+
+        assertNull( compareRequest.getAssertionValue() );
+    }
+
+
+    /**
+     * Test parsing of a request without the Assertion element
+     */
+    @Test
+    public void testRequestWithoutAssertion()
+    {
+        testParsingFail( CompareRequestTest.class, "request_without_assertion.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 complete Assertion element
+     */
+    @Test
+    public void testRequestWith2CompleteAssertions()
+    {
+        testParsingFail( CompareRequestTest.class, "request_with_2_complete_assertions.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with 1 Assertion element without the name attribute
+     */
+    @Test
+    public void testRequestWith1AssertionWithoutNameAttribute()
+    {
+        testParsingFail( CompareRequestTest.class, "request_with_1_assertion_without_name_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with 1 Assertion element without the Value element
+     */
+    @Test
+    public void testRequestWith1AssertionWithoutValue()
+    {
+        testParsingFail( CompareRequestTest.class, "request_with_1_assertion_without_value.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with 1 Assertion element with 2 Value elements
+     */
+    @Test
+    public void testRequestWith1AssertionWith2Value()
+    {
+        testParsingFail( CompareRequestTest.class, "request_with_1_assertion_with_2_values.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( CompareRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/compareResponse/CompareResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/compareResponse/CompareResponseTest.java
new file mode 100644
index 0000000..7740d0c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/compareResponse/CompareResponseTest.java
@@ -0,0 +1,553 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.compareResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Compare Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CompareResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, compareResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdbelow0()
+    {
+        testParsingFail( CompareResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = compareResponse.getControls();
+
+        assertEquals( 1, compareResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = compareResponse.getControls();
+
+        assertEquals( 1, compareResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = compareResponse.getControls();
+
+        assertEquals( 2, compareResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = compareResponse.getControls();
+
+        assertEquals( 3, compareResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( CompareResponseTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( CompareResponseTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_result_code.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_empty_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_1_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with an empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                CompareResponseTest.class.getResource( "response_with_1_empty_referral.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_2_referrals.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apple.com/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( CompareResponseTest.class.getResource( "response_with_matchedDN_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CompareResponse compareResponse = ( CompareResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = compareResponse.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( CompareResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( CompareResponseTest.class, "response_with_wrong_descr.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/delRequest/DelRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/delRequest/DelRequestTest.java
new file mode 100644
index 0000000..ce03c9e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/delRequest/DelRequestTest.java
@@ -0,0 +1,311 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.delRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Del Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DelRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request without the dn attribute
+     */
+    @Test
+    public void testRequestWithoutDn()
+    {
+        testParsingFail( DelRequestTest.class, "request_without_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the dn attribute
+     */
+    @Test
+    public void testRequestWithDn()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( DelRequestTest.class.getResource( "request_with_dn_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteRequest delRequest = ( DeleteRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", delRequest.getName().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( DelRequestTest.class.getResource( "request_with_requestID_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteRequest delRequest = ( DeleteRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, delRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( DelRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( DelRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteRequest delRequest = ( DeleteRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = delRequest.getControls();
+
+        assertEquals( 1, delRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                DelRequestTest.class.getResource( "request_with_1_control_base64_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteRequest delRequest = ( DeleteRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = delRequest.getControls();
+
+        assertEquals( 1, delRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( DelRequestTest.class.getResource( "request_with_1_control_empty_value.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteRequest delRequest = ( DeleteRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = delRequest.getControls();
+
+        assertEquals( 1, delRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( DelRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            fail( e.getMessage() );
+        }
+
+        DeleteRequest delRequest = ( DeleteRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = delRequest.getControls();
+
+        assertEquals( 2, delRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( DelRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteRequest delRequest = ( DeleteRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = delRequest.getControls();
+
+        assertEquals( 3, delRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( DelRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/delResponse/DelResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/delResponse/DelResponseTest.java
new file mode 100644
index 0000000..46914b9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/delResponse/DelResponseTest.java
@@ -0,0 +1,550 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.delResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Del Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DelResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_requestID_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, delResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( DelResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = delResponse.getControls();
+
+        assertEquals( 1, delResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlemptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = delResponse.getControls();
+
+        assertEquals( 1, delResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = delResponse.getControls();
+
+        assertEquals( 2, delResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = delResponse.getControls();
+
+        assertEquals( 3, delResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( DelResponseTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( DelResponseTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser
+                .setInput( DelResponseTest.class.getResource( "response_with_result_code.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_empty_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_1_referral.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with an empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_1_empty_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser
+                .setInput( DelResponseTest.class.getResource( "response_with_2_referrals.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apple.com/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( DelResponseTest.class.getResource( "response_with_matchedDN_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        DeleteResponse delResponse = ( DeleteResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = delResponse.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( DelResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( DelResponseTest.class, "response_with_wrong_descr.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/errorResponse/ErrorResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/errorResponse/ErrorResponseTest.java
new file mode 100644
index 0000000..1a10bf0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/errorResponse/ErrorResponseTest.java
@@ -0,0 +1,373 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.errorResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.dsmlv2.response.ErrorResponse;
+import org.apache.directory.api.dsmlv2.response.ErrorResponse.ErrorResponseType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests for the Error Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ErrorResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, errorResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( ErrorResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response without Type attribute
+     */
+    @Test
+    public void testResponseWithoutType()
+    {
+        testParsingFail( ErrorResponseTest.class, "response_without_type.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with type == notAttempted
+     */
+    @Test
+    public void testResponseWithTypeNotAttempted()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_notAttempted.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.NOT_ATTEMPTED, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type == couldNotConnect
+     */
+    @Test
+    public void testResponseWithTypeCouldNotConnect()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_couldNotConnect.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.COULD_NOT_CONNECT, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type == connectionClosed
+     */
+    @Test
+    public void testResponseWithTypeConnectionClosed()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_connectionClosed.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.CONNECTION_CLOSED, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type == malformedRequest
+     */
+    @Test
+    public void testResponseWithTypeMalformedRequest()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_malformedRequest.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.MALFORMED_REQUEST, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type == gatewayInternalError
+     */
+    @Test
+    public void testResponseWithTypeGatewayInternalError()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_gatewayInternalError.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.GATEWAY_INTERNAL_ERROR, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type == authenticationFailed
+     */
+    @Test
+    public void testResponseWithTypeAuthenticationFailed()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_authenticationFailed.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.AUTHENTICATION_FAILED, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type == unresolvableURI
+     */
+    @Test
+    public void testResponseWithTypeUnresolvableURI()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_unresolvableURI.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.UNRESOLVABLE_URI, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type == other
+     */
+    @Test
+    public void testResponseWithTypeOther()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_type_other.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( ErrorResponseType.OTHER, errorResponse.getErrorType() );
+    }
+
+
+    /**
+     * Test parsing of a response with type in error
+     */
+    @Test
+    public void testResponseWithTypeError()
+    {
+        testParsingFail( ErrorResponseTest.class, "response_with_type_inError.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Message
+     */
+    @Test
+    public void testResponseWithMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_message.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( "Connection refused", errorResponse.getMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Message
+     */
+    @Test
+    public void testResponseWithEmptyMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ErrorResponseTest.class.getResource( "response_with_empty_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ErrorResponse errorResponse = ( ErrorResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertNull( errorResponse.getMessage() );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/extendedRequest/ExtendedRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/extendedRequest/ExtendedRequestTest.java
new file mode 100644
index 0000000..562bc2e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/extendedRequest/ExtendedRequestTest.java
@@ -0,0 +1,395 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2.extendedRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.dsmlv2.request.ExtendedRequestDsml;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Extended Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ExtendedRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, extendedRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( ExtendedRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = extendedRequest.getControls();
+
+        assertEquals( 1, extendedRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_1_control_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = extendedRequest.getControls();
+
+        assertEquals( 1, extendedRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = extendedRequest.getControls();
+
+        assertEquals( 1, extendedRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = extendedRequest.getControls();
+
+        assertEquals( 2, extendedRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = extendedRequest.getControls();
+
+        assertEquals( 3, extendedRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with a RequestValue element
+     */
+    @Test
+    public void testRequestWithRequestValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_requestValue.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "foobar", new String( extendedRequest.getRequestValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a RequestValue element with Base64 value
+     */
+    @Test
+    public void testRequestWithBase64RequestValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_base64_requestValue.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "DSMLv2.0 rocks!!", new String( extendedRequest.getRequestValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 requestValue Elements
+     */
+    @Test
+    public void testRequestWith2RequestValue()
+    {
+        testParsingFail( ExtendedRequestTest.class, "request_with_2_requestValue.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 requestName Elements
+     */
+    @Test
+    public void testRequestWith2RequestName()
+    {
+        testParsingFail( ExtendedRequestTest.class, "request_with_2_requestName.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an empty requestName
+     */
+    @Test
+    public void testRequestWithEmptyRequestName()
+    {
+        testParsingFail( ExtendedRequestTest.class, "request_with_empty_requestName.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an empty RequestValue
+     */
+    @Test
+    public void testRequestWithEmptyRequestValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ExtendedRequestTest.class.getResource( "request_with_empty_requestValue.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedRequestDsml<?, ?> extendedRequest =
+            ( ExtendedRequestDsml<?, ?> ) parser.getBatchRequest().getCurrentRequest();
+        assertNull( extendedRequest.getRequestValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( ExtendedRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/extendedResponse/ExtendedResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/extendedResponse/ExtendedResponseTest.java
new file mode 100644
index 0000000..7e459fc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/extendedResponse/ExtendedResponseTest.java
@@ -0,0 +1,744 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.extendedResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.dsmlv2.response.ExtendedResponseDsml;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Extended Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ExtendedResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, extendedResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( ExtendedResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, extendedResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, extendedResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 2, extendedResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 3, extendedResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( ExtendedResponseTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( ExtendedResponseTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_result_code.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_empty_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_1_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_1_empty_referral.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_2_referrals.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apple.com/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_matchedDN_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = extendedResponse.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( ExtendedResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Response Name
+     */
+    @Test
+    public void testResponseWithResponseName()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_responseName.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        try
+        {
+            assertEquals( Oid.fromString( "1.2.3.4.5.6.7.8.9.0" ).toString(), extendedResponse.getResponseName().toString() );
+        }
+        catch ( DecoderException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with empty Response Name
+     */
+    @Test
+    public void testResponseWithEmptyResponseName()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_empty_responseName.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponse extendedResponse = ( ExtendedResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( "", extendedResponse.getResponseName().toString() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Response Name
+     */
+    @Test
+    public void testResponseWithWrongResponseName()
+    {
+        testParsingFail( ExtendedResponseTest.class, "response_with_wrong_responseName.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Response
+     */
+    @Test
+    public void testResponseWithResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_response.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponseDsml extendedResponse = ( ExtendedResponseDsml ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( "This is a response", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with Base64 Response
+     */
+    @Test
+    public void testResponseWithBase64Response()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                ExtendedResponseTest.class.getResource( "response_with_base64_response.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponseDsml extendedResponse = ( ExtendedResponseDsml ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( "DSMLv2.0 rocks!!", new String( extendedResponse.getResponseValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Response
+     */
+    @Test
+    public void testResponseWithEmptyResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_empty_response.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponseDsml extendedResponse = ( ExtendedResponseDsml ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( "", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with Response Name and Response
+     */
+    @Test
+    public void testResponseWithResponseNameAndResponse()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ExtendedResponseTest.class.getResource( "response_with_responseName_and_response.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ExtendedResponseDsml extendedResponse = ( ExtendedResponseDsml ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( "This is a response", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+
+        try
+        {
+            assertEquals( Oid.fromString( "1.2.3.4.5.6.7.8.9.0" ).toString(), extendedResponse.getResponseName().toString() );
+        }
+        catch ( DecoderException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( ExtendedResponseTest.class, "response_with_wrong_descr.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modDNRequest/ModifyDNRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modDNRequest/ModifyDNRequestTest.java
new file mode 100644
index 0000000..dbdb1c5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modDNRequest/ModifyDNRequestTest.java
@@ -0,0 +1,470 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.modDNRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Modify Dn Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyDNRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, modifyDNRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdbelowBelow0()
+    {
+        testParsingFail( ModifyDNRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyDNRequest.getControls();
+
+        assertEquals( 1, modifyDNRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 Value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_1_control_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyDNRequest.getControls();
+
+        assertEquals( 1, modifyDNRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyDNRequest.getControls();
+
+        assertEquals( 1, modifyDNRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyDNRequest.getControls();
+
+        assertEquals( 2, modifyDNRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyDNRequest.getControls();
+
+        assertEquals( 3, modifyDNRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request without dn attribute
+     */
+    @Test
+    public void testRequestWithoutDnAttribute()
+    {
+        testParsingFail( ModifyDNRequestTest.class, "request_without_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request without newrdn attribute
+     */
+    @Test
+    public void testRequestWithoutNewRdnAttribute()
+    {
+        testParsingFail( ModifyDNRequestTest.class, "request_without_newrdn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request without dn and newrdn attributes
+     */
+    @Test
+    public void testRequestWithDnAndNewRdnAttributes()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_dn_and_newrdn_attributes.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", modifyDNRequest.getName().getNormName() );
+
+        assertEquals( "CN=Steve Jobs", modifyDNRequest.getNewRdn().getName() );
+    }
+
+
+    /**
+     * Test parsing of a request with deleteoldrdn to true
+     */
+    @Test
+    public void testRequestWithDeleteOldRdnTrue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                ModifyDNRequestTest.class.getResource( "request_with_deleteoldrdn_true.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertTrue( modifyDNRequest.getDeleteOldRdn() );
+    }
+
+
+    /**
+     * Test parsing of a request with deleteoldrdn to 1
+     */
+    @Test
+    public void testRequestWithDeleteOldRdn1()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_deleteoldrdn_1.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertTrue( modifyDNRequest.getDeleteOldRdn() );
+    }
+
+
+    /**
+     * Test parsing of a request with deleteoldrdn to false
+     */
+    @Test
+    public void testRequestWithDeleteOldRdnFalse()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_deleteoldrdn_false.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertFalse( modifyDNRequest.getDeleteOldRdn() );
+    }
+
+
+    /**
+     * Test parsing of a request with deleteoldrdn to 0
+     */
+    @Test
+    public void testRequestWithDeleteOldRdn0()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_deleteoldrdn_0.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertFalse( modifyDNRequest.getDeleteOldRdn() );
+    }
+
+
+    /**
+     * Test parsing of a request with deleteoldrdn to an error value
+     */
+    @Test
+    public void testRequestWithDeleteOldRdnError()
+    {
+        testParsingFail( ModifyDNRequestTest.class, "request_with_deleteoldrdn_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with newSuperior attribute
+     */
+    @Test
+    public void testRequestWithNewSuperior()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyDNRequestTest.class.getResource( "request_with_newSuperior_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnRequest modifyDNRequest = ( ModifyDnRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "cn=Steve Jobs,ou=Dev,dc=apple,dc=com", modifyDNRequest.getNewSuperior().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( ModifyDNRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modDNResponse/ModifyDNResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modDNResponse/ModifyDNResponseTest.java
new file mode 100644
index 0000000..4e6cf0c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modDNResponse/ModifyDNResponseTest.java
@@ -0,0 +1,553 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.modDNResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Modify Dn Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyDNResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, modifyDNResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( ModifyDNResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyDNResponse.getControls();
+
+        assertEquals( 1, modifyDNResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyDNResponse.getControls();
+
+        assertEquals( 1, modifyDNResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyDNResponse.getControls();
+
+        assertEquals( 2, modifyDNResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyDNResponse.getControls();
+
+        assertEquals( 3, modifyDNResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( ModifyDNResponseTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( ModifyDNResponseTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_result_code.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_empty_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_1_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with an empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_1_empty_referral.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_2_referrals.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apple.com/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyDNResponseTest.class.getResource( "response_with_matchedDN_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyDnResponse modifyDNResponse = ( ModifyDnResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyDNResponse.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( ModifyDNResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( ModifyDNResponseTest.class, "response_with_wrong_descr.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyRequest/ModifyRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyRequest/ModifyRequestTest.java
new file mode 100644
index 0000000..1290278
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyRequest/ModifyRequestTest.java
@@ -0,0 +1,667 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.modifyRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Modify Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                ModifyRequestTest.class.getResource( "request_with_requestID_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, modifyRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( ModifyRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyRequest.getControls();
+
+        assertEquals( 1, modifyRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 Value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_1_control_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyRequest.getControls();
+
+        assertEquals( 1, modifyRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyRequest.getControls();
+
+        assertEquals( 1, modifyRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser
+                .setInput( ModifyRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyRequest.getControls();
+
+        assertEquals( 2, modifyRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = modifyRequest.getControls();
+
+        assertEquals( 3, modifyRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request without dn attribute
+     */
+    @Test
+    public void testRequestWithoutDnAttribute()
+    {
+        testParsingFail( ModifyRequestTest.class, "request_without_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a Modification element
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWith1Modification() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_1_modification.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+
+        Attribute attribute = modification.getAttribute();
+
+        assertEquals( "directreport", attribute.getId() );
+        assertEquals( "CN=John Smith, DC=microsoft, DC=com", attribute.get().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Modification element with Base64 Value
+     * @throws NamingException
+     * @throws UnsupportedEncodingException
+     */
+    @Test
+    public void testRequestWith1ModificationBase64Value() throws LdapException, UnsupportedEncodingException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_1_modification_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+        Attribute attribute = modification.getAttribute();
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+
+        assertEquals( "directreport", attribute.getId() );
+
+        String expected = new String( new byte[]
+            { 'c', 'n', '=', 'E', 'm', 'm', 'a', 'n', 'u', 'e', 'l', ' ', 'L', ( byte ) 0xc3, ( byte ) 0xa9, 'c', 'h',
+                'a', 'r', 'n', 'y', ',', ' ', 'o', 'u', '=', 'p', 'e', 'o', 'p', 'l', 'e', ',', ' ', 'd', 'c', '=',
+                'e', 'x', 'a', 'm', 'p', 'l', 'e', ',', ' ', 'd', 'c', '=', 'c', 'o', 'm' }, "UTF-8" );
+
+        assertEquals( expected, attribute.get().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 Modification elements
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWith2Modifications() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_2_modifications.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 2, modifications.size() );
+
+        Iterator<Modification> iter = modifications.iterator();
+
+        Modification modification = iter.next();
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+        Attribute attribute = modification.getAttribute();
+        assertEquals( "directreport", attribute.getId() );
+
+        assertEquals( "CN=John Smith, DC=microsoft, DC=com", attribute.get().getString() );
+
+        modification = iter.next();
+
+        attribute = modification.getAttribute();
+
+        assertEquals( "sn", attribute.getId() );
+        assertEquals( ModificationOperation.REPLACE_ATTRIBUTE, modification.getOperation() );
+
+        assertEquals( "CN=Steve Jobs, DC=apple, DC=com", attribute.get().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request without name attribute to the Modification element
+     */
+    @Test
+    public void testRequestWithoutNameAttribute()
+    {
+        testParsingFail( ModifyRequestTest.class, "request_without_name_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request without operation attribute to the Modification element
+     */
+    @Test
+    public void testRequestWithoutOperationAttribute()
+    {
+        testParsingFail( ModifyRequestTest.class, "request_without_operation_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with operation attribute to Add value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithOperationAdd() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_operation_add.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+    }
+
+
+    /**
+     * Test parsing of a request with operation attribute to Delete value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithOperationDelete() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_operation_delete.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, modification.getOperation() );
+    }
+
+
+    /**
+     * Test parsing of a request with operation attribute to Replace value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithOperationReplace() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_operation_replace.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+
+        assertEquals( ModificationOperation.REPLACE_ATTRIBUTE, modification.getOperation() );
+    }
+
+
+    /**
+     * Test parsing of a request without operation attribute to the Modification element
+     */
+    @Test
+    public void testRequestWithOperationError()
+    {
+        testParsingFail( ModifyRequestTest.class, "request_with_operation_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a Modification element without Value element
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithModificationWithoutValue() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_modification_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+        Attribute attribute = modification.getAttribute();
+
+        assertEquals( "directreport", attribute.getId() );
+        assertEquals( 0, attribute.size() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Modification element
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithModificationWith2Values() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_modification_with_2_values.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+        Attribute attribute = modification.getAttribute();
+
+        assertEquals( "directreport", attribute.getId() );
+
+        assertEquals( 2, attribute.size() );
+
+        assertTrue( attribute.contains( "CN=John Smith, DC=microsoft, DC=com" ) );
+        assertTrue( attribute.contains( "CN=Steve Jobs, DC=apple, DC=com" ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a Modification element with an empty value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithModificationWithEmptyValue() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( ModifyRequestTest.class.getResource( "request_with_modification_with_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyRequest modifyRequest = ( ModifyRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+        assertEquals( 1, modifications.size() );
+
+        Modification modification = modifications.iterator().next();
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+        Attribute attribute = modification.getAttribute();
+
+        assertEquals( "directreport", attribute.getId() );
+
+        assertEquals( 1, attribute.size() );
+        assertEquals( "", attribute.get().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( ModifyRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyResponse/ModifyResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyResponse/ModifyResponseTest.java
new file mode 100644
index 0000000..69178dc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/modifyResponse/ModifyResponseTest.java
@@ -0,0 +1,553 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.modifyResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Modify Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyResponseTest extends AbstractResponseTest
+{
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        assertEquals( 456, modifyResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( ModifyResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyResponse.getControls();
+
+        assertEquals( 1, modifyResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyResponse.getControls();
+
+        assertEquals( 1, modifyResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyResponse.getControls();
+
+        assertEquals( 2, modifyResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+        Map<String, Control> controls = modifyResponse.getControls();
+
+        assertEquals( 3, modifyResponse.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( ModifyResponseTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( ModifyResponseTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_result_code.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_empty_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_1_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with an empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_1_empty_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_2_referrals.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apple.com/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( ModifyResponseTest.class.getResource( "response_with_matchedDN_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        ModifyResponse modifyResponse = ( ModifyResponse ) parser.getBatchResponse().getCurrentResponse();
+
+        LdapResult ldapResult = modifyResponse.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( ModifyResponseTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( ModifyResponseTest.class, "response_with_wrong_descr.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchRequest/SearchRequestTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchRequest/SearchRequestTest.java
new file mode 100644
index 0000000..1b313d8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchRequest/SearchRequestTest.java
@@ -0,0 +1,2449 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.searchRequest;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.dsmlv2.AbstractTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.dsmlv2.request.SearchRequestDsml;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.ApproximateNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.api.ldap.model.filter.LessEqNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests for the Del Request parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchRequestTest extends AbstractTest
+{
+    /**
+     * Test parsing of a request without the dn attribute
+     */
+    @Test
+    public void testRequestWithoutDn()
+    {
+        testParsingFail( SearchRequestTest.class, "request_without_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the dn attribute
+     */
+    @Test
+    public void testRequestWithDn()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_dn_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( "ou=marketing,dc=microsoft,dc=com", searchRequest.getBase().getName() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute
+     */
+    @Test
+    public void testRequestWithRequestId()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                SearchRequestTest.class.getResource( "request_with_requestID_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 456, searchRequest.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a request with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testRequestWithRequestIdBelow0()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element
+     */
+    @Test
+    public void testRequestWith1Control()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_1_control.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = searchRequest.getControls();
+
+        assertEquals( 1, searchRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with Base64 value
+     */
+    @Test
+    public void testRequestWith1ControlBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_1_control_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = searchRequest.getControls();
+
+        assertEquals( 1, searchRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "DSMLv2.0 rocks!!", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a (optional) Control element with empty value
+     */
+    @Test
+    public void testRequestWith1ControlEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = searchRequest.getControls();
+
+        assertEquals( 1, searchRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 (optional) Control elements
+     */
+    @Test
+    public void testRequestWith2Controls()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser
+                .setInput( SearchRequestTest.class.getResource( "request_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = searchRequest.getControls();
+
+        assertEquals( 2, searchRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a request with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testRequestWith3ControlsWithoutValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+        Map<String, Control> controls = searchRequest.getControls();
+
+        assertEquals( 3, searchRequest.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a request without the Filter element
+     */
+    @Test
+    public void testRequestWithoutFilter()
+    {
+        testParsingFail( SearchRequestTest.class, "request_without_filter.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request without scope attribute
+     */
+    @Test
+    public void testRequestWithoutScopeAttribute()
+    {
+        testParsingFail( SearchRequestTest.class, "request_without_scope_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with scope attribute to BaseObject value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithScopeBaseObject()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_scope_baseObject.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( SearchScope.OBJECT, searchRequest.getScope() );
+    }
+
+
+    /**
+     * Test parsing of a request with scope attribute to SingleLevel value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithScopeSingleLevel()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_scope_singleLevel.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+    }
+
+
+    /**
+     * Test parsing of a request with scope attribute to WholeSubtree value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithScopeWholeSubtree()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_scope_wholeSubtree.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( SearchScope.SUBTREE, searchRequest.getScope() );
+    }
+
+
+    /**
+     * Test parsing of a request with scope attribute to Error value
+     */
+    @Test
+    public void testRequestWithScopeError()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_scope_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request without derefAliases attribute
+     */
+    @Test
+    public void testRequestWithoutDerefAliasesAttribute()
+    {
+        testParsingFail( SearchRequestTest.class, "request_without_derefAliases_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with derefAliases attribute to derefAlways value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithDerefAliasesDerefAlways()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_derefAliases_derefAlways.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+    }
+
+
+    /**
+     * Test parsing of a request with derefAliases attribute to derefFindingBaseObj value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithDerefAliasesDerefFindingBaseObj()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_derefAliases_derefFindingBaseObj.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( AliasDerefMode.DEREF_FINDING_BASE_OBJ, searchRequest.getDerefAliases() );
+    }
+
+
+    /**
+     * Test parsing of a request with derefAliases attribute to derefinSearching value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithDerefAliasesDerefinSearching()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_derefAliases_derefInSearching.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( AliasDerefMode.DEREF_IN_SEARCHING, searchRequest.getDerefAliases() );
+    }
+
+
+    /**
+     * Test parsing of a request with derefAliases attribute to neverDerefAliases value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithDerefAliasesNeverDerefAliases()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_derefAliases_neverDerefAliases.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( AliasDerefMode.NEVER_DEREF_ALIASES, searchRequest.getDerefAliases() );
+    }
+
+
+    /**
+     * Test parsing of a request with derefAliases attribute to Error value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithDerefAliasesError()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_derefAliases_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the sizeLimit (optional) attribute
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithSizeLimitAttribute()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                SearchRequestTest.class.getResource( "request_with_sizeLimit_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+    }
+
+
+    /**
+     * Test parsing of a request with sizeLimit attribute to Error value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithSizeLimitError()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_sizeLimit_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with the timeLimit (optional) attribute
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithTimeLimitAttribute()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                SearchRequestTest.class.getResource( "request_with_timeLimit_attribute.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertEquals( 60, searchRequest.getTimeLimit() );
+    }
+
+
+    /**
+     * Test parsing of a request with timeLimit attribute to Error value
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithTimeLimitError()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_timeLimit_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to true
+     */
+    @Test
+    public void testRequestWithTypesOnlyTrue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_typesOnly_true.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertTrue( searchRequest.getTypesOnly() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to 1
+     */
+    @Test
+    public void testRequestWithTypesOnly1()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_typesOnly_1.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertTrue( searchRequest.getTypesOnly() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to false
+     */
+    @Test
+    public void testRequestWithTypesOnlyFalse()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_typesOnly_false.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertFalse( searchRequest.getTypesOnly() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to 0
+     */
+    @Test
+    public void testRequestWithTypesOnlyRdn0()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_typesOnly_0.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertFalse( searchRequest.getTypesOnly() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to an error value
+     */
+    @Test
+    public void testRequestWithTypesOnlyError()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_typesOnly_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 Filter elements
+     */
+    @Test
+    public void testRequestWith2Filters()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_2_filters.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with Attibutes Element but not any Attribute element
+     */
+    @Test
+    public void testRequestWithAttributesButNoAttribute()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_attributes_but_no_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        assertTrue( true );
+    }
+
+
+    /**
+     * Test parsing of a request with 2 Attributes elements
+     */
+    @Test
+    public void testRequestWith2AttributesElements()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_2_attributes_elements.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attributes element with 1 Attribute element
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithAttributes1Attribute() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_attributes_1_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 1, attributes.size() );
+
+        String attribute = attributes.get( 0 );
+        assertEquals( "sn", attribute );
+    }
+
+
+    /**
+     * Test parsing of a request with an Attributes element with 2 Attribute elements
+     * @throws NamingException
+     */
+    @Test
+    public void testRequestWithAttributes2Attribute() throws LdapException
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "request_with_attributes_2_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 2, attributes.size() );
+
+        String attribute1 = attributes.get( 0 );
+        assertEquals( "sn", attribute1 );
+
+        String attribute2 = attributes.get( 1 );
+        assertEquals( "givenName", attribute2 );
+    }
+
+
+    /**
+     * Test parsing of a request with 1 Attribute without name attribute
+     */
+    @Test
+    public void testRequestWithAttributeWithoutNameAttribute()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_attribute_without_name_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with empty Filter element
+     */
+    @Test
+    public void testRequestWithEmptyFilter()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_empty_filter.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an And Filter
+     */
+    @Test
+    public void testRequestWithAndFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_and.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof AndNode );
+    }
+
+
+    /**
+     * Test parsing of a request with an Or Filter
+     */
+    @Test
+    public void testRequestWithOrFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser
+                .setInput( SearchRequestTest.class.getResource( "filters/request_with_or.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof OrNode );
+    }
+
+
+    /**
+     * Test parsing of a request with an Or Filter
+     */
+    @Test
+    public void testRequestWithNotFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_not.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof NotNode );
+    }
+
+
+    /**
+     * Test parsing of a request with empty Filter element
+     */
+    @Test
+    public void testRequestWithNotFilterWith2Children()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_not_with_2_children.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an approxMatch Filter
+     */
+    @Test
+    public void testRequestWithApproxMatchFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                SearchRequestTest.class.getResource( "filters/request_with_approxMatch.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ApproximateNode );
+
+        ApproximateNode<?> approxMatchFilter = ( ApproximateNode<?> ) filter;
+
+        assertEquals( "sn", approxMatchFilter.getAttribute() );
+
+        assertEquals( "foobar", approxMatchFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an approxMatch Filter with base64 value
+     */
+    @Test
+    public void testRequestWithApproxMatchFilterBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_approxMatch_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ApproximateNode );
+
+        ApproximateNode<?> approxMatchFilter = ( ApproximateNode<?> ) filter;
+
+        assertEquals( "sn", approxMatchFilter.getAttribute() );
+
+        assertEquals( "DSMLv2.0 rocks!!", approxMatchFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an approxMatch Filter with empty value
+     */
+    @Test
+    public void testRequestWithApproxMatchFilterEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_approxMatch_with_empty_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ApproximateNode );
+
+        ApproximateNode<?> approxMatchFilter = ( ApproximateNode<?> ) filter;
+
+        assertEquals( "sn", approxMatchFilter.getAttribute() );
+
+        assertNull( approxMatchFilter.getValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with approxMatch Filter but no name attribute
+     */
+    @Test
+    public void testRequestWithApproxMatchFilterWithoutName()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_approxMatch_without_name.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with approxMatch Filter but no value element
+     */
+    @Test
+    public void testRequestWithApproxMatchFilterWithoutValue()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_approxMatch_without_value.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with approxMatch Filter with 2 Value elements
+     */
+    @Test
+    public void testRequestWithApproxMatchFilterWith2Values()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_approxMatch_with_2_values.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an greaterOrEqual Filter
+     */
+    @Test
+    public void testRequestWithGreaterOrEqualFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_greaterOrEqual.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof GreaterEqNode );
+
+        GreaterEqNode<?> greaterEqFilter = ( GreaterEqNode<?> ) filter;
+
+        assertEquals( "sn", greaterEqFilter.getAttribute() );
+
+        assertEquals( "foobar", greaterEqFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an greaterOrEqual Filter with base64 value
+     */
+    @Test
+    public void testRequestWithGreaterOrEqualFilterBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_greaterOrEqual_base64_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof GreaterEqNode );
+
+        GreaterEqNode<?> greaterEqFilter = ( GreaterEqNode<?> ) filter;
+
+        assertEquals( "sn", greaterEqFilter.getAttribute() );
+
+        assertEquals( "DSMLv2.0 rocks!!", greaterEqFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an greaterOrEqual Filter with an empty value
+     */
+    @Test
+    public void testRequestWithGreaterOrEqualFilterEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_greaterOrEqual_with_empty_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof GreaterEqNode );
+
+        GreaterEqNode<?> greaterEqFilter = ( GreaterEqNode<?> ) filter;
+
+        assertEquals( "sn", greaterEqFilter.getAttribute() );
+
+        assertNull( greaterEqFilter.getValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with greaterOrEqual Filter but no name attribute
+     */
+    @Test
+    public void testRequestWithGreaterOrEqualFilterWithoutName()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_greaterOrEqual_without_name.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with greaterOrEqual Filter but no value element
+     */
+    @Test
+    public void testRequestWithGreaterOrEqualFilterWithoutValue()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_greaterOrEqual_without_value.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with greaterOrEqual Filter with 2 Value elements
+     */
+    @Test
+    public void testRequestWithGreaterOrEqualFilterWith2Values()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_greaterOrEqual_with_2_values.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an lessOrEqual Filter
+     */
+    @Test
+    public void testRequestWithLessOrEqualFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput(
+                SearchRequestTest.class.getResource( "filters/request_with_lessOrEqual.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof LessEqNode );
+
+        LessEqNode<?> lessOrEqFilter = ( LessEqNode<?> ) filter;
+
+        assertEquals( "sn", lessOrEqFilter.getAttribute() );
+
+        assertEquals( "foobar", lessOrEqFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an lessOrEqual Filter with Base64 value
+     */
+    @Test
+    public void testRequestWithLessOrEqualFilterBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_lessOrEqual_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof LessEqNode );
+
+        LessEqNode<?> lessOrEqFilter = ( LessEqNode<?> ) filter;
+
+        assertEquals( "sn", lessOrEqFilter.getAttribute() );
+
+        assertEquals( "DSMLv2.0 rocks!!", lessOrEqFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an lessOrEqual Filter
+     */
+    @Test
+    public void testRequestWithLessOrEqualFilterEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_lessOrEqual_with_empty_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof LessEqNode );
+
+        LessEqNode<?> lessOrEqFilter = ( LessEqNode<?> ) filter;
+
+        assertEquals( "sn", lessOrEqFilter.getAttribute() );
+
+        assertNull( lessOrEqFilter.getValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with lessOrEqual Filter but no name attribute
+     */
+    @Test
+    public void testRequestWithLessOrEqualFilterWithoutName()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_lessOrEqual_without_name.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with lessOrEqual Filter but no value element
+     */
+    @Test
+    public void testRequestWithLessOrEqualFilterWithoutValue()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_lessOrEqual_without_value.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with lessOrEqual Filter with 2 Value elements
+     */
+    @Test
+    public void testRequestWithLessOrEqualFilterWith2Values()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_lessOrEqual_with_2_values.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an Equality Filter
+     */
+    @Test
+    public void testRequestWithEqualityMatchFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_equalityMatch.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof EqualityNode );
+
+        EqualityNode<?> equalityFilter = ( EqualityNode<?> ) filter;
+
+        assertEquals( "sn", equalityFilter.getAttribute() );
+        assertEquals( "foobar", equalityFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Equality Filter with base64 value
+     */
+    @Test
+    public void testRequestWithEqualityMatchFilterBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class
+                .getResource( "filters/request_with_equalityMatch_base64_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof EqualityNode );
+
+        EqualityNode<?> equalityFilter = ( EqualityNode<?> ) filter;
+
+        assertEquals( "sn", equalityFilter.getAttribute() );
+
+        assertEquals( "DSMLv2.0 rocks!!", equalityFilter.getValue().getString() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Equality Filter with an empty value
+     */
+    @Test
+    public void testRequestWithEqualityMatchFilterWithEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_equalityMatch_with_empty_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof EqualityNode );
+
+        EqualityNode<?> equalityFilter = ( EqualityNode<?> ) filter;
+
+        assertEquals( "sn", equalityFilter.getAttribute() );
+
+        assertNull( equalityFilter.getValue() );
+    }
+
+
+    /**
+     * Test parsing of a request with EqualityMatch Filter but no name attribute
+     */
+    @Test
+    public void testRequestWithEqualityMatchFilterWithoutName()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_equalityMatch_without_name.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with EqualityMatch Filter but no value element
+     */
+    @Test
+    public void testRequestWithEqualityMatchFilterWithoutValue()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_equalityMatch_without_value.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with EqualityMatch Filter with 2 Value elements
+     */
+    @Test
+    public void testRequestWithEqualityMatchFilterWith2Values()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_equalityMatch_with_2_values.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an Present Filter
+     */
+    @Test
+    public void testRequestWithPresentFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_present.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof PresenceNode );
+
+        PresenceNode presentFilter = ( PresenceNode ) filter;
+
+        assertEquals( "givenName", presentFilter.getAttribute() );
+    }
+
+
+    /**
+     * Test parsing of a request with Present Filter without name attribute
+     */
+    @Test
+    public void testRequestWithPresentWithoutName()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_present_without_name.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with an ExtensibleMatch Filter
+     */
+    @Test
+    public void testRequestWithExtensibleMatchFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_extensibleMatch.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertEquals( "A Value", extensibleMatchFilter.getValue().getString() );
+
+        assertEquals( false, extensibleMatchFilter.hasDnAttributes() );
+    }
+
+
+    /**
+     * Test parsing of a request with an ExtensibleMatch Filter
+     */
+    @Test
+    public void testRequestWithExtensibleMatchFilterBase64Value()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_extensibleMatch_base64_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertEquals( "DSMLv2.0 rocks!!", extensibleMatchFilter.getValue().getString() );
+
+        assertEquals( false, extensibleMatchFilter.hasDnAttributes() );
+    }
+
+
+    /**
+     * Test parsing of a request with an ExtensibleMatch Filter with empty value
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithEmptyValue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_extensibleMatch_with_empty_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertNull( extensibleMatchFilter.getValue() );
+
+        assertEquals( false, extensibleMatchFilter.hasDnAttributes() );
+    }
+
+
+    /**
+     * Test parsing of a request with ExtensibleMatch Filter without Value element
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithoutValue()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_extensibleMatch_without_value.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with ExtensibleMatch Filter with 2 Value elements
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWith2Values()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_extensibleMatch_with_2_values.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to true
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithDnAttributesTrue()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_extensibleMatch_with_dnAttributes_true.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertTrue( extensibleMatchFilter.hasDnAttributes() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to 1
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithDnAttributes1()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_extensibleMatch_with_dnAttributes_1.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertTrue( extensibleMatchFilter.hasDnAttributes() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to false
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithDnAttributesFalse()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_extensibleMatch_with_dnAttributes_false.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertFalse( extensibleMatchFilter.hasDnAttributes() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to 0
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithDnAttributes0()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_extensibleMatch_with_dnAttributes_0.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertFalse( extensibleMatchFilter.hasDnAttributes() );
+    }
+
+
+    /**
+     * Test parsing of a request with typesOnly to an error value
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithDnAttributesError()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_extensibleMatch_with_dnAttributes_error.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a matchingRule attribute
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithMatchingRule()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_extensibleMatch_with_matchingRule.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertEquals( "AMatchingRuleName", extensibleMatchFilter.getMatchingRuleId() );
+    }
+
+
+    /**
+     * Test parsing of a request with a name attribute
+     */
+    @Test
+    public void testRequestWithExtensibleMatchWithName()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_extensibleMatch_with_name.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof ExtensibleNode );
+
+        ExtensibleNode extensibleMatchFilter = ( ExtensibleNode ) filter;
+
+        assertEquals( "givenName", extensibleMatchFilter.getAttribute() );
+    }
+
+
+    /**
+     * Test parsing of a request with an Substrings Filter
+     */
+    @Test
+    public void testRequestWithSubstringsFilter()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertEquals( "sn", substringFilter.getAttribute() );
+    }
+
+
+    /**
+     * Test parsing of a request with Substrings Filter without name
+     */
+    @Test
+    public void testRequestWithSubstringsWithoutName()
+    {
+        testParsingFail( SearchRequestTest.class, "filters/request_with_substrings_without_name.xml" );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Initial element
+     */
+    @Test
+    public void testRequestWithSubstrings1Initial()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_initial.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertEquals( "jack", substringFilter.getInitial().toString() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Initial element with Base64 value
+     */
+    @Test
+    public void testRequestWithSubstrings1Base64Initial()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_substrings_1_base64_initial.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertEquals( "DSMLv2.0 rocks!!", substringFilter.getInitial().toString() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 emptyInitial element
+     */
+    @Test
+    public void testRequestWithSubstrings1EmptyInitial()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class
+                .getResource( "filters/request_with_substrings_1_empty_initial.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertNull( substringFilter.getInitial() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Initial and 1 Any elements
+     */
+    @Test
+    public void testRequestWithSubstrings1Initial1Any()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class
+                .getResource( "filters/request_with_substrings_1_initial_1_any.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertEquals( "jack", substringFilter.getInitial() );
+
+        List<String> initials = substringFilter.getAny();
+
+        assertEquals( 1, initials.size() );
+
+        assertEquals( "kate", initials.get( 0 ).toString() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Initial and 1 Final elements
+     */
+    @Test
+    public void testRequestWithSubstrings1Initial1Final()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource(
+                "filters/request_with_substrings_1_initial_1_final.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertEquals( "jack", substringFilter.getInitial() );
+
+        assertEquals( "john", substringFilter.getFinal() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Any element
+     */
+    @Test
+    public void testRequestWithSubstrings1Any()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_any.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        List<String> initials = substringFilter.getAny();
+
+        assertEquals( 1, initials.size() );
+        assertEquals( "kate", initials.get( 0 ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Any element
+     */
+    @Test
+    public void testRequestWithSubstrings1Base64Any()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_base64_any.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        List<String> initials = substringFilter.getAny();
+
+        assertEquals( 1, initials.size() );
+        assertEquals( "DSMLv2.0 rocks!!", initials.get( 0 ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 empty Any element
+     */
+    @Test
+    public void testRequestWithSubstrings1EmptyAny()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_empty_any.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        List<String> initials = substringFilter.getAny();
+
+        assertEquals( 0, initials.size() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Any element
+     */
+    @Test
+    public void testRequestWithSubstrings2Any()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_2_any.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        List<String> initials = substringFilter.getAny();
+
+        assertEquals( 2, initials.size() );
+
+        assertEquals( "kate", initials.get( 0 ) );
+
+        assertEquals( "sawyer", initials.get( 1 ) );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Any and 1 Final elements
+     */
+    @Test
+    public void testRequestWithSubstrings1Any1Final()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_any_1_final.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        List<String> initials = substringFilter.getAny();
+
+        assertEquals( 1, initials.size() );
+
+        assertEquals( "kate", initials.get( 0 ) );
+
+        assertEquals( "john", substringFilter.getFinal() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Final element
+     */
+    @Test
+    public void testRequestWithSubstrings1Final()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_final.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertEquals( "john", substringFilter.getFinal().toString() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 Final element
+     */
+    @Test
+    public void testRequestWithSubstrings1Base64Final()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_base64_final.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertEquals( "DSMLv2.0 rocks!!", substringFilter.getFinal().toString() );
+    }
+
+
+    /**
+     * Test parsing of a request with a Substrings Filter with 1 empty Final element
+     */
+    @Test
+    public void testRequestWithSubstrings1EmptyFinal()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_substrings_1_empty_final.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof SubstringNode );
+
+        SubstringNode substringFilter = ( SubstringNode ) filter;
+
+        assertNull( substringFilter.getFinal() );
+    }
+
+
+    /**
+     * Test parsing of a request with a needed requestID attribute
+     * 
+     * DIRSTUDIO-1
+     */
+    @Test
+    public void testRequestWithNeededRequestId()
+    {
+        testParsingFail( SearchRequestTest.class, "request_with_needed_requestID.xml" );
+    }
+
+    
+    /**
+     * Test parsing of a request with a nested nodes DIRSHARED-137
+     */
+    @Test
+    public void testRequestWithNestedNodes()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = newParser();
+
+            parser.setInput( SearchRequestTest.class.getResource( "filters/request_with_nested_connector_nodes.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequestDsml searchRequest = ( SearchRequestDsml ) parser.getBatchRequest().getCurrentRequest();
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof AndNode );
+
+        assertEquals( "(&(|(sn=*foo*)(cn=*foo*))(|(ou=*josopuram*)(o=*k*)))", filter.toString() );
+        
+        //System.out.println( searchRequest.toDsml( new DefaultElement( "root" ) ).asXML() );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/SearchResponseTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/SearchResponseTest.java
new file mode 100644
index 0000000..50d28bd
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/SearchResponseTest.java
@@ -0,0 +1,354 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.searchResponse;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.dsmlv2.response.SearchResponse;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Search Result Done Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResponseTest extends AbstractResponseTest
+{
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResponseTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated();
+
+        assertEquals( 456, searchResponse.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( SearchResponseTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a Response with a Search Result Done
+     */
+    @Test
+    public void testResponseWithSRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResponseTest.class.getResource( "response_with_1_SRD.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated();
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 1 Search Result Entry and a Search Result Done
+     */
+    @Test
+    public void testResponseWith1SRE1SRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResponseTest.class.getResource( "response_with_1_SRE_1_SRD.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated();
+
+        assertEquals( 1, searchResponse.getSearchResultEntryList().size() );
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 1 Search Result Entry and a Search Result Done
+     */
+    @Test
+    public void testResponseWith0SRE1SRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResponseTest.class.getResource( "response_with_0_SRE_1_SRD.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated();
+
+        assertEquals( 0, searchResponse.getSearchResultEntryList().size() );
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 1 Search Result Reference and a Search Result Done
+     */
+    @Test
+    public void testResponseWith1SRR1SRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResponseTest.class.getResource( "response_with_1_SRR_1_SRD.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+
+        assertEquals( 1, searchResponse.getSearchResultReferenceList().size() );
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 1 Search Result Entry, 1 Search Result Reference and a Search Result Done
+     */
+    @Test
+    public void testResponseWith1SRE1SRR1SRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                SearchResponseTest.class.getResource( "response_with_1_SRE_1_SRR_1_SRD.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+
+        assertEquals( 1, searchResponse.getSearchResultEntryList().size() );
+
+        assertEquals( 1, searchResponse.getSearchResultReferenceList().size() );
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 2 Search Result Entry and a Search Result Done
+     */
+    @Test
+    public void testResponseWith2SRE1SRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResponseTest.class.getResource( "response_with_2_SRE_1_SRD.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+
+        assertEquals( 2, searchResponse.getSearchResultEntryList().size() );
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 2 Search Result Reference and a Search Result Done
+     */
+    @Test
+    public void testResponseWith2SRR1SRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResponseTest.class.getResource( "response_with_2_SRR_1_SRD.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+
+        assertEquals( 2, searchResponse.getSearchResultReferenceList().size() );
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 2 Search Result Entry, 2 Search Result Reference and a Search Result Done
+     */
+    @Test
+    public void testResponseWith2SRE2SRR1SRD()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                SearchResponseTest.class.getResource( "response_with_2_SRE_2_SRR_1_SRD.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated();
+
+        assertEquals( 2, searchResponse.getSearchResultEntryList().size() );
+
+        assertEquals( 2, searchResponse.getSearchResultReferenceList().size() );
+
+        assertNotNull( searchResponse.getSearchResultDone() );
+    }
+
+
+    /**
+     * Test parsing of a response with no Search Result Done
+     */
+    @Test
+    public void testResponseWith0SRD()
+    {
+        testParsingFail( SearchResponseTest.class, "response_with_0_SRD.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Search Result Entry but no Search Result Done
+     */
+    @Test
+    public void testResponseWith1SRE0SRD()
+    {
+        testParsingFail( SearchResponseTest.class, "response_with_1_SRE_0_SRD.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Search Result Reference but no Search Result Done
+     */
+    @Test
+    public void testResponseWith1SRR0SRD()
+    {
+        testParsingFail( SearchResponseTest.class, "response_with_1_SRR_0_SRD.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/SearchResultDoneTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/SearchResultDoneTest.java
new file mode 100644
index 0000000..0e4a7bf
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/SearchResultDoneTest.java
@@ -0,0 +1,579 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.searchResponse.searchResultDone;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.dsmlv2.response.SearchResponse;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Search Result Done Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResultDoneTest extends AbstractResponseTest
+{
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+        Map<String, Control> controls = searchResultDone.getControls();
+
+        assertEquals( 1, searchResultDone.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+        Map<String, Control> controls = searchResultDone.getControls();
+
+        assertEquals( 1, searchResultDone.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+        Map<String, Control> controls = searchResultDone.getControls();
+
+        assertEquals( 2, searchResultDone.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated() )
+                .getSearchResultDone();
+        Map<String, Control> controls = searchResultDone.getControls();
+
+        assertEquals( 3, searchResultDone.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+
+        assertEquals( 456, searchResultDone.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( SearchResultDoneTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response without Result Code element
+     */
+    @Test
+    public void testResponseWithoutResultCode()
+    {
+        testParsingFail( SearchResultDoneTest.class, "response_without_result_code.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code element but a not integer value
+     */
+    @Test
+    public void testResponseWithResultCodeNotInteger()
+    {
+        testParsingFail( SearchResultDoneTest.class, "response_with_result_code_not_integer.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with Result Code
+     */
+    @Test
+    public void testResponseWithResultCode()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_result_code.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated() )
+                .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        assertEquals( ResultCodeEnum.PROTOCOL_ERROR, ldapResult.getResultCode() );
+    }
+
+
+    /**
+     * Test parsing of a response with Error Message
+     */
+    @Test
+    public void testResponseWithErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_error_message.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        assertEquals( "Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2", ldapResult
+            .getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with empty Error Message
+     */
+    @Test
+    public void testResponseWithEmptyErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_empty_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        assertNull( ldapResult.getDiagnosticMessage() );
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral
+     */
+    @Test
+    public void testResponseWith1Referral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_1_referral.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated() )
+                .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with an empty Referral
+     */
+    @Test
+    public void testResponseWith1EmptyReferral()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_1_empty_referral.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated() )
+                .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 0, referrals.size() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Referral elements
+     */
+    @Test
+    public void testResponseWith2Referrals()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_2_referrals.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 2, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apple.com/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with a Referral and an Error Message
+     */
+    @Test
+    public void testResponseWith1ReferralAndAnErrorMessage()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_1_referral_and_error_message.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        Collection<String> referrals = ldapResult.getReferral().getLdapUrls();
+
+        assertEquals( 1, referrals.size() );
+
+        try
+        {
+            assertTrue( referrals.contains( new LdapUrl( "ldap://www.apache.org/" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with MatchedDN attribute
+     */
+    @Test
+    public void testResponseWithMatchedDNAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultDoneTest.class.getResource( "response_with_matchedDN_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getSearchResultDone();
+
+        LdapResult ldapResult = searchResultDone.getLdapResult();
+
+        assertEquals( "cn=Bob Rush,ou=Dev,dc=Example,dc=COM", ldapResult.getMatchedDn().getNormName() );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong matched Dn
+     */
+    @Test
+    public void testResponseWithWrongMatchedDN()
+    {
+        testParsingFail( SearchResultDoneTest.class, "response_with_wrong_matchedDN_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong Descr attribute
+     */
+    @Test
+    public void testResponseWithWrongDescr()
+    {
+        testParsingFail( SearchResultDoneTest.class, "response_with_wrong_descr.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/SearchResultEntryTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/SearchResultEntryTest.java
new file mode 100644
index 0000000..60ebddc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/SearchResultEntryTest.java
@@ -0,0 +1,585 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.dsmlv2.searchResponse.searchResultEntry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.dsmlv2.response.SearchResponse;
+import org.apache.directory.api.dsmlv2.response.SearchResponseDsml;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests for the Search Result Entry Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResultEntryTest extends AbstractResponseTest
+{
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+        SearchResultEntry searchResultEntry =
+            searchResponse.getCurrentSearchResultEntry();
+        Map<String, Control> controls =
+            searchResponse.getCurrentSearchResultEntry().getControls();
+
+        assertEquals( 1, searchResultEntry.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+        SearchResultEntry searchResultEntry =
+            searchResponse.getCurrentSearchResultEntry();
+        Map<String, Control> controls = searchResultEntry.getControls();
+
+        assertEquals( 1, searchResultEntry.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_2_controls.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+        SearchResultEntry searchResultEntry =
+            searchResponse.getCurrentSearchResultEntry();
+        Map<String, Control> controls = searchResultEntry.getControls();
+
+        assertEquals( 2, searchResultEntry.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertFalse( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponse searchResponse = ( SearchResponse )
+            parser.getBatchResponse().getCurrentResponse().getDecorated();
+        SearchResultEntry searchResultEntry =
+            searchResponse.getCurrentSearchResultEntry();
+        Map<String, Control> controls = searchResultEntry.getControls();
+
+        assertEquals( 3, searchResultEntry.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response without dn Attribute
+     */
+    @Test
+    public void testResponseWithoutDnAttribute()
+    {
+        testParsingFail( SearchResultEntryTest.class, "response_without_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with wrong dn Attribute
+     */
+    @Test
+    public void testResponseWithWrongDnAttribute()
+    {
+        testParsingFail( SearchResultEntryTest.class, "response_with_wrong_dn_attribute.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with dn Attribute
+     */
+    @Test
+    public void testResponseWithDnAttribute()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_dn_attribute.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResponseDsml searchResponseDsml = ( SearchResponseDsml )
+            parser.getBatchResponse().getCurrentResponse();
+        SearchResponse response = ( SearchResponse ) searchResponseDsml.getDecorated();
+        SearchResultEntry searchResultEntry = response.getSearchResultEntryList().get( 0 );
+
+        assertEquals( "dc=example,dc=com", searchResultEntry.getObjectName().toString() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getCurrentSearchResultEntry();
+
+        assertEquals( 456, searchResultEntry.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( SearchResultEntryTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with 0 Attr
+     */
+    @Test
+    public void testResponseWith0Attr()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_0_attr.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        assertTrue( true );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Attr 0 Value
+     */
+    @Test
+    public void testResponseWith1Attr0Value()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                SearchResultEntryTest.class.getResource( "response_with_1_attr_0_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getCurrentSearchResultEntry();
+
+        Entry entry = searchResultEntry.getEntry();
+        assertEquals( 1, entry.size() );
+
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "dc", attribute.getUpId() );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Attr 1 Value
+     */
+    @Test
+    public void testResponseWith1Attr1Value()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                SearchResultEntryTest.class.getResource( "response_with_1_attr_1_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getCurrentSearchResultEntry();
+
+        Entry entry = searchResultEntry.getEntry();
+        assertEquals( 1, entry.size() );
+
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "dc", attribute.getUpId() );
+
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertEquals( "example", value.getString() );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Attr 1 Base64 Value
+     * @throws UnsupportedEncodingException
+     */
+    @Test
+    public void testResponseWith1Attr1Base64Value() throws UnsupportedEncodingException
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_1_attr_1_base64_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getCurrentSearchResultEntry();
+
+        Entry entry = searchResultEntry.getEntry();
+        assertEquals( 1, entry.size() );
+
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "cn", attribute.getUpId() );
+        assertEquals( 1, attribute.size() );
+
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+
+        String expected = new String( new byte[]
+            { 'E', 'm', 'm', 'a', 'n', 'u', 'e', 'l', ' ', 'L', ( byte ) 0xc3, ( byte ) 0xa9, 'c', 'h', 'a', 'r', 'n',
+                'y' }, "UTF-8" );
+        assertEquals( expected, value.getString() );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Attr 1 empty Value
+     */
+    @Test
+    public void testResponseWith1Attr1EmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultEntryTest.class.getResource( "response_with_1_attr_1_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getCurrentSearchResultEntry();
+
+        Entry entry = searchResultEntry.getEntry();
+        assertEquals( 1, entry.size() );
+
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "dc", attribute.getUpId() );
+        assertEquals( 1, attribute.size() );
+
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertEquals( "", value.getString() );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Attr 2 Value
+     */
+    @Test
+    public void testResponseWith1Attr2Value()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                SearchResultEntryTest.class.getResource( "response_with_1_attr_2_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getCurrentSearchResultEntry();
+
+        Entry entry = searchResultEntry.getEntry();
+        assertEquals( 1, entry.size() );
+
+        Iterator<Attribute> attributeIterator = entry.iterator();
+        Attribute attribute = attributeIterator.next();
+        assertEquals( "objectclass", attribute.getUpId() );
+        assertEquals( 2, attribute.size() );
+
+        Iterator<Value<?>> valueIterator = attribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertEquals( "top", value.getString() );
+        assertTrue( valueIterator.hasNext() );
+        value = valueIterator.next();
+        assertEquals( "domain", value.getString() );
+        assertFalse( valueIterator.hasNext() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 Attr 1 Value
+     */
+    @Test
+    public void testResponseWith2Attr1Value()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                SearchResultEntryTest.class.getResource( "response_with_2_attr_1_value.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ( ( SearchResponse ) parser.getBatchResponse().getCurrentResponse()
+            .getDecorated() )
+            .getCurrentSearchResultEntry();
+
+        Entry entry = searchResultEntry.getEntry();
+        assertEquals( 2, entry.size() );
+
+        Attribute objectClassAttribute = entry.get( "objectclass" );
+        assertEquals( 1, objectClassAttribute.size() );
+
+        Iterator<Value<?>> valueIterator = objectClassAttribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        Value<?> value = valueIterator.next();
+        assertEquals( "top", value.getString() );
+        assertFalse( valueIterator.hasNext() );
+
+        Attribute dcAttribute = entry.get( "dc" );
+        assertEquals( 1, objectClassAttribute.size() );
+
+        valueIterator = dcAttribute.iterator();
+        assertTrue( valueIterator.hasNext() );
+        value = valueIterator.next();
+        assertEquals( "example", value.getString() );
+        assertFalse( valueIterator.hasNext() );
+    }
+
+
+    /**
+     * Test parsing of a response with 1 Attr without name Attribute
+     */
+    @Test
+    public void testResponseWith1AttrWithoutNameAttribute()
+    {
+        testParsingFail( SearchResultEntryTest.class, "response_with_1_attr_without_name_attribute.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/SearchResultReferenceTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/SearchResultReferenceTest.java
new file mode 100644
index 0000000..51103a3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/SearchResultReferenceTest.java
@@ -0,0 +1,374 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.dsmlv2.searchResponse.searchResultReference;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.dsmlv2.AbstractResponseTest;
+import org.apache.directory.api.dsmlv2.DsmlControl;
+import org.apache.directory.api.dsmlv2.Dsmlv2ResponseParser;
+import org.apache.directory.api.dsmlv2.response.SearchResponse;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests for the Search Result Reference Response parsing
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResultReferenceTest extends AbstractResponseTest
+{
+    /**
+     * Test parsing of a response with a (optional) Control element
+     */
+    @Test
+    public void testResponseWith1Control()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultReferenceTest.class.getResource( "response_with_1_control.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+        Map<String, Control> controls = searchResultReference.getControls();
+
+        assertEquals( 1, searchResultReference.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertEquals( "Some text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with a (optional) Control element with empty value
+     */
+    @Test
+    public void testResponseWith1ControlEmptyValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultReferenceTest.class.getResource( "response_with_1_control_empty_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+        Map<String, Control> controls = searchResultReference.getControls();
+
+        assertEquals( 1, searchResultReference.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.643" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.643", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a response with 2 (optional) Control elements
+     */
+    @Test
+    public void testResponseWith2Controls()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput(
+                SearchResultReferenceTest.class.getResource( "response_with_2_controls.xml" ).openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+        Map<String, Control> controls = searchResultReference.getControls();
+
+        assertEquals( 2, searchResultReference.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.789" );
+
+        assertNotNull( control );
+        assertEquals( "1.2.840.113556.1.4.789", control.getOid() );
+        assertEquals( "Some other text", Strings.utf8ToString( ( ( DsmlControl<?> ) control ).getValue() ) );
+    }
+
+
+    /**
+     * Test parsing of a response with 3 (optional) Control elements without value
+     */
+    @Test
+    public void testResponseWith3ControlsWithoutValue()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultReferenceTest.class.getResource( "response_with_3_controls_without_value.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+        Map<String, Control> controls = searchResultReference.getControls();
+
+        assertEquals( 3, searchResultReference.getControls().size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.456" );
+
+        assertNotNull( control );
+        assertTrue( control.isCritical() );
+        assertEquals( "1.2.840.113556.1.4.456", control.getOid() );
+        assertFalse( ( ( DsmlControl<?> ) control ).hasValue() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute
+     */
+    @Test
+    public void testResponseWithRequestId()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultReferenceTest.class.getResource( "response_with_requestID_attribute.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+
+        assertEquals( 456, searchResultReference.getMessageId() );
+    }
+
+
+    /**
+     * Test parsing of a Response with the (optional) requestID attribute below 0
+     */
+    @Test
+    public void testResponseWithRequestIdBelow0()
+    {
+        testParsingFail( SearchResultReferenceTest.class, "response_with_requestID_below_0.xml" );
+    }
+
+
+    /**
+     * Test parsing of a response with 0 Ref
+     */
+    @Test
+    public void testResponseWith0Ref()
+    {
+        testParsingFail( SearchResultReferenceTest.class, "response_with_0_ref.xml" );
+    }
+
+
+    /**
+     * Test parsing of a Response with 1 Ref
+     */
+    @Test
+    public void testResponseWith1Ref()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultReferenceTest.class.getResource( "response_with_1_ref.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+
+        Collection<String> references = searchResultReference.getReferral().getLdapUrls();
+
+        assertEquals( 1, references.size() );
+
+        try
+        {
+            assertTrue( references.contains( new LdapUrl( "ldap://localhost" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a Response with 1 Ref
+     */
+    @Test
+    public void testResponseWith1EmptyRef()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultReferenceTest.class.getResource( "response_with_1_empty_ref.xml" )
+                .openStream(), "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+
+        Collection<String> references = searchResultReference.getReferral().getLdapUrls();
+
+        assertEquals( 0, references.size() );
+    }
+
+
+    /**
+     * Test parsing of a Response with 2 Ref
+     */
+    @Test
+    public void testResponseWith2Ref()
+    {
+        Dsmlv2ResponseParser parser = null;
+        try
+        {
+            parser = new Dsmlv2ResponseParser( getCodec() );
+
+            parser.setInput( SearchResultReferenceTest.class.getResource( "response_with_2_ref.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ( ( SearchResponse ) parser.getBatchResponse()
+            .getCurrentResponse().getDecorated() ).getCurrentSearchResultReference();
+
+        Collection<String> references = searchResultReference.getReferral().getLdapUrls();
+
+        assertEquals( 2, references.size() );
+
+        try
+        {
+            assertTrue( references.contains( new LdapUrl( "ldap://localhost" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+
+        try
+        {
+            assertTrue( references.contains( new LdapUrl( "ldap://www.apache.org" ).toString() ) );
+        }
+        catch ( LdapURLEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test parsing of a response with 1 wrong Ref
+     */
+    @Test
+    public void testResponseWith1WrongRef()
+    {
+        testParsingFail( SearchResultReferenceTest.class, "response_with_1_wrong_ref.xml" );
+    }
+}
diff --git a/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/soap/SoapDsmlParsingTest.java b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/soap/SoapDsmlParsingTest.java
new file mode 100644
index 0000000..891a3e0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/java/org/apache/directory/api/dsmlv2/soap/SoapDsmlParsingTest.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.dsmlv2.soap;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
+import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.junit.Test;
+
+
+/**
+ * Class which tests the parsing of DSML documents embedded in a SOAP envelope.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SoapDsmlParsingTest
+{
+
+    @Test
+    public void testParsingRequestsOneByOne() throws Exception
+    {
+
+        Dsmlv2Parser parser = new Dsmlv2Parser( false );
+
+        parser.setInput( SoapDsmlParsingTest.class.getResource( "soap-dsml-multiple-operation-requests.xml" )
+            .openStream(),
+            "UTF-8" );
+
+        parser.parseBatchRequest();
+
+        BatchRequestDsml batchReq = parser.getBatchRequest();
+
+        assertNotNull( batchReq );
+        assertFalse( batchReq.isStoringRequests() );
+
+        assertTrue( batchReq.getRequests().isEmpty() );
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getNextRequest();
+
+        assertTrue( searchRequest.getTypesOnly() );
+
+        // assert again that the batch request object is not storing requests
+        assertTrue( batchReq.getRequests().isEmpty() );
+
+        searchRequest = ( SearchRequest ) parser.getNextRequest();
+
+        assertFalse( searchRequest.getTypesOnly() );
+
+        assertNull( parser.getNextRequest() );
+
+        // assert again that the batch request object is not storing requests
+        assertTrue( batchReq.getRequests().isEmpty() );
+
+        assertNotNull( batchReq.getCurrentRequest() );
+    }
+
+
+    /**
+     * Test parsing of a request without a SOAP header
+     */
+    @Test
+    public void testBatchRequestWithoutSoapHeader()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = new Dsmlv2Parser();
+
+            parser.setInput( SoapDsmlParsingTest.class.getResource( "soap-dsml-req-without-header.xml" ).openStream(),
+                "UTF-8" );
+
+            SearchRequest searchRequest = ( SearchRequest ) parser.getNextRequest();
+
+            assertTrue( searchRequest.getTypesOnly() );
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+    }
+
+
+    /**
+     * Test parsing of a request *with* a SOAP header
+     */
+    @Test
+    public void testBatchRequestWithSoapHeader()
+    {
+        Dsmlv2Parser parser = null;
+        try
+        {
+            parser = new Dsmlv2Parser();
+
+            parser.setInput( SoapDsmlParsingTest.class.getResource( "soap-dsml-req-with-header.xml" ).openStream(),
+                "UTF-8" );
+
+            parser.parse();
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+
+        SearchRequest searchRequest = ( SearchRequest ) parser.getBatchRequest().getCurrentRequest();
+
+        assertTrue( searchRequest.getTypesOnly() );
+    }
+
+}
diff --git a/trunk/dsml/parser/src/test/resources/log4j.properties b/trunk/dsml/parser/src/test/resources/log4j.properties
new file mode 100644
index 0000000..c3be193
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/log4j.properties
@@ -0,0 +1,22 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_0_abandonID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_0_abandonID_attribute.xml
new file mode 100644
index 0000000..8c7af73
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_0_abandonID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="0" >
+	<abandonRequest abandonID="0">
+	</abandonRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control.xml
new file mode 100644
index 0000000..bccc53b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..2de0334
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<abandonRequest abandonID="123">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..ffe23b9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..7b2ff85
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_2_controls.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..50a17c2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_abandonID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_abandonID_attribute.xml
new file mode 100644
index 0000000..f65fcf2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_abandonID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123">
+	</abandonRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..ab3290e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_needed_requestID.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123">
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..d718087
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123" requestID="456">
+	</abandonRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..a892f64
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest abandonID="123" requestID="-1">
+	</abandonRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_without_abandonID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_without_abandonID_attribute.xml
new file mode 100644
index 0000000..ff917e8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/abandonRequest/request_without_abandonID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<abandonRequest>
+	</abandonRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_empty_value.xml
new file mode 100644
index 0000000..716a88d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_empty_value.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<attr name="objectclass"><value></value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_2_values.xml
new file mode 100644
index 0000000..cb6b5b0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_2_values.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value><value>person</value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_base64_value.xml
new file mode 100644
index 0000000..a923490
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_base64_value.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<attr name="objectclass">
+			<value xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</value>
+		</attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_value.xml
new file mode 100644
index 0000000..4217f82
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_with_value.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_without_name_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_without_name_attribute.xml
new file mode 100644
index 0000000..596d266
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_without_name_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<attr><value>top</value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_without_value.xml
new file mode 100644
index 0000000..778a0b5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_attr_without_value.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<attr name="objectclass"></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control.xml
new file mode 100644
index 0000000..94d60e7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..4bd6739
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..582e178
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_2_attr_with_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_2_attr_with_value.xml
new file mode 100644
index 0000000..5b231f6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_2_attr_with_value.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value></attr>
+		<attr name="objectclass"><value>person</value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..22d3fac
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_2_controls.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..849c7c2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_dn_attribute.xml
new file mode 100644
index 0000000..e9cf131
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_dn_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..4e86ef6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_needed_requestID.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..6c1a8ab
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest requestID="456" dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..a5f8384
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest requestID="-1" dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_without_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_without_dn_attribute.xml
new file mode 100644
index 0000000..e750713
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addRequest/request_without_dn_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addRequest>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_control.xml
new file mode 100644
index 0000000..2b906f0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..d5615d8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..7149290
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_empty_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral></referral>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_referral.xml
new file mode 100644
index 0000000..ec62f63
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..5ac0577
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<referral>ldap://www.apache.org</referral>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_2_controls.xml
new file mode 100644
index 0000000..c8182d3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_2_referrals.xml
new file mode 100644
index 0000000..bb47019
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_2_referrals.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+    	<referral>ldap://www.apple.com</referral>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..63b30c8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_empty_error_message.xml
new file mode 100644
index 0000000..5df46ae
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_empty_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage></errorMessage>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_error_message.xml
new file mode 100644
index 0000000..d57ab51
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..01daf69
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10" matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..8d9a5f0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="456">
+		<resultCode code="0" descr="success"/>
+	</addResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..76991e0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="-1">
+		<resultCode code="0" descr="success"/>
+	</addResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_result_code.xml
new file mode 100644
index 0000000..2b393cf
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_result_code.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..d0a6254
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_result_code_not_integer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="error" descr="protocolError"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_wrong_descr.xml
new file mode 100644
index 0000000..87975f6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_wrong_descr.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+		<resultCode code="0" descr="succes"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..6907011
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10" matchedDN="This is a wrong matchedDN">
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_without_result_code.xml
new file mode 100644
index 0000000..d9de783
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/addResponse/response_without_result_code.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<addResponse requestID="10">
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control.xml
new file mode 100644
index 0000000..69aa3a9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..0b5816d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..44ff418
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..bc9e5cb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_2_controls.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..0d33a9d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..b153ba8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_needed_requestID.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_principal_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_principal_attribute.xml
new file mode 100644
index 0000000..e5ed017
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_principal_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..30343ee
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest requestID="456" principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..459b305
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest requestID="-1" principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_without_principal_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_without_principal_attribute.xml
new file mode 100644
index 0000000..774378f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authRequest/request_without_principal_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authRequest>
+	</authRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_control.xml
new file mode 100644
index 0000000..f2d8a11
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..9e13d0d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..3c9f055
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_empty_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral></referral>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_referral.xml
new file mode 100644
index 0000000..957480e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..226e4b8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<referral>ldap://www.apache.org</referral>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_2_controls.xml
new file mode 100644
index 0000000..ff2b76b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_2_referrals.xml
new file mode 100644
index 0000000..682274f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_2_referrals.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+    	<referral>ldap://www.apple.com</referral>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..ccf779d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_empty_error_message.xml
new file mode 100644
index 0000000..21b4f18
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_empty_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage></errorMessage>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_error_message.xml
new file mode 100644
index 0000000..8946df4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..f0f4b20
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10" matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..36da350
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="456">
+		<resultCode code="0" descr="success"/>
+	</authResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..bb07ef6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="-1">
+		<resultCode code="0" descr="success"/>
+	</authResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_result_code.xml
new file mode 100644
index 0000000..bdc5dab
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_result_code.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..ba4a15b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_result_code_not_integer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="error" descr="protocolError"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_wrong_descr.xml
new file mode 100644
index 0000000..8fcecd0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_wrong_descr.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+		<resultCode code="0" descr="succes"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..81db6ae
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10" matchedDN="This is a wrong matchedDN">
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_without_result_code.xml
new file mode 100644
index 0000000..3e64e7d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/authResponse/response_without_result_code.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<authResponse requestID="10">
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_0_request.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_0_request.xml
new file mode 100644
index 0000000..167a3d5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_0_request.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AbandonRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AbandonRequest.xml
new file mode 100644
index 0000000..a268f93
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AbandonRequest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<abandonRequest abandonID="123">
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AddRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AddRequest.xml
new file mode 100644
index 0000000..ce22de6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AddRequest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<addRequest requestID="5" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value></attr>
+		<attr name="objectclass"><value>person</value></attr>
+		<attr name="sn"><value>snvalue</value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AuthRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AuthRequest.xml
new file mode 100644
index 0000000..bf3fdd1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AuthRequest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AuthRequest_1_AddRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AuthRequest_1_AddRequest.xml
new file mode 100644
index 0000000..26815f9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_AuthRequest_1_AddRequest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</authRequest>
+	<addRequest requestID="5" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value></attr>
+		<attr name="objectclass"><value>person</value></attr>
+		<attr name="sn"><value>snvalue</value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_CompareRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_CompareRequest.xml
new file mode 100644
index 0000000..8c0818c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_CompareRequest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<compareRequest requestID="9" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<assertion name="sn"><value>CN=Michael Scofield, DC=prisonbreak, Dc=com</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_DelRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_DelRequest.xml
new file mode 100644
index 0000000..f030c98
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_DelRequest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<delRequest requestID="7" dn="CN=Bob Rush,DC=Example,DC=COM">
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ExtendedRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ExtendedRequest.xml
new file mode 100644
index 0000000..4f37177
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ExtendedRequest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<extendedRequest requestID="12">
+		<requestName>1.2.6.1.4.1.18060.1.1.1.100.2</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ModDNRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ModDNRequest.xml
new file mode 100644
index 0000000..072a8d9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ModDNRequest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<modDNRequest requestID="10" dn="CN=Bobby Rush,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ModifyRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ModifyRequest.xml
new file mode 100644
index 0000000..6d317ab
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_ModifyRequest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<modifyRequest requestID="13" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<modification name="sn" operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+			<value>CN=Michael Scofield, DC=prisonbreak, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_SearchRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_SearchRequest.xml
new file mode 100644
index 0000000..53f5a26
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_1_SearchRequest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<searchRequest requestID="14" 
+				   dn="dc=example,dc=com"
+				   scope="wholeSubtree"
+				   derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="objectclass">
+				<any>o</any>
+			</substrings>		
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_AbandonRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_AbandonRequest.xml
new file mode 100644
index 0000000..dabe452
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_AbandonRequest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<abandonRequest abandonID="123">
+	</abandonRequest>
+	<abandonRequest abandonID="123">
+	</abandonRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_AddRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_AddRequest.xml
new file mode 100644
index 0000000..70a5a08
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_AddRequest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<addRequest requestID="5" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value></attr>
+		<attr name="objectclass"><value>person</value></attr>
+		<attr name="sn"><value>snvalue</value></attr>
+	</addRequest>
+	<addRequest requestID="5" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value></attr>
+		<attr name="objectclass"><value>person</value></attr>
+		<attr name="sn"><value>snvalue</value></attr>
+	</addRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_CompareRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_CompareRequest.xml
new file mode 100644
index 0000000..a09407f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_CompareRequest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<compareRequest requestID="9" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<assertion name="sn"><value>CN=Michael Scofield, DC=prisonbreak, Dc=com</value></assertion>
+	</compareRequest>
+	<compareRequest requestID="9" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<assertion name="sn"><value>CN=Michael Scofield, DC=prisonbreak, Dc=com</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_DelRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_DelRequest.xml
new file mode 100644
index 0000000..ab32719
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_DelRequest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<delRequest requestID="7" dn="CN=Bob Rush,DC=Example,DC=COM">
+	</delRequest>
+	<delRequest requestID="7" dn="CN=Bob Rush,DC=Example,DC=COM">
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ExtendedRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ExtendedRequest.xml
new file mode 100644
index 0000000..765348f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ExtendedRequest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<extendedRequest requestID="12">
+		<requestName>1.2.6.1.4.1.18060.1.1.1.100.2</requestName>
+	</extendedRequest>
+	<extendedRequest requestID="12">
+		<requestName>1.2.6.1.4.1.18060.1.1.1.100.2</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ModDNRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ModDNRequest.xml
new file mode 100644
index 0000000..1497725
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ModDNRequest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<modDNRequest requestID="10" dn="CN=Bobby Rush,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush">
+	</modDNRequest>
+	<modDNRequest requestID="10" dn="CN=Bobby Rush,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ModifyRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ModifyRequest.xml
new file mode 100644
index 0000000..1349180
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_ModifyRequest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<modifyRequest requestID="13" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<modification name="sn" operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+			<value>CN=Michael Scofield, DC=prisonbreak, DC=com</value>
+		</modification>
+	</modifyRequest>
+	<modifyRequest requestID="13" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<modification name="sn" operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+			<value>CN=Michael Scofield, DC=prisonbreak, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_SearchRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_SearchRequest.xml
new file mode 100644
index 0000000..8e5fa33
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_2_SearchRequest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<searchRequest requestID="14" 
+				   dn="dc=example,dc=com"
+				   scope="wholeSubtree"
+				   derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="objectclass">
+				<any>o</any>
+			</substrings>		
+		</filter>
+	</searchRequest>
+	<searchRequest requestID="15" 
+				   dn="dc=example,dc=com"
+				   scope="wholeSubtree"
+				   derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="objectclass">
+				<any>o</any>
+			</substrings>		
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..50a3196
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..5e0decd
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="-1">
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_wrong_placed_AuthRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_wrong_placed_AuthRequest.xml
new file mode 100644
index 0000000..80a98a1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchRequest/request_with_wrong_placed_AuthRequest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+	<addRequest requestID="5" dn="CN=Bob Rush,DC=Example,DC=COM">
+		<attr name="objectclass"><value>top</value></attr>
+		<attr name="objectclass"><value>person</value></attr>
+		<attr name="sn"><value>snvalue</value></attr>
+	</addRequest>
+	<authRequest principal="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</authRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_0_response.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_0_response.xml
new file mode 100644
index 0000000..2c10460
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_0_response.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_AddResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_AddResponse.xml
new file mode 100644
index 0000000..1cfd37d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_AddResponse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_AuthResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_AuthResponse.xml
new file mode 100644
index 0000000..8d606b7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_AuthResponse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authResponse requestID="20">
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_CompareResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_CompareResponse.xml
new file mode 100644
index 0000000..42ce3bb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_CompareResponse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareResponse requestID="30">
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_DelResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_DelResponse.xml
new file mode 100644
index 0000000..444c356
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_DelResponse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delResponse requestID="40">
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ErrorResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ErrorResponse.xml
new file mode 100644
index 0000000..709bd56
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ErrorResponse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<errorResponse type="couldNotConnect" requestID="80">
+		<message>Connection refused</message>
+	</errorResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ExtendedResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ExtendedResponse.xml
new file mode 100644
index 0000000..7543299
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ExtendedResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedResponse requestID="70">
+    	<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<responseName>1.2.3.4.5.6.7.8.9.0</responseName>
+		<response>A response</response>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ModDNResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ModDNResponse.xml
new file mode 100644
index 0000000..89d1362
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ModDNResponse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNResponse requestID="60">
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ModifyResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ModifyResponse.xml
new file mode 100644
index 0000000..e3cb8b3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_ModifyResponse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyResponse requestID="50">
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_SearchResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_SearchResponse.xml
new file mode 100644
index 0000000..93f7fa3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_1_SearchResponse.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<searchResponse requestID="90">
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_AddResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_AddResponse.xml
new file mode 100644
index 0000000..bec99d5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_AddResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<addResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+	<addResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+	</addResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_AuthResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_AuthResponse.xml
new file mode 100644
index 0000000..3f54c91
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_AuthResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<authResponse requestID="20">
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+	<authResponse requestID="20">
+		<resultCode code="0" descr="success"/>
+	</authResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_CompareResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_CompareResponse.xml
new file mode 100644
index 0000000..ca664e1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_CompareResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareResponse requestID="30">
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+	<compareResponse requestID="30">
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_DelResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_DelResponse.xml
new file mode 100644
index 0000000..76c0b9e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_DelResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delResponse requestID="40">
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+	<delResponse requestID="40">
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ErrorResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ErrorResponse.xml
new file mode 100644
index 0000000..97a5dd9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ErrorResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<errorResponse type="couldNotConnect" requestID="80">
+		<message>Connection refused</message>
+	</errorResponse>
+	<errorResponse type="couldNotConnect" requestID="80">
+		<message>Connection refused</message>
+	</errorResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ExtendedResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ExtendedResponse.xml
new file mode 100644
index 0000000..d6552d5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ExtendedResponse.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedResponse requestID="70">
+    	<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<responseName>1.2.3.4.5.6.7.8.9.0</responseName>
+		<response>A response</response>
+	</extendedResponse>
+	<extendedResponse requestID="70">
+    	<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<responseName>1.2.3.4.5.6.7.8.9.0</responseName>
+		<response>A response</response>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ModDNResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ModDNResponse.xml
new file mode 100644
index 0000000..4e0998f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ModDNResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNResponse requestID="60">
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+	<modDNResponse requestID="60">
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ModifyResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ModifyResponse.xml
new file mode 100644
index 0000000..c7a5487
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_ModifyResponse.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyResponse requestID="50">
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+	<modifyResponse requestID="50">
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_SearchResponse.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_SearchResponse.xml
new file mode 100644
index 0000000..818eaf8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_2_SearchResponse.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<searchResponse requestID="90">
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+	<searchResponse requestID="90">
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..771a05e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="1234567890">
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..00c44cc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/batchResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" requestID="-1">
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_empty_value.xml
new file mode 100644
index 0000000..eecedee
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_empty_value.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"><value></value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_with_2_values.xml
new file mode 100644
index 0000000..81ca720
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_with_2_values.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"><value>Johnson</value></assertion>
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_without_name_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_without_name_attribute.xml
new file mode 100644
index 0000000..7267f38
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_without_name_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_without_value.xml
new file mode 100644
index 0000000..8107be2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_assertion_without_value.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"/>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_complete_assertion.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_complete_assertion.xml
new file mode 100644
index 0000000..411d917
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_complete_assertion.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_complete_assertion_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_complete_assertion_base64_value.xml
new file mode 100644
index 0000000..c1ac937
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_complete_assertion_base64_value.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"><value xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control.xml
new file mode 100644
index 0000000..f4c5915
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..3ee6bb6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..c7a4157
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_2_complete_assertions.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_2_complete_assertions.xml
new file mode 100644
index 0000000..2ce206e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_2_complete_assertions.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"><value>Johnson</value></assertion>
+		<assertion name="sn"><value>Thomson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..7f80563
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..96c2be8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_dn_attribute.xml
new file mode 100644
index 0000000..411d917
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_dn_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..7c45944
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_needed_requestID.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..a9e7d54
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM" requestID="456">
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..4dce2b3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM" requestID="-1">
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_without_assertion.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_without_assertion.xml
new file mode 100644
index 0000000..09b8d38
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_without_assertion.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_without_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_without_dn_attribute.xml
new file mode 100644
index 0000000..7916fa6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareRequest/request_without_dn_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<compareRequest>
+		<assertion name="sn"><value>Johnson</value></assertion>
+	</compareRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_control.xml
new file mode 100644
index 0000000..c9d5e4e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..f356bc6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..a7d4985
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_empty_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral></referral>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_referral.xml
new file mode 100644
index 0000000..5d2795e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..c8755d3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<referral>ldap://www.apache.org</referral>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_2_controls.xml
new file mode 100644
index 0000000..5938397
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_2_referrals.xml
new file mode 100644
index 0000000..1ec7b7b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_2_referrals.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+    	<referral>ldap://www.apple.com</referral>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..25a7d49
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_empty_error_message.xml
new file mode 100644
index 0000000..ce71e51
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_empty_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage></errorMessage>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_error_message.xml
new file mode 100644
index 0000000..18da70f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..2442227
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10" matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..560bb6f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="456">
+		<resultCode code="0" descr="success"/>
+	</compareResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..deaf89e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="-1">
+		<resultCode code="0" descr="success"/>
+	</compareResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_result_code.xml
new file mode 100644
index 0000000..ad6df96
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_result_code.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..c88a200
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_result_code_not_integer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="error" descr="protocolError"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_wrong_descr.xml
new file mode 100644
index 0000000..c0f3c96
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_wrong_descr.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+		<resultCode code="0" descr="succes"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..fec33a3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10" matchedDN="This is a wrong matchedDN">
+		<resultCode code="0" descr="success"/>
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_without_result_code.xml
new file mode 100644
index 0000000..99ced25
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/compareResponse/response_without_result_code.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<compareResponse requestID="10">
+	</compareResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control.xml
new file mode 100644
index 0000000..60b4aff
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..469348d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<delRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..c4af740
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..f4d1d94
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_2_controls.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..895cb3e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_dn_attribute.xml
new file mode 100644
index 0000000..731934d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_dn_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..f35fbe4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_needed_requestID.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..ef198d7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest requestID="456" dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..68d5762
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest requestID="-1" dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_without_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_without_dn_attribute.xml
new file mode 100644
index 0000000..fe71fed
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delRequest/request_without_dn_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<delRequest>
+	</delRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_control.xml
new file mode 100644
index 0000000..6e6c316
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..1eb1be9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..acbf8d7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_empty_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral></referral>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_referral.xml
new file mode 100644
index 0000000..8fae3aa
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..71bfd3f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<referral>ldap://www.apache.org</referral>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_2_controls.xml
new file mode 100644
index 0000000..6771e65
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_2_referrals.xml
new file mode 100644
index 0000000..477be79
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_2_referrals.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+    	<referral>ldap://www.apple.com</referral>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..39401ad
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_empty_error_message.xml
new file mode 100644
index 0000000..8a70916
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_empty_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage></errorMessage>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_error_message.xml
new file mode 100644
index 0000000..7027959
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..d02e41b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10" matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..d5aeb4b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="456">
+		<resultCode code="0" descr="success"/>
+	</delResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..f98db77
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="-1">
+		<resultCode code="0" descr="success"/>
+	</delResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_result_code.xml
new file mode 100644
index 0000000..4f5ed52
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_result_code.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..02c843f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_result_code_not_integer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="error" descr="protocolError"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_wrong_descr.xml
new file mode 100644
index 0000000..389542f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_wrong_descr.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+		<resultCode code="0" descr="succes"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..84a1858
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10" matchedDN="This is a wrong matchedDN">
+		<resultCode code="0" descr="success"/>
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_without_result_code.xml
new file mode 100644
index 0000000..c2f078f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/delResponse/response_without_result_code.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<delResponse requestID="10">
+	</delResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_empty_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_empty_message.xml
new file mode 100644
index 0000000..10e7baf
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_empty_message.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="couldNotConnect">
+		<message></message>
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_message.xml
new file mode 100644
index 0000000..370c228
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_message.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="couldNotConnect">
+		<message>Connection refused</message>
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..7051908
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="couldNotConnect">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..324d467
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="-1">
+	<errorResponse requestID="-1" type="couldNotConnect">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_authenticationFailed.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_authenticationFailed.xml
new file mode 100644
index 0000000..6e743bb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_authenticationFailed.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="authenticationFailed">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_connectionClosed.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_connectionClosed.xml
new file mode 100644
index 0000000..a20a6bf
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_connectionClosed.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="connectionClosed">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_couldNotConnect.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_couldNotConnect.xml
new file mode 100644
index 0000000..7051908
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_couldNotConnect.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="couldNotConnect">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_gatewayInternalError.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_gatewayInternalError.xml
new file mode 100644
index 0000000..400cb39
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_gatewayInternalError.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="gatewayInternalError">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_inError.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_inError.xml
new file mode 100644
index 0000000..31c8734
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_inError.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="error">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_malformedRequest.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_malformedRequest.xml
new file mode 100644
index 0000000..3167a97
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_malformedRequest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="malformedRequest">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_notAttempted.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_notAttempted.xml
new file mode 100644
index 0000000..b7f76b5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_notAttempted.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="notAttempted">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_other.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_other.xml
new file mode 100644
index 0000000..2b0fd33
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_other.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="other">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_unresolvableURI.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_unresolvableURI.xml
new file mode 100644
index 0000000..4b10162
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_with_type_unresolvableURI.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456" type="unresolvableURI">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_without_type.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_without_type.xml
new file mode 100644
index 0000000..7865d27
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/errorResponse/response_without_type.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<errorResponse requestID="456">
+	</errorResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control.xml
new file mode 100644
index 0000000..b291b1a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..405f68c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<extendedRequest>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..b695f0b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..d37f52f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_requestName.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_requestName.xml
new file mode 100644
index 0000000..aac512c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_requestName.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<requestName>1.3.563.52.425</requestName>
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_requestValue.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_requestValue.xml
new file mode 100644
index 0000000..a435a84
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_2_requestValue.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<extendedRequest>
+		<requestName>1.3.563.52.425</requestName>
+		<requestValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</requestValue>
+		<requestValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</requestValue>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..3153f94
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_base64_requestValue.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_base64_requestValue.xml
new file mode 100644
index 0000000..b29cc36
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_base64_requestValue.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<extendedRequest>
+		<requestName>1.3.563.52.425</requestName>
+		<requestValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</requestValue>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_empty_requestName.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_empty_requestName.xml
new file mode 100644
index 0000000..0ca1e1b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_empty_requestName.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3c.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3c.org/2001/XMLSchema">
+	<extendedRequest>
+		<requestName></requestName>
+		<requestValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</requestValue>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_empty_requestValue.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_empty_requestValue.xml
new file mode 100644
index 0000000..876fe8c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_empty_requestValue.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<requestName>1.3.563.52.425</requestName>
+		<requestValue></requestValue>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..44329ff
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_needed_requestID.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..82ad843
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest requestID="456">
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..c6df3a3f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest requestID="-1">
+		<requestName>1.3.563.52.425</requestName>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestValue.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestValue.xml
new file mode 100644
index 0000000..a865b43
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_with_requestValue.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+		<requestName>1.3.563.52.425</requestName>
+		<requestValue>foobar</requestValue>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_without_requestName.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_without_requestName.xml
new file mode 100644
index 0000000..534a577
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedRequest/request_without_requestName.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<extendedRequest>
+	</extendedRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_control.xml
new file mode 100644
index 0000000..36eb3dc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..836d96e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..bbf673f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_empty_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral></referral>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_referral.xml
new file mode 100644
index 0000000..899a1a3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..e79ba04
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<referral>ldap://www.apache.org</referral>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_2_controls.xml
new file mode 100644
index 0000000..a1e2e83
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_2_referrals.xml
new file mode 100644
index 0000000..16e39e8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_2_referrals.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+    	<referral>ldap://www.apple.com</referral>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..4a28397
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_base64_response.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_base64_response.xml
new file mode 100644
index 0000000..5dcb2d2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_base64_response.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+		<response xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</response>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_error_message.xml
new file mode 100644
index 0000000..8e4b247
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage></errorMessage>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_response.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_response.xml
new file mode 100644
index 0000000..5ee3e2d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_response.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+		<response></response>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_responseName.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_responseName.xml
new file mode 100644
index 0000000..d23369a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_empty_responseName.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+		<responseName></responseName>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_error_message.xml
new file mode 100644
index 0000000..2916ff3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..eedac94
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10" matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..ea70a29
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="456">
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..a50fafc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="-1">
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_response.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_response.xml
new file mode 100644
index 0000000..140bf5f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_response.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+		<response>This is a response</response>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_responseName.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_responseName.xml
new file mode 100644
index 0000000..9f4541e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_responseName.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+		<responseName>1.2.3.4.5.6.7.8.9.0</responseName>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_responseName_and_response.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_responseName_and_response.xml
new file mode 100644
index 0000000..479948a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_responseName_and_response.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+		<responseName>1.2.3.4.5.6.7.8.9.0</responseName>
+		<response>This is a response</response>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_result_code.xml
new file mode 100644
index 0000000..b6f18ce
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_result_code.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..4616d70
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_result_code_not_integer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="error" descr="protocolError"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_descr.xml
new file mode 100644
index 0000000..17e7e34
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_descr.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="succes"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..0478aaf
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10" matchedDN="This is a wrong matchedDN">
+		<resultCode code="0" descr="success"/>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_responseName.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_responseName.xml
new file mode 100644
index 0000000..8a171b7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_with_wrong_responseName.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+		<resultCode code="0" descr="success"/>
+		<responseName>Wrong ResponseName</responseName>
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_without_result_code.xml
new file mode 100644
index 0000000..c2b829c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/extendedResponse/response_without_result_code.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<extendedResponse requestID="10">
+	</extendedResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control.xml
new file mode 100644
index 0000000..2fecea4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush2">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..47fa8a3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush2">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..dd352ec
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush2">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..f7b32ee
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush2">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..f59d07b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush2">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_0.xml
new file mode 100644
index 0000000..89f4167
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_0.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+				newrdn="CN=Bob Rush2"
+				deleteoldrdn="0">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_1.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_1.xml
new file mode 100644
index 0000000..e14b98b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_1.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+				newrdn="CN=Bob Rush2"
+				deleteoldrdn="1">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_error.xml
new file mode 100644
index 0000000..433fa6f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_error.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+				newrdn="CN=Bob Rush2"
+				deleteoldrdn="error">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_false.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_false.xml
new file mode 100644
index 0000000..6ae1ce4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_false.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+				newrdn="CN=Bob Rush2"
+				deleteoldrdn="false">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_true.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_true.xml
new file mode 100644
index 0000000..7028214
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_deleteoldrdn_true.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+				newrdn="CN=Bob Rush2"
+				deleteoldrdn="true">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_dn_and_newrdn_attributes.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_dn_and_newrdn_attributes.xml
new file mode 100644
index 0000000..3c2bcbb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_dn_and_newrdn_attributes.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+				newrdn="CN=Steve Jobs">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..c807123
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_needed_requestID.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+								newrdn="CN=Bob Rush2">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_newSuperior_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_newSuperior_attribute.xml
new file mode 100644
index 0000000..27dc26e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_newSuperior_attribute.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+				newrdn="CN=Bob Rush2"
+				newSuperior="CN=Steve Jobs,OU=Dev,DC=apple,DC=com">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..8bd0982
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+					newrdn="CN=Bob Rush2"
+					requestID="456">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..953638a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM"
+					newrdn="CN=Bob Rush2"
+					requestID="-1">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_without_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_without_dn_attribute.xml
new file mode 100644
index 0000000..aff61b3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_without_dn_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest newrdn="CN=Bob Rush2">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_without_newrdn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_without_newrdn_attribute.xml
new file mode 100644
index 0000000..3decbab
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNRequest/request_without_newrdn_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modDNRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</modDNRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_control.xml
new file mode 100644
index 0000000..e1f737e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..4e0ecab
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..92aacf0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_empty_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral></referral>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_referral.xml
new file mode 100644
index 0000000..6758f54
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..7eefbaa
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<referral>ldap://www.apache.org</referral>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_2_controls.xml
new file mode 100644
index 0000000..457415e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_2_referrals.xml
new file mode 100644
index 0000000..66d9aa5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_2_referrals.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+    	<referral>ldap://www.apple.com</referral>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..d006345
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_empty_error_message.xml
new file mode 100644
index 0000000..baa345d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_empty_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage></errorMessage>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_error_message.xml
new file mode 100644
index 0000000..34bcd4f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..0361cdb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10" matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..9a43418
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="456">
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..b55aaab
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="-1">
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_result_code.xml
new file mode 100644
index 0000000..5fc37f1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_result_code.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..6e89127
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_result_code_not_integer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="error" descr="protocolError"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_wrong_descr.xml
new file mode 100644
index 0000000..af06882
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_wrong_descr.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+		<resultCode code="0" descr="succes"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..df66be1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10" matchedDN="This is a wrong matchedDN">
+		<resultCode code="0" descr="success"/>
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_without_result_code.xml
new file mode 100644
index 0000000..d2081dd
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modDNResponse/response_without_result_code.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modDNResponse requestID="10">
+	</modDNResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control.xml
new file mode 100644
index 0000000..2de7089
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..caa3002
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..8dc30b0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification.xml
new file mode 100644
index 0000000..dc83a0f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification_base64_value.xml
new file mode 100644
index 0000000..9930b05
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_1_modification_base64_value.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="add">
+			<value xsi:type="xsd:base64Binary">Y249RW1tYW51ZWwgTMOpY2hhcm55LCBvdT1wZW9wbGUsIGRjPWV4YW1wbGUsIGRjPWNvbQ==</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..f8fca59
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_2_controls.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_2_modifications.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_2_modifications.xml
new file mode 100644
index 0000000..03db041
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_2_modifications.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+		<modification name="sn" operation="replace">
+			<value>CN=Steve Jobs, DC=apple, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..6edf9fb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_with_2_values.xml
new file mode 100644
index 0000000..5c7293e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_with_2_values.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+			<value>CN=Steve Jobs, DC=apple, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_with_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_with_empty_value.xml
new file mode 100644
index 0000000..93df27c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_with_empty_value.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="add">
+			<value></value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_without_value.xml
new file mode 100644
index 0000000..00815a2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_modification_without_value.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="add">
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..ccb8a68
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_needed_requestID.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_add.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_add.xml
new file mode 100644
index 0000000..dc83a0f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_add.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_delete.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_delete.xml
new file mode 100644
index 0000000..62688e1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_delete.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="delete">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_error.xml
new file mode 100644
index 0000000..ab8f60d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_error.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="error">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_replace.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_replace.xml
new file mode 100644
index 0000000..444af68
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_operation_replace.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport" operation="replace">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..602ff34
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM" requestID="456">
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..6b6050b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM" requestID="-1">
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_dn_attribute.xml
new file mode 100644
index 0000000..787d885
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_dn_attribute.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_name_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_name_attribute.xml
new file mode 100644
index 0000000..2d84d14
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_name_attribute.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification operation="add">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_operation_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_operation_attribute.xml
new file mode 100644
index 0000000..4392c87
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyRequest/request_without_operation_attribute.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<modifyRequest dn="CN=Bob Rush,OU=Dev,DC=Example,DC=COM">
+		<modification name="directReport">
+			<value>CN=John Smith, DC=microsoft, DC=com</value>
+		</modification>
+	</modifyRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_control.xml
new file mode 100644
index 0000000..d301b80
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_control.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..82606f9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_control_empty_value.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..3542838
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_empty_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral></referral>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_referral.xml
new file mode 100644
index 0000000..5e0a5c6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_referral.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..e80d493
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		<referral>ldap://www.apache.org</referral>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_2_controls.xml
new file mode 100644
index 0000000..5e41421
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_2_controls.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse>
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_2_referrals.xml
new file mode 100644
index 0000000..8a25f7c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_2_referrals.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<referral>ldap://www.apache.org</referral>
+    	<referral>ldap://www.apple.com</referral>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..3983f0a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_3_controls_without_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_empty_error_message.xml
new file mode 100644
index 0000000..da639a6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_empty_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage></errorMessage>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_error_message.xml
new file mode 100644
index 0000000..664675e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_error_message.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+    	<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..b61d77a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10" matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..e4b6084
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="456">
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..0308785
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="-1">
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>	
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_result_code.xml
new file mode 100644
index 0000000..d4337f0
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_result_code.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="2" descr="protocolError"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..e81195a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_result_code_not_integer.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="error" descr="protocolError"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_wrong_descr.xml
new file mode 100644
index 0000000..4a31009
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_wrong_descr.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+		<resultCode code="0" descr="succes"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..cfc1813
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10" matchedDN="This is a wrong matchedDN">
+		<resultCode code="0" descr="success"/>
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_without_result_code.xml
new file mode 100644
index 0000000..61fce48
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/modifyResponse/response_without_result_code.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<modifyResponse requestID="10">
+	</modifyResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_and.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_and.xml
new file mode 100644
index 0000000..0f8cecb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_and.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<and>
+				<approxMatch name="sn">
+					<value>foobar</value>
+				</approxMatch>
+				<approxMatch name="sn">
+					<value>foobar</value>
+				</approxMatch>
+			</and>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch.xml
new file mode 100644
index 0000000..cccc276
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>foobar</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_base64_value.xml
new file mode 100644
index 0000000..9184dff
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_base64_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_with_2_values.xml
new file mode 100644
index 0000000..8f5fa5c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_with_2_values.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>foobar</value>
+				<value>foobar</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_with_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_with_empty_value.xml
new file mode 100644
index 0000000..1a2891d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_with_empty_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value></value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_without_name.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_without_name.xml
new file mode 100644
index 0000000..f714a01
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_without_name.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch>
+				<value>foobar</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_without_value.xml
new file mode 100644
index 0000000..62a19f1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_approxMatch_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch.xml
new file mode 100644
index 0000000..d422f29
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<equalityMatch name="sn">
+				<value>foobar</value>
+			</equalityMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_base64_value.xml
new file mode 100644
index 0000000..a4e007f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_base64_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<equalityMatch name="sn">
+				<value xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</value>
+			</equalityMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_with_2_values.xml
new file mode 100644
index 0000000..65cedff
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_with_2_values.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<equalityMatch name="sn">
+				<value>foobar</value>
+				<value>foobar</value>
+			</equalityMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_with_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_with_empty_value.xml
new file mode 100644
index 0000000..c516db3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_with_empty_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<equalityMatch name="sn">
+				<value></value>
+			</equalityMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_without_name.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_without_name.xml
new file mode 100644
index 0000000..e61f8fa
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_without_name.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<equalityMatch>
+				<value>foobar</value>
+			</equalityMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_without_value.xml
new file mode 100644
index 0000000..b52c13c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_equalityMatch_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<equalityMatch>
+			</equalityMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch.xml
new file mode 100644
index 0000000..73d4f39
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch>
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_base64_value.xml
new file mode 100644
index 0000000..9bf3d98
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_base64_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch>
+				<value xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_2_values.xml
new file mode 100644
index 0000000..3fde350
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_2_values.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch>
+				<value>A Value</value>
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_0.xml
new file mode 100644
index 0000000..10576f6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_0.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch dnAttributes="0">
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_1.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_1.xml
new file mode 100644
index 0000000..303f3a5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_1.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch dnAttributes="1">
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_error.xml
new file mode 100644
index 0000000..39bcfbc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_error.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch dnAttributes="error">
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_false.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_false.xml
new file mode 100644
index 0000000..babbd7c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_false.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch dnAttributes="false">
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_true.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_true.xml
new file mode 100644
index 0000000..5407b2b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_dnAttributes_true.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch dnAttributes="true">
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_empty_value.xml
new file mode 100644
index 0000000..d7772d1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_empty_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch name="givenName">
+				<value></value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_matchingRule.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_matchingRule.xml
new file mode 100644
index 0000000..5fa722b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_matchingRule.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch matchingRule="AMatchingRuleName">
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_name.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_name.xml
new file mode 100644
index 0000000..be26e82
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_with_name.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch name="givenName">
+				<value>A Value</value>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_without_value.xml
new file mode 100644
index 0000000..cc7b8d4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_extensibleMatch_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<extensibleMatch>
+			</extensibleMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual.xml
new file mode 100644
index 0000000..e4be376
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<greaterOrEqual name="sn">
+				<value>foobar</value>
+			</greaterOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_base64_value.xml
new file mode 100644
index 0000000..8c2d564
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_base64_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<greaterOrEqual name="sn">
+				<value xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</value>
+			</greaterOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_with_2_values.xml
new file mode 100644
index 0000000..295dd41
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_with_2_values.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<greaterOrEqual name="sn">
+				<value>foobar</value>
+				<value>foobar</value>
+			</greaterOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_with_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_with_empty_value.xml
new file mode 100644
index 0000000..5676c98
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_with_empty_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<greaterOrEqual name="sn">
+				<value></value>
+			</greaterOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_without_name.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_without_name.xml
new file mode 100644
index 0000000..8cd7493
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_without_name.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<greaterOrEqual>
+				<value>foobar</value>
+			</greaterOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_without_value.xml
new file mode 100644
index 0000000..c67993f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_greaterOrEqual_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<greaterOrEqual>
+			</greaterOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual.xml
new file mode 100644
index 0000000..bab08c7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<lessOrEqual name="sn">
+				<value>foobar</value>
+			</lessOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_base64_value.xml
new file mode 100644
index 0000000..246d522
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_base64_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<lessOrEqual name="sn">
+				<value xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</value>
+			</lessOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_with_2_values.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_with_2_values.xml
new file mode 100644
index 0000000..3775773
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_with_2_values.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<lessOrEqual name="sn">
+				<value>foobar</value>
+				<value>foobar</value>
+			</lessOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_with_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_with_empty_value.xml
new file mode 100644
index 0000000..dfa2afa
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_with_empty_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<lessOrEqual name="sn">
+				<value></value>
+			</lessOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_without_name.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_without_name.xml
new file mode 100644
index 0000000..9bfca8a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_without_name.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<lessOrEqual>
+				<value>foobar</value>
+			</lessOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_without_value.xml
new file mode 100644
index 0000000..064a0fe
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_lessOrEqual_without_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<lessOrEqual>
+			</lessOrEqual>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_nested_connector_nodes.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_nested_connector_nodes.xml
new file mode 100644
index 0000000..3550817
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_nested_connector_nodes.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
+	license agreements. See the NOTICE file distributed with this work for additional 
+	information regarding copyright ownership. The ASF licenses this file to 
+	you under the Apache License, Version 2.0 (the "License"); you may not use 
+	this file except in compliance with the License. You may obtain a copy of 
+	the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required 
+	by applicable law or agreed to in writing, software distributed under the 
+	License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
+	OF ANY KIND, either express or implied. See the License for the specific 
+	language governing permissions and limitations under the License. -->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+	<searchRequest dn="dc=example,dc=com"
+		scope="baseObject" derefAliases="neverDerefAliases">
+		<filter>
+			<and>
+				<or>
+					<substrings name="sn">
+						<any>foo</any>
+					</substrings>
+					<substrings name="cn">
+						<any>foo</any>
+					</substrings>
+				</or>
+				<or>
+					<substrings name="ou">
+						<any>josopuram</any>
+					</substrings>
+					<substrings name="o">
+						<any>k</any>
+					</substrings>
+				</or>
+			</and>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_not.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_not.xml
new file mode 100644
index 0000000..dccadec
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_not.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<not>
+				<approxMatch name="sn">
+					<value>foobar</value>
+				</approxMatch>
+			</not>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_not_with_2_children.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_not_with_2_children.xml
new file mode 100644
index 0000000..552e5ee
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_not_with_2_children.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<not>
+				<approxMatch>
+					<value name="sn">foobar</value>
+				</approxMatch>
+				<approxMatch>
+					<value name="sn">foobar</value>
+				</approxMatch>
+			</not>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_or.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_or.xml
new file mode 100644
index 0000000..77d9424
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_or.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<or>
+				<approxMatch name="sn">
+					<value>foobar</value>
+				</approxMatch>
+			</or>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_present.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_present.xml
new file mode 100644
index 0000000..51ce388
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_present.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<present name="givenName">
+			</present>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_present_without_name.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_present_without_name.xml
new file mode 100644
index 0000000..bf5cc07
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_present_without_name.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<present>
+			</present>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings.xml
new file mode 100644
index 0000000..29af447
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_any.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_any.xml
new file mode 100644
index 0000000..2bbe0a4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_any.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<any>kate</any>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_any_1_final.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_any_1_final.xml
new file mode 100644
index 0000000..f8b656b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_any_1_final.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<any>kate</any>
+				<final>john</final>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_any.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_any.xml
new file mode 100644
index 0000000..208efc3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_any.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<any xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</any>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_final.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_final.xml
new file mode 100644
index 0000000..65f4a1b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_final.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<final xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</final>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_initial.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_initial.xml
new file mode 100644
index 0000000..5be2686
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_base64_initial.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<initial xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</initial>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_any.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_any.xml
new file mode 100644
index 0000000..70118e8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_any.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<any></any>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_final.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_final.xml
new file mode 100644
index 0000000..b4d3370
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_final.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<final></final>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_initial.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_initial.xml
new file mode 100644
index 0000000..3737c9a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_empty_initial.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<initial></initial>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_final.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_final.xml
new file mode 100644
index 0000000..7546260
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_final.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<final>john</final>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial.xml
new file mode 100644
index 0000000..df28434
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<initial>jack</initial>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial_1_any.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial_1_any.xml
new file mode 100644
index 0000000..006f0ce
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial_1_any.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<initial>jack</initial>
+				<any>kate</any>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial_1_final.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial_1_final.xml
new file mode 100644
index 0000000..2d5da0c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_1_initial_1_final.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<initial>jack</initial>
+				<final>john</final>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_2_any.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_2_any.xml
new file mode 100644
index 0000000..53c7d14
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_2_any.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings name="sn">
+				<any>kate</any>
+				<any>sawyer</any>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_without_name.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_without_name.xml
new file mode 100644
index 0000000..97dd773
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/filters/request_with_substrings_without_name.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<substrings>
+			</substrings>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control.xml
new file mode 100644
index 0000000..9692b4f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control_base64_value.xml
new file mode 100644
index 0000000..1130dd1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control_base64_value.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue xsi:type="xsd:base64Binary">RFNNTHYyLjAgcm9ja3MhIQ==</controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control_empty_value.xml
new file mode 100644
index 0000000..65df139
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_1_control_empty_value.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_attributes_elements.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_attributes_elements.xml
new file mode 100644
index 0000000..50e64bc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_attributes_elements.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+		<attributes>
+		</attributes>
+		<attributes>
+		</attributes>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_controls.xml
new file mode 100644
index 0000000..15e2ffa
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_controls.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+			<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_filters.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_filters.xml
new file mode 100644
index 0000000..fecdbf9
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_2_filters.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_3_controls_without_value.xml
new file mode 100644
index 0000000..0980b26
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_3_controls_without_value.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+		</control>
+		<control type="1.2.840.113556.1.4.789" criticality="false">
+		</control>
+		<control type="1.2.840.113556.1.4.456" criticality="true">
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attribute_without_name_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attribute_without_name_attribute.xml
new file mode 100644
index 0000000..2b76bc1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attribute_without_name_attribute.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+		<attributes>
+			<attribute />
+		</attributes>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_1_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_1_attribute.xml
new file mode 100644
index 0000000..935cdc8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_1_attribute.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+		<attributes>
+			<attribute name="sn"/>
+		</attributes>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_2_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_2_attribute.xml
new file mode 100644
index 0000000..506727d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_2_attribute.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+		<attributes>
+			<attribute name="sn"/>
+			<attribute name="givenName"/>
+		</attributes>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_but_no_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_but_no_attribute.xml
new file mode 100644
index 0000000..76d6553
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_attributes_but_no_attribute.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+		<attributes>
+		</attributes>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefAlways.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefAlways.xml
new file mode 100644
index 0000000..fd2e172
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefAlways.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="derefAlways">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefFindingBaseObj.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefFindingBaseObj.xml
new file mode 100644
index 0000000..cc61016
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefFindingBaseObj.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="derefFindingBaseObj">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefInSearching.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefInSearching.xml
new file mode 100644
index 0000000..7221733
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_derefInSearching.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="derefInSearching">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_error.xml
new file mode 100644
index 0000000..c0904eb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_error.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="error">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_neverDerefAliases.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_neverDerefAliases.xml
new file mode 100644
index 0000000..9692b4f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_derefAliases_neverDerefAliases.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_dn_attribute.xml
new file mode 100644
index 0000000..631dca3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_dn_attribute.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_empty_filter.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_empty_filter.xml
new file mode 100644
index 0000000..5fb47cd
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_empty_filter.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_needed_requestID.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_needed_requestID.xml
new file mode 100644
index 0000000..20f07df
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_needed_requestID.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest processing="parallel" responseOrder="unordered" xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_requestID_attribute.xml
new file mode 100644
index 0000000..b3412be
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_requestID_attribute.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest requestID="456"
+				dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_requestID_below_0.xml
new file mode 100644
index 0000000..f61e369
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_requestID_below_0.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest requestID="-1"
+				dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_baseObject.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_baseObject.xml
new file mode 100644
index 0000000..9692b4f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_baseObject.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_error.xml
new file mode 100644
index 0000000..75ad6ec
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_error.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="error"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_singleLevel.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_singleLevel.xml
new file mode 100644
index 0000000..abcdc18
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_singleLevel.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_wholeSubtree.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_wholeSubtree.xml
new file mode 100644
index 0000000..f5331c4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_scope_wholeSubtree.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="wholeSubtree"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_sizeLimit_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_sizeLimit_attribute.xml
new file mode 100644
index 0000000..0d2691a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_sizeLimit_attribute.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases"
+				sizeLimit="1000">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_sizeLimit_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_sizeLimit_error.xml
new file mode 100644
index 0000000..040909d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_sizeLimit_error.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases"
+				sizeLimit="error">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_timeLimit_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_timeLimit_attribute.xml
new file mode 100644
index 0000000..5a0bbb5
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_timeLimit_attribute.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases"
+				timeLimit="60">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_timeLimit_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_timeLimit_error.xml
new file mode 100644
index 0000000..7d5f5fc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_timeLimit_error.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases"
+				timeLimit="error">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_0.xml
new file mode 100644
index 0000000..17586b2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_0.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases"
+				typesOnly="0">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_1.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_1.xml
new file mode 100644
index 0000000..879ccb4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases"
+				typesOnly="1">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_error.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_error.xml
new file mode 100644
index 0000000..dd01c9e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_error.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases"
+				typesOnly="error">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_false.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_false.xml
new file mode 100644
index 0000000..6cf8e56
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_false.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases"
+				typesOnly="false">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_true.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_true.xml
new file mode 100644
index 0000000..e5a4d26
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_with_typesOnly_true.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject"
+				derefAliases="neverDerefAliases"
+				typesOnly="true">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_derefAliases_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_derefAliases_attribute.xml
new file mode 100644
index 0000000..8ffbca2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_derefAliases_attribute.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="baseObject">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_dn_attribute.xml
new file mode 100644
index 0000000..f68d5f1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_dn_attribute.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_filter.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_filter.xml
new file mode 100644
index 0000000..493ffcc
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_filter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				scope="singleLevel"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_scope_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_scope_attribute.xml
new file mode 100644
index 0000000..cb44e89
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchRequest/request_without_scope_attribute.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchRequest xmlns="urn:oasis:names:tc:DSML:2.0:core">
+<searchRequest dn="ou=marketing,dc=microsoft,dc=com"
+				derefAliases="neverDerefAliases">
+		<control type="1.2.840.113556.1.4.643" criticality="true">
+			<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+		</control>
+		<filter>
+			<approxMatch name="sn">
+				<value>toto</value>
+			</approxMatch>
+		</filter>
+	</searchRequest>
+</batchRequest>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_0_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_0_SRD.xml
new file mode 100644
index 0000000..9e86371
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_0_SRD.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_0_SRE_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_0_SRE_1_SRD.xml
new file mode 100644
index 0000000..486f08f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_0_SRE_1_SRD.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+  <searchResponse>
+    <searchResultDone>
+      <resultCode code="0" descr="success"/>
+    </searchResultDone>
+  </searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRD.xml
new file mode 100644
index 0000000..1bc84ce
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRD.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_0_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_0_SRD.xml
new file mode 100644
index 0000000..16c1708
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_0_SRD.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value>example</value>
+			</attr>
+			<attr name="objectclass">
+	            <value>top</value>
+				<value>domain</value>
+				<value>extensibleObject</value>
+			</attr>
+      	</searchResultEntry>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_1_SRD.xml
new file mode 100644
index 0000000..e79b632
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_1_SRD.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value>example</value>
+			</attr>
+			<attr name="objectclass">
+	            <value>top</value>
+				<value>domain</value>
+				<value>extensibleObject</value>
+			</attr>
+      	</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_1_SRR_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_1_SRR_1_SRD.xml
new file mode 100644
index 0000000..f05316d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRE_1_SRR_1_SRD.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value>example</value>
+			</attr>
+			<attr name="objectclass">
+	            <value>top</value>
+				<value>domain</value>
+				<value>extensibleObject</value>
+			</attr>
+      	</searchResultEntry>
+		<searchResultReference>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRR_0_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRR_0_SRD.xml
new file mode 100644
index 0000000..5470b34
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRR_0_SRD.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRR_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRR_1_SRD.xml
new file mode 100644
index 0000000..d2514e7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_1_SRR_1_SRD.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRE_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRE_1_SRD.xml
new file mode 100644
index 0000000..b2d53fb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRE_1_SRD.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value>example</value>
+			</attr>
+			<attr name="objectclass">
+	            <value>top</value>
+				<value>domain</value>
+				<value>extensibleObject</value>
+			</attr>
+      	</searchResultEntry>
+		<searchResultEntry dn="cn=Bob Rush,dc=Example,dc=COM">
+			<attr name="objectclass">
+				<value>person</value>
+				<value>top</value>
+			</attr>
+			<attr name="sn">
+				<value>snvalue</value>
+			</attr>
+			<attr name="cn">
+				<value>Bob Rush</value>
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRE_2_SRR_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRE_2_SRR_1_SRD.xml
new file mode 100644
index 0000000..ab719e8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRE_2_SRR_1_SRD.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value>example</value>
+			</attr>
+			<attr name="objectclass">
+	            <value>top</value>
+				<value>domain</value>
+				<value>extensibleObject</value>
+			</attr>
+      	</searchResultEntry>
+      	<searchResultEntry dn="cn=Bob Rush,dc=Example,dc=COM">
+			<attr name="objectclass">
+				<value>person</value>
+				<value>top</value>
+			</attr>
+			<attr name="sn">
+				<value>snvalue</value>
+			</attr>
+			<attr name="cn">
+				<value>Bob Rush</value>
+			</attr>
+		</searchResultEntry>
+		<searchResultReference>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultReference>
+			<ref>ldap://ldap.apache.org</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRR_1_SRD.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRR_1_SRD.xml
new file mode 100644
index 0000000..bbd5c4d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_2_SRR_1_SRD.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultReference>
+			<ref>ldap://ldap.apache.org</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..f9207c8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_requestID_attribute.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse requestID="456">
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..85196ef
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/response_with_requestID_below_0.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse requestID="-1">
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_control.xml
new file mode 100644
index 0000000..4204a7b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_control.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..70a0a2f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_control_empty_value.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue></controlValue>
+			</control>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_empty_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_empty_referral.xml
new file mode 100644
index 0000000..0f9c45a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_empty_referral.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<resultCode code="2" descr="protocolError"/>
+    		<referral></referral>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_referral.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_referral.xml
new file mode 100644
index 0000000..f5a8015
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_referral.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<resultCode code="2" descr="protocolError"/>
+    		<referral>ldap://www.apache.org</referral>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_referral_and_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_referral_and_error_message.xml
new file mode 100644
index 0000000..c1916ad
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_1_referral_and_error_message.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<resultCode code="2" descr="protocolError"/>
+    		<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+			<referral>ldap://www.apache.org</referral>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_2_controls.xml
new file mode 100644
index 0000000..7b28e8e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_2_controls.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+			<control type="1.2.840.113556.1.4.789" criticality="false">
+				<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+			</control>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_2_referrals.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_2_referrals.xml
new file mode 100644
index 0000000..0e1d436
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_2_referrals.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<resultCode code="2" descr="protocolError"/>
+    		<referral>ldap://www.apache.org</referral>
+    		<referral>ldap://www.apple.com</referral>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..67236a7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_3_controls_without_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+			</control>
+			<control type="1.2.840.113556.1.4.789" criticality="false">
+			</control>
+			<control type="1.2.840.113556.1.4.456" criticality="true">
+			</control>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_empty_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_empty_error_message.xml
new file mode 100644
index 0000000..92ac475
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_empty_error_message.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>	
+			<resultCode code="2" descr="protocolError"/>
+    		<errorMessage></errorMessage>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_error_message.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_error_message.xml
new file mode 100644
index 0000000..c0e12fb
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_error_message.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>	
+			<resultCode code="2" descr="protocolError"/>
+    		<errorMessage>Unrecognized extended operation EXTENSION_OID: 1.2.6.1.4.1.18060.1.1.1.100.2</errorMessage>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_matchedDN_attribute.xml
new file mode 100644
index 0000000..76ff35d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_matchedDN_attribute.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone matchedDN="CN=Bob Rush, OU=Dev, DC=Example, DC=COM">
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..1dfd941
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_requestID_attribute.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone requestID="456">
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..b0ee6f2
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_requestID_below_0.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone requestID="-1">
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_result_code.xml
new file mode 100644
index 0000000..cc92cba
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_result_code.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>	
+			<resultCode code="2" descr="protocolError"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_result_code_not_integer.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_result_code_not_integer.xml
new file mode 100644
index 0000000..270c015
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_result_code_not_integer.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>	
+			<resultCode code="error" descr="protocolError"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_wrong_descr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_wrong_descr.xml
new file mode 100644
index 0000000..46224cf
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_wrong_descr.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+			<resultCode code="0" descr="succes"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_wrong_matchedDN_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_wrong_matchedDN_attribute.xml
new file mode 100644
index 0000000..8df770d
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_with_wrong_matchedDN_attribute.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone matchedDN="This is a wrong matchedDN">
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_without_result_code.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_without_result_code.xml
new file mode 100644
index 0000000..b657581
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultDone/response_without_result_code.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultDone>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_0_attr.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_0_attr.xml
new file mode 100644
index 0000000..74575e3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_0_attr.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_0_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_0_value.xml
new file mode 100644
index 0000000..bf44b7c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_0_value.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc" >
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_base64_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_base64_value.xml
new file mode 100644
index 0000000..db9d354
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_base64_value.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+	<searchResponse>
+		<searchResultEntry dn="uid=elecharny,dc=example,dc=com">
+			<attr name="cn">
+				<value xsi:type="xsd:base64Binary">RW1tYW51ZWwgTMOpY2hhcm55</value>
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_empty_value.xml
new file mode 100644
index 0000000..564a5d8
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_empty_value.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value></value>
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_value.xml
new file mode 100644
index 0000000..abc2c5a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_1_value.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value>example</value>
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_2_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_2_value.xml
new file mode 100644
index 0000000..2c7d8f6
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_2_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="objectclass">
+	            <value>top</value>
+				<value>domain</value>
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_without_name_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_without_name_attribute.xml
new file mode 100644
index 0000000..afffd4a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_attr_without_name_attribute.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr>
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_control.xml
new file mode 100644
index 0000000..40aff89
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_control.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..3b56689
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_1_control_empty_value.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue></controlValue>
+			</control>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_2_attr_1_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_2_attr_1_value.xml
new file mode 100644
index 0000000..d1f03e1
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_2_attr_1_value.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<attr name="dc">
+				<value>example</value>
+			</attr>
+			<attr name="objectclass">
+	            <value>top</value>
+			</attr>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_2_controls.xml
new file mode 100644
index 0000000..8327e60
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_2_controls.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+			<control type="1.2.840.113556.1.4.789" criticality="false">
+				<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+			</control>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..7a4256c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_3_controls_without_value.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+			</control>
+			<control type="1.2.840.113556.1.4.789" criticality="false">
+			</control>
+			<control type="1.2.840.113556.1.4.456" criticality="true">
+			</control>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>		
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_dn_attribute.xml
new file mode 100644
index 0000000..74575e3
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_dn_attribute.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com">
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..8ce11b7
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_requestID_attribute.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com" requestID="456">
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..2cbd799
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_requestID_below_0.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="dc=example,dc=com" requestID="-1">
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_wrong_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_wrong_dn_attribute.xml
new file mode 100644
index 0000000..120a865
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_with_wrong_dn_attribute.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry dn="This is a wrong DN">
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_without_dn_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_without_dn_attribute.xml
new file mode 100644
index 0000000..5be15e4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultEntry/response_without_dn_attribute.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultEntry>
+		</searchResultEntry>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_0_ref.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_0_ref.xml
new file mode 100644
index 0000000..0960923
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_0_ref.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_control.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_control.xml
new file mode 100644
index 0000000..e3437be
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_control.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_control_empty_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_control_empty_value.xml
new file mode 100644
index 0000000..cc6cbe4
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_control_empty_value.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue></controlValue>
+			</control>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_empty_ref.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_empty_ref.xml
new file mode 100644
index 0000000..95eba1f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_empty_ref.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>			
+			<ref></ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_ref.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_ref.xml
new file mode 100644
index 0000000..659186f
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_ref.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>			
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_wrong_ref.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_wrong_ref.xml
new file mode 100644
index 0000000..03b0e6e
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_1_wrong_ref.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>			
+			<ref>http://thisIsAWrongRef.com</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_2_controls.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_2_controls.xml
new file mode 100644
index 0000000..c17172b
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_2_controls.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+				<controlValue><!-- comment -->Some text<!-- another --></controlValue>
+			</control>
+			<control type="1.2.840.113556.1.4.789" criticality="false">
+				<controlValue><!-- comment -->Some other text<!-- another --></controlValue>
+			</control>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_2_ref.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_2_ref.xml
new file mode 100644
index 0000000..a071c66
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_2_ref.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>			
+			<ref>ldap://localhost</ref>
+			<ref>ldap://www.apache.org</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_3_controls_without_value.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_3_controls_without_value.xml
new file mode 100644
index 0000000..a2e1884
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_3_controls_without_value.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference>
+			<control type="1.2.840.113556.1.4.643" criticality="true">
+			</control>
+			<control type="1.2.840.113556.1.4.789" criticality="false">
+			</control>
+			<control type="1.2.840.113556.1.4.456" criticality="true">
+			</control>
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>		
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_requestID_attribute.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_requestID_attribute.xml
new file mode 100644
index 0000000..68fd309
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_requestID_attribute.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference requestID="456">
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_requestID_below_0.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_requestID_below_0.xml
new file mode 100644
index 0000000..e63024a
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/searchResponse/searchResultReference/response_with_requestID_below_0.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<batchResponse xmlns="urn:oasis:names:tc:DSML:2.0:core" resquestID="1234567890">
+	<searchResponse>
+		<searchResultReference requestID="-1">
+			<ref>ldap://localhost</ref>
+		</searchResultReference>
+		<searchResultDone>
+			<resultCode code="0" descr="success"/>
+		</searchResultDone>
+	</searchResponse>
+</batchResponse>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-multiple-operation-requests.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-multiple-operation-requests.xml
new file mode 100644
index 0000000..3767f8c
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-multiple-operation-requests.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
+	<soap-env:Body>
+		<dsml:batchRequest xmlns:dsml="urn:oasis:names:tc:DSML:2:0:core"
+			xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<searchRequest dn="uid=admin,ou=system" scope="baseObject"
+				derefAliases="neverDerefAliases" typesOnly="true">
+				<filter>
+					<approxMatch name="uid">
+						<value>admin</value>
+					</approxMatch>
+				</filter>
+			</searchRequest>
+
+			<searchRequest dn="ou=schema" scope="baseObject"
+				derefAliases="neverDerefAliases" typesOnly="false">
+				<filter>
+					<approxMatch name="cn">
+						<value>inetOrgPerson</value>
+					</approxMatch>
+				</filter>
+			</searchRequest>
+		</dsml:batchRequest>
+	</soap-env:Body>
+</soap-env:Envelope>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-req-with-header.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-req-with-header.xml
new file mode 100644
index 0000000..5b47957
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-req-with-header.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
+	<soap-env:header>
+		<t:Transaction xmlns:t="http://example.org/2001/06/tx"
+			soap-env:mustUnderstand="true">
+			5 
+	    </t:Transaction>
+	    <t:header xmlns:t="http://example.org/2001/06/tx">
+	    </t:header>
+	</soap-env:header>
+	<soap-env:Body>
+		<dsml:batchRequest xmlns:dsml="urn:oasis:names:tc:DSML:2:0:core"
+			xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<searchRequest dn="uid=admin,ou=system" scope="baseObject"
+				derefAliases="neverDerefAliases" typesOnly="true">
+				<filter>
+					<approxMatch name="uid">
+						<value>admin</value>
+					</approxMatch>
+				</filter>
+			</searchRequest>
+		</dsml:batchRequest>
+	</soap-env:Body>
+</soap-env:Envelope>
\ No newline at end of file
diff --git a/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-req-without-header.xml b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-req-without-header.xml
new file mode 100644
index 0000000..b839b51
--- /dev/null
+++ b/trunk/dsml/parser/src/test/resources/org/apache/directory/api/dsmlv2/soap/soap-dsml-req-without-header.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
+	<soap-env:Body>
+		<dsml:batchRequest xmlns:dsml="urn:oasis:names:tc:DSML:2:0:core"
+			xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+			<searchRequest dn="uid=admin,ou=system" scope="baseObject"
+				derefAliases="neverDerefAliases" typesOnly="true">
+				<filter>
+					<approxMatch name="uid">
+						<value>admin</value>
+					</approxMatch>
+				</filter>
+			</searchRequest>
+		</dsml:batchRequest>
+	</soap-env:Body>
+</soap-env:Envelope>
\ No newline at end of file
diff --git a/trunk/dsml/pom.xml b/trunk/dsml/pom.xml
new file mode 100644
index 0000000..200b31c
--- /dev/null
+++ b/trunk/dsml/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-dsml-parent</artifactId>
+  <name>Apache Directory LDAP API DSML Parent</name>
+  <inceptionYear>2003</inceptionYear>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>engine</module>
+    <module>parser</module>
+  </modules>
+
+</project>
diff --git a/trunk/dsml/src/site/site.xml b/trunk/dsml/src/site/site.xml
new file mode 100644
index 0000000..b6ec180
--- /dev/null
+++ b/trunk/dsml/src/site/site.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="modules" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/i18n/pom.xml b/trunk/i18n/pom.xml
new file mode 100644
index 0000000..220b876
--- /dev/null
+++ b/trunk/i18n/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-i18n</artifactId>
+  <name>Apache Directory LDAP API I18n</name>
+  <packaging>bundle</packaging> 
+  <description>Internationalization of errors and other messages</description>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration> 
+          <forkMode>always</forkMode>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.i18n</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.i18n;version=${project.version};-noimport:=true
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/i18n/src/checkstyle/suppressions.xml b/trunk/i18n/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..f017bf7
--- /dev/null
+++ b/trunk/i18n/src/checkstyle/suppressions.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <suppress checks="JavadocVariable"
+              files="I18n.java"/>
+</suppressions>
diff --git a/trunk/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java b/trunk/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
new file mode 100644
index 0000000..48ae1e4
--- /dev/null
+++ b/trunk/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
@@ -0,0 +1,892 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.i18n;
+
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+
+/**
+ * Provides i18n handling of error codes.
+ * About formatting see also {@link MessageFormat}
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum I18n
+{
+    // asn1
+    ERR_00001_BAD_TRANSITION_FROM_STATE("ERR_00001_BAD_TRANSITION_FROM_STATE"),
+    ERR_00002_BAD_TRANSITION("ERR_00002_BAD_TRANSITION"),
+    ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER("ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER"),
+    ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL("ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL"),
+    ERR_00005_LENGTH_OVERFLOW("ERR_00005_LENGTH_OVERFLOW"),
+    ERR_00006_LENGTH_EXTENSION_RESERVED("ERR_00006_LENGTH_EXTENSION_RESERVED"),
+    ERR_00007_TLV_NULL("ERR_00007_TLV_NULL"),
+    ERR_00008_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH("ERR_00008_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH"),
+    ERR_00009_MORE_TLV_EXPECTED("ERR_00009_MORE_TLV_EXPECTED"),
+    ERR_00010_TRUNCATED_PDU("ERR_00010_TRUNCATED_PDU"),
+    ERR_00011_LENGTH_TOO_LONG_FOR_DEFINITE_FORM("ERR_00011_LENGTH_TOO_LONG_FOR_DEFINITE_FORM"),
+    ERR_00013_ODD_NUM_OF_CHARS("ERR_00013_ODD_NUM_OF_CHARS"),
+    ERR_00014_ILLEGAL_HEX_CHAR("ERR_00014_ILLEGAL_HEX_CHAR"),
+    ERR_00016_END_OF_STREAM("ERR_00016_END_OF_STREAM"),
+    ERR_00017_EOF_FOUND_LENGTH_EXPECTED("ERR_00017_EOF_FOUND_LENGTH_EXPECTED"),
+    ERR_00018_DER_LENGTH_ABOVE_4_BYTES("ERR_00018_DER_LENGTH_ABOVE_4_BYTES"),
+    ERR_00019_EOF_FOUND_IN_LENGTH("ERR_00019_EOF_FOUND_IN_LENGTH"),
+    ERR_00020_CORRUPTED_STREAM("ERR_00020_CORRUPTED_STREAM"),
+    ERR_00021_EOF_FOUND_IN_OBJECT("ERR_00021_EOF_FOUND_IN_OBJECT"),
+    ERR_00022_READ_PAST_END_OF_FILE("ERR_00022_READ_PAST_END_OF_FILE"),
+    ERR_00023_UNKNOWN_BER_OBJECT("ERR_00023_UNKNOWN_BER_OBJECT"),
+    ERR_00024_OBJECT_NOT_DER_ENCODABLE("ERR_00024_OBJECT_NOT_DER_ENCODABLE"),
+    ERR_00025_DER_OCTET_STRING_EXPECTED("ERR_DER_OCTET_STRING_EXPECTED_00025"),
+    ERR_00026_CANNOT_CONVERT_OCTETS("ERR_00026_CANNOT_CONVERT_OCTETS"),
+    ERR_00027_NOT_IMPLEMENTED("ERR_00027_NOT_IMPLEMENTED"),
+    ERR_00028_INTERNAL_ERROR_ENCODING_BITSTRING("ERR_00028_INTERNAL_ERROR_ENCODING_BITSTRING"),
+    ERR_00029_NULL_OR_NEG_LENGTH_NOT_ALLOWED("ERR_00029_NULL_OR_NEG_LENGTH_NOT_ALLOWED"),
+    ERR_00030_BIT_NUMBER_OUT_OF_BOUND("ERR_00030_BIT_NUMBER_OUT_OF_BOUND"),
+    ERR_00031_CANNOT_FIND_BIT("ERR_00031_CANNOT_FIND_BIT"),
+    ERR_00032_NULL_OID("ERR_00032_NULL_OID"),
+    ERR_00033_INVALID_OID("ERR_00033_INVALID_OID"),
+    ERR_00034_0_BYTES_LONG_BOOLEAN("ERR_00034_0_BYTES_LONG_BOOLEAN"),
+    ERR_00035_N_BYTES_LONG_BOOLEAN("ERR_00035_N_BYTES_LONG_BOOLEAN"),
+    ERR_00036_0_BYTES_LONG_INTEGER("ERR_00036_0_BYTES_LONG_INTEGER"),
+    ERR_00037_ABOVE_4_BYTES_INTEGER("ERR_00037_ABOVE_4_BYTES_INTEGER"),
+    ERR_00038_VALUE_NOT_IN_RANGE("ERR_00038_VALUE_NOT_IN_RANGE"),
+    ERR_00039_0_BYTES_LONG_LONG("ERR_00039_0_BYTES_LONG_LONG"),
+    ERR_00041_CURRENT_LENGTH_EXCEED_EXPECTED_LENGTH("ERR_00041_CURRENT_LENGTH_EXCEED_EXPECTED_LENGTH"),
+    ERR_00042_PDU_SIZE_TOO_LONG("ERR_00042_PDU_SIZE_TOO_LONG"),
+    ERR_00043_REMAINING_BYTES_FOR_DECODED_PDU("ERR_00043_REMAINING_BYTES_FOR_DECODED_PDU"),
+
+    // cursor
+    ERR_02001_MONITOR("ERR_02001_MONITOR"),
+    ERR_02002_FAILURE_ON_UNDERLYING_CURSOR("ERR_02002_FAILURE_ON_UNDERLYING_CURSOR"),
+    ERR_02003_REMOVAL_NOT_SUPPORTED("ERR_02003_REMOVAL_NOT_SUPPORTED"),
+    ERR_02004_EMPTY_CURSOR("ERR_02004_EMPTY_CURSOR"),
+    ERR_02005_START_INDEX_OUT_OF_RANGE("ERR_02005_START_INDEX_OUT_OF_RANGE"),
+    ERR_02006_END_INDEX_OUT_OF_RANGE("ERR_02006_END_INDEX_OUT_OF_RANGE"),
+    ERR_02007_START_INDEX_ABOVE_END_INDEX("ERR_02007_START_INDEX_ABOVE_END_INDEX"),
+    ERR_02008_LIST_MAY_BE_SORTED("ERR_02008_LIST_MAY_BE_SORTED"),
+    ERR_02009_CURSOR_NOT_POSITIONED("ERR_02009_CURSOR_NOT_POSITIONED"),
+    ERR_02010_NO_COMPARATOR_CANT_MOVE_BEFORE("ERR_02010_NO_COMPARATOR_CANT_MOVE_BEFORE"),
+    ERR_02011_NO_COMPARATOR_CANT_MOVE_AFTER("ERR_02011_NO_COMPARATOR_CANT_MOVE_AFTER"),
+    ERR_02012_CANNOT_ACCESS_IF_BEFORE_FIRST("ERR_02012_CANNOT_ACCESS_IF_BEFORE_FIRST"),
+    ERR_02013_CANNOT_ACCESS_IF_AFTER_LAST("ERR_02013_CANNOT_ACCESS_IF_AFTER_LAST"),
+    ERR_02014_UNSUPPORTED_OPERATION("ERR_02014_UNSUPPORTED_OPERATION"),
+
+    // dsml-parser
+    ERR_03001("ERR_03001"),
+    ERR_03002("ERR_03002"),
+    ERR_03003("ERR_03003"),
+    ERR_03004("ERR_03004"),
+    ERR_03005("ERR_03005"),
+    ERR_03006("ERR_03006"),
+    ERR_03007("ERR_03007"),
+    ERR_03008("ERR_03008"),
+    ERR_03009("ERR_03009"),
+    ERR_03010("ERR_03010"),
+    ERR_03011("ERR_03011"),
+    ERR_03012("ERR_03012"),
+    ERR_03013("ERR_03013"),
+    ERR_03014("ERR_03014"),
+    ERR_03015("ERR_03015"),
+    ERR_03016("ERR_03016"),
+    ERR_03017("ERR_03017"),
+    ERR_03018("ERR_03018"),
+    ERR_03019("ERR_03019"),
+    ERR_03020("ERR_03020"),
+    ERR_03021("ERR_03021"),
+    ERR_03022("ERR_03022"),
+    ERR_03023("ERR_03023"),
+    ERR_03024("ERR_03024"),
+    ERR_03025("ERR_00025"),
+    ERR_03026("ERR_03026"),
+    ERR_03027("ERR_03027"),
+    ERR_03028("ERR_03028"),
+    ERR_03029("ERR_03029"),
+    ERR_03030("ERR_03030"),
+    ERR_03031("ERR_03031"),
+    ERR_03032("ERR_03032"),
+    ERR_03033("ERR_03033"),
+    ERR_03034("ERR_03034"),
+    ERR_03035("ERR_03035"),
+    ERR_03036("ERR_03036"),
+    ERR_03037("ERR_03037"),
+    ERR_03038("ERR_03038"),
+    ERR_03039("ERR_03039"),
+    ERR_03040("ERR_03040"),
+
+    // dsml-engine
+    ERR_03101_MISSING_CONNECTION_TO("ERR_03101_MISSING_CONNECTION_TO"),
+
+    // ldap
+    ERR_04001_NULL_IDENTIFICATION_TAG("ERR_04001_NULL_IDENTIFICATION_TAG"),
+    ERR_04002_BAD_PRECENDENCE("ERR_04002_BAD_PRECENDENCE"),
+    ERR_04003_NULL_AUTHENTICATION_LEVEL("ERR_04003_NULL_AUTHENTICATION_LEVEL"),
+    ERR_04004_PARSER_FAILURE_ACI_ITEM("ERR_04004_PARSER_FAILURE_ACI_ITEM"),
+    ERR_04005("ERR_04005"),
+    ERR_04006("ERR_04006"),
+    ERR_04007("ERR_04007"),
+    ERR_04008("ERR_04008"),
+    ERR_04009("ERR_04009"),
+    ERR_04010("ERR_04010"),
+    ERR_04011("ERR_04011"),
+    ERR_04012("ERR_04012"),
+    ERR_04013("ERR_04013"),
+    ERR_04014("ERR_04014"),
+    ERR_04015("ERR_04015"),
+    ERR_04016("ERR_04016"),
+    ERR_04017("ERR_04017"),
+    ERR_04018("ERR_04018"),
+    ERR_04019("ERR_04019"),
+    ERR_04020("ERR_04020"),
+    ERR_04021("ERR_04021"),
+    ERR_04022("ERR_04022"),
+    ERR_04023("ERR_04023"),
+    ERR_04024("ERR_04024"),
+    ERR_04025("ERR_04025"),
+    ERR_04026("ERR_04026"),
+    ERR_04027("ERR_04027"),
+    ERR_04028("ERR_04028"),
+    ERR_04029("ERR_04029"),
+    ERR_04030("ERR_04030"),
+    ERR_04031("ERR_04031"),
+    ERR_04032("ERR_04032"),
+    ERR_04033("ERR_04033"),
+    ERR_04034("ERR_04034"),
+    ERR_04035("ERR_04035"),
+    ERR_04036("ERR_04036"),
+    ERR_04037("ERR_04037"),
+    ERR_04038("ERR_04038"),
+    ERR_04039("ERR_04039"),
+    ERR_04040("ERR_04040"),
+    ERR_04041("ERR_04041"),
+    ERR_04042("ERR_04042"),
+    ERR_04043("ERR_04043"),
+    ERR_04044("ERR_04044"),
+    ERR_04045("ERR_04045"),
+    ERR_04046("ERR_04046"),
+    ERR_04047("ERR_04047"),
+    ERR_04048("ERR_04048"),
+    ERR_04049("ERR_04049"),
+    ERR_04050("ERR_04050"),
+    ERR_04051("ERR_04051"),
+    ERR_04052("ERR_04052"),
+    ERR_04053("ERR_04053"),
+    ERR_04054("ERR_04054"),
+    ERR_04055("ERR_04055"),
+    ERR_04056("ERR_04056"),
+    ERR_04057("ERR_04057"),
+    ERR_04058("ERR_04058"),
+    ERR_04059("ERR_04059"),
+    ERR_04060("ERR_04060"),
+    ERR_04061("ERR_04061"),
+    ERR_04062("ERR_04062"),
+    ERR_04063("ERR_04063"),
+    ERR_04064("ERR_04064"),
+    ERR_04065("ERR_04065"),
+    ERR_04066("ERR_04066"),
+    ERR_04067("ERR_04067"),
+    ERR_04068("ERR_04068"),
+    ERR_04069("ERR_04069"),
+    ERR_04070("ERR_04070"),
+    ERR_04071("ERR_04071"),
+    ERR_04072("ERR_04072"),
+    ERR_04073("ERR_04073"),
+    ERR_04074("ERR_04074"),
+    ERR_04075("ERR_04075"),
+    ERR_04076("ERR_04076"),
+    ERR_04077("ERR_04077"),
+    ERR_04078("ERR_04078"),
+    ERR_04079("ERR_04079"),
+    ERR_04080("ERR_04080"),
+    ERR_04081("ERR_04081"),
+    ERR_04082("ERR_04082"),
+    ERR_04083("ERR_04083"),
+    ERR_04084("ERR_04084"),
+    ERR_04085("ERR_04085"),
+    ERR_04086("ERR_04086"),
+    ERR_04087("ERR_04087"),
+    ERR_04088("ERR_04088"),
+    ERR_04089("ERR_04089"),
+    ERR_04090("ERR_04090"),
+    ERR_04091("ERR_04091"),
+    ERR_04092("ERR_04092"),
+    ERR_04093("ERR_04093"),
+    ERR_04094("ERR_04094"),
+    ERR_04095("ERR_04095"),
+    ERR_04096("ERR_04096"),
+    ERR_04097("ERR_04097"),
+    ERR_04098("ERR_04098"),
+    ERR_04099("ERR_04099"),
+    ERR_04100("ERR_04100"),
+    ERR_04101("ERR_04101"),
+    ERR_04102("ERR_04102"),
+    ERR_04103("ERR_04103"),
+    ERR_04104("ERR_04104"),
+    ERR_04105("ERR_04105"),
+    ERR_04106("ERR_04106"),
+    ERR_04107("ERR_04107"),
+    ERR_04108("ERR_04108"),
+    ERR_04109("ERR_04109"),
+    ERR_04110("ERR_04110"),
+    ERR_04111("ERR_04111"),
+    ERR_04112("ERR_04112"),
+    ERR_04113("ERR_04113"),
+    ERR_04114("ERR_04114"),
+    ERR_04115("ERR_04115"),
+    ERR_04116("ERR_04116"),
+    ERR_04117("ERR_04117"),
+    ERR_04118("ERR_04118"),
+    ERR_04119("ERR_04119"),
+    ERR_04120("ERR_04120"),
+    ERR_04121("ERR_04121"),
+    ERR_04122("ERR_04122"),
+    ERR_04123("ERR_04123"),
+    ERR_04124("ERR_04124"),
+    ERR_04125("ERR_04125"),
+    ERR_04126("ERR_04126"),
+    ERR_04127("ERR_04127"),
+    ERR_04128("ERR_04128"),
+    ERR_04129("ERR_04129"),
+    ERR_04130("ERR_04130"),
+    ERR_04131("ERR_04131"),
+    ERR_04132("ERR_04132"),
+    ERR_04133("ERR_04133"),
+    ERR_04134("ERR_04134"),
+    ERR_04135("ERR_04135"),
+    ERR_04136("ERR_04136"),
+    ERR_04137("ERR_04137"),
+    ERR_04138("ERR_04138"),
+    ERR_04139("ERR_04139"),
+    ERR_04140_UNACCEPTABLE_RESULT_CODE("ERR_04140_UNACCEPTABLE_RESULT_CODE"),
+    ERR_04141("ERR_04141"),
+    ERR_04142("ERR_04142"),
+    ERR_04143("ERR_04143"),
+    ERR_04144("ERR_04144"),
+    ERR_04145("ERR_04145"),
+    ERR_04146("ERR_04146"),
+    ERR_04147("ERR_04147"),
+    ERR_04148("ERR_04148"),
+    ERR_04149("ERR_04149"),
+    ERR_04150("ERR_04150"),
+    ERR_04151("ERR_04151"),
+    ERR_04152("ERR_04152"),
+    ERR_04153("ERR_04153"),
+    ERR_04154("ERR_04154"),
+    ERR_04155("ERR_04155"),
+    ERR_04156("ERR_04156"),
+    ERR_04157("ERR_04157"),
+    ERR_04158("ERR_04158"),
+    ERR_04159("ERR_04159"),
+    ERR_04160("ERR_04160"),
+    ERR_04161("ERR_04161"),
+    ERR_04162("ERR_04162"),
+    ERR_04163("ERR_04163"),
+    ERR_04164("ERR_04164"),
+    ERR_04165("ERR_04165"),
+    ERR_04166("ERR_04166"),
+    ERR_04167("ERR_04167"),
+    ERR_04168("ERR_04168"),
+    ERR_04169("ERR_04169"),
+    ERR_04170("ERR_04170"),
+    ERR_04171("ERR_04171"),
+    ERR_04172("ERR_04172"),
+    ERR_04173("ERR_04173"),
+    ERR_04174("ERR_04174"),
+    ERR_04175("ERR_04175"),
+    ERR_04176("ERR_04176"),
+    ERR_04177("ERR_04177"),
+    ERR_04178("ERR_04178"),
+    ERR_04179("ERR_04179"),
+    ERR_04180("ERR_04180"),
+    ERR_04181("ERR_04181"),
+    ERR_04182("ERR_04182"),
+    ERR_04183("ERR_04183"),
+    ERR_04184("ERR_04184"),
+    ERR_04185("ERR_04185"),
+    ERR_04186("ERR_04186"),
+    ERR_04187("ERR_04187"),
+    ERR_04188("ERR_04188"),
+    ERR_04189("ERR_04189"),
+    ERR_04190("ERR_04190"),
+    ERR_04191("ERR_04191"),
+    ERR_04192("ERR_04192"),
+    ERR_04193("ERR_04193"),
+    ERR_04194("ERR_04194"),
+    ERR_04195("ERR_04195"),
+    ERR_04196("ERR_04196"),
+    ERR_04197("ERR_04197"),
+    ERR_04198("ERR_04198"),
+    ERR_04199("ERR_04199"),
+    ERR_04200("ERR_04200"),
+    ERR_04201("ERR_04201"),
+    ERR_04202("ERR_04202"),
+    ERR_04203("ERR_04203"),
+    ERR_04204("ERR_04204"),
+    ERR_04205("ERR_04205"),
+    ERR_04206("ERR_04206"),
+    ERR_04207("ERR_04207"),
+    ERR_04208("ERR_04208"),
+    ERR_04209_EMPTY_TYPE_NOT_ALLOWED("ERR_04209_EMPTY_TYPE_NOT_ALLOWED"),
+    ERR_04210("ERR_04210"),
+    ERR_04211("ERR_04211"),
+    ERR_04212("ERR_04212"),
+    ERR_04213("ERR_04213"),
+    ERR_04214("ERR_04214"),
+    ERR_04215("ERR_04215"),
+    ERR_04216("ERR_04216"),
+    ERR_04217("ERR_04217"),
+    ERR_04218("ERR_04218"),
+    ERR_04219_ARGUMENT1_NULL("ERR_04219_ARGUMENT1_NULL"),
+    ERR_04220_ARGUMENT2_NULL("ERR_04220_ARGUMENT2_NULL"),
+    ERR_04221("ERR_04221"),
+    ERR_04222("ERR_04222"),
+    ERR_04223("ERR_04223"),
+    ERR_04224("ERR_04224"),
+    ERR_04225("ERR_04225"),
+    ERR_04226("ERR_04226"),
+    ERR_04227("ERR_04227"),
+    ERR_04228("ERR_04228"),
+    ERR_04229("ERR_04229"),
+    ERR_04230("ERR_04230"),
+    ERR_04231("ERR_04231"),
+    ERR_04232("ERR_04232"),
+    ERR_04233("ERR_04233"),
+    ERR_04234("ERR_04234"),
+    ERR_04235("ERR_04235"),
+    ERR_04236("ERR_04236"),
+    ERR_04237("ERR_04237"),
+    ERR_04238("ERR_04238"),
+    ERR_04239("ERR_04239"),
+    ERR_04240("ERR_04240"),
+    ERR_04241("ERR_04241"),
+    ERR_04242("ERR_04242"),
+    ERR_04243("ERR_04243"),
+    ERR_04244("ERR_04244"),
+    ERR_04245("ERR_04245"),
+    ERR_04246("ERR_04246"),
+    ERR_04247("ERR_04247"),
+    ERR_04248("ERR_04248"),
+    ERR_04249("ERR_04249"),
+    ERR_04250("ERR_04250"),
+    ERR_04251("ERR_04251"),
+    ERR_04252("ERR_04252"),
+    ERR_04253("ERR_04253"),
+    ERR_04254("ERR_04254"),
+    ERR_04255("ERR_04255"),
+    ERR_04256("ERR_04256"),
+    ERR_04257("ERR_04257"),
+    ERR_04258("ERR_04258"),
+    ERR_04259("ERR_04259"),
+    ERR_04260("ERR_04260"),
+    ERR_04261("ERR_04261"),
+    ERR_04262("ERR_04262"),
+    ERR_04263("ERR_04263"),
+    ERR_04264("ERR_04264"),
+    ERR_04265("ERR_04265"),
+    ERR_04266("ERR_04266"),
+    ERR_04267("ERR_04267"),
+    ERR_04268_OID_NOT_FOUND("ERR_04268_OID_NOT_FOUND"),
+    ERR_04269("ERR_04269"),
+    ERR_04270("ERR_04270"),
+    ERR_04271("ERR_04271"),
+    ERR_04272("ERR_04272"),
+    ERR_04273("ERR_04273"),
+    ERR_04274("ERR_04274"),
+    ERR_04275("ERR_04275"),
+    ERR_04276("ERR_04276"),
+    ERR_04277("ERR_04277"),
+    ERR_04278("ERR_04278"),
+    ERR_04279("ERR_04279"),
+    ERR_04280("ERR_04280"),
+    ERR_04281("ERR_04281"),
+    ERR_04282("ERR_04282"),
+    ERR_04283("ERR_04283"),
+    ERR_04284("ERR_04284"),
+    ERR_04285("ERR_04285"),
+    ERR_04286("ERR_04286"),
+    ERR_04287("ERR_04287"),
+    ERR_04288("ERR_04288"),
+    ERR_04289("ERR_04289"),
+    ERR_04290("ERR_04290"),
+    ERR_04291("ERR_04291"),
+    ERR_04292("ERR_04292"),
+    ERR_04293("ERR_04293"),
+    ERR_04294("ERR_04294"),
+    ERR_04295("ERR_04295"),
+    ERR_04296("ERR_04296"),
+    ERR_04297("ERR_04297"),
+    ERR_04298("ERR_04298"),
+    ERR_04299("ERR_04299"),
+    ERR_04300("ERR_04300"),
+    ERR_04301("ERR_04301"),
+    ERR_04302("ERR_04302"),
+    ERR_04303("ERR_04303"),
+    ERR_04304("ERR_04304"),
+    ERR_04305("ERR_04305"),
+    ERR_04306("ERR_04306"),
+    ERR_04307("ERR_04307"),
+    ERR_04308("ERR_04308"),
+    ERR_04309("ERR_04309"),
+    ERR_04310("ERR_04310"),
+    ERR_04311("ERR_04311"),
+    ERR_04312("ERR_04312"),
+    ERR_04313("ERR_04313"),
+    ERR_04314("ERR_04314"),
+    ERR_04315("ERR_04315"),
+    ERR_04316("ERR_04316"),
+    ERR_04317("ERR_04317"),
+    ERR_04318("ERR_04318"),
+    ERR_04319("ERR_04319"),
+    ERR_04320("ERR_04320"),
+    ERR_04321("ERR_04321"),
+    ERR_04322("ERR_04322"),
+    ERR_04323("ERR_04323"),
+    ERR_04324("ERR_04324"),
+    ERR_04325("ERR_04325"),
+    ERR_04326("ERR_04326"),
+    ERR_04327("ERR_04327"),
+    ERR_04328("ERR_04328"),
+    ERR_04329("ERR_04329"),
+    ERR_04330("ERR_04330"),
+    ERR_04331("ERR_04331"),
+    ERR_04332("ERR_04332"),
+    ERR_04333("ERR_04333"),
+    ERR_04334("ERR_04334"),
+    ERR_04335("ERR_04335"),
+    ERR_04336("ERR_04336"),
+    ERR_04337("ERR_04337"),
+    ERR_04338("ERR_04338"),
+    ERR_04339("ERR_04339"),
+    ERR_04340("ERR_04340"),
+    ERR_04341("ERR_04341"),
+    ERR_04342("ERR_04342"),
+    ERR_04343("ERR_04343"),
+    ERR_04344("ERR_04344"),
+    ERR_04345("ERR_04345"),
+    ERR_04346("ERR_04346"),
+    ERR_04347("ERR_04347"),
+    ERR_04348("ERR_04348"),
+    ERR_04349("ERR_04349"),
+    ERR_04350("ERR_04350"),
+    ERR_04351("ERR_04351"),
+    ERR_04352("ERR_04352"),
+    ERR_04353("ERR_04353"),
+    ERR_04354("ERR_04354"),
+    ERR_04355("ERR_04355"),
+    ERR_04356("ERR_04356"),
+    ERR_04357("ERR_04357"),
+    ERR_04358("ERR_04358"),
+    ERR_04359("ERR_04359"),
+    ERR_04360("ERR_04360"),
+    ERR_04361("ERR_04361"),
+    ERR_04362("ERR_04362"),
+    ERR_04363("ERR_04363"),
+    ERR_04364("ERR_04364"),
+    ERR_04365("ERR_04365"),
+    ERR_04366("ERR_04366"),
+    ERR_04367("ERR_04367"),
+    ERR_04368("ERR_04368"),
+    ERR_04369("ERR_04369"),
+    ERR_04370("ERR_04370"),
+    ERR_04371("ERR_04371"),
+    ERR_04372("ERR_04372"),
+    ERR_04373("ERR_04373"),
+    ERR_04374("ERR_04374"),
+    ERR_04375("ERR_04375"),
+    ERR_04376("ERR_04376"),
+    ERR_04377("ERR_04377"),
+    ERR_04378("ERR_04378"),
+    ERR_04379("ERR_04379"),
+    ERR_04380("ERR_04380"),
+    ERR_04381("ERR_04381"),
+    ERR_04382("ERR_04382"),
+    ERR_04383("ERR_04383"),
+    ERR_04384("ERR_04384"),
+    ERR_04385("ERR_04385"),
+    ERR_04386("ERR_04386"),
+    ERR_04387("ERR_04387"),
+    ERR_04388("ERR_04388"),
+    ERR_04389("ERR_04389"),
+    ERR_04390("ERR_04390"),
+    ERR_04391("ERR_04391"),
+    ERR_04392("ERR_04392"),
+    ERR_04393("ERR_04393"),
+    ERR_04394("ERR_04394"),
+    ERR_04395("ERR_04395"),
+    ERR_04396("ERR_04396"),
+    ERR_04397("ERR_04397"),
+    ERR_04398("ERR_04398"),
+    ERR_04399("ERR_04399"),
+    ERR_04400("ERR_04400"),
+    ERR_04401("ERR_04401"),
+    ERR_04402("ERR_04402"),
+    ERR_04403("ERR_04403"),
+    ERR_04404("ERR_04404"),
+    ERR_04405("ERR_04405"),
+    ERR_04406("ERR_04406"),
+    ERR_04407("ERR_04407"),
+    ERR_04408("ERR_04408"),
+    ERR_04409("ERR_04409"),
+    ERR_04410("ERR_04410"),
+    ERR_04411("ERR_04411"),
+    ERR_04412("ERR_04412"),
+    ERR_04413("ERR_04413"),
+    ERR_04414("ERR_04414"),
+    ERR_04415("ERR_04415"),
+    ERR_04416("ERR_04416"),
+    ERR_04417("ERR_04417"),
+    ERR_04418("ERR_04418"),
+    ERR_04419("ERR_04419"),
+    ERR_04420("ERR_04420"),
+    ERR_04421("ERR_04421"),
+    ERR_04422("ERR_04422"),
+    ERR_04423("ERR_04423"),
+    ERR_04424("ERR_04424"),
+    ERR_04425("ERR_04425"),
+    ERR_04426("ERR_04426"),
+    ERR_04427("ERR_04427"),
+    ERR_04428("ERR_04428"),
+    ERR_04429("ERR_04429"),
+    ERR_04430("ERR_04430"),
+    ERR_04431("ERR_04431"),
+    ERR_04432("ERR_04432"),
+    ERR_04433("ERR_04433"),
+    ERR_04434("ERR_04434"),
+    ERR_04435("ERR_04435"),
+    ERR_04436("ERR_04436"),
+    ERR_04437("ERR_04437"),
+    ERR_04438("ERR_04438"),
+    ERR_04439("ERR_04439"),
+    ERR_04440("ERR_04440"),
+    ERR_04441("ERR_04441"),
+    ERR_04442_NOT_EXISTING_ATRIBUTE_TYPE("ERR_04442_NOT_EXISTING_ATRIBUTE_TYPE"),
+    ERR_04443("ERR_04443"),
+    ERR_04444("ERR_04444"),
+    ERR_04445("ERR_04445"),
+    ERR_04446("ERR_04446"),
+    ERR_04447_CANNOT_NORMALIZE_VALUE("ERR_04447_CANNOT_NORMALIZE_VALUE"),
+    ERR_04448("ERR_04448"),
+    ERR_04449("ERR_04449"),
+    ERR_04450("ERR_04450"),
+    ERR_04451("ERR_04451"),
+    ERR_04452("ERR_04452"),
+    ERR_04453("ERR_04453"),
+    ERR_04454("ERR_04454"),
+    ERR_04455("ERR_04455"),
+    ERR_04456("ERR_04456"),
+    ERR_04457_NULL_ATTRIBUTE_ID("ERR_04457_NULL_ATTRIBUTE_ID"),
+    ERR_04458("ERR_04458"),
+    ERR_04459("ERR_04459"),
+    ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED("ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED"),
+    ERR_04461("ERR_04461"),
+    ERR_04462("ERR_04462"),
+    ERR_04463("ERR_04463"),
+    ERR_04464("ERR_04464"),
+    ERR_04465("ERR_04465"),
+    ERR_04466("ERR_04466"),
+    ERR_04467("ERR_04467"),
+    ERR_04468("ERR_04468"),
+    ERR_04469("ERR_04469"),
+    ERR_04470("ERR_04470"),
+    ERR_04471("ERR_04471"),
+    ERR_04472("ERR_04472"),
+    ERR_04473_NOT_VALID_VALUE("ERR_04473_NOT_VALID_VALUE"),
+    ERR_04474("ERR_04474"),
+    ERR_04475("ERR_04475"),
+    ERR_04476("ERR_04476"),
+    ERR_04477_NO_VALID_AT_FOR_THIS_ID("ERR_04477_NO_VALID_AT_FOR_THIS_ID"),
+    ERR_04478_NO_VALUE_NOT_ALLOWED("ERR_04478_NO_VALUE_NOT_ALLOWED"),
+    ERR_04479_INVALID_SYNTAX_VALUE("ERR_04479_INVALID_SYNTAX_VALUE"),
+    ERR_04480_END_OF_STREAM("ERR_04480_END_OF_STREAM"),
+    ERR_04481_ENTRY_NULL_VALUE("ERR_04481_ENTRY_NULL_VALUE"),
+    ERR_04482_CANNOT_SUBTYPE_COLLECTIVE("ERR_04482_CANNOT_SUBTYPE_COLLECTIVE"),
+    ERR_04483_COLLECTIVE_NOT_MULTI_VALUED("ERR_04483_COLLECTIVE_NOT_MULTI_VALUED"),
+    ERR_04484_COLLECTIVE_NOT_ALLOWED_IN_MUST("ERR_04484_COLLECTIVE_NOT_ALLOWED_IN_MUST"),
+    ERR_04485_COLLECTIVE_NOT_ALLOWED_IN_MAY("ERR_04485_COLLECTIVE_NOT_ALLOWED_IN_MAY"),
+    ERR_04486_VALUE_ALREADY_EXISTS("ERR_04486_VALUE_ALREADY_EXISTS"),
+    ERR_04487_ATTRIBUTE_IS_SINGLE_VALUED("ERR_04487_ATTRIBUTE_IS_SINGLE_VALUED"),
+
+    // ldap-constants
+    ERR_05001_UNKNOWN_AUTHENT_LEVEL("ERR_05001_UNKNOWN_AUTHENT_LEVEL"),
+
+    // ldap-converter
+    ERR_06001_EMPTY_OR_NULL_SCHEMA_OBJECT("ERR_06001_EMPTY_OR_NULL_SCHEMA_OBJECT"),
+    ERR_06002_PARSER_FAILURE("ERR_06002_PARSER_FAILURE"),
+    ERR_06003_NO_NAME("ERR_06003_NO_NAME"),
+    ERR_06004_CANNOT_GENERATE_SOURCES("ERR_06004_CANNOT_GENERATE_SOURCES"),
+    ERR_06005_NULL_SCHEMA("ERR_06005_NULL_SCHEMA"),
+    ERR_06006_NO_PROPERTY("ERR_06006_NO_PROPERTY"),
+
+    // ldap-jndi
+    // no exceptions to translate
+
+    // ldap-schema
+    ERR_08001("ERR_08001"),
+    ERR_08002("ERR_08002"),
+    ERR_08003("ERR_08003"),
+    ERR_08004("ERR_08004"),
+    ERR_08005("ERR_08005"),
+    ERR_08006("ERR_08006"),
+
+    // ldap-schema
+    ERR_09001_DIRECTORY_CREATION_FAILED("ERR_09001_DIRECTORY_CREATION_FAILED"),
+
+    // ldap-schema-loader
+    ERR_10001("ERR_10001"),
+    ERR_10002("ERR_10002"),
+    ERR_10003("ERR_10003"),
+    ERR_10004("ERR_10004"),
+    ERR_10005("ERR_10005"),
+    ERR_10006("ERR_10006"),
+    ERR_10007("ERR_10007"),
+    ERR_10008("ERR_10008"),
+    ERR_10009("ERR_10009"),
+    ERR_10010("ERR_10010"),
+    ERR_10011("ERR_10011"),
+    ERR_10012("ERR_10012"),
+    ERR_10013("ERR_10013"),
+    ERR_10014("ERR_10014"),
+    ERR_10015("ERR_10015"),
+    ERR_10016("ERR_10016"),
+    ERR_10017("ERR_10017"),
+    ERR_10018("ERR_10018"),
+    ERR_10019("ERR_10019"),
+    ERR_10020("ERR_10020"),
+    ERR_10021("ERR_10021"),
+    ERR_10022("ERR_10022"),
+    ERR_10023("ERR_10023"),
+    ERR_10024("ERR_10024"),
+    ERR_10025("ERR_10025"),
+    ERR_10026("ERR_10026"),
+    ERR_10027("ERR_10027"),
+    ERR_10028("ERR_10028"),
+
+    // ldap-schema-manager
+    ERR_11001("ERR_11001"),
+    ERR_11002("ERR_11002"),
+    ERR_11003("ERR_11003"),
+    ERR_11004("ERR_11004"),
+    ERR_11005("ERR_11005"),
+    ERR_11006("ERR_11006"),
+    ERR_11007("ERR_11007"),
+    ERR_11008("ERR_11008"),
+    ERR_11009("ERR_11009"),
+    ERR_11010("ERR_11010"),
+    ERR_11011("ERR_11011"),
+    ERR_11012("ERR_11012"),
+    ERR_11013("ERR_11013"),
+
+    // ldap-schema-manager
+    ERR_12001_UNKNOWN_CHANGE_TYPE("ERR_12001_UNKNOWN_CHANGE_TYPE"),
+    ERR_12002_ENTRY_WITH_TWO_DNS("ERR_12002_ENTRY_WITH_TWO_DNS"),
+    ERR_12003_LDIF_ENTRY_WITH_TWO_DNS("ERR_12003_LDIF_ENTRY_WITH_TWO_DNS"),
+    ERR_12004_CHANGE_NOT_ALLOWED("ERR_12004_CHANGE_NOT_ALLOWED"),
+    ERR_12005_NO_CHANGE("ERR_12005_NO_CHANGE"),
+    ERR_12006_EXPECTING_ATTRIBUTE_TYPE("ERR_12006_EXPECTING_ATTRIBUTE_TYPE"),
+    ERR_12007_BAD_ATTRIBUTE("ERR_12007_BAD_ATTRIBUTE"),
+    ERR_12008_CANNOT_PARSE_LDIF_BUFFER("ERR_12008_CANNOT_PARSE_LDIF_BUFFER"),
+    ERR_12009_ERROR_PARSING_LDIF_BUFFER("ERR_12009_ERROR_PARSING_LDIF_BUFFER"),
+    ERR_12010_CANNOT_FIND_FILE("ERR_12010_CANNOT_FIND_FILE"),
+    ERR_12011_CANNOT_READ_FILE("ERR_12011_CANNOT_READ_FILE"),
+    ERR_12012_EMPTY_DN_NOT_ALLOWED("ERR_12012_EMPTY_DN_NOT_ALLOWED"),
+    ERR_12013_NO_DN("ERR_12013_NO_DN"),
+    ERR_12014_BASE64_DN_EXPECTED("ERR_12014_BASE64_DN_EXPECTED"),
+    ERR_12015_INVALID_BASE64_DN("ERR_12015_INVALID_BASE64_DN"),
+    ERR_12016_DN_EXPECTED("ERR_12016_DN_EXPECTED"),
+    ERR_12017_INVALID_DN("ERR_12017_INVALID_DN"),
+    ERR_12018_FILE_NOT_FOUND("ERR_12018_FILE_NOT_FOUND"),
+    ERR_12019_BAD_URL_FILE_NOT_FOUND("ERR_12019_BAD_URL_FILE_NOT_FOUND"),
+    ERR_12020_FILE_TOO_BIG("ERR_12020_FILE_TOO_BIG"),
+    ERR_12022_ERROR_READING_FILE("ERR_12022_ERROR_READING_FILE"),
+    ERR_12023_ERROR_READING_BAD_URL("ERR_12023_ERROR_READING_BAD_URL"),
+    ERR_12024_CANNOT_CLOSE_FILE("ERR_12024_CANNOT_CLOSE_FILE"),
+    ERR_12025_BAD_PROTOCOL("ERR_12025_BAD_PROTOCOL"),
+    ERR_12026_UNSUPPORTED_PROTOCOL("ERR_12026_UNSUPPORTED_PROTOCOL"),
+    ERR_12027_BAD_URL("ERR_12027_BAD_URL"),
+    ERR_12029_CONTROL_WITHOUT_OID("ERR_12029_CONTROL_WITHOUT_OID"),
+    ERR_12031_INVALID_OID("ERR_12031_INVALID_OID"),
+    ERR_12033_INVALID_CRITICALITY("ERR_12033_INVALID_CRITICALITY"),
+    ERR_12035_BAD_MODRDN_OPERATION("ERR_12035_BAD_MODRDN_OPERATION"),
+    ERR_12038_NO_DELETEOLDRDN("ERR_12038_NO_DELETEOLDRDN"),
+    ERR_12040_BAD_MODIFY_SEPARATOR("ERR_12040_BAD_MODIFY_SEPARATOR"),
+    ERR_12042_BAD_MODIFY_SEPARATOR_2("ERR_12042_BAD_MODIFY_SEPARATOR_2"),
+    ERR_12044("ERR_12044"),
+    ERR_12045("ERR_12045"),
+    ERR_12046("ERR_12046"),
+    ERR_12047("ERR_12047"),
+    ERR_12048("ERR_12048"),
+    ERR_12049("ERR_12049"),
+    ERR_12050("ERR_12050"),
+    ERR_12051("ERR_12051"),
+    ERR_12052("ERR_12052"),
+    ERR_12053("ERR_12053"),
+    ERR_12054("ERR_12054"),
+    ERR_12055("ERR_12055"),
+    ERR_12056("ERR_12056"),
+    ERR_12057_BAD_ATTRIBUTE("ERR_12057_BAD_ATTRIBUTE"),
+    ERR_12058_UNKNOWN_ENTRY_TYPE("ERR_12058_UNKNOWN_ENTRY_TYPE"),
+    ERR_12059_UNKNOWN_ENTRY("ERR_12059_UNKNOWN_ENTRY"),
+    ERR_12060_VERSION_NOT_A_NUMBER("ERR_12060_VERSION_NOT_A_NUMBER"),
+    ERR_12061_LDIF_PARSING_ERROR("ERR_12061_LDIF_PARSING_ERROR"),
+    ERR_12062_EMPTY_CONTINUATION_LINE("ERR_12062_EMPTY_CONTINUATION_LINE"),
+    ERR_12063_ERROR_WHILE_READING_LDIF_LINE("ERR_12063_ERROR_WHILE_READING_LDIF_LINE"),
+    ERR_12064_EMPTY_FILE_NAME("ERR_12064_EMPTY_FILE_NAME"),
+    ERR_12066("ERR_12066"),
+    ERR_12067("ERR_12067"),
+    ERR_12068("ERR_12068"),
+    ERR_12069("ERR_12069"),
+    ERR_12070("ERR_12070"),
+    ERR_12071("ERR_12071"),
+    ERR_12072("ERR_12072"),
+    ERR_12073("ERR_12073"),
+    ERR_12074("ERR_12074"),
+    ERR_12075("ERR_12075"),
+    ERR_12076("ERR_12076"),
+    ERR_12077("ERR_12077"),
+    ERR_12078("ERR_12078"),
+    ERR_12079("ERR_12079"),
+    ERR_12080("ERR_12080"),
+    ERR_12081("ERR_12081"),
+    ERR_12082("ERR_12082"),
+    ERR_12083("ERR_12083"),
+    ERR_12084("ERR_12084"),
+    ERR_12085("ERR_12085"),
+    ERR_12086("ERR_12086"),
+    ERR_12087("ERR_12087");
+
+    /** The error code */
+    private String errorCode;
+
+
+    /**
+     * Creates a new instance of I18n.
+     * 
+     * @param errorCode the error code
+     */
+    private I18n( String errorCode )
+    {
+        this.errorCode = errorCode;
+    }
+
+
+    /**
+     * Getter for the field <code>errorCode</code>.
+     *
+     * @return the errorCode
+     * @since 0.9.20
+     */
+    public String getErrorCode()
+    {
+        return errorCode;
+    }
+
+    /** The file containing the errors */
+    private static final ResourceBundle ERR_BUNDLE = ResourceBundle
+        .getBundle( "org/apache/directory/api/i18n/errors" );
+
+    /** The file containing the messages */
+    private static final ResourceBundle MSG_BUNDLE = ResourceBundle
+        .getBundle( "org/apache/directory/api/i18n/messages" );
+
+
+    /**
+     *
+     * Translate an error code with argument(s)
+     *
+     * @param err The error code
+     * @param args The argument(s)
+     * @return The translated error
+     */
+    public static String err( I18n err, Object... args )
+    {
+        try
+        {
+            return err + " " + MessageFormat.format( ERR_BUNDLE.getString( err.getErrorCode() ), args );
+        }
+        catch ( Exception e )
+        {
+            StringBuilder sb = new StringBuilder();
+            boolean comma = false;
+
+            for ( Object obj : args )
+            {
+                if ( comma )
+                {
+                    sb.append( "," );
+                }
+                else
+                {
+                    comma = true;
+                }
+
+                sb.append( obj );
+            }
+            return err + " (" + sb.toString() + ")";
+        }
+    }
+
+
+    /**
+     *
+     * Translate a message with argument(s)
+     *
+     * @param msg The message
+     * @param args The argument(s)
+     * @return The translated error
+     */
+    public static String msg( String msg, Object... args )
+    {
+        try
+        {
+            return MessageFormat.format( MSG_BUNDLE.getString( msg ), args );
+        }
+        catch ( MissingResourceException mre )
+        {
+            try
+            {
+                return MessageFormat.format( msg, args );
+            }
+            catch ( Exception e )
+            {
+                StringBuilder sb = new StringBuilder();
+                boolean comma = false;
+
+                for ( Object obj : args )
+                {
+                    if ( comma )
+                    {
+                        sb.append( "," );
+                    }
+                    else
+                    {
+                        comma = true;
+                    }
+
+                    sb.append( obj );
+                }
+
+                return msg + " (" + sb.toString() + ")";
+            }
+        }
+    }
+}
diff --git a/trunk/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties b/trunk/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
new file mode 100644
index 0000000..c576d77
--- /dev/null
+++ b/trunk/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
@@ -0,0 +1,761 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#  
+#    http://www.apache.org/licenses/LICENSE-2.0
+#  
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License. 
+#  
+#
+
+# asn1
+ERR_00001_BAD_TRANSITION_FROM_STATE=Bad transition from state {0}, tag {1}
+ERR_00002_BAD_TRANSITION=Bad transition !
+ERR_00003_CANNOT_PUT_PDU_IN_NULL_BUFFER=Cannot put a PDU in a null buffer !
+ERR_00004_PDU_BUFFER_SIZE_TOO_SMALL=The PDU buffer size is too small !
+ERR_00005_LENGTH_OVERFLOW=Overflow : can''t have more than 4 bytes long length
+ERR_00006_LENGTH_EXTENSION_RESERVED=Length reserved extension used
+ERR_00007_TLV_NULL=The current container TLV is null.
+ERR_00008_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH=The current Value length {0} is above the expected length {1}
+ERR_00009_MORE_TLV_EXPECTED=The PDU is decoded, but we should have had more TLVs
+ERR_00010_TRUNCATED_PDU=Truncated PDU. Some elements are lacking, accordingly to the grammar
+ERR_00011_LENGTH_TOO_LONG_FOR_DEFINITE_FORM=Length above 126 bytes are not allowed for a definite form Length
+ERR_00013_ODD_NUM_OF_CHARS=Odd number of characters.
+ERR_00014_ILLEGAL_HEX_CHAR=Illegal hexadecimal character {0} at index {1}
+ERR_00016_END_OF_STREAM=End of stream.
+ERR_00017_EOF_FOUND_LENGTH_EXPECTED=EOF found when length expected.
+ERR_00018_DER_LENGTH_ABOVE_4_BYTES=DER length more than 4 bytes.
+ERR_00019_EOF_FOUND_IN_LENGTH=EOF found reading length.
+ERR_00020_CORRUPTED_STREAM=Corrupted steam - negative length found.
+ERR_00021_EOF_FOUND_IN_OBJECT=EOF encountered in middle of object.
+ERR_00022_READ_PAST_END_OF_FILE=Attempt to read past end of file.
+ERR_00023_UNKNOWN_BER_OBJECT=Unknown BER object encountered.
+ERR_00024_OBJECT_NOT_DER_ENCODABLE=Object not DEREncodable.
+ERR_00025_DER_OCTET_STRING_EXPECTED={0} found in input should only contain DEROctetString.
+ERR_00020_CANNOT_CONVERT_OCTETS=Exception converting octets {0}
+ERR_00020_NOT_IMPLEMENTED=Not implemented: {0}
+ERR_00020_INTERNAL_ERROR_ENCODING_BITSTRING_00028=Internal error encoding BitString.
+ERR_00020_NULL_OR_NEG_LENGTH_NOT_ALLOWED=Null or negative length are not allowed
+ERR_00030_BIT_NUMBER_OUT_OF_BOUND=Bad bit number : out of bound
+ERR_00031_CANNOT_FIND_BIT=Cannot get a bit at position {0} when the BitString contains only {1} ints
+ERR_00032_NULL_OID=Null OID
+ERR_00033_INVALID_OID=Invalid OID : {0}
+ERR_00034_0_BYTES_LONG_BOOLEAN=The value is 0 byte long. This is not allowed for a boolean
+ERR_00035_N_BYTES_LONG_BOOLEAN=The value is not 1 byte long. This is not allowed for a boolean
+ERR_00036_0_BYTES_LONG_INTEGER=The value is 0 byte long. This is not allowed for an integer
+ERR_00037_ABOVE_4_BYTES_INTEGER=The value is more than 4 bytes long. This is not allowed for an integer
+ERR_00038_VALUE_NOT_IN_RANGE=The value is not in the range [{0}, {1}]
+ERR_00039_0_BYTES_LONG_LONG=The value is 0 byte long. This is not allowed for a long
+ERR_00041_CURRENT_LENGTH_EXCEED_EXPECTED_LENGTH=Current Length is above expected Length
+ERR_00042_PDU_SIZE_TOO_LONG=The PDU current size ({1}) exceeds the maximum allowed PDU size ({2})
+ERR_00043_REMAINING_BYTES_FOR_DECODED_PDU=The PDU has been fully decoded but there are still bytes in the buffer.
+
+
+# asn1-codec
+ERR_01001=Encoded result is not a ByteBuffer: {0}
+
+# cursor
+ERR_02001_MONITOR=monitor
+ERR_02002_FAILURE_ON_UNDERLYING_CURSOR=Failure on underlying Cursor.
+ERR_02003_REMOVAL_NOT_SUPPORTED=Underlying Cursor does not support removal.
+ERR_02004_EMPTY_CURSOR=This cursor is empty and cannot return elements!
+ERR_02005_START_INDEX_OUT_OF_RANGE=start index ''{0}'' out of range
+ERR_02006_END_INDEX_OUT_OF_RANGE=end index ''{0}'' out of range
+ERR_02007_START_INDEX_ABOVE_END_INDEX=start index ''{0}'' greater than or equal to end index ''{1}'' just does not make sense
+ERR_02008_LIST_MAY_BE_SORTED=don''t know if list is sorted and checking that is not worth it
+ERR_02009_CURSOR_NOT_POSITIONED=Cursor not positioned at an element
+ERR_02010_NO_COMPARATOR_CANT_MOVE_BEFORE=Without a comparator I cannot advance to just before the specified element.
+ERR_02011_NO_COMPARATOR_CANT_MOVE_AFTER=Without a comparator I cannot advance to just after the specified element.
+ERR_02012_CANNOT_ACCESS_IF_BEFORE_FIRST=Cannot access element if positioned before first.
+ERR_02013_CANNOT_ACCESS_IF_AFTER_LAST=Cannot access element if positioned after last.
+ERR_02014_UNSUPPORTED_OPERATION=The method method {0} is not supported
+
+# dsml-parser
+ERR_03001={0} - Line {1} - Column {2}
+ERR_03002=A requestID must be specified to each request when Processing is Parallel and ReponseOrder is Unordered.
+ERR_03003=Internal Error: {0}
+ERR_03004=Unknown type
+ERR_03005=type attribute is required
+ERR_03006=Incorrect value for ''type'' attribute. This is not an OID.
+ERR_03007=Incorrect value for ''criticality'' attribute
+ERR_03008=An unexpected error ocurred : {0}
+ERR_03009=the given resultCode is not an integer
+ERR_03010=code attribute is required
+ERR_03011=descr (''{0}'') doesn''t match with the possible values
+ERR_03012=name attribute is required
+ERR_03013=Unknown value for ''processing'' attribute.
+ERR_03014=Unknown value for ''onError'' attribute.
+ERR_03015=Unknown value for ''responseOrder'' attribute.
+ERR_03016=requestID attribute is required
+ERR_03017=the given abandonID is not an integer
+ERR_03018=abandonID attribute is required
+ERR_03019=dn attribute is required
+ERR_03020=can not add attribute value
+ERR_03021=principal attribute is required
+ERR_03022=The request name can''t be null
+ERR_03023=newrdn attribute is required
+ERR_03024=Incorrect value for ''deleteoldrdn'' attribute
+ERR_03025=operation attribute is required
+ERR_03026=unknown scope. Scope must be ''baseObject'', ''singleLevel'' or ''wholeSubtree''.
+ERR_03027=scope attribute is required
+ERR_03028=unknown derefAliases value. derefAliases must be ''neverDerefAliases'', ''derefInSearching'', ''derefFindingBaseObj'' or ''derefAlways''.
+ERR_03029=derefAliases attribute is required
+ERR_03030=the given sizeLimit is not an integer
+ERR_03031=the given timeLimit is not an integer
+ERR_03032=typesOnly must be a boolean (''true'' or ''false'').
+ERR_03033=dnAttributes must be a boolean (''true'' or ''false'').
+ERR_03034=Incorrect value for ''type'' attribute. This is not an OID.
+ERR_03035=type attribute is required
+ERR_03036=The tag {0} can''t be found at this position
+ERR_03037=An IOException occurred during parsing : {0}
+ERR_03038=The attribute requestID {0} can''t be below 0
+ERR_03039=the given requestID is not an integer
+ERR_03040=unable to find the batch request
+
+# dsml-parser
+ERR_03101_MISSING_CONNECTION_TO BIND=Missing connection, can not bind
+
+# ldap
+ERR_04001_NULL_IDENTIFICATION_TAG=identificationTag parameter is null
+ERR_04002_BAD_PRECENDENCE=precedence parameter not in [0-255] : {0}
+ERR_04003_NULL_AUTHENTICATION_LEVEL=authenticationLevel parameter is null
+ERR_04004_PARSER_FAILURE_ACI_ITEM=Parser failure on ACIItem\:\n\t{0}\nAntlr exception trace\:\n{1} [Line:{2} - Column:{3}]
+ERR_04005=The PDU buffer size is too small !
+ERR_04006=The And filter PDU must not be empty
+ERR_04007=The attribute description is empty
+ERR_04008=The type can''t be null
+ERR_04009=The Not filter PDU must not be empty
+ERR_04010=The Or filter PDU must not be empty
+ERR_04011=The Referrals must not be null
+ERR_04012=The Substring filter PDU must not be empty
+ERR_04013=Incorrect DN given : {0} ({1}) is invalid : {2}
+ERR_04014=Incorrect DN given : {0}
+ERR_04015=The URL {0} is not valid \: {1} 
+ERR_04016=Invalid URL : {0}
+ERR_04017=The name must not be null
+ERR_04018=The result code {0} is invalid : {1}. The result code must be between (0 .. 121)
+ERR_04019=The substring any filter is empty
+ERR_04020=The substring final filter is empty
+ERR_04021=The URL {0} is not valid : {1}
+ERR_04022=The type cannot be null in a MatchingRuleAssertion
+ERR_04023=Cannot put a PDU in a null buffer !
+ERR_04024=failed to decode the refreshDeletes flag for SyncDoneValueControl
+ERR_04025=failed to decode the refreshDone flag for SyncInfoValueControl
+ERR_04026=failed to decode the refreshDeletes flag for SyncInfoValueControl
+ERR_04027=Bad UUID value, its length is incorrect ( it should be 16 bytes long)
+ERR_04028=failed to decode the mode for SyncRequestValueControl
+ERR_04029=failed to decode the reloadHint flag for SyncRequestValueControl
+ERR_04030=failed to decode the mode for SyncStateValueControl
+ERR_04031=failed to decode the cancelId, the value should be between 0 and 2^31-1, it is ''{0}''
+ERR_04032=invalid target DN {0}
+ERR_04033=failed to decode the target DN, it cannot be null or empty it is ''{0}''
+ERR_04034=invalid issuer DN {0}
+ERR_04035=invalid subject DN {0}
+ERR_04036=failed to decode the delay, the value should be between 0 and 86400 seconds, it is ''{0}''
+ERR_04037=failed to decode the timeOffline, the value should be between 0 and 720 minutes, it is ''{0}''
+ERR_04038=The stored procedure language is null
+ERR_04039=The procedure can''t be null
+ERR_04040=The parameter type can''t be null
+ERR_04041=The parameter value can''t be null
+ERR_04042=The parameter value is empty. This is not allowed.
+ERR_04043=The request name must not be null
+ERR_04044=failed to decode the changeType for EntryChangeControl
+ERR_04045=The previousDN field should not contain anything if the changeType is not MODDN
+ERR_04046=Previous DN is not allowed for this change type
+ERR_04047=Bad Previous DN : ''{0}''
+ERR_04048=failed to decode the previous DN
+ERR_04049=failed to decode the changeNumber for EntryChangeControl
+ERR_04050=failed to decode the size for PagedSearchControl
+ERR_04051=failed to decode the changeTypes for PSearchControl
+ERR_04052=failed to decode the changesOnly for PSearchControl
+ERR_04053=failed to decode the returnECs for PSearchControl
+ERR_04054=The visibility flag {0} is invalid : {1}. It should be 0 or 255
+ERR_04055=Undefined changeType value: {0}
+ERR_04056=Cannot have a null matching rule and a null type
+ERR_04057=Cannot have more than one Filter within a Not Filter
+ERR_04058=Cannot have a null initial, any and final substring
+ERR_04059=Expected either a byte[] or ByteBuffer argument but got a {0}
+ERR_04060=Ldap decoder failure : {0}
+ERR_04061=Ldap decoder failure!
+ERR_04062=Ldap decoder failure, PDU does not contain enough data
+ERR_04063=The input stream does not contain a full PDU
+ERR_04064=Ldap decoder failure : The input stream does not contain a full PDU
+ERR_04065=Ldap encoder failed to encode object: {0}, error : {1}
+ERR_04066=The LdapMessage has a zero length. This is not allowed
+ERR_04067=The LdapMessage should not be empty
+ERR_04068=The messageId has a zero length. This is not allowed
+ERR_04069=The messageId should not be null
+ERR_04070=The Message Id {0} is invalid : {1}. The message ID must be between (0 .. 2 147 483 647)
+ERR_04071=The length of a UnBindRequest must be null, the actual value is {0}
+ERR_04072=The length of a UnBindRequest must be null
+ERR_04073=The entry must not be null
+ERR_04074=The DN to delete : {0} ({1}) is invalid : {2}
+ERR_04075=The AbandonRequest messageId must not be null
+ERR_04076=The Abandonned Message Id {0} is invalid : {1}. The message ID must be between (0 .. 2 147 483 647)
+ERR_04077=The BindRequest must not be null
+ERR_04078=The version {0} is invalid : {1}. The version must be between (0 .. 127)
+ERR_04079=The SaslCredential must not be null
+ERR_04080=The Referrals must not be null
+ERR_04081=The AttributeType can''t be empty
+ERR_04082=Invalid operation ({0}), it should be 0, 1 or 2
+ERR_04083=The type can''t be null
+ERR_04084=The AddRequest must not be null
+ERR_04085=Empty entry DN given
+ERR_04086=Null or empty types are not allowed
+ERR_04087=Error while injecting the AttributeType
+ERR_04088=The AddResponse must not be null
+ERR_04089=The entry must not be null
+ERR_04090=The newrdn must not be null
+ERR_04091=The oldRdn flag {0} is invalid : {1}. It should be 0 or 255
+ERR_04092=The new superior must not be null if the flag ''delete old DN'' is set to true
+ERR_04093=The attribute description must not be null
+ERR_04094=The CompareResponse must not be null
+ERR_04095=The name must not be null
+ERR_04096=The length of a control must not be null
+ERR_04097=The OID must not be null
+ERR_04098=The control type {0} is not a valid OID
+ERR_04099=Invalid control OID : {0}
+ERR_04100=The control criticality flag {0} is invalid : {1}. It should be 0 or 255
+ERR_04101=The scope is not in [0..2] : {0}
+ERR_04102=The derefAlias is not in [0..3] : {0}
+ERR_04103=The sizeLimit is not a valid Integer: {0}
+ERR_04104=The timeLimit is not a valid Integer: {0}
+ERR_04105=The types only flag {0} is invalid : {1}. It should be 0 or 255
+ERR_04106=The attribute description should not be null
+ERR_04107=The substrings sequence is empty
+ERR_04108=The substring initial filter is empty
+ERR_04109=The matching rule is empty
+ERR_04110=The DN attributes flag {0} is invalid : {1}. It should be 0 or 255
+ERR_04111=Could not parse matchedDn while transforming Codec value to Internal: {0}
+ERR_04112=Error while transforming a ExprNode : {0}
+ERR_04113=shouldn''t happen - if it does then we have issues
+ERR_04114=The CSN must not be null or empty
+ERR_04115=The CSN''s length is incorrect, it should be 40 chars long
+ERR_04116=Cannot find a ''#'' in the CSN ''{0}''
+ERR_04117=The timestamp is not long enough
+ERR_04118=Cannot parse the timestamp: ''{0}''
+ERR_04119=The microseconds part is invalid
+ERR_04120=Missing a ''#'' in the CSN ''{0}''
+ERR_04121=The changeCount ''{0}'' is not a valid number
+ERR_04122=Missing a ''#'' in the CSN ''{0}''
+ERR_04123=The replicaID must not be null or empty
+ERR_04124=The replicaId ''{0}'' is not a valid number
+ERR_04125=The operationNumber is absent
+ERR_04126=The operationNumber ''{0}'' is not a valid number
+ERR_04127=I don't really know how to compare anything other than ServerBinaryValues at this point in time.
+ERR_04128=Cannot compare {0} with the unknown value {1} 
+ERR_04129=Unknown value type: {0}
+ERR_04130=The value is expected to be a byte[]
+ERR_04131=The value is expected to be a String
+ERR_04132=An ID cannnot be null, empty, or resolved to an emtpy value when trimmed
+ERR_04133=The attributeType ID should not be null or empty
+ERR_04134=An exception has been raised while looking for attribute id ''{0}''
+ERR_04135=The AttributeType list should not be null
+ERR_04136=The AttributeType list should not contain null values
+ERR_04137=The attribute ''{0}'' does not exist in the entry
+ERR_04138=The removal of values for the missing ''{0}'' attribute is not possible
+ERR_04139=Cannot validate {0} with a null SyntaxChecker
+ERR_04140_UNACCEPTABLE_RESULT_CODE=Unacceptable result code for this exception type: {0}
+ERR_04141={0} is not an acceptable result code.
+ERR_04142=Only UNWILLING_TO_PERFORM and UNAVAILABLE_CRITICAL_EXTENSION result codes are allowed to be used with this exception
+ERR_04143=Only the following LDAP result codes can be used: {0}
+ERR_04144=ScopeNode can''t be part of a refinement
+ERR_04145=AssertionNode can''t be part of a refinement
+ERR_04146=AssertionValue expected
+ERR_04147=Expected MatchingRule or assertionValue
+ERR_04148=MatchingRule expected
+ERR_04149=Not a valid escaped value
+ERR_04150=Bad substring
+ERR_04151=Bad char
+ERR_04152=Expecting a ''\='' 
+ERR_04153=An item is expected
+ERR_04154=Empty filterComp
+ERR_04155=No ''('' at the beginning of the filter
+ERR_04156=Bad filter
+ERR_04157=The filter has no right parenthese
+ERR_04158=Empty filter
+ERR_04159=Cannot add more than one element to a negation node.
+ERR_04160=Unknown JNDI scope constant value: {0}
+ERR_04161=Unknown LDAP URL scope value: {0}
+ERR_04162=Invalid attribute {0} for a refinement
+ERR_04163=Unknown SyncStateTypeEnum value {0}
+ERR_04164=Failed to encode payload GracefulShutdownRequest
+ERR_04165=failed to decode payload
+ERR_04166=The result code can only be one of: {0}, {1}, {2}
+ERR_04167=Failed to encode payload CertGenerateRequest
+ERR_04168=the OID is fixed: {0}
+ERR_04169=Failed to decode response value
+ERR_04170=Failed while parsing LDAP url {0}
+ERR_04171=Failed to encode message value.
+ERR_04172=Failed while decoding response
+ERR_04173=the response is hardcoded as zero length array
+ERR_04174=Failed to encode payload StoredProcedureRequest
+ERR_04175=class loading of procedure type not implemented
+ERR_04176=conversion of value to java type not implemented
+ERR_04177=provider monitor class {0} not found
+ERR_04178=provider monitor class {0} does not expose a public default constructor
+ERR_04179=provider monitor class {0} failed during instantiation
+ERR_04180=Could not instantiate provider - environment does not specify {0} property!
+ERR_04181=Count not find the Provider class {0}
+ERR_04182=Count not invoke the Provider''s factory method: {0}.getProvider() - it may not exist!
+ERR_04183=Count not invoke the Provider''s factory method: {0}.getProvider() - it does seem to be a public method!
+ERR_04184=Call to Provider''s factory method\: {0}.getProvider() threw the following exception\:\n{1}
+ERR_04185=RFC 2251 [Section 4.11]: Abandon, Bind, Unbind, and StartTLS operations cannot be abandoned.
+ERR_04186=Unrecognized value ''{0}'' for {1} JNDI property.\nExpected a value of either always, never, searching, or finding.
+ERR_04187=Class has bug: check for valid enumeration values
+ERR_04188=The type cannot be empty or null
+ERR_04189=The User Provided type cannot be empty or null
+ERR_04190=The User provided name does not contains an ''=''
+ERR_04191=The AVA type cannot be null or empty
+ERR_04192=Unexpected character ''{0}'' at position {1}. Excpected '','' or '';''.
+ERR_04193=RDN must not be empty
+ERR_04194=RDN must not be null
+ERR_04195=Unexpected character ''{0}'' at position {1}. Excpected start of attributeType.
+ERR_04196=Unexpected character ''{0}'' at position {1}. Excpected start of attributeType descr.
+ERR_04197=Unexpected character ''{0}'' at position {1}. Excpected numericoid.
+ERR_04198=Numeric OID must contain at least one dot.
+ERR_04199=Unexpected character ''{0}'' at position {1}. Excpected start of attributeType numericoid.
+ERR_04200=Unexpected character ''{0}'' at position {1}. Excpected EQUALS ''=''.
+ERR_04201=No more characters available at position {0}
+ERR_04202=A value is missing on some RDN
+ERR_04203=Impossible to get the position {0}, the DN only has {1} RDNs
+ERR_04204=Failed to parse RDN for name {0}
+ERR_04205=Exceeded number of elements in the current object
+ERR_04206=The posn({0}) should be in the range [0, {1}]
+ERR_04207=The clone operation has failed
+ERR_04208=Assertion failure : cannot clone the object
+ERR_04209_EMPTY_TYPE_NOT_ALLOWED=Empty type not allowed in a DN
+ERR_04210=Cannot serialize a NULL DN
+ERR_04211=The DN should have been normalized before being serialized
+ERR_04212=The DN should have been normalized before being serialized {0}
+ERR_04213=This value is not in hex form, we have an odd number of hex chars
+ERR_04214=This value is not in hex form
+ERR_04215=Unescaped special characters are not allowed
+ERR_04216=This class is not aware of schema information and cannot normalize
+ERR_04217=None of the arguments are Comparable objects\:\n\targ1 \= {0}\n\targ2 \= {1}
+ERR_04218=I do not know how to handle dn comparisons with objects of class: {0}
+ERR_04219_ARGUMENT1_NULL=Argument ''obj1'' is null
+ERR_04220_ARGUMENT2_NULL=Argument ''obj2'' is null
+ERR_04221=Matching rule not found: {0}
+ERR_04222=The value stored in a non Human Readable attribute as a String should be convertible to a byte[]
+ERR_04223=The value stored in an Human Readable attribute as a byte[] should be convertible to a String
+ERR_04224=Invalid value : {0}
+ERR_04225=Encountered name based id of {0} which was not found in the OID registry
+ERR_04226=I do not know how to handle NameAndOptionalUID normalization with objects of class: {0}
+ERR_04227=Cannot parse a null AttributeType
+ERR_04228=Parser failure on attribute type description\:\n{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04229=Parser failure on attribute type description\:\n\t{0}\nAntlr message\: {1}
+ERR_04230=Cannot parse a null DITContentRule
+ERR_04231=Parser failure on DIT content rule description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04232=Parser failure on DIT content rule description\:\n\t{0}\nAntlr message\: {1}
+ERR_04233=Cannot parse a null DITStructureRule description
+ERR_04234=Parser failure on DIT structure rule description\:\n\t{0}\nAntlr message\: {1}nAntlr column\: {2}
+ERR_04235=Parser failure on DIT structure rule description\:\n\t{0}\nAntlr message\: {1}
+ERR_04236=Cannot parse a null LdapComparator description
+ERR_04237=Parser failure on comparator description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04238=Parser failure on comparator description\:\n\t{0}\nAntlr message\: {1}
+ERR_04239=Cannot parse a null LdapSyntax
+ERR_04240=Parser failure on LDAP syntay description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04241=Parser failure on LDAP syntay description\:\n\t{0}\nAntlr message\: {1}
+ERR_04242=Cannot parse a null MatchingRule
+ERR_04243=Parser failure on matching rule description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04244=Parser failure on matching rule description\:\n\t{0}\nAntlr message\: {1}
+ERR_04245=Cannot parse a null MatchingRuleUse
+ERR_04246=Parser failure on matching rule description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04247=Parser failure on matching rule description\:\n\t{0}\nAntlr message\: {1}
+ERR_04248=Cannot parse a null NameForm
+ERR_04249=Parser failure on name form description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2} 
+ERR_04250="Parser failure on name form description\:\n\t{0}\nAntlr message\: {1}
+ERR_04251=Cannot parse a null Normalizer description
+ERR_04252=Parser failure on normalizer description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04253=Parser failure on normalizer description\:\n\t{0}\nAntlr message\: {1}
+ERR_04254=Cannot parse a null LdapComparator description
+ERR_04255=Parser failure on object class description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04256=Parser failure on object class description\:\n\t{0}\nAntlr message\: {1}
+ERR_04257=No object identifier macro with name {0}
+ERR_04258=The schemaObject is either null or is the empty String!
+ERR_04259="Parser failure on syntax checker description\:\n\t{0}\nAntlr message\: {1}\nAntlr column\: {2}
+ERR_04260=Parser failure on syntax checker description\:\n\t{0}\nAntlr message\: {1}
+ERR_04261=entry cannot be null
+ERR_04262=entry must have a valid cn attribute
+ERR_04263=RuleId {0} not found in ruleId to schema name map!
+ERR_04264=DITStructureRule with RuleId {0} already registered!
+ERR_04265=DITStructureRule for ruleId {0} does not exist!
+ERR_04266=name cannot be null
+ERR_04267=Looks like the arg is not a numeric OID
+ERR_04268_OID_NOT_FOUND=OID ''{0}'' not found in oid to schema name map!
+ERR_04269={0} for OID {1} does not exist!
+ERR_04270={0} with OID {1} already registered!
+ERR_04271={0} with name {1} already registered!
+ERR_04272=OID {0} is not a numeric OID
+ERR_04273={0} with OID {1} not registered!
+ERR_04274=Can''t find an OID for the name {0}
+ERR_04275=Cannot modify the AttributeTypeRegistry copy
+ERR_04276=Cannot modify the ComparatorRegistry copy
+ERR_04277=Cannot modify the DITContentRuleRegistry copy
+ERR_04278=Cannot modify the DITStructureRuleRegistry copy
+ERR_04279=Cannot modify the LdapSyntaxRegistry copy
+ERR_04280=Cannot modify the MatchingRuleRegistry copy
+ERR_04281=Cannot modify the MatchingRuleUseRegistry copy
+ERR_04282=Cannot modify the NameFormRegistry copy
+ERR_04283=Cannot modify the NormalizerRegistry copy
+ERR_04284=Cannot modify the ObjectClassRegistry copy
+ERR_04285=Cannot modify the SyntaxCheckerRegistry copy
+ERR_04286=OID ''{0}'' was not found within the OID registry
+ERR_04287=There is no SchemaObject associated with OID ''{0}''
+ERR_04288=OID ''{0}'' was not found within the OID registry
+ERR_04289=Cannot register a Null SchemaObject !
+ERR_04290=The given SchemaObject does not have a valid OID
+ERR_04291=There is already a SchemaObject for OID ''{0}''
+ERR_04292=Cannot build the references for {0}, error : {1}
+ERR_04293=Cannot remove the references for {0}, error : {1}
+ERR_04294=The MatchingRule {0} does not have a syntax. This is invalid
+ERR_04295=The MatchingRule {0} does not have a normalizer. This is invalid
+ERR_04296=The MatchingRule {0} does not have a comparator. This is invalid
+ERR_04297=The AttributeType {0} can''t have itself as a superior, or a cycle has been detected while processing the superior''s tree
+ERR_04298=The AttributeType {0} does not have a superior nor a Syntax. This is invalid
+ERR_04299=The ObjectClass {0} has some AttribteType in MAY which is already declared in one of its superior MUST
+ERR_04300=The ObjectClass {0} can''t have itself as a superior, or a cycle has been detected while processing the superior''s tree, or this superior has already been added \: \n{1}
+ERR_04301=Registering of {0}:{1} failed, it''s already present in the Registries
+ERR_04302=Unregistering of {0}:{1} failed, it''s not present in the Registries
+ERR_04303=Cannot find the SUPERIOR object {0} while building cross-references for the {1} AttributeType.
+ERR_04304=A cycle has been detected in the superior hierarchyOid while building cross-references for the {0} AttributeType.
+ERR_04305=Cannot find the SUPERIOR object {0} while building cross-references for the {1} AttributeType.
+ERR_04306=Cannot find a Syntax object {0} while building cross-references for the {1} AttributeType.
+ERR_04307=The AttributeType {0} must have a syntax OID or a superior, it does not have any.
+ERR_04308=Cannot find an Equality MatchingRule object for {0} while building cross-references for the {1} AttributeType.
+ERR_04309=Cannot find an EQUALITY MatchingRule instance for {0} while building cross-references for the {1} AttributeType.
+ERR_04310=Cannot find a Ordering MatchingRule object for {0} while building cross-references for the {1} AttributeType.
+ERR_04311=Cannot find an ORDERING MatchingRule instance for {0} while building cross-references for the {1} AttributeType.
+ERR_04312=Cannot find a SUBSTR MatchingRule object for {0} while building cross-references for the {1} AttributeType.
+ERR_04313=Cannot find a SUBSTR MatchingRule instance for {0} while building cross-references for the {1} AttributeType.
+ERR_04314=The attributeType {0} must have the same USAGE than its superior
+ERR_04315=The attributeType {0} is a USER-APPLICATION attribute, it must be USER-MODIFIABLE
+ERR_04316=The attributeType {0} is a COLLECTIVE AttributeType, it must be a USER-APPLICATION attributeType too.
+ERR_04317=The created MatchingRule must refers to an existing SYNTAX element
+ERR_04318=Cannot register the SchemaObject {0}, an ABSTRACT ObjectClass cannot inherit from an {1} ObjectClass :/n {2}
+ERR_04319=Cannot register the SchemaObject {0}, an AUXILIARY ObjectClass cannot inherit from a STRUCTURAL ObjectClass :/n {1}
+ERR_04320=Cannot register the SchemaObject {0}, a STRUCTURAL ObjectClass cannot inherit from an AUXILIARY ObjectClass :/n {1}
+ERR_04321=Cannot register the SchemaObject {0}, the given SUPERIOR does not exist : {1}
+ERR_04322=Cannot register the SchemaObject {0}, there are some duplicate AT in the MAY : {1}
+ERR_04323=Cannot register the SchemaObject {0}, the AT we want to add to MAY does not exist : {1}
+ERR_04324=Cannot register the SchemaObject {0}, there are some duplicate AT in the MUST : {1}
+ERR_04325=Cannot register the SchemaObject {0}, there are some duplicate AT in MAY and MUST : {1}
+ERR_04326=Cannot register the SchemaObject {0}, the AT we want to add to MUST does not exist : {1}
+ERR_04327=Unknown objectClass type name ''{0}'': options are AUXILIARY, STRUCTURAL, ABSTRACT.
+ERR_04328=undefined modification type: {0}
+ERR_04329=Parser failure on subtree specification\:\n\t{0}\nAntlr exception trace\:\n{1}
+ERR_04330=A negative minimum base distance is undefined!
+ERR_04331=TriggerSpecification cannot be initialized with any NULL argument.
+ERR_04332=TriggerSpecification cannot be initialized with emtpy SPSPec list.
+ERR_04333=Parser failure on Trigger Specification\:\n\t{0}\nAntlr exception trace\:\n{1}
+ERR_04334=Overlapping partitions are not allowed
+ERR_04335=Invalid Character 0x{0}
+ERR_04336=Unregistered or previously used component: {0}
+ERR_04337=The Array must not be null
+ERR_04338=Index: {0}, Length: {1}
+ERR_04339=Cannot figure out attribute ID if both args are null
+ERR_04340=Cannot take difference of attributes with different IDs!
+ERR_04341=Cannot figure out attribute ID if both args are null
+ERR_04342=Cannot take union of attributes with different IDs!
+ERR_04343=An empty option is not allowed
+ERR_04344=Invalid OID, missing ''.''
+ERR_04345=Invalid OID, missing a number after a ''.''
+ERR_04346=Empty attributes
+ERR_04347=Bad char in attribute
+ERR_04348=Miscalculated data length (wrote {0} instead of {1})
+ERR_04349=The Integer did not match either specified value
+ERR_04350=The String did not match any specified value
+ERR_04351=The Array must not be null
+ERR_04352=Array is empty
+ERR_04353=The array must not contain any null elements
+ERR_04354=initialSize must be greater than zero
+ERR_04355=Unexpected IllegalAccessException
+ERR_04356=The PrintWriter must not be null
+ERR_04357=The List must not be null
+ERR_04358=Calendar must not be null.
+ERR_04359=generalizedTime is null
+ERR_04360=Generalized Time too short, doesn''t contain field ''minute'' or ''fraction of hour'' or ''timezone''.
+ERR_04361=Generalized Time too short, doesn''t contain field ''second'' or ''fraction of minute'' or ''timezone''.
+ERR_04362=Generalized Time too short, doesn''t contain field ''fraction of second'' or ''timezone''.
+ERR_04363=Invalid Time too short, expected field ''fraction of second'' or ''timezone''.
+ERR_04364=Invalid Time too short, expected field ''second'' or ''fraction of minute'' or ''timezone''.
+ERR_04365=Invalid Generalized Time, expected field ''minute'' or ''fraction of hour'' or ''timezone''.
+ERR_04366=Invalid date/time values.
+ERR_04367=Generalized Time too short, doesn''t contain field ''timezone''.
+ERR_04368=Invalid Generalized Time, expected ''timezone'' as the last field.
+ERR_04369=Invalid Generalized Time, expected field ''timezone'' must contain 2 or 4 digits.
+ERR_04370=Invalid Generalized Time, expected ''timezone'' as the last field.
+ERR_04371=Generalized Time too short, doesn''t contain number for ''fraction''.
+ERR_04372=Generalized Time too short, doesn''t contain field 'second'.
+ERR_04373=Invalid Generalized Time, field ''second'' is not numeric.
+ERR_04374=Generalized Time too short, doesn''t contain field ''minute''.
+ERR_04375=Invalid Generalized Time, field ''minute'' is not numeric.
+ERR_04376=Generalized Time too short, doesn''t contain field ''hour''.
+ERR_04377=Invalid Generalized Time, field ''hour'' is not numeric.
+ERR_04378=Generalized Time too short, doesn''t contain field ''day''.
+ERR_04379=Invalid Generalized Time, field ''day'' is not numeric.
+ERR_04380=Generalized Time too short, doesn''t contain field ''month''.
+ERR_04381=Invalid Generalized Time, field ''month'' is not numeric.
+ERR_04382=Generalized Time too short, doesn''t contain field ''century/year''.
+ERR_04383=Invalid Generalized Time, field ''century/year'' is not numeric.
+ERR_04384=HashCodeBuilder requires a non zero initial value
+ERR_04385=HashCodeBuilder requires an odd initial value
+ERR_04386=HashCodeBuilder requires a non zero multiplier
+ERR_04387=HashCodeBuilder requires an odd multiplier
+ERR_04388=The object to build a hash code for must not be null
+ERR_04389=Putting attributes not supported by immutable attributes
+ERR_04390=Removing attributes not supported by immutable attributes
+ERR_04391=Now why would you want to clone() an immutable object in the first place.
+ERR_04392=Value addition not supported for immutable attribute
+ERR_04393=Value removal not supported for immutable attribute
+ERR_04394=Clearing all values not supported for immutable attribute
+ERR_04395=Now why would you ever want to clone an immutable object?
+ERR_04396=Value alteration is not supported for immutable attribute
+ERR_04397=Iterator[] arg must not be null, empty or composed of less than two Iterators
+ERR_04398=A LdapUrl must start with "ldap\://" or "ldaps\://"
+ERR_04399=The hostport is invalid
+ERR_04400=Bad character, position {0}, ''{1}'', ''/'' expected
+ERR_04401=The DN is invalid
+ERR_04402=Bad character, position {0}, ''{1}'', ''?'' expected
+ERR_04403=Attributes are invalid
+ERR_04404=Scope is invalid
+ERR_04405=Filter is invalid
+ERR_04406=Extensions are invalid
+ERR_04407=Invalid character at the end of the ldapUrl
+ERR_04408=The string is empty : this is not a valid LdapURL.
+ERR_04409=Bad Ldap URL : {0}
+ERR_04410=The byte array is empty : this is not a valid LdapURL.
+ERR_04411=Parameter may not be null
+ERR_04412=charset may not be null or empty
+ERR_04413=HttpClient requires ASCII support
+ERR_04414=Invalid URL encoding
+ERR_04415=Common element, "{0}" detected for Mandatory and Optional components.
+ERR_04416=Unregistered or previously used component: {0}
+ERR_04417={0} is not ancestually related to context: {1}
+ERR_04418=invalid name - a name cannot start with a ''+'': {0}
+ERR_04419=The Nestable implementation passed to the NestableDelegate(Nestable) constructor must extend java.lang.Throwable"
+ERR_04420=The start index was out of bounds: {0}
+ERR_04421=The start index was out of bounds: {0} >= {1}
+ERR_04422=Adding duplicate keys is not permitted.
+ERR_04423=can''t get keys from prefs
+ERR_04424=Unexpected IllegalAccessException: {0}
+ERR_04425=bad iterator type: {0}
+ERR_04426=remove() must follow next()
+ERR_04427={0} < 0
+ERR_04428={0} >= {1}
+ERR_04429=Regex was null
+ERR_04430=Ldap regex must have wild cards!
+ERR_04431=Expected string to start with a ''#'' character. Invalid hex encoded string for empty or null string.
+ERR_04432=Expected string to start with a ''\#'' character. Invalid hex encoded string\: {0} 
+ERR_04433=Expected string to be non-null with valid index.
+ERR_04434=Expected string to be non-empty with valid index.
+ERR_04435=The DN must contain valid escaped characters.
+ERR_04436=The DN must not ends with a ''\\''.
+ERR_04437=Caught a SecurityException reading the system property ''{0}''; the SystemUtils property value will default to null.
+ERR_04438=The style must not be null
+ERR_04439=Usage - java org.mortbay.util.UnixCrypt <key> <salt>
+ERR_04440=Crypt={0}
+ERR_04441=Cannot modify the SchemaObject {0}, it has been locked
+ERR_04442_NOT_EXISTING_ATRIBUTE_TYPE=The AttributeType {0} does not exist
+ERR_04443=Failed to compare normalized values for {0} and {1}
+ERR_04444=I don''t really know how to compare anything other than ServerBinaryValues at this point in time.
+ERR_04445=There is no Syntax associated with this attributeType
+ERR_04446=Cannot use standard serialization for a ServerStringValue
+ERR_04447_CANNOT_NORMALIZE_VALUE=Cannot normalize the wrapped value {0}
+ERR_04448=I don''t know what to do if value is not a ServerStringValue
+ERR_04449=The value ''{0}'' can't be normalized, it hasn''t been added
+ERR_04450=The value ''{0}'' is incorrect, it hasn''t been added
+ERR_04451=The value must be a String, as its AttributeType is H/R
+ERR_04452=The value must be a byte[], as its AttributeType is not H/R
+ERR_04453=The upID ({0}) is not an OID or is different from the AttributeType OID ({1})
+ERR_04454=Cannot use standard serialization for a ServerAttribute
+ERR_04455=The ID ''{0}''is incompatible with the AttributeType''s id ''{1}''
+ERR_04456=An ID cannnot be null, empty, or resolved to an emtpy value when trimmed
+ERR_04457_NULL_ATTRIBUTE_ID=The ID should not be null or empty
+ERR_04458=Cannot add an attribute without an ID
+ERR_04459=We have had an error while adding the ''{0}'' AttributeType : {1}
+ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED=The attributeType should not be null
+ERR_04461=Only String values supported for objectClass attribute
+ERR_04462=The EntryAttribute list should not contain null elements
+ERR_04463=The ''{0}'' id is not compatible with the ''{1}'' attribute type
+ERR_04464=Error while adding values into the ''{0}'' attribute. Error \: {1} 
+ERR_04465=The removal of values for the missing ''{0}'' attribute is not possible
+ERR_04466=The removal of values for the bad ''{0}'' attribute is not possible
+ERR_04467=The AttributeType list should not contain null values
+ERR_04468=Cannot use standard serialization for a ServerAttribute
+ERR_04469=Cannot use standard serialization for a ServerEntry
+ERR_04470=Cannot read the attribute as it''s OID (''{0}'') does not exist
+ERR_04471=Cannot serialize a Modification with no attribute
+ERR_04472=The attribute ''{0}'' is incorrect
+ERR_04473_NOT_VALID_VALUE=Not a valid value ''{0}'' for the AttributeType ''{1}''
+ERR_04474=Expected string to normalize
+ERR_04475=Expected byte[] to normalize
+ERR_04476=Cannot set an AttributeType {0} when another one ({1}) is already present
+ERR_04477_NO_VALID_AT_FOR_THIS_ID=Cannot find a valid AttributeType for the ''{0}'' id
+ERR_04478_NO_VALUE_NOT_ALLOWED=Cannot create or add an Attribute with no value in it
+ERR_04479_INVALID_SYNTAX_VALUE= The value ''{0}'' does not respect the AttributeType ''{1}'' syntax
+ERR_04480_END_OF_STREAM=End of stream
+ERR_04481_ENTRY_NULL_VALUE=Entry can''t be null
+ERR_04482_CANNOT_SUBTYPE_COLLECTIVE=The Collective Attribute ({0}) cannot be subtyped ({1})
+ERR_04483_COLLECTIVE_NOT_MULTI_VALUED=The Collective Attribute ({0}) cannot be single valued
+ERR_04484_COLLECTIVE_NOT_ALLOWED_IN_MUST=The Collective Attribute ({0}) cannot be added in the MUST list of the {1} ObjectClass
+ERR_04485_COLLECTIVE_NOT_ALLOWED_IN_MAY=The Collective Attribute ({0}) cannot be added in the MAY list of the {1} ObjectClass
+ERR_04486_VALUE_ALREADY_EXISTS=The value ''{0}'' already exists in the attribute ({1})
+ERR_04487_ATTRIBUTE_IS_SINGLE_VALUED=The attribute ''{0}'' is single valued, we can't add no more values into it
+
+# ldap-constants
+ERR_05001_UNKNOWN_AUTHENT_LEVEL=Unknown AuthenticationLevel {0}
+
+# ldap-converter
+ERR_06001_EMPTY_OR_NULL_SCHEMA_OBJECT=The schemaObject is either null or is empty!
+ERR_06002_PARSER_FAILURE=Parser failure on\:\n\t{0}\nAntlr exception trace\:\n{1}
+ERR_06003_NO_NAME={0} the schema configuration element must specify a name.
+ERR_06004_CANNOT_GENERATE_SOURCES=Failed while generating sources for {0} : {1}
+ERR_06005_NULL_SCHEMA=Can''t generate a ldif for a null schema
+ERR_06006_NO_PROPERTY=the schema property must be set
+
+# ldap-jndi
+# no exception to translate
+ERR_08001=Cannot overwrite yet schema output directory already exists: {0}
+ERR_08002=Cannot copy non-existant source file {0}
+ERR_08003=Cannot have more than one entry in a schema ldif file : {0}
+ERR_08004=Exception occurred while parsing the ldif file {0} : {1}
+ERR_08005=Should not be hitting root without schema/schema pattern.
+ERR_08006=parent cannot be null
+
+# ldap-schema
+ERR_09001_DIRECTORY_CREATION_FAILED=The directory {0} could not be created
+
+# ldap-schema-loader
+ERR_10001=The attribute must be binary
+ERR_10002=Failed to access attribute bytes.
+ERR_10003=Failed to load schema LDIF file {0}
+ERR_10004=Expecting to find a schema.ldif file in provided baseDirectory path ''{0}'' but no such file found.
+ERR_10005={0} entry must have a valid {1} attribute, it''s null
+ERR_10006=Comparator OID {0} is not a valid OID 
+ERR_10007={0} entry cannot be null
+ERR_10008={0} Schema description cannot be null
+ERR_10009=The schema {0} does not exists or is not loaded
+ERR_10010=entry cannot be null
+ERR_10011=entry must have a valid cn attribute
+ERR_10012=entry must have a valid {0} attribute
+ERR_10013=Cannot add the SyntaxChecker {0}, as the associated schema ({1}) is not loaded
+ERR_10014=Cannot add the SyntaxChecker {0} into the registries, as the associated schema ({1}) is disabled
+ERR_10015=The Comparator''s OID ({0}) is different from the loaded class'' OID ({1})
+ERR_10016=Cannot add the Comparator {0}, as the associated schema ({1}) is not loaded
+ERR_10017=Cannot add the Comparator {0} into the registries, as the associated schema ({1}) is disabled
+ERR_10018=Cannot add the Normalizer {0}, as the associated schema ({1}) is not loaded
+ERR_10019=Cannot add the Normalizer {0} into the registries, as the associated schema ({1}) is disabled
+ERR_10020=Cannot add the Syntax {0}, as the associated schema ({1}) is not loaded
+ERR_10021=Cannot add the SyntaxChecker {0} into the registries, as the associated schema ({1}) is disabled
+ERR_10022=Cannot add the MatchingRule {0}, as the associated schema ({1}) is not loaded
+ERR_10023=Cannot add the MatchingRule {0} into the registries, as the associated schema ({1}) is disabled
+ERR_10024=Cannot add the ObjectClass {0}, as the associated schema ({1}) is not loaded
+ERR_10025=Cannot add the ObjectClass {0} into the registries, as the associated schema ({1}) is disabled
+ERR_10026=Cannot add the AttributeType {0}, as the associated schema ({1}) is not loaded
+ERR_10027=Cannot add the AttributeType {0} into the registries, as the associated schema ({1}) is disabled
+ERR_10028={0} entry must have a valid {1} attribute
+
+# ldap-schema-manager
+ERR_11001=Cannot load the unknown schema {0}
+ERR_11002=Cannot load the Schema {0} as one of its dependencies has not been loaded
+ERR_11003=Need to implement factory method for creating a DitContentRule
+ERR_11004=Need to implement factory method for creating a DitStructureRule
+ERR_11005=Need to implement factory method for creating a MatchingRuleUse
+ERR_11006=Need to implement factory method for creating a NameForm
+ERR_11007=the SchemaObject {0} cannot be added, it''s not a valid LoadableSchemaObject.
+ERR_11008=Oid {0} for new schema entity is not unique.
+ERR_11009=Cannot add the SchemaObject {0} into a non existing schema {1} 
+ERR_11010=Cannot inject the SchemaObject {0} as it''s not associated with a schema
+ERR_11011=Oid {0} for new schema entity does not exist.
+ERR_11012=Cannot remove {0} for the registries, it would become inconsistent. The following SchemaObjects are referencing this SchemaObject : {1}
+ERR_11013=Cannot delete the SchemaObject {0} as it''s not associated with a schema
+
+# ldif
+ERR_12001_UNKNOWN_CHANGE_TYPE=Unknown change type value {0}
+ERR_12002_ENTRY_WITH_TWO_DNS=An entry must not have two DNs, at line {0}
+ERR_12003_LDIF_ENTRY_WITH_TWO_DNS=A ldif entry should not have two DNs
+ERR_12004_CHANGE_NOT_ALLOWED=We cannot have changes when reading a file which already contains entries, at line {0}
+ERR_12005_NO_CHANGE=No changes within entries
+ERR_12006_EXPECTING_ATTRIBUTE_TYPE=Expecting an attribute type
+ERR_12007_BAD_ATTRIBUTE=Bad attribute
+ERR_12008_CANNOT_PARSE_LDIF_BUFFER=Cannot parse the ldif buffer : {0}
+ERR_12009_ERROR_PARSING_LDIF_BUFFER=Error while parsing the ldif buffer
+ERR_12010_CANNOT_FIND_FILE=Cannot find file {0}
+ERR_12011_CANNOT_READ_FILE=Cannot read file {0}
+ERR_12012_EMPTY_DN_NOT_ALLOWED=A ldif entry must have a non empty DN, at line {0}
+ERR_12013_NO_DN=No DN for entry
+ERR_12014_BASE64_DN_EXPECTED=The ldif entry is supposed to have a base 64 encoded DN, at line {0}
+ERR_12015_INVALID_BASE64_DN=Invalid base 64 encoded DN
+ERR_12016_DN_EXPECTED=A ldif entry must start with a DN, at line {0}
+ERR_12017_INVALID_DN=The DN {0} is not valid, at line {1}
+ERR_12018_FILE_NOT_FOUND=File {0} not found, at line {1}
+ERR_12019_BAD_URL_FILE_NOT_FOUND=Bad URL, file not found
+ERR_12020_FILE_TOO_BIG=File {0} is too big, at line {1}
+ERR_12022_ERROR_READING_FILE=File {0} error reading, at line {1}
+ERR_12023_ERROR_READING_BAD_URL=Bad URL, file can''t be read
+ERR_12024_CANNOT_CLOSE_FILE=Error while closing the stream : {0}, at line {1}
+ERR_12025_BAD_PROTOCOL=Protocols other than file: are not supported
+ERR_12026_UNSUPPORTED_PROTOCOL=Unsupported URL protocol, at line {0}
+ERR_12027_BAD_URL=Bad URL {0}, at line {1}
+ERR_12029_CONTROL_WITHOUT_OID=The control does not have an OID, at line {0}
+ERR_12031_INVALID_OID=The OID {0} is not valid, at line {1}
+ERR_12033_INVALID_CRITICALITY=The control must have a valid criticality, at line {0}
+ERR_12035_BAD_MODRDN_OPERATION=A modrdn operation must start with a "newrdn\:", at line {0}
+ERR_12038_NO_DELETEOLDRDN=A modrdn operation must contains a "deleteoldrdn\:", at line {0}
+ERR_12040_BAD_MODIFY_SEPARATOR=Bad state : we should have come from an ATTRVAL_SPEC, at line {0}
+ERR_12042_BAD_MODIFY_SEPARATOR_2=Bad state : we should have come from a MOD_SPEC or an ATTRVAL_SPEC, at line {0}
+ERR_12044=The modified attribute and the attribute value spec must be equal, at line {0}
+ERR_12045=Bad modify attribute
+ERR_12046=A moddn operation must contains a "newsuperior\:", at line {0}
+ERR_12047=Bad moddn operation, no newsuperior
+ERR_12048=Unknown operation, at line {0}
+ERR_12049=Bad operation
+ERR_12050=We already have had a control, at line {0}
+ERR_12051=Control misplaced
+ERR_12052=We already have had a changeType, at line {0}
+ERR_12053=ChangeType misplaced
+ERR_12054=We can''t have a Attribute/Value pair after a control or a changeType, at line {0}
+ERR_12055=AttributeType misplaced
+ERR_12056=Expecting an attribute type, at line {0}
+ERR_12057_BAD_ATTRIBUTE=Bad attribute
+ERR_12058_UNKNOWN_ENTRY_TYPE=Unknown entry type, at line {0}
+ERR_12059_UNKNOWN_ENTRY=Unknown entry
+ERR_12060_VERSION_NOT_A_NUMBER=The version is not a number, at line {0}
+ERR_12061_LDIF_PARSING_ERROR=Ldif parsing error
+ERR_12062_EMPTY_CONTINUATION_LINE=Cannot have an empty continuation line, at line {0}
+ERR_12063_ERROR_WHILE_READING_LDIF_LINE=Error while reading ldif lines
+ERR_12064_EMPTY_FILE_NAME=Cannot parse an empty file name !
+ERR_12066=Cannot parse the file {0}, it does not exist
+ERR_12067=Filename {0} not found.
+ERR_12068=Cannot find file {0}
+ERR_12069=Cannot parse the ldif buffer : {0}
+ERR_12070=Error while parsing the ldif buffer
+ERR_12071=Premature termination of LDIF iterator
+ERR_12072=Error while parsing ldif : {0}
+ERR_12073=Could not deduce reverse modifications from provided modifications: {0}
+ERR_12074=newSuperiorDn must not be null
+ERR_12075=modifiedDn must not be null
+ERR_12076=Don''t think about moving the rootDSE.
+ERR_12077=The newRdn must not be null
+ERR_12078=The modified Dn must not be null
+ERR_12079=Don''t think about renaming the rootDSE.
+ERR_12080=Can''t rename an entry using the same name ...
+ERR_12081=Invalid Entry : a deleted entry should not contain attributes
+ERR_12082=Invalid Entry : a added or modified entry should contain attributes
+ERR_12083=Invalid Entry : a modifyDN operation entry should not contain attributes
+ERR_12084=The length of each line must be at least 2 chars long
+ERR_12085=The Attribute ID #{0} must be a String
+ERR_12086=The Attribute value #{0} must be a String or a byte[]
+ERR_12087=A value is missing at the end
diff --git a/trunk/i18n/src/main/resources/org/apache/directory/api/i18n/messages.properties b/trunk/i18n/src/main/resources/org/apache/directory/api/i18n/messages.properties
new file mode 100644
index 0000000..f10f002
--- /dev/null
+++ b/trunk/i18n/src/main/resources/org/apache/directory/api/i18n/messages.properties
@@ -0,0 +1,19 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#  
+#    http://www.apache.org/licenses/LICENSE-2.0
+#  
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License. 
+#  
+#
diff --git a/trunk/i18n/src/site/site.xml b/trunk/i18n/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/i18n/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/integ-osgi/pom.xml b/trunk/integ-osgi/pom.xml
new file mode 100644
index 0000000..e15ed0d
--- /dev/null
+++ b/trunk/integ-osgi/pom.xml
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.directory.api</groupId>
+        <artifactId>api-parent</artifactId>
+        <version>1.0.0-M32</version>
+    </parent>
+
+    <artifactId>api-integ-osgi</artifactId>
+    <name>Apache Directory API OSGi Integration Tests</name>
+
+    <dependencies>
+        <!-- Bundles under test -->
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-client-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-net-mina</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-schema-converter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-extras-aci</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-extras-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-extras-sp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-ldap-extras-trigger</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-dsml-engine</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>xml-apis</groupId>
+                    <artifactId>xml-apis</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- Test and PAX dependencies -->
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.javax-inject</artifactId>
+            <version>1_2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-forked</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-junit4</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-link-mvn</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-aether</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <scope>test</scope>
+        </dependency>
+<!--         <dependency> -->
+<!--             <groupId>org.eclipse</groupId> -->
+<!--             <artifactId>osgi</artifactId> -->
+<!--             <version>3.9.1-v20140110-1610</version> -->
+<!--             <scope>test</scope> -->
+<!--         </dependency> -->
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <phase>generate-resources</phase>
+                        <configuration>
+                            <includeScope>runtime</includeScope>
+                            <outputFile>${project.build.directory}/test-classes/deps.txt</outputFile>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>
+                                            org.apache.maven.plugins
+                                        </groupId>
+                                        <artifactId>
+                                            maven-dependency-plugin
+                                        </artifactId>
+                                        <versionRange>
+                                            [2.8,)
+                                        </versionRange>
+                                        <goals>
+                                            <goal>copy-dependencies</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore />
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+</project>
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiAsn1ApiOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiAsn1ApiOsgiTest.java
new file mode 100644
index 0000000..cebc2fb
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiAsn1ApiOsgiTest.java
@@ -0,0 +1,46 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.util.BitString;
+import org.apache.directory.api.asn1.util.Oid;
+
+
+public class ApiAsn1ApiOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.asn1.api";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new EncoderException( "foo" );
+        Oid.fromString( "1.2.3" );
+        new BitString( 8 );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiAsn1BerOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiAsn1BerOsgiTest.java
new file mode 100644
index 0000000..a9432c9
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiAsn1BerOsgiTest.java
@@ -0,0 +1,49 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.asn1.actions.CheckNotNullLength;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+
+
+public class ApiAsn1BerOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.asn1.ber";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new CheckNotNullLength<Asn1Container>();
+        new Asn1Decoder().getMaxLengthLength();
+        new BerValue().init( 5 );
+        new TLV( 1 ).getValue();
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiDsmlEngineOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiDsmlEngineOsgiTest.java
new file mode 100644
index 0000000..6c29dc1
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiDsmlEngineOsgiTest.java
@@ -0,0 +1,42 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.dsmlv2.engine.Dsmlv2Engine;
+
+
+public class ApiDsmlEngineOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.dsmlv2.engine";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new Dsmlv2Engine( "host", 9999, "user", "password" );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiDsmlParserOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiDsmlParserOsgiTest.java
new file mode 100644
index 0000000..4011d08
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiDsmlParserOsgiTest.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.dsmlv2.ParserUtils;
+import org.apache.directory.api.dsmlv2.request.AddRequestDsml;
+import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
+import org.apache.directory.api.dsmlv2.request.SearchRequestDsml;
+import org.apache.directory.api.dsmlv2.response.LdapResultDsml;
+import org.apache.directory.api.dsmlv2.response.SearchResponse;
+import org.apache.directory.api.dsmlv2.response.SearchResultDoneDsml;
+import org.apache.directory.api.dsmlv2.response.SearchResultEntryDsml;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.AddRequestImpl;
+import org.apache.directory.api.ldap.model.message.LdapResultImpl;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.dom4j.tree.BaseElement;
+
+
+public class ApiDsmlParserOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.dsmlv2.parser";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new Dsmlv2Grammar();
+
+        new AddRequestDsml( null );
+        new SearchRequestDsml( null );
+
+        ParserUtils.base64Encode( "abc" );
+        new Dn( "cn=foo" );
+        new LdapUrl( "ldap://example.com/" );
+        ResultCodeEnum.TOO_LATE.getMessage();
+        ParserUtils.needsBase64Encoding( null );
+        ParserUtils.parseAndVerifyRequestID( "5", null );
+        new BaseElement( "foo" );
+        context.getService( context.getServiceReference( LdapApiService.class.getName() ) );
+        new AddRequestImpl();
+        new ReferralImpl();
+        new LdapResultImpl();
+
+        new SearchResponse();
+        new LdapResultDsml( null, null, null );
+        new SearchResultEntryDsml( null );
+        new SearchResultDoneDsml( null );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiI18nOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiI18nOsgiTest.java
new file mode 100644
index 0000000..6aee474
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiI18nOsgiTest.java
@@ -0,0 +1,47 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+public class ApiI18nOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.i18n";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        I18n errorCode = I18n.ERR_00001_BAD_TRANSITION_FROM_STATE;
+        assertNotNull( errorCode );
+        assertNotNull( errorCode.getErrorCode() );
+        assertNotNull( I18n.err( errorCode ) );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapClientApiOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapClientApiOsgiTest.java
new file mode 100644
index 0000000..b722ee8
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapClientApiOsgiTest.java
@@ -0,0 +1,67 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.commons.pool.PoolableObjectFactory;
+import org.apache.commons.pool.impl.GenericObjectPool.Config;
+import org.apache.directory.ldap.client.api.DefaultPoolableLdapConnectionFactory;
+import org.apache.directory.ldap.client.api.Krb5LoginConfiguration;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapConnectionConfig;
+import org.apache.directory.ldap.client.api.LdapConnectionPool;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+import org.apache.directory.ldap.client.api.SaslGssApiRequest;
+import org.apache.directory.ldap.client.api.future.AddFuture;
+import org.apache.directory.ldap.client.api.search.FilterBuilder;
+import org.apache.directory.ldap.client.template.LdapConnectionTemplate;
+
+
+public class ApiLdapClientApiOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.client.api";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new LdapNetworkConnection().close();
+        new SaslGssApiRequest();
+        new Krb5LoginConfiguration();
+        new AddFuture( new LdapNetworkConnection(), 2 );
+        new LdapConnectionTemplate( new LdapConnectionPool( new DefaultPoolableLdapConnectionFactory(
+            new LdapConnectionConfig() ) ) );
+        FilterBuilder.and( FilterBuilder.not( FilterBuilder.contains( "cn", "a", "b" ) ) ).toString();
+
+        // Test for DIRAPI-239
+        PoolableObjectFactory<LdapConnection> factory = new DefaultPoolableLdapConnectionFactory(
+            new LdapConnectionConfig() );
+        Config config = new Config();
+        LdapConnectionPool ldapConnectionPool = new LdapConnectionPool( factory, config );
+        ldapConnectionPool.getLdapApiService();
+        ldapConnectionPool.getTestOnBorrow();
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapCodecCoreOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapCodecCoreOsgiTest.java
new file mode 100644
index 0000000..931fbaa
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapCodecCoreOsgiTest.java
@@ -0,0 +1,107 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.inject.Inject;
+
+import org.apache.directory.api.ldap.codec.LdapStatesEnum;
+import org.apache.directory.api.ldap.codec.actions.addRequest.InitAddRequest;
+import org.apache.directory.api.ldap.codec.actions.addResponse.InitAddResponse;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.InitBindRequest;
+import org.apache.directory.api.ldap.codec.actions.bindResponse.InitBindResponse;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.InitSearchRequest;
+import org.apache.directory.api.ldap.codec.actions.searchResultDone.InitSearchResultDone;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AndFilter;
+import org.apache.directory.api.ldap.codec.search.SubstringFilter;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+
+public class ApiLdapCodecCoreOsgiTest extends ApiOsgiTestBase
+{
+
+    @Inject
+    LdapApiService ldapApiService;
+
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.codec.core";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        LdapStatesEnum.END_STATE.isEndState();
+
+        new InitBindRequest();
+        new InitBindResponse();
+        new InitAddRequest();
+        new InitAddResponse();
+        new InitSearchRequest();
+        new InitSearchResultDone();
+
+        new AndFilter();
+        new SubstringFilter();
+
+        SearchRequest decoratedMessage = new SearchRequestImpl();
+        new SearchRequestDecorator( ldapApiService, decoratedMessage );
+    }
+
+
+    @Test
+    public void testInjectLdapApiService()
+    {
+        assertNotNull( ldapApiService );
+    }
+
+
+    @Test
+    public void testLookupLdapApiService()
+    {
+        ServiceReference<LdapApiService> serviceReference = context.getServiceReference( LdapApiService.class );
+        Object service = context.getService( serviceReference );
+        assertNotNull( service );
+        assertTrue( service instanceof LdapApiService );
+    }
+
+
+    @Test
+    public void testLdapApiServiceFactoryIsInitializedByOsgi()
+    {
+        assertTrue( LdapApiServiceFactory.isInitialized() );
+        assertFalse( LdapApiServiceFactory.isUsingStandaloneImplementation() );
+        assertNotNull( LdapApiServiceFactory.getSingleton() );
+        assertNotNull( LdapApiServiceFactory.getSingleton().getProtocolCodecFactory() );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasAciOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasAciOsgiTest.java
new file mode 100644
index 0000000..804182a
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasAciOsgiTest.java
@@ -0,0 +1,61 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.ldap.aci.ACIItemChecker;
+import org.apache.directory.api.ldap.aci.ACIItemParser;
+import org.apache.directory.api.ldap.aci.GrantAndDenial;
+import org.apache.directory.api.ldap.aci.MicroOperation;
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+import org.apache.directory.api.ldap.aci.UserClass;
+
+
+public class ApiLdapExtrasAciOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.extras.aci";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        GrantAndDenial.GRANT_BROWSE.toString();
+        MicroOperation.BROWSE.getName();
+        UserClass.THIS_ENTRY.toString();
+        ProtectedItem.ENTRY.toString();
+
+        new ACIItemChecker( null ).parse( "" );
+        new ACIItemParser( null ).parse( "" );
+
+        String spec = "{ identificationTag \"test\", precedence 14, authenticationLevel simple, "
+            + "itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { "
+            + "precedence 1, protectedItems { attributeType { userPassword } }, grantsAndDenials "
+            + "{ denyRead, denyReturnDN, denyBrowse } }, { precedence 2, protectedItems "
+            + "{ entry, allUserAttributeTypesAndValues }, grantsAndDenials "
+            + "{ grantReturnDN, grantRead, grantBrowse } } } } }";
+        new ACIItemParser( null ).parse( spec );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasCodecApiOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasCodecApiOsgiTest.java
new file mode 100644
index 0000000..fcb1fd4
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasCodecApiOsgiTest.java
@@ -0,0 +1,63 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.ldap.extras.controls.SynchronizationModeEnum;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSyncImpl;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyImpl;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValueImpl;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValueImpl;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponseImpl;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponseImpl;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponseImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+public class ApiLdapExtrasCodecApiOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.extras.codec.api";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        SynchronizationModeEnum.REFRESH_AND_PERSIST.getValue();
+        new AdDirSyncImpl().getOid();
+        new PasswordPolicyImpl().getOid();
+        new SyncStateValueImpl( true ).getCookie();
+        new SyncInfoValueImpl().getType();
+        new PasswordModifyRequestImpl().getUserIdentity();
+        new PasswordModifyResponseImpl( 5 ).setResponseName( "foo" );
+        new WhoAmIRequestImpl();
+        new WhoAmIResponseImpl().setDn( new Dn( "uid=admin,ou=system" ) );
+        new StartTlsRequestImpl();
+        new StartTlsResponseImpl();
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasCodecOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasCodecOsgiTest.java
new file mode 100644
index 0000000..58ec71f
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasCodecOsgiTest.java
@@ -0,0 +1,64 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.inject.Inject;
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.startTls.StartTlsRequestDecorator;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+public class ApiLdapExtrasCodecOsgiTest extends ApiOsgiTestBase
+{
+
+    @Inject
+    LdapApiService ldapApiService;
+
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.extras.codec";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        CodecControl<? extends Control> control = ldapApiService.newControl( PasswordPolicy.OID );
+        assertNotNull( control );
+        assertTrue( control instanceof PasswordPolicyDecorator );
+
+        ExtendedRequest extendedRequest = ldapApiService.newExtendedRequest( StartTlsRequest.EXTENSION_OID, null );
+        assertNotNull( extendedRequest );
+        assertTrue( extendedRequest instanceof StartTlsRequestDecorator );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasSpOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasSpOsgiTest.java
new file mode 100644
index 0000000..1fc2b85
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasSpOsgiTest.java
@@ -0,0 +1,42 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.ldap.sp.LdapContextParameter;
+
+
+public class ApiLdapExtrasSpOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.extras.sp";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new LdapContextParameter( "foo" );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasTriggerOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasTriggerOsgiTest.java
new file mode 100644
index 0000000..c923ae2
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasTriggerOsgiTest.java
@@ -0,0 +1,43 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.ldap.trigger.TriggerSpecificationParser;
+
+
+public class ApiLdapExtrasTriggerOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.extras.trigger";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        String spec = "AFTER Delete CALL \"BackupUtilities.backupDeletedEntry\" ($name, $deletedEntry);";
+        new TriggerSpecificationParser().parse( spec );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasUtilOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasUtilOsgiTest.java
new file mode 100644
index 0000000..03faf8c
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapExtrasUtilOsgiTest.java
@@ -0,0 +1,51 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import static org.junit.Assert.assertEquals;
+
+import javax.naming.Name;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.util.JndiUtils;
+import org.apache.directory.api.ldap.util.tree.DnNode;
+
+
+public class ApiLdapExtrasUtilOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.extras.util";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        Dn dn = new Dn( "cn=foo" );
+        Name name = JndiUtils.toName( dn );
+        assertEquals( name.toString(), dn.toString() );
+        new DnNode<Object>().add( dn ).getParent();
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapModelOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapModelOsgiTest.java
new file mode 100644
index 0000000..7c26919
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapModelOsgiTest.java
@@ -0,0 +1,72 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.ldap.model.entry.AttributeUtils;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.parsers.ObjectClassDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+
+
+public class ApiLdapModelOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.model";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new Dn( "dc=example,dc=com" ); // uses FastDnParser
+        new Dn( "cn=a+sn=b,dc=example,dc=com" ); // uses ComplexDnparser (antlr based)
+        new StringValue( "foo" );
+        new DefaultAttribute( "cn" );
+        new DefaultEntry();
+
+        AttributeUtils.toJndiAttribute( new DefaultAttribute( "cn" ) );
+        
+        new BindRequestImpl();
+
+        new EqualityNode<String>( "cn", new StringValue( "foo" ) );
+
+        new LdapUrl( "ldap://ldap.example.com:10389/dc=example,dc=com?objectclass" );
+
+        new ObjectClassDescriptionSchemaParser()
+            .parse( "( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )" );
+        
+        SchemaObject schemaObject = new LdapSyntax( "1.2.3" );
+        new Registries().getGlobalOidRegistry().register( schemaObject );
+        new Registries().getLoadedSchemas();
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapNetMinaOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapNetMinaOsgiTest.java
new file mode 100644
index 0000000..fb5b181
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapNetMinaOsgiTest.java
@@ -0,0 +1,73 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.inject.Inject;
+
+import org.apache.directory.api.ldap.codec.protocol.mina.LdapProtocolCodecFactory;
+import org.apache.directory.api.ldap.codec.protocol.mina.LdapProtocolDecoder;
+import org.apache.directory.api.ldap.codec.protocol.mina.LdapProtocolEncoder;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+
+public class ApiLdapNetMinaOsgiTest extends ApiOsgiTestBase
+{
+
+    @Inject
+    LdapProtocolCodecFactory ldapProtocolCodecFactory;
+
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.net.mina";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new LdapProtocolDecoder();
+        new LdapProtocolEncoder();
+    }
+
+
+    @Test
+    public void testInjectLdapProtocolCodecFactory()
+    {
+        assertNotNull( ldapProtocolCodecFactory );
+    }
+
+
+    @Test
+    public void testLookupLdapProtocolCodecFactory()
+    {
+        ServiceReference<LdapProtocolCodecFactory> serviceReference = context.getServiceReference( LdapProtocolCodecFactory.class );
+        Object service = context.getService( serviceReference );
+        assertNotNull( service );
+        assertTrue( service instanceof LdapProtocolCodecFactory );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapSchemaConverterOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapSchemaConverterOsgiTest.java
new file mode 100644
index 0000000..32450ae
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapSchemaConverterOsgiTest.java
@@ -0,0 +1,60 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.schema.converter.Schema;
+import org.apache.directory.api.ldap.schema.converter.SchemaToLdif;
+
+
+public class ApiLdapSchemaConverterOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.schema.converter";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        List<Schema> schemas = new ArrayList<Schema>();
+
+        Schema schema = new Schema();
+        schema.setName( "foo" );
+        schema.setInput( new ByteArrayInputStream(
+            "attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14 NAME ( 'at' 'attribute' ) )".getBytes() ) );
+
+        Writer out = new StringWriter( 2048 );
+        schema.setOutput( out );
+        schemas.add( schema );
+
+        SchemaToLdif.transform( schemas );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapSchemaDataOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapSchemaDataOsgiTest.java
new file mode 100644
index 0000000..e9466fa
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiLdapSchemaDataOsgiTest.java
@@ -0,0 +1,50 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+
+
+public class ApiLdapSchemaDataOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.ldap.schema";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+        loader.getAllEnabled();
+        loader.getAllSchemas();
+
+        SchemaManager schemaManager = new DefaultSchemaManager();
+        schemaManager.getEnabled();
+        schemaManager.getDisabled();
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiOsgiTestBase.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiOsgiTestBase.java
new file mode 100644
index 0000000..30df072
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiOsgiTestBase.java
@@ -0,0 +1,156 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.url;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.exam.util.PathUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public abstract class ApiOsgiTestBase
+{
+
+    @Inject
+    protected BundleContext context;
+
+    private static Set<String> skips = new HashSet<String>();
+//    static
+//    {
+//        skips.add( "antlr-2.7.7.jar" );
+//        skips.add( "xpp3-1.1.4c.jar" );
+//        skips.add( "dom4j-1.6.1.jar" );
+//    }
+
+
+    @Configuration
+    public Option[] config() throws IOException
+    {
+        List<Option> dependencies = new ArrayList<Option>();
+
+        URL resource = getClass().getResource( "/" );
+        File targetTestClassesDir = new File( resource.getFile() );
+        File targetDependenciesDir = new File( targetTestClassesDir.getParent(), "dependency" );
+        File[] files = targetDependenciesDir.listFiles();
+        for ( File file : files )
+        {
+            if ( !skips.contains( file.getName() ) )
+            {
+                dependencies.add( url( file.toURI().toString() ) );
+            }
+        }
+
+        // shuffle dependencies, there mustn't be any dependency on order
+        Collections.shuffle( dependencies );
+
+        return options(
+            systemProperty( "org.ops4j.pax.logging.DefaultServiceLog.level" ).value( "WARN" ),
+            systemProperty( "logback.configurationFile" ).value(
+                "file:" + PathUtils.getBaseDir() + "/src/test/resources/logback.xml" ),
+            systemPackages( "javax.xml.stream;version=1.0.0", "javax.xml.stream.util;version=1.0.0",
+                "javax.xml.stream.events;version=1.0.0" ), mavenBundle( "ch.qos.logback", "logback-classic", "1.0.6" ),
+            mavenBundle( "ch.qos.logback", "logback-core", "1.0.6" ), junitBundles(),
+            composite( dependencies.toArray( new Option[0] ) ) );
+    }
+
+
+    @Test
+    public void testInjectContext()
+    {
+        assertNotNull( context );
+    }
+
+
+    @Test
+    public void testBundleActivation()
+    {
+        String bundleName = getBundleName();
+
+        boolean bundleFound = false;
+        boolean bundleActive = false;
+        Bundle[] bundles = context.getBundles();
+        for ( Bundle bundle : bundles )
+        {
+            //System.out.println( "### bundle=" + bundle + " " + bundle.getState() );
+            if ( bundle != null && bundle.getSymbolicName() != null && bundle.getSymbolicName().equals( bundleName ) )
+            {
+                bundleFound = true;
+                if ( bundle.getState() == Bundle.ACTIVE )
+                {
+                    bundleActive = true;
+                }
+            }
+        }
+
+        assertTrue( "Bundle " + bundleName + " not found.", bundleFound );
+        assertTrue( "Bundle " + bundleName + " is not active.", bundleActive );
+    }
+
+
+    /**
+     * @return the symbolic name of the bundle under test.
+     */
+    protected abstract String getBundleName();
+
+
+    @Test
+    public void testUseBundleClasses() throws Exception
+    {
+        useBundleClasses();
+    }
+
+
+    /**
+     * Implementations should use the bundle's classes to check if they are accessible.
+     * @throws Exception
+     */
+    protected abstract void useBundleClasses() throws Exception;
+
+}
diff --git a/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiUtilOsgiTest.java b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiUtilOsgiTest.java
new file mode 100644
index 0000000..8221c94
--- /dev/null
+++ b/trunk/integ-osgi/src/test/java/org/apache/directory/api/osgi/ApiUtilOsgiTest.java
@@ -0,0 +1,52 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.osgi;
+
+
+import java.util.Date;
+
+import org.apache.directory.api.util.EmptyEnumeration;
+import org.apache.directory.api.util.GeneralizedTime;
+import org.apache.directory.api.util.Hex;
+import org.apache.directory.api.util.SingletonEnumeration;
+import org.apache.directory.api.util.exception.MultiException;
+
+
+public class ApiUtilOsgiTest extends ApiOsgiTestBase
+{
+
+    @Override
+    protected String getBundleName()
+    {
+        return "org.apache.directory.api.util";
+    }
+
+
+    @Override
+    protected void useBundleClasses() throws Exception
+    {
+        new GeneralizedTime( new Date() ).getHour();
+        new MultiException();
+        new EmptyEnumeration<String>();
+        new SingletonEnumeration<String>( "foo" );
+        Hex.decodeHexString( "#60" );
+    }
+
+}
diff --git a/trunk/integ-osgi/src/test/resources/exam.properties b/trunk/integ-osgi/src/test/resources/exam.properties
new file mode 100644
index 0000000..12af2ff
--- /dev/null
+++ b/trunk/integ-osgi/src/test/resources/exam.properties
@@ -0,0 +1,18 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+
+pax.exam.logging = none
diff --git a/trunk/integ-osgi/src/test/resources/logback.xml b/trunk/integ-osgi/src/test/resources/logback.xml
new file mode 100644
index 0000000..a284c18
--- /dev/null
+++ b/trunk/integ-osgi/src/test/resources/logback.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<configuration>
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>
\ No newline at end of file
diff --git a/trunk/integ/pom.xml b/trunk/integ/pom.xml
new file mode 100644
index 0000000..bdc06a1
--- /dev/null
+++ b/trunk/integ/pom.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-integ</artifactId>
+  <name>Apache Directory API Integration Tests</name>
+
+  <!-- 
+     NOTE: This is a temporary module and area where we may
+     decide to remove it after figuring out a better place 
+     to put these tests. For now it keeps tests that would 
+     otherwise clutter api-schema or cause cycles if put
+     in the rightful position where they belong.
+
+     The odd ldap api tests can be put here, it matters not
+     that they depend on ApacheDS jars for the test scope,
+     since this module is not used for anything other than 
+     integration tests.
+   -->
+  
+  <description>
+    A place to put integration tests that if put in their rightful
+    project position would incure some cyclic dependencies even if
+    the dependencies were test scoped dependencies. 
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-schema-data</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-aci</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-net-mina</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-standalone</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <properties>
+    <codec.plugin.directory>${project.build.directory}/pluginDirectory</codec.plugin.directory>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>process-test-resources</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>${project.groupId}</groupId>
+                  <artifactId>api-ldap-extras-codec</artifactId>
+                  <version>${project.version}</version>
+                  <outputDirectory>${codec.plugin.directory}</outputDirectory>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/integ/src/checkstyle/suppressions.xml b/trunk/integ/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..f5768dd
--- /dev/null
+++ b/trunk/integ/src/checkstyle/suppressions.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <suppress files=".*" checks="MethodName" />
+    <suppress files="org.apache.directory.api.ldap.entry.SchemaAwareAttributeTest" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.name.DnTest" checks="FileLength" />
+</suppressions>
diff --git a/trunk/integ/src/site/site.xml b/trunk/integ/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/integ/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/aci/ACIItemCheckerTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/aci/ACIItemCheckerTest.java
new file mode 100644
index 0000000..18430b2
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/aci/ACIItemCheckerTest.java
@@ -0,0 +1,355 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class for ACIItem checker (wrapper).
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ACIItemCheckerTest
+{
+    /** the ACIItem checker wrapper */
+    private static ACIItemChecker checker;
+
+
+    /**
+     * Initialization
+     */
+    @BeforeClass
+    public static void init() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+        schemaManager.loadAllEnabled();
+
+        checker = new ACIItemChecker( schemaManager );
+    }
+
+
+    /**
+     * Tests the checker with an ACIItem of ItemFirst main component.
+     */
+    @Test
+    public void testItemFirst() throws Exception
+    {
+        String spec =
+            " {  "
+                + "   identificationTag  \"id1\" , "
+                + "   precedence 114  , "
+                + "   authenticationLevel simple  , "
+                + "   itemOrUserFirst itemFirst  :"
+                + "   { "
+                + "     protectedItems  "
+                + "     { "
+                + "       entry  , "
+                + "       attributeType { 1.2.3    , ou }  ,"
+                + "       attributeValue { ou=people  , cn=Ersin  }  , "
+                + "       rangeOfValues (cn=ErsinEr) , "
+                + "       classes and : "
+                + "       { "
+                + "         item: xyz , "
+                + "         or:{item:X,item:Y}   "
+                + "       }"
+                + "     }  , "
+                + "     itemPermissions "
+                + "     { "
+                + "       { "
+                + "         userClasses "
+                + "         {"
+                + "           allUsers  , "
+                + "           userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } ,"
+                + "           subtree { { base \"ou=people\" } } "
+                + "         }   , "
+                + "         grantsAndDenials  {  denyCompare  , grantModify } "
+                + "       },"
+                + "       { "
+                + "         precedence 10, "
+                + "         userClasses "
+                + "         {"
+                + "           allUsers  , "
+                + "           userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } ,"
+                + "           subtree { { base \"ou=people\" } } "
+                + "         }   , "
+                + "         grantsAndDenials  {  denyCompare  , grantModify } "
+                + "       } "
+                + "     } "
+                + "   }"
+                + " }";
+
+        checker.parse( spec );
+    }
+
+
+    /**
+     * Tests the checker with an ACIItem of UserFirst main component.
+     */
+    @Test
+    public void testUserFirst() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {cn=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testAllowAddAllUsers() throws Exception
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testCombo() throws Exception
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers, name { \"ou=blah\" } }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testOrderOfProtectedItemsDoesNotMatter() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testOrderOfUserClassesDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  name { \"ou=people,cn=ersin\" }, allUsers, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {dc=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testItemPermissionComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { grantsAndDenials  {  denyCompare  , grantModify }, userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testUserPermissionComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { grantsAndDenials { grantBrowse }, protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {cn=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testOrderOfMainACIComponentsDoesNotMatter() throws Exception
+    {
+        String spec = "{   itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {cn=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }, "
+            + " identificationTag \"id2\"   , authenticationLevel none, precedence 14 }   ";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testRestrictedValueComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\"}, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , "
+            + "maxValueCount { { type 10.11.12, maxCount 10 }, { maxCount 20, type 11.12.13  } } "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    @Test
+    public void testMaxValueCountComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , "
+            + "restrictedBy { { type 10.11.12, valuesIn ou }, { valuesIn cn, type 11.12.13  } } "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    /**
+     * Test case for DIRSERVER-891
+     */
+    @Test
+    public void testInvalidAttributeValue()
+    {
+        String spec;
+
+        // no name-value-pair
+        spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue { must_be_a_name_value_pair } , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ minimum 7, maximum 9, base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + " maximum   2, minimum  1 } } }  }  }   ";
+        try
+        {
+            checker.parse( spec );
+            fail( "Expected ParseException, invalid protected item 'attributeValue { must_be_a_name_value_pair }'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        // no name-value-pair
+        spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue { x=y,m=n,k=l,x } , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ minimum 7, maximum 9, base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + " maximum   2, minimum  1 } } }  }  }   ";
+        try
+        {
+            checker.parse( spec );
+            fail( "Expected ParseException, invalid protected item 'attributeValue { must_be_a_name_value_pair }'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+    }
+
+
+    /**
+     * Test case for DIRSERVER-891
+     */
+    @Test
+    public void testIncomplete()
+    {
+        String spec;
+
+        spec = "{ }";
+        try
+        {
+            checker.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        spec = "{ identificationTag \"id2\" }";
+        try
+        {
+            checker.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        spec = "{ identificationTag \"id2\", precedence 14 } ";
+        try
+        {
+            checker.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        spec = "{ identificationTag \"id2\", precedence 14, authenticationLevel none } ";
+        try
+        {
+            checker.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/aci/ACIItemParserTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/aci/ACIItemParserTest.java
new file mode 100644
index 0000000..a5bd700
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/aci/ACIItemParserTest.java
@@ -0,0 +1,867 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class for ACIItem parser (wrapper).
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ACIItemParserTest
+{
+
+    /** the ACIItem parser wrapper */
+    private static ACIItemParser parser;
+
+
+    /**
+     * Initialization
+     */
+    @BeforeClass
+    public static void init() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+        schemaManager.loadAllEnabled();
+
+        parser = new ACIItemParser( schemaManager );
+    }
+
+
+    private void checkItemToString( String spec, ACIItem item ) throws Exception
+    {
+        // try to parse the result of item.toString() again
+        parser.parse( item.toString() );
+    }
+
+
+    /**
+     * Tests the parser with a rangeOfValues with a nested filter.
+     */
+    @Test
+    public void testRangeOfValues() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  "
+            + "{ rangeOfValues (&(&(|(|(cn=ccc)(!(cn=ddd))(&(cn=aaa)(cn=bbb)))))) " + "}  , itemPermissions {  } } }";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+
+        spec = " { identificationTag \"id8\", precedence 0, authenticationLevel simple "
+            + ", itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { "
+            + " { protectedItems { rangeOfValues (&(cn=test)(sn=test)) }, grantsAndDenials { grantAdd } }, "
+            + "{ protectedItems { rangeOfValues (|(!(cn=aaa))(sn=bbb)) }, grantsAndDenials { grantAdd } } "
+            + " } } }";
+
+        item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    /**
+     * Tests the parser with an ACIItem of ItemFirst main component.
+     */
+    @Test
+    public void testItemFirst() throws Exception
+    {
+        String spec =
+            "{  "
+               + "  identificationTag  \"id1\" , "
+               + "  precedence 114  , "
+               + "  authenticationLevel simple  , "
+               + "  itemOrUserFirst itemFirst  :"
+               + "  { "
+               + "    protectedItems  { entry  , attributeType { 2.5.4.3    , ou } , "
+               + "    attributeValue { ou=people  , cn=Ersin  }  , "
+               + "    rangeOfValues (cn=ErsinEr) , "
+               + "    classes and : { item: xyz , or:{item:X,item:Y}   }"
+               + "  }  , "
+               + "  itemPermissions "
+               + "  { "
+               + "    { "
+               + "      userClasses "
+               + "        {"
+               + "          allUsers  , "
+               + "          userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } , "
+               + "          subtree { { base \"ou=people\" } } "
+               + "        }   , "
+               + "      grantsAndDenials  {  denyCompare  , grantModify } "
+               + "    },"
+               + "    { "
+               + "      precedence 10, "
+               + "      userClasses "
+               + "      {"
+               + "        allUsers  , "
+               + "        userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } ,"
+               + "        subtree { { base \"ou=people\" } } "
+               + "      }   , "
+               + "      grantsAndDenials  {  denyCompare  , grantModify } } "
+               + "    } "
+               + "  }"
+               + "}";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    /**
+     * Tests the parser with an ACIItem of UserFirst main component.
+     */
+    @Test
+    public void testUserFirst() throws Exception
+    {
+        String spec =
+            "{ "
+                + "  identificationTag \"id2\"   , "
+                + "  precedence 14, "
+                + "  authenticationLevel none  , "
+                + "  itemOrUserFirst userFirst:  "
+                + "  { "
+                + "    userClasses "
+                + "    {  "
+                + "      allUsers  , "
+                + "      name { \"ou=people,cn=ersin\" }, "
+                + "      subtree "
+                + "      {"
+                + "        { base \"ou=system\" }, "
+                + "        { "
+                + "          base \"ou=ORGANIZATIONUNIT\","
+                + "          minimum  1, "
+                + "          maximum   2 "
+                + "        } "
+                + "      } "
+                + "    }  , "
+                + "    userPermissions "
+                + "    { "
+                + "      { "
+                + "        protectedItems"
+                + "        { "
+                + "          entry  , "
+                + "          attributeType { cn  , ou }  , "
+                + "          attributeValue {cn=y,sn=n,dc=l} , "
+                + "          rangeOfValues (cn=ErsinEr) "
+                + "        }  , "
+                + "        grantsAndDenials { grantBrowse } "
+                + "      } "
+                + "    } "
+                + "  }  "
+                + "}   ";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testAllowAddAllUsers() throws Exception
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testCombo() throws Exception
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers, name { \"ou=blah\" } }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testOrderOfProtectedItemsDoesNotMatter() throws Exception
+    {
+        String spec =
+            " {  "
+                + "   identificationTag  \"id1\" , "
+                + "   precedence 114  , "
+                + "   authenticationLevel simple  , "
+                + "   itemOrUserFirst itemFirst  :"
+                + "   { "
+                + "     protectedItems  "
+                + "     { "
+                + "       attributeType { 2.5.4.3    , ou }, "
+                + "       entry , "
+                + "       rangeOfValues (cn=ErsinEr) , "
+                + "       attributeValue { ou=people  , cn=Ersin  },"
+                + "       classes and : "
+                + "       { item: xyz , or:{item:X,item:Y}   }"
+                + "     }  , "
+                + "     itemPermissions "
+                + "     { "
+                + "       { "
+                + "         userClasses "
+                + "         {"
+                + "           allUsers  , "
+                + "           userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,sn=d\" } "
+                + "           , "
+                + "           subtree "
+                + "           { "
+                + "             { base \"ou=people\" } "
+                + "           } "
+                + "         }   , "
+                + "         grantsAndDenials  "
+                + "         {  "
+                + "           denyCompare  , "
+                + "           grantModify "
+                + "         } "
+                + "       },"
+                + "       { "
+                + "         precedence 10, "
+                + "         userClasses "
+                + "         {"
+                + "           allUsers  , "
+                + "           userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+                + "           , subtree { { base \"ou=people\" } } "
+                + "         }   , "
+                + "         grantsAndDenials  {  denyCompare  , grantModify } "
+                + "       } "
+                + "     } "
+                + "   }"
+                + " }";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testOrderOfUserClassesDoesNotMatter() throws Exception
+    {
+        String spec =
+            "{ "
+                + "  identificationTag \"id2\"   , "
+                + "  precedence 14, "
+                + "  authenticationLevel none  , "
+                + "  itemOrUserFirst userFirst:  "
+                + "  { "
+                + "    userClasses "
+                + "    {  "
+                + "      name { \"ou=people,cn=ersin\" }, "
+                + "      allUsers, "
+                + "      subtree "
+                + "      {"
+                + "        { base \"ou=system\" }, "
+                + "        { "
+                + "          base \"ou=ORGANIZATIONUNIT\","
+                + "          minimum  1, "
+                + "          maximum   2 "
+                + "        } "
+                + "      } "
+                + "    }  , "
+                + "    userPermissions "
+                + "    { "
+                + "      { "
+                + "        protectedItems"
+                + "        { "
+                + "          entry  , "
+                + "          attributeType { cn  , ou }  , "
+                + "          attributeValue {cn=y,sn=n,dc=l} , "
+                + "          rangeOfValues (cn=ErsinEr) "
+                + "        }  , "
+                + "        grantsAndDenials { grantBrowse } "
+                + "      } "
+                + "    } "
+                + "  }  "
+                + "}";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testOrderOfProtectedItemsDoesNotMatterButDuplicatesMatter() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        try
+        {
+            parser.parse( spec );
+            fail( "testItemFirstOrderOfProtectedItemsDoesNotMatterButDuplicatesMatter() should not have run this line." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testOrderOfUserClassesDoesNotMatterButDuplicatesMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  name { \"ou=people,cn=ersin\" }, allUsers, allUsers, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        try
+        {
+            parser.parse( spec );
+            fail( "testUserFirstOrderOfUserClassesDoesNotMatterButDuplicatesMatter() should not have run this line." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testItemPermissionComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec =
+            " {  "
+                + "   identificationTag  \"id1\" , "
+                + "   precedence 114  , "
+                + "   authenticationLevel simple  , "
+                + "   itemOrUserFirst itemFirst  :"
+                + "   { "
+                + "     protectedItems  "
+                + "     { "
+                + "       attributeType { 2.5.4.3    , ou }, "
+                + "       entry , "
+                + "       rangeOfValues (cn=ErsinEr) , "
+                + "       attributeValue { ou=people  , cn=Ersin  },"
+                + "       classes and : { item: xyz , or:{item:X,item:Y}   }"
+                + "     }  , "
+                + "     itemPermissions "
+                + "     { "
+                + "       { "
+                + "         grantsAndDenials  "
+                + "         {  "
+                + "           denyCompare  , grantModify "
+                + "         }, "
+                + "         userClasses "
+                + "         {"
+                + "           allUsers  , "
+                + "           userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+                + "           , subtree { { base \"ou=people\" } } "
+                + "         }   "
+                + "       },"
+                + "       { "
+                + "         precedence 10, "
+                + "         userClasses "
+                + "         {"
+                + "           allUsers  , "
+                + "           userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+                + "           , subtree { { base \"ou=people\" } } "
+                + "         }   , "
+                + "         grantsAndDenials  {  denyCompare  , grantModify } "
+                + "       } "
+                + "     } "
+                + "   }"
+                + " }";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testItemPermissionComponentsOrderDoesNotMatterButDuplicatesMatter() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }, grantsAndDenials  {  denyCompare  , grantModify }, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        try
+        {
+            parser.parse( spec );
+            fail( "testItemPermissionComponentsOrderDoesNotMatterButDuplicatesMatter() should not have run this line." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testUserPermissionComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec =
+            "{ "
+               + "  identificationTag \"id2\"   , "
+               + "  precedence 14, "
+               + "  authenticationLevel none  , "
+               + "  itemOrUserFirst userFirst:  "
+               + "  { "
+               + "    userClasses "
+               + "    {  "
+               + "      allUsers  , "
+               + "      name { \"ou=people,cn=ersin\" }, "
+               + "      subtree "
+               + "      {"
+               + "        { base \"ou=system\" }, "
+               + "        { "
+               + "          base \"ou=ORGANIZATIONUNIT\","
+               + "          minimum  1, "
+               + "          maximum   2 "
+               + "        } "
+               + "      } "
+               + "    }  , "
+               + "    userPermissions "
+               + "    { "
+               + "      { "
+               + "        grantsAndDenials { grantBrowse }, "
+               + "        protectedItems"
+               + "        { "
+               + "          entry  , "
+               + "          attributeType { cn  , ou }  , "
+               + "          attributeValue {cn=y,sn=n,dc=l} , "
+               + "          rangeOfValues (cn=ErsinEr) "
+               + "        }  "
+               + "      } "
+               + "    } "
+               + "  }  "
+               + "}   ";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testUserPermissionComponentsOrderDoesNotMatterButDuplicatesMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { grantsAndDenials { grantBrowse }, grantsAndDenials { grantBrowse }, protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  } } }  }   ";
+
+        try
+        {
+            parser.parse( spec );
+            fail( "testUserPermissionComponentsOrderDoesNotMatterButDuplicatesMatter() should not have run this line." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testOrderOfMainACIComponentsDoesNotMatter() throws Exception
+    {
+        String spec =
+            "{   "
+               + "  itemOrUserFirst userFirst:  "
+               + "  { "
+               + "    userClasses "
+               + "    {  "
+               + "      allUsers  , "
+               + "      name { \"ou=people,cn=ersin\" }, "
+               + "      subtree "
+               + "      {"
+               + "        { base \"ou=system\" }, "
+               + "        { "
+               + "          base \"ou=ORGANIZATIONUNIT\","
+               + "          minimum  1, "
+               + "          maximum   2 "
+               + "        } "
+               + "      } "
+               + "    }  , "
+               + "    userPermissions "
+               + "    { "
+               + "      { "
+               + "        protectedItems"
+               + "        { "
+               + "          entry  , "
+               + "          attributeType { cn  , ou }  , "
+               + "          attributeValue {cn=y,sn=n,dc=l} , "
+               + "          rangeOfValues (cn=ErsinEr) "
+               + "        }  , "
+               + "        grantsAndDenials { grantBrowse } "
+               + "      } "
+               + "    } "
+               + "  }, "
+               + "  identificationTag \"id2\"   , "
+               + "  authenticationLevel none, "
+               + "  precedence 14 "
+               + "}   ";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testOrderOfMainACIComponentsDoesNotMatterButDuplicatesMatter() throws Exception
+    {
+        String spec = "{   itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }, "
+            + " identificationTag \"id2\"   , authenticationLevel none, authenticationLevel simple, precedence 14 }   ";
+
+        try
+        {
+            parser.parse( spec );
+            fail( "testOrderOfMainACIComponentsDoesNotMatterButDuplicatesMatter() should not have run this line." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testOrderOfMainACIComponentsDoesNotMatterButMissingsMatter() throws Exception
+    {
+        String spec = "{   itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }, "
+            + " identificationTag \"id2\"   , precedence 14 }   ";
+
+        try
+        {
+            parser.parse( spec );
+            fail( "testOrderOfMainACIComponentsDoesNotMatterButMissingsMatter() should not have run this line." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testGrantAndDenialBitsOrderDoesNotMatterButDuplicatesMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers }  , "
+            + "userPermissions { { protectedItems{ entry  }  , grantsAndDenials { grantBrowse, grantInvoke, denyAdd, grantBrowse } } } }  }";
+
+        try
+        {
+            parser.parse( spec );
+            fail( "testGrantAndDenialBitsOrderDoesNotMatterButDuplicatesMatter() should not have run this line." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testMaxValueCountComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec =
+            "{ "
+                + "  identificationTag \"id2\"   , "
+                + "  precedence 14, "
+                + "  authenticationLevel none  , "
+                + "  itemOrUserFirst userFirst:  "
+                + "  { "
+                + "    userClasses "
+                + "    {  "
+                + "      allUsers  , "
+                + "      name { \"ou=people,cn=ersin\" }, "
+                + "      subtree "
+                + "      {"
+                + "        { base \"ou=system\"}, "
+                + "        { base \"ou=ORGANIZATIONUNIT\", minimum  1, maximum   2 } "
+                + "      } "
+                + "    }  , "
+                + "    userPermissions "
+                + "    { "
+                + "      { "
+                + "        protectedItems"
+                + "        { "
+                + "          entry  , "
+                + "          maxValueCount "
+                + "          { "
+                + "            { type 2.5.4.3, maxCount 10 }, "
+                + "            { maxCount 20, type 2.5.4.3  } "
+                + "          } "
+                + "        }  , "
+                + "        grantsAndDenials { grantBrowse } "
+                + "      } "
+                + "    } "
+                + "  } "
+                + "}   ";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testRestrictedValueComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , "
+            + "restrictedBy { { type 2.5.4.3, valuesIn ou }, { valuesIn cn, type 2.5.4.3  } } "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    @Test
+    public void testMaxImmSubComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , maxImmSub 5 "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    /**
+     * Test case for DIRSERVER-891
+     */
+    @Test
+    public void testInvalidAttributeValue()
+    {
+        String spec;
+
+        // no name-value-pair
+        spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue { must_be_a_name_value_pair } , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ minimum 7, maximum 9, base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + " maximum   2, minimum  1 } } }  }  }   ";
+        try
+        {
+            parser.parse( spec );
+            fail( "Expected ParseException, invalid protected item 'attributeValue { must_be_a_name_value_pair }'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        // no name-value-pair
+        spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue { x=y,m=n,k=l,x } , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ minimum 7, maximum 9, base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + " maximum   2, minimum  1 } } }  }  }   ";
+        try
+        {
+            parser.parse( spec );
+            fail( "Expected ParseException, invalid protected item 'attributeValue { x=y,m=n,k=l,x }'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+    }
+
+
+    @Test
+    public void testUserClassParentOfEntry() throws Exception
+    {
+        String spec =
+            "{ "
+                + "  identificationTag \"id\"   , "
+                + "  precedence 10, "
+                + "  authenticationLevel none  , "
+                + "  itemOrUserFirst userFirst:  "
+                + "  { "
+                + "    userClasses "
+                + "    {  "
+                + "      parentOfEntry  , "
+                + "      name { \"cn=ersin,ou=people\" }, "
+                + "      subtree "
+                + "      {"
+                + "        { base \"ou=system\" }, "
+                + "        { "
+                + "          base \"ou=ORGANIZATIONUNIT\","
+                + "          minimum  1, "
+                + "          maximum   2 "
+                + "        } "
+                + "      } "
+                + "    }  , "
+                + "    userPermissions "
+                + "    { "
+                + "      { "
+                + "        protectedItems"
+                + "        { "
+                + "          entry  , "
+                + "          attributeType { cn  , ou }  , "
+                + "          attributeValue {cn=y,sn=n,dc=l} , "
+                + "          rangeOfValues (cn=ErsinEr) "
+                + "        }  , "
+                + "        grantsAndDenials { grantBrowse } "
+                + "      } "
+                + "    } "
+                + "  } "
+                + "}   ";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+    }
+
+
+    /**
+     * Test case for DIRSTUDIO-440
+     */
+    @Test
+    public void testPrecedenceOfUserFirst() throws Exception
+    {
+        String spec = "{ identificationTag \"test\", precedence 14, authenticationLevel simple, "
+            + "itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { "
+            + "precedence 1, protectedItems { attributeType { userPassword } }, grantsAndDenials "
+            + "{ denyRead, denyReturnDN, denyBrowse } }, { precedence 2, protectedItems "
+            + "{ entry, allUserAttributeTypesAndValues }, grantsAndDenials "
+            + "{ grantReturnDN, grantRead, grantBrowse } } } } }";
+
+        ACIItem item = parser.parse( spec );
+        checkItemToString( spec, item );
+
+        UserFirstACIItem userFirstItem = ( UserFirstACIItem ) item;
+        int aciPrecedence = userFirstItem.getPrecedence();
+        assertEquals( 14, aciPrecedence );
+        for ( UserPermission permission : userFirstItem.getUserPermission() )
+        {
+            int precedence = permission.getPrecedence();
+            if ( precedence == 1 )
+            {
+                assertEquals( 1, precedence );
+            }
+            else if ( precedence == 2 )
+            {
+                assertEquals( 2, precedence );
+            }
+            else
+            {
+                fail( "Got precedence " + precedence + ", expected precedence 1 or 2." );
+            }
+        }
+    }
+
+
+    /**
+     * Test case for DIRSERVER-891
+     */
+    @Test
+    public void testIncomplete()
+    {
+        String spec;
+
+        spec = "{ }";
+        try
+        {
+            parser.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        spec = "{ identificationTag \"id2\" }";
+        try
+        {
+            parser.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        spec = "{ identificationTag \"id2\", precedence 14 } ";
+        try
+        {
+            parser.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+
+        spec = "{ identificationTag \"id2\", precedence 14, authenticationLevel none } ";
+        try
+        {
+            parser.parse( spec );
+            fail( "Expected ParseException, ACIItem is incomplete'" );
+        }
+        catch ( ParseException e )
+        {
+            // Expected
+        }
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/codec/api/StandaloneLdapCodecServiceTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/codec/api/StandaloneLdapCodecServiceTest.java
new file mode 100644
index 0000000..5da9857
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/codec/api/StandaloneLdapCodecServiceTest.java
@@ -0,0 +1,111 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.codec.standalone.StandaloneLdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequest;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequestImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Tests for StandaloneLdapCodecService.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StandaloneLdapCodecServiceTest
+{
+    @BeforeClass
+    public static void setupLdapApiService() throws Exception
+    {
+        // Load the extension points
+        System.setProperty( StandaloneLdapApiService.CONTROLS_LIST,
+            "org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory,"
+                + "org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory,"
+                + "org.apache.directory.api.ldap.codec.controls.proxiedauthz.ProxiedAuthzFactory,"
+                + "org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory,"
+                + "org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory,"
+                + "org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory,"
+                + "org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.vlv_impl.VirtualListViewRequestFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.vlv_impl.VirtualListViewResponseFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncDoneValueFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncInfoValueFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncRequestValueFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncStateValueFactory,"
+                + "org.apache.directory.api.ldap.extras.controls.ad_impl.AdDirSyncFactory" );
+
+        System
+            .setProperty(
+                StandaloneLdapApiService.EXTENDED_OPERATIONS_LIST,
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelFactory,"
+                    + "org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration.CertGenerationFactory,"
+                    + "org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown.GracefulShutdownFactory,"
+                    + "org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureFactory,"
+                    + "org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyFactory,"
+                    + "org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectFactory,"
+                    + "org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI.WhoAmIFactory,"
+                    + "org.apache.directory.api.ldap.extras.extended.ads_impl.startTls.StartTlsFactory" );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.codec.standalone.StandaloneLdapCodecService#StandaloneLdapCodecService()}.
+     */
+    @Test
+    public void testLoadingExtras() throws Exception
+    {
+        LdapApiService codec = LdapApiServiceFactory.getSingleton();
+
+        assertTrue( codec.isControlRegistered( PasswordPolicy.OID ) );
+
+        CodecControl<? extends Control> control = codec.newControl( PasswordPolicy.OID );
+        assertNotNull( control );
+        assertNotNull( codec );
+    }
+
+
+    /**
+     * Test an extended operation.
+     */
+    @Test
+    public void testLoadingExtendedOperation() throws Exception
+    {
+        LdapApiService codec = LdapApiServiceFactory.getSingleton();
+        StoredProcedureRequest req = new StoredProcedureRequestImpl();
+        req.setLanguage( "Java" );
+        req.setProcedure( Strings.getBytesUtf8( "bogusProc" ) );
+
+        assertNotNull( req );
+        assertNotNull( codec );
+
+        StoredProcedureRequest decorator = ( StoredProcedureRequest ) codec.decorate( req );
+        assertNotNull( decorator );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareAttributeSerializationTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareAttributeSerializationTest.java
new file mode 100644
index 0000000..8b147af
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareAttributeSerializationTest.java
@@ -0,0 +1,218 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.entry;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * Test the Attribute Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaAwareAttributeSerializationTest
+{
+    private static byte[] data1 = new byte[]
+        { 0x01, 0x02, 0x03, 0x04 };
+    private static byte[] data2 = new byte[]
+        { 0x05, 0x06, 0x07, 0x08 };
+    private static byte[] data3 = new byte[]
+        { 0x09, 0x0A, 0x0B, 0x0C };
+
+    private static AttributeType cn = null;
+    private static AttributeType userCertificate = null;
+
+    private static SchemaManager schemaManager;
+
+
+    /**
+     * Initialize OIDs maps for normalization
+     */
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+        cn = schemaManager.getAttributeType( "cn" );
+        userCertificate = schemaManager.getAttributeType( "userCertificate" );
+    }
+
+
+    @Test
+    public void testEntryAttributeNoStringValueSerialization() throws IOException, ClassNotFoundException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute1 = new DefaultAttribute( cn );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute( cn );
+        attribute2.readExternal( in );
+        attribute2.apply( cn );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeOneStringValueSerialization() throws IOException, ClassNotFoundException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute1 = new DefaultAttribute( "CommonName", cn, "test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute( cn );
+        attribute2.readExternal( in );
+        attribute2.apply( cn );
+
+        assertEquals( attribute1, attribute2 );
+        assertEquals( "CommonName", attribute2.getUpId() );
+    }
+
+
+    @Test
+    public void testEntryAttributeManyStringValuesSerialization() throws IOException, ClassNotFoundException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute1 = new DefaultAttribute( "CN", cn, "test1", "test2", "test3" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute( cn );
+        attribute2.readExternal( in );
+        attribute2.apply( cn );
+
+        assertEquals( attribute1, attribute2 );
+        assertEquals( "CN", attribute2.getUpId() );
+    }
+
+
+    @Test
+    public void testEntryAttributeNoBinaryValueSerialization() throws IOException, ClassNotFoundException,
+        LdapInvalidAttributeValueException, LdapInvalidAttributeValueException
+    {
+        Attribute attribute1 = new DefaultAttribute( userCertificate );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute( userCertificate );
+        attribute2.readExternal( in );
+        attribute2.apply( userCertificate );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeOneBinaryValueSerialization() throws IOException, ClassNotFoundException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute1 = new DefaultAttribute( userCertificate, data1 );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute( userCertificate );
+        attribute2.readExternal( in );
+        attribute2.apply( userCertificate );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeManyBinaryValuesSerialization() throws IOException, ClassNotFoundException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute1 = new DefaultAttribute( "UserCertificate", userCertificate, data1, data2, data3 );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute( userCertificate );
+        attribute2.readExternal( in );
+        attribute2.apply( userCertificate );
+
+        assertEquals( attribute1, attribute2 );
+        assertEquals( "UserCertificate", attribute2.getUpId() );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareAttributeTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareAttributeTest.java
new file mode 100644
index 0000000..b4e4022
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareAttributeTest.java
@@ -0,0 +1,2135 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+/**
+ * Test the schema aware Attribute
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaAwareAttributeTest
+{
+    private AttributeType atCN = null;
+    private AttributeType atDC;
+    private AttributeType atSN;
+    private AttributeType atName;
+
+    // A SINGLE-VALUE attribute
+    private AttributeType atC;
+
+    // A Binary attribute
+    private AttributeType atPwd;
+
+    // A String attribute which allows null value
+    private AttributeType atEMail;
+
+    private final Value<String> nullStringValue = new StringValue( ( String ) null );
+    private final Value<byte[]> nullBinaryValue = new BinaryValue( ( byte[] ) null );
+    private static final byte[] BYTES1 = new byte[]
+        { 'a', 'b' };
+    private static final byte[] BYTES2 = new byte[]
+        { 'b' };
+    private static final byte[] BYTES3 = new byte[]
+        { 'c' };
+    private static final byte[] BYTES4 = new byte[]
+        { 'd' };
+
+    private final StringValue stringValue1 = new StringValue( "a" );
+    private final StringValue stringValue2 = new StringValue( "b" );
+    private final StringValue stringValue3 = new StringValue( "c" );
+    private final StringValue stringValue4 = new StringValue( "d" );
+
+    private final BinaryValue binaryValue1 = new BinaryValue( BYTES1 );
+    private final BinaryValue binaryValue2 = new BinaryValue( BYTES2 );
+    private final BinaryValue binaryValue3 = new BinaryValue( BYTES3 );
+    private final BinaryValue binaryValue4 = new BinaryValue( BYTES4 );
+
+    private static SchemaManager schemaManager;
+
+
+    /**
+     * Serialize a DefaultEntryAttribute
+     */
+    private ByteArrayOutputStream serializeValue( DefaultAttribute value ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+            value.writeExternal( oOut );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a DefaultEntryAttribute
+     */
+    private DefaultAttribute deserializeValue( ByteArrayOutputStream out, AttributeType at ) throws IOException,
+        ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+
+            DefaultAttribute value = new DefaultAttribute( at );
+            value.readExternal( oIn );
+
+            return value;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    @BeforeClass
+    public static void startup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    /**
+     * Initialize the schemaManager
+     */
+    @Before
+    public void setup() throws Exception
+    {
+        atCN = schemaManager.getAttributeType( "cn" );
+        atDC = schemaManager.lookupAttributeTypeRegistry( "dc" );
+        atC = schemaManager.lookupAttributeTypeRegistry( "c" );
+        atSN = schemaManager.lookupAttributeTypeRegistry( "sn" );
+        atPwd = schemaManager.lookupAttributeTypeRegistry( "userpassword" );
+        atEMail = schemaManager.lookupAttributeTypeRegistry( "email" );
+        atName = schemaManager.lookupAttributeTypeRegistry( "name" );
+    }
+
+
+    /**
+     * Test method isValid( SyntaxChecker )
+     */
+    @Test
+    public void testIsValidSyntaxChecker() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( "test" );
+
+        attr.add( "test", "another test" );
+
+        assertTrue( attr.isValid( atCN ) );
+
+        attr.add( "test an invalid '\uFFFD' char" );
+        assertFalse( attr.isValid( atCN ) );
+    }
+
+
+    @Test
+    public void testAddOneValue() throws Exception
+    {
+        AttributeType at = TestEntryUtils.getIA5StringAttributeType();
+
+        DefaultAttribute attr = new DefaultAttribute( at );
+
+        // Add a String value
+        attr.add( "test" );
+
+        assertEquals( 1, attr.size() );
+
+        assertTrue( attr.getAttributeType().getSyntax().isHumanReadable() );
+
+        Value<?> value = attr.get();
+
+        assertTrue( value instanceof StringValue );
+        assertEquals( "test", ( ( StringValue ) value ).getString() );
+
+        // Add a binary value
+        assertEquals( 0, attr.add( new byte[]
+            { 0x01 } ) );
+
+        // Add a Value
+        Value<?> ssv = new StringValue( at, "test2" );
+
+        attr.add( ssv );
+
+        assertEquals( 2, attr.size() );
+
+        Set<String> expected = new HashSet<String>();
+        expected.add( "test" );
+        expected.add( "test2" );
+
+        for ( Value<?> val : attr )
+        {
+            if ( expected.contains( val.getValue() ) )
+            {
+                expected.remove( val.getValue() );
+            }
+            else
+            {
+                fail();
+            }
+        }
+
+        assertEquals( 0, expected.size() );
+    }
+
+
+    @Test
+    public void testAddTwoValue() throws Exception
+    {
+        AttributeType at = TestEntryUtils.getIA5StringAttributeType();
+
+        DefaultAttribute attr = new DefaultAttribute( at );
+
+        // Add String values
+        attr.add( "test" );
+        attr.add( "test2" );
+
+        assertEquals( 2, attr.size() );
+
+        assertTrue( attr.getAttributeType().getSyntax().isHumanReadable() );
+
+        Set<String> expected = new HashSet<String>();
+        expected.add( "test" );
+        expected.add( "test2" );
+
+        for ( Value<?> val : attr )
+        {
+            if ( expected.contains( val.getValue() ) )
+            {
+                expected.remove( val.getValue() );
+            }
+            else
+            {
+                fail();
+            }
+        }
+
+        assertEquals( 0, expected.size() );
+    }
+
+
+    @Test
+    public void testAddNullValue() throws Exception
+    {
+        AttributeType at = TestEntryUtils.getIA5StringAttributeType();
+
+        DefaultAttribute attr = new DefaultAttribute( at );
+
+        // Add a null value
+        attr.add( new StringValue( at, null ) );
+
+        assertEquals( 1, attr.size() );
+
+        assertTrue( attr.getAttributeType().getSyntax().isHumanReadable() );
+
+        Value<?> value = attr.get();
+
+        assertTrue( value instanceof StringValue );
+        assertNull( ( ( StringValue ) value ).getValue() );
+    }
+
+
+    @Test
+    public void testGetAttribute() throws Exception
+    {
+        AttributeType at = TestEntryUtils.getIA5StringAttributeType();
+
+        DefaultAttribute attr = new DefaultAttribute( at );
+
+        attr.add( "Test1" );
+        attr.add( "Test2" );
+        attr.add( "Test3" );
+
+        assertEquals( "1.1", attr.getId() );
+        assertEquals( 3, attr.size() );
+        assertTrue( attr.contains( "Test1" ) );
+        assertTrue( attr.contains( "Test2" ) );
+        assertTrue( attr.contains( "Test3" ) );
+    }
+
+
+    /**
+     * Test the contains() method
+     */
+    @Test
+    public void testContains() throws Exception
+    {
+        AttributeType at = TestEntryUtils.getIA5StringAttributeType();
+
+        DefaultAttribute attr = new DefaultAttribute( at );
+
+        attr.add( "Test  1" );
+        attr.add( "Test  2" );
+        attr.add( "Test  3" );
+
+        assertTrue( attr.contains( "test 1" ) );
+        assertTrue( attr.contains( "Test 2" ) );
+        assertTrue( attr.contains( "TEST     3" ) );
+    }
+
+
+    /**
+     * Test method getBytes()
+     */
+    @Test
+    public void testGetBytes() throws LdapInvalidAttributeValueException
+    {
+        Attribute attr1 = new DefaultAttribute( atPwd );
+
+        attr1.add( ( byte[] ) null );
+        assertNull( attr1.getBytes() );
+
+        Attribute attr2 = new DefaultAttribute( atPwd );
+
+        attr2.add( BYTES1, BYTES2 );
+        assertTrue( Arrays.equals( BYTES1, attr2.getBytes() ) );
+
+        Attribute attr3 = new DefaultAttribute( atCN );
+
+        attr3.add( "a", "b" );
+
+        try
+        {
+            attr3.getBytes();
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException ivae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test method getId()
+     */
+    @Test
+    public void testGetId()
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        assertEquals( "2.5.4.3", attr.getId() );
+
+        attr.setUpId( "  CN  " );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "  CN  ", attr.getUpId() );
+
+        attr.setUpId( "  CommonName  " );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "  CommonName  ", attr.getUpId() );
+
+        attr.setUpId( "  2.5.4.3  " );
+        assertEquals( "2.5.4.3", attr.getId() );
+    }
+
+
+    /**
+     * Test method getString()
+     */
+    @Test
+    public void testGetString() throws LdapInvalidAttributeValueException
+    {
+        Attribute attr1 = new DefaultAttribute( atDC );
+
+        assertEquals( 1, attr1.add( ( String ) null ) );
+
+        Attribute attr2 = new DefaultAttribute( atDC );
+
+        attr2.add( "a" );
+        assertEquals( "a", attr2.getString() );
+
+        Attribute attr3 = new DefaultAttribute( atPwd );
+
+        attr3.add( BYTES1, BYTES2 );
+
+        try
+        {
+            attr3.getString();
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException ivae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test method getUpId
+     */
+    @Test
+    public void testGetUpId()
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        assertNotNull( attr.getUpId() );
+        assertEquals( "cn", attr.getUpId() );
+
+        attr.setUpId( "CN" );
+        assertEquals( "CN", attr.getUpId() );
+
+        attr.setUpId( "  Cn  " );
+        assertEquals( "  Cn  ", attr.getUpId() );
+
+        attr.setUpId( "  2.5.4.3  " );
+        assertEquals( "  2.5.4.3  ", attr.getUpId() );
+    }
+
+
+    /**
+     * Test method hashCode()
+     */
+    @Test
+    public void testHashCode() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atDC );
+        Attribute attr2 = new DefaultAttribute( atSN );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+
+        attr2.apply( atDC );
+        assertEquals( attr1.hashCode(), attr2.hashCode() );
+
+        attr1.add( ( String ) null );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+
+        attr1.clear();
+        assertEquals( attr1.hashCode(), attr2.hashCode() );
+
+        attr1.add( "a", "b" );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+
+        attr2.add( "a", "b" );
+        assertEquals( attr1.hashCode(), attr2.hashCode() );
+
+        // Order matters
+        attr2.clear();
+        attr2.add( "b", "a" );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+
+        Attribute attr3 = new DefaultAttribute( atPwd );
+        Attribute attr4 = new DefaultAttribute( atPwd );
+        assertNotSame( attr3.hashCode(), attr4.hashCode() );
+
+        attr3.add( ( byte[] ) null );
+        assertNotSame( attr3.hashCode(), attr4.hashCode() );
+
+        attr3.clear();
+        assertEquals( attr3.hashCode(), attr4.hashCode() );
+
+        attr3.add( new byte[]
+            { 0x01, 0x02 }, new byte[]
+            { 0x03, 0x04 } );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+
+        attr4.add( new byte[]
+            { 0x01, 0x02 }, new byte[]
+            { 0x03, 0x04 } );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+
+        // Order matters
+        attr4.clear();
+        attr4.add( new byte[]
+            { 0x03, 0x04 }, new byte[]
+            { 0x01, 0x02 } );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+    }
+
+
+    /**
+     * Test method SetId(String)
+     */
+    @Test
+    public void testSetId()
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        attr.setUpId( "Cn" );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "Cn", attr.getUpId() );
+
+        attr.setUpId( " CN " );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( " CN ", attr.getUpId() );
+
+        attr.setUpId( " 2.5.4.3 " );
+        assertEquals( " 2.5.4.3 ", attr.getUpId() );
+        assertEquals( "2.5.4.3", attr.getId() );
+
+        attr.setUpId( " commonName " );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( " commonName ", attr.getUpId() );
+
+        attr.setUpId( null );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+
+        attr.setUpId( "" );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+
+        attr.setUpId( "  " );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+
+        try
+        {
+            attr.setUpId( " SN " );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test method isValid()
+     */
+    @Test
+    public void testIsValid() throws Exception
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        // No value, this should not be valid
+        assertFalse( attr.isValid( atCN ) );
+
+        attr.add( "test", "test2", "A123\\;" );
+        assertTrue( attr.isValid( atCN ) );
+
+        // If we try to add a wrong value, it will not be added. The
+        // attribute remains valid.
+        assertEquals( 0, attr.add( new byte[]
+            { 0x01 } ) );
+        assertTrue( attr.isValid( atCN ) );
+
+        // test a SINGLE-VALUE attribute. CountryName is SINGLE-VALUE
+        attr.clear();
+        attr.apply( atC );
+        attr.add( "FR" );
+        assertTrue( attr.isValid( atC ) );
+        assertEquals( 0, attr.add( "US" ) );
+        assertFalse( attr.contains( "US" ) );
+        assertTrue( attr.isValid( atC ) );
+    }
+
+
+    /**
+     * Test method add( Value... )
+     */
+    @Test
+    public void testAddValueArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atDC );
+
+        int nbAdded = attr1.add( ( String ) null );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( nullStringValue, attr1.get() );
+
+        Attribute attr2 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr2.add( new BinaryValue( atPwd, null ) );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr2.isHumanReadable() );
+        assertEquals( nullBinaryValue, attr2.get() );
+
+        Attribute attr3 = new DefaultAttribute( atCN );
+
+        nbAdded = attr3.add( new StringValue( atCN, "a" ), new StringValue( atCN, "b" ) );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr3.isHumanReadable() );
+        assertTrue( attr3.contains( "a" ) );
+        assertTrue( attr3.contains( "b" ) );
+
+        Attribute attr4 = new DefaultAttribute( atCN );
+
+        nbAdded = attr4.add( new BinaryValue( atPwd, BYTES1 ), new BinaryValue( atPwd, BYTES2 ) );
+        assertEquals( 0, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertFalse( attr4.contains( BYTES1 ) );
+        assertFalse( attr4.contains( BYTES2 ) );
+
+        Attribute attr5 = new DefaultAttribute( atCN );
+
+        nbAdded = attr5.add( new StringValue( atCN, "c" ), new BinaryValue( atPwd, BYTES1 ) );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr5.isHumanReadable() );
+        assertFalse( attr5.contains( "ab" ) );
+        assertTrue( attr5.contains( "c" ) );
+
+        Attribute attr6 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr6.add( new BinaryValue( atPwd, BYTES1 ), new StringValue( atCN, "c" ) );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr6.isHumanReadable() );
+        assertTrue( attr6.contains( BYTES1 ) );
+        assertFalse( attr6.contains( BYTES3 ) );
+
+        Attribute attr7 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr7.add( new BinaryValue( atPwd, null ), new StringValue( atCN, "c" ) );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr7.isHumanReadable() );
+        assertTrue( attr7.contains( nullBinaryValue ) );
+        assertFalse( attr7.contains( BYTES3 ) );
+
+        Attribute attr8 = new DefaultAttribute( atDC );
+
+        nbAdded = attr8.add( new StringValue( atDC, null ), new BinaryValue( atPwd, BYTES1 ) );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr8.isHumanReadable() );
+        assertTrue( attr8.contains( nullStringValue ) );
+        assertFalse( attr8.contains( "ab" ) );
+
+        Attribute attr9 = new DefaultAttribute( atDC );
+
+        nbAdded = attr9.add( new StringValue( ( String ) null ), new StringValue( "ab" ) );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr9.isHumanReadable() );
+        assertTrue( attr9.contains( nullStringValue ) );
+        assertTrue( attr9.contains( "ab" ) );
+
+        Attribute attr10 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr10.add( new BinaryValue( ( byte[] ) null ), new BinaryValue( BYTES1 ) );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr10.isHumanReadable() );
+        assertTrue( attr10.contains( nullBinaryValue ) );
+        assertTrue( attr10.contains( BYTES1 ) );
+    }
+
+
+    /**
+     * Test method add( String... )
+     */
+    @Test
+    public void testAddStringArray() throws LdapInvalidAttributeValueException
+    {
+        Attribute attr1 = new DefaultAttribute( atDC );
+
+        int nbAdded = attr1.add( ( String ) null );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( nullStringValue, attr1.get() );
+
+        Attribute attr2 = new DefaultAttribute( atDC );
+
+        nbAdded = attr2.add( "" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( "", attr2.getString() );
+
+        Attribute attr3 = new DefaultAttribute( atCN );
+
+        nbAdded = attr3.add( "t" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr3.isHumanReadable() );
+        assertEquals( "t", attr3.getString() );
+
+        Attribute attr4 = new DefaultAttribute( atCN );
+
+        nbAdded = attr4.add( "a", "b", "c", "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "a", attr4.getString() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+
+        nbAdded = attr4.add( "e" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "a", attr4.getString() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+        assertTrue( attr4.contains( "e" ) );
+
+        nbAdded = attr4.add( BYTES1 );
+        assertEquals( 0, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "a", attr4.getString() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+        assertTrue( attr4.contains( "e" ) );
+        assertFalse( attr4.contains( "ab" ) );
+
+        Attribute attr5 = new DefaultAttribute( atEMail );
+
+        nbAdded = attr5.add( "a", "b", ( String ) null, "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( "a" ) );
+        assertTrue( attr5.contains( "b" ) );
+        assertTrue( attr5.contains( nullStringValue ) );
+        assertTrue( attr5.contains( "d" ) );
+
+        Attribute attr6 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr6.add( "a", ( String ) null );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr6.isHumanReadable() );
+    }
+
+
+    /**
+     * Test method add( byte[]... )
+     */
+    @Test
+    public void testAddByteArray() throws LdapInvalidAttributeValueException
+    {
+        Attribute attr1 = new DefaultAttribute( atPwd );
+
+        int nbAdded = attr1.add( ( byte[] ) null );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr1.isHumanReadable() );
+        assertTrue( Arrays.equals( nullBinaryValue.getBytes(), attr1.getBytes() ) );
+
+        Attribute attr2 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr2.add( StringConstants.EMPTY_BYTES );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr2.isHumanReadable() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, attr2.getBytes() ) );
+
+        Attribute attr3 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr3.add( BYTES1 );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr3.isHumanReadable() );
+        assertTrue( Arrays.equals( BYTES1, attr3.getBytes() ) );
+
+        Attribute attr4 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr4.add( BYTES1, BYTES2, BYTES3, BYTES4 );
+        assertEquals( 4, nbAdded );
+        assertFalse( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( BYTES1 ) );
+        assertTrue( attr4.contains( BYTES2 ) );
+        assertTrue( attr4.contains( BYTES3 ) );
+        assertTrue( attr4.contains( BYTES4 ) );
+
+        Attribute attr5 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr5.add( BYTES1, BYTES2, ( byte[] ) null, BYTES3 );
+        assertEquals( 4, nbAdded );
+        assertFalse( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( BYTES1 ) );
+        assertTrue( attr5.contains( BYTES2 ) );
+        assertTrue( attr5.contains( ( byte[] ) null ) );
+        assertTrue( attr5.contains( BYTES3 ) );
+
+        Attribute attr6 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr6.add( "ab", ( String ) null );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr6.isHumanReadable() );
+    }
+
+
+    /**
+     * Test method clear()
+     */
+    @Test
+    public void testClear() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( "email", atEMail );
+
+        assertEquals( 0, attr.size() );
+
+        attr.add( ( String ) null, "a", "b" );
+        assertEquals( 3, attr.size() );
+
+        attr.clear();
+        assertTrue( attr.isHumanReadable() );
+        assertEquals( 0, attr.size() );
+        assertEquals( atEMail, attr.getAttributeType() );
+    }
+
+
+    /**
+     * Test method contains( Value... ) throws LdapException
+     */
+    @Test
+    public void testContainsValueArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atEMail );
+
+        assertEquals( 0, attr1.size() );
+        assertFalse( attr1.contains( stringValue1 ) );
+        assertFalse( attr1.contains( nullStringValue ) );
+
+        attr1.add( ( String ) null );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( nullStringValue ) );
+
+        attr1.remove( ( String ) null );
+        assertFalse( attr1.contains( nullStringValue ) );
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( "a", "b", "c" );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( stringValue1 ) );
+        assertTrue( attr1.contains( stringValue2 ) );
+        assertTrue( attr1.contains( stringValue3 ) );
+        assertTrue( attr1.contains( stringValue1, stringValue3 ) );
+        assertFalse( attr1.contains( stringValue4 ) );
+        assertFalse( attr1.contains( nullStringValue ) );
+
+        Attribute attr2 = new DefaultAttribute( atPwd );
+        assertEquals( 0, attr2.size() );
+        assertFalse( attr2.contains( BYTES1 ) );
+        assertFalse( attr2.contains( nullBinaryValue ) );
+
+        attr2.add( ( byte[] ) null );
+        assertEquals( 1, attr2.size() );
+        assertTrue( attr2.contains( nullBinaryValue ) );
+
+        attr2.remove( ( byte[] ) null );
+        assertFalse( attr2.contains( nullBinaryValue ) );
+        assertEquals( 0, attr2.size() );
+
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+        assertEquals( 3, attr2.size() );
+        assertTrue( attr2.contains( binaryValue1 ) );
+        assertTrue( attr2.contains( binaryValue2 ) );
+        assertTrue( attr2.contains( binaryValue3 ) );
+        assertFalse( attr2.contains( nullBinaryValue ) );
+    }
+
+
+    /**
+     * Test method contains( String... )
+     */
+    @Test
+    public void testContainsStringArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atEMail );
+
+        assertEquals( 0, attr1.size() );
+        assertFalse( attr1.contains( "a" ) );
+        assertFalse( attr1.contains( ( String ) null ) );
+
+        attr1.add( ( String ) null );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( ( String ) null ) );
+
+        attr1.remove( ( String ) null );
+        assertFalse( attr1.contains( ( String ) null ) );
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( "a", "b", "c" );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( "a" ) );
+        assertTrue( attr1.contains( "b" ) );
+        assertTrue( attr1.contains( "c" ) );
+        assertFalse( attr1.contains( "e" ) );
+        assertFalse( attr1.contains( ( String ) null ) );
+    }
+
+
+    /**
+     * Test method contains( byte[]... )
+     */
+    @Test
+    public void testContainsByteArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atPwd );
+
+        assertEquals( 0, attr1.size() );
+        assertFalse( attr1.contains( BYTES1 ) );
+        assertFalse( attr1.contains( ( byte[] ) null ) );
+
+        attr1.add( ( byte[] ) null );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( ( byte[] ) null ) );
+
+        attr1.remove( ( byte[] ) null );
+        assertFalse( attr1.contains( ( byte[] ) null ) );
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( BYTES1, BYTES2, BYTES3 );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( BYTES1 ) );
+        assertTrue( attr1.contains( BYTES2 ) );
+        assertTrue( attr1.contains( BYTES3 ) );
+        assertFalse( attr1.contains( BYTES4 ) );
+        assertFalse( attr1.contains( ( byte[] ) null ) );
+    }
+
+
+    /**
+     * Test method testEquals()
+     */
+    @Test
+    public void testEquals() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atCN );
+
+        assertFalse( attr1.equals( null ) );
+
+        Attribute attr2 = new DefaultAttribute( atCN );
+
+        assertTrue( attr1.equals( attr2 ) );
+
+        attr2.setUpId( "CN" );
+        assertTrue( attr1.equals( attr2 ) );
+
+        attr1.setUpId( "CommonName" );
+        assertTrue( attr1.equals( attr2 ) );
+
+        attr1.setUpId( "CN" );
+        assertTrue( attr1.equals( attr2 ) );
+
+        attr1.add( "a", "b", "c" );
+        attr2.add( "c", "b", "a" );
+        assertTrue( attr1.equals( attr2 ) );
+
+        assertTrue( attr1.equals( attr2 ) );
+
+        Attribute attr3 = new DefaultAttribute( atPwd );
+        Attribute attr4 = new DefaultAttribute( atPwd );
+
+        attr3.add( nullBinaryValue );
+        attr4.add( nullBinaryValue );
+        assertTrue( attr3.equals( attr4 ) );
+
+        Attribute attr5 = new DefaultAttribute( atPwd );
+        Attribute attr6 = new DefaultAttribute( atDC );
+        assertFalse( attr5.equals( attr6 ) );
+
+        attr5.add( nullBinaryValue );
+        attr6.add( nullStringValue );
+        assertFalse( attr5.equals( attr6 ) );
+
+        Attribute attr7 = new DefaultAttribute( atCN );
+        Attribute attr8 = new DefaultAttribute( atPwd );
+
+        attr7.add( "a" );
+        attr8.add( BYTES2 );
+        assertFalse( attr7.equals( attr8 ) );
+
+        Attribute attr9 = new DefaultAttribute( atCN );
+        Attribute attr10 = new DefaultAttribute( atPwd );
+
+        attr9.add( "a" );
+        attr9.add( BYTES2 );
+        attr10.add( "a", "b" );
+        assertFalse( attr9.equals( attr10 ) );
+
+        Attribute attr11 = new DefaultAttribute( atPwd, BYTES1 );
+        Attribute attr12 = new DefaultAttribute( atPwd, BYTES1 );
+
+        assertTrue( attr11.get().equals( attr12.get() ) );
+        assertTrue( attr12.get().equals( attr11.get() ) );
+
+        Attribute attr13 = new DefaultAttribute( "userPassword", BYTES1 );
+
+        assertTrue( attr11.get().equals( attr13.get() ) );
+        assertTrue( attr13.get().equals( attr11.get() ) );
+
+        Attribute attr14 = new DefaultAttribute( "userPassword", BYTES1 );
+
+        assertTrue( attr14.get().equals( attr13.get() ) );
+        assertTrue( attr13.get().equals( attr14.get() ) );
+    }
+
+
+    /**
+     * Test method get()
+     */
+    @Test
+    public void testGet() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "dc", atDC );
+
+        attr1.add( ( String ) null );
+        assertEquals( nullStringValue, attr1.get() );
+
+        Attribute attr2 = new DefaultAttribute( "email", atEMail );
+
+        attr2.add( "a", "b", "c" );
+        assertEquals( "a", attr2.get().getString() );
+
+        attr2.remove( "a" );
+        assertEquals( "b", attr2.get().getString() );
+
+        attr2.remove( "b" );
+        assertEquals( "c", attr2.get().getString() );
+
+        attr2.remove( "c" );
+        assertNull( attr2.get() );
+
+        Attribute attr3 = new DefaultAttribute( "userPassword", atPwd );
+
+        attr3.add( BYTES1, BYTES2, BYTES3 );
+        assertTrue( Arrays.equals( BYTES1, attr3.get().getBytes() ) );
+
+        attr3.remove( BYTES1 );
+        assertTrue( Arrays.equals( BYTES2, attr3.get().getBytes() ) );
+
+        attr3.remove( BYTES2 );
+        assertTrue( Arrays.equals( BYTES3, attr3.get().getBytes() ) );
+
+        attr3.remove( BYTES3 );
+        assertNull( attr2.get() );
+    }
+
+
+    /**
+     * Test method getAll()
+     */
+    @Test
+    public void testIterator2() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( atEMail );
+
+        Iterator<Value<?>> iterator = attr.iterator();
+        assertFalse( iterator.hasNext() );
+
+        attr.add( nullStringValue );
+        iterator = attr.iterator();
+        assertTrue( iterator.hasNext() );
+
+        Value<?> value = iterator.next();
+        assertEquals( nullStringValue, value );
+
+        attr.clear();
+        iterator = attr.iterator();
+        assertFalse( iterator.hasNext() );
+
+        attr.add( "a", "b", "c" );
+        iterator = attr.iterator();
+        assertTrue( iterator.hasNext() );
+        assertEquals( "a", iterator.next().getString() );
+        assertEquals( "b", iterator.next().getString() );
+        assertEquals( "c", iterator.next().getString() );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    /**
+     * Test method size()
+     */
+    @Test
+    public void testSize() throws Exception
+    {
+        Attribute attr1 = new DefaultAttribute( atDC );
+
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( ( String ) null );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( atCN );
+
+        attr2.add( "a", "b" );
+        assertEquals( 2, attr2.size() );
+
+        attr2.clear();
+        assertEquals( 0, attr2.size() );
+
+        Attribute attr3 = new DefaultAttribute( atC );
+
+        attr3.add( "US" );
+        assertEquals( 1, attr3.size() );
+
+        // TODO : forbid addition of more than 1 value for SINGLE-VALUE attributes
+        attr3.add( "FR" );
+        assertEquals( 1, attr3.size() );
+    }
+
+
+    /**
+     * Test method put( byte[]... )
+     */
+    @Test
+    public void testPutByteArray() throws LdapException, Exception
+    {
+        Attribute attr1 = new DefaultAttribute( atPwd );
+
+        int nbAdded = attr1.add( ( byte[] ) null );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr1.isHumanReadable() );
+        assertTrue( Arrays.equals( nullBinaryValue.getBytes(), attr1.getBytes() ) );
+
+        Attribute attr2 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr2.add( StringConstants.EMPTY_BYTES );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr2.isHumanReadable() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, attr2.getBytes() ) );
+
+        Attribute attr3 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr3.add( BYTES1 );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr3.isHumanReadable() );
+        assertTrue( Arrays.equals( BYTES1, attr3.getBytes() ) );
+
+        Attribute attr4 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr4.add( BYTES1, BYTES2 );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( BYTES1 ) );
+        assertTrue( attr4.contains( BYTES2 ) );
+
+        attr4.clear();
+        nbAdded = attr4.add( BYTES3, BYTES4 );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( BYTES3 ) );
+        assertTrue( attr4.contains( BYTES4 ) );
+
+        Attribute attr5 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr5.add( BYTES1, BYTES2, ( byte[] ) null, BYTES3 );
+        assertEquals( 4, nbAdded );
+        assertFalse( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( BYTES1 ) );
+        assertTrue( attr5.contains( BYTES2 ) );
+        assertTrue( attr5.contains( ( byte[] ) null ) );
+        assertTrue( attr5.contains( BYTES3 ) );
+
+        Attribute attr6 = new DefaultAttribute( atPwd );
+
+        assertFalse( attr6.isHumanReadable() );
+        nbAdded = attr6.add( BYTES1, ( byte[] ) null );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr6.contains( BYTES1 ) );
+        assertTrue( attr6.contains( ( byte[] ) null ) );
+    }
+
+
+    /**
+     * Test method put( String... )
+     */
+    @Test
+    public void testPutStringArray() throws LdapInvalidAttributeValueException
+    {
+        Attribute attr1 = new DefaultAttribute( atDC );
+
+        int nbAdded = attr1.add( ( String ) null );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( nullStringValue, attr1.get() );
+
+        Attribute attr2 = new DefaultAttribute( atDC );
+
+        nbAdded = attr2.add( "" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( "", attr2.getString() );
+
+        Attribute attr3 = new DefaultAttribute( atDC );
+
+        nbAdded = attr3.add( "t" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr3.isHumanReadable() );
+        assertEquals( "t", attr3.getString() );
+
+        Attribute attr4 = new DefaultAttribute( atEMail );
+
+        nbAdded = attr4.add( "a", "b", "c", "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "a", attr4.getString() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+
+        attr4.clear();
+        nbAdded = attr4.add( "e" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "e", attr4.getString() );
+        assertFalse( attr4.contains( "a" ) );
+        assertFalse( attr4.contains( "b" ) );
+        assertFalse( attr4.contains( "c" ) );
+        assertFalse( attr4.contains( "d" ) );
+        assertTrue( attr4.contains( "e" ) );
+
+        attr4.clear();
+        nbAdded = attr4.add( BYTES1 );
+        assertEquals( 0, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+
+        Attribute attr5 = new DefaultAttribute( atEMail );
+
+        nbAdded = attr5.add( "a", "b", ( String ) null, "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( "a" ) );
+        assertTrue( attr5.contains( "b" ) );
+        assertTrue( attr5.contains( nullStringValue ) );
+        assertTrue( attr5.contains( "d" ) );
+
+        Attribute attr6 = new DefaultAttribute( atPwd );
+
+        nbAdded = attr6.add( "a", ( String ) null );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr6.isHumanReadable() );
+    }
+
+
+    /**
+     * Test method put( Value... )
+     */
+    @Test
+    public void testPutValueArray() throws Exception
+    {
+        Attribute attr1 = new DefaultAttribute( atDC );
+
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( nullStringValue );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( nullStringValue ) );
+
+        attr1.clear();
+        attr1.add( stringValue1, stringValue2, stringValue3 );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( stringValue1 ) );
+        assertTrue( attr1.contains( stringValue2 ) );
+        assertTrue( attr1.contains( stringValue3 ) );
+
+        attr1.clear();
+        attr1.add( stringValue1, nullStringValue, stringValue3 );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( stringValue1 ) );
+        assertTrue( attr1.contains( nullStringValue ) );
+        assertTrue( attr1.contains( stringValue3 ) );
+
+        attr1.clear();
+        attr1.add( stringValue1, nullStringValue, binaryValue3 );
+        assertEquals( 2, attr1.size() );
+        assertTrue( attr1.contains( stringValue1 ) );
+        assertTrue( attr1.contains( nullStringValue ) );
+        assertFalse( attr1.contains( stringValue3 ) );
+
+        Attribute attr2 = new DefaultAttribute( atPwd );
+        assertEquals( 0, attr2.size() );
+
+        attr2.add( nullBinaryValue );
+        assertEquals( 1, attr2.size() );
+        assertTrue( attr2.contains( nullBinaryValue ) );
+
+        attr2.clear();
+        attr2.add( binaryValue1, binaryValue2, binaryValue3 );
+        assertEquals( 3, attr2.size() );
+        assertTrue( attr2.contains( binaryValue1 ) );
+        assertTrue( attr2.contains( binaryValue2 ) );
+        assertTrue( attr2.contains( binaryValue3 ) );
+
+        attr2.clear();
+        attr2.add( binaryValue1, nullBinaryValue, stringValue3 );
+        assertEquals( 2, attr2.size() );
+        assertTrue( attr2.contains( binaryValue1 ) );
+        assertTrue( attr2.contains( nullBinaryValue ) );
+        assertFalse( attr2.contains( binaryValue3 ) );
+    }
+
+
+    /**
+     * Test method remove( Value... )
+     */
+    @Test
+    public void testRemoveValueArray() throws Exception
+    {
+        Attribute attr1 = new DefaultAttribute( atEMail );
+
+        assertFalse( attr1.remove( stringValue1 ) );
+
+        attr1.add( "a", "b", "c" );
+        assertTrue( attr1.remove( stringValue1 ) );
+        assertEquals( 2, attr1.size() );
+
+        assertTrue( attr1.remove( stringValue2, stringValue3 ) );
+        assertEquals( 0, attr1.size() );
+
+        assertFalse( attr1.remove( stringValue4 ) );
+
+        attr1.clear();
+        attr1.add( "a", "b", "c" );
+        assertFalse( attr1.remove( stringValue2, stringValue4 ) );
+        assertEquals( 2, attr1.size() );
+
+        attr1.clear();
+        attr1.add( "a", ( String ) null, "b" );
+        assertTrue( attr1.remove( nullStringValue, stringValue1 ) );
+        assertEquals( 1, attr1.size() );
+
+        attr1.clear();
+        attr1.add( "a", ( String ) null, "b" );
+        attr1.add( BYTES3 );
+        assertFalse( attr1.remove( nullStringValue, stringValue1, binaryValue3 ) );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( atPwd );
+
+        assertFalse( attr2.remove( binaryValue1 ) );
+
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+        assertTrue( attr2.remove( binaryValue1 ) );
+        assertEquals( 2, attr2.size() );
+
+        assertTrue( attr2.remove( binaryValue2, binaryValue3 ) );
+        assertEquals( 0, attr2.size() );
+
+        assertFalse( attr2.remove( binaryValue4 ) );
+
+        attr2.clear();
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+        assertFalse( attr2.remove( binaryValue2, stringValue4 ) );
+        assertEquals( 2, attr2.size() );
+
+        attr2.clear();
+        attr2.add( BYTES1, ( byte[] ) null, BYTES3 );
+        assertFalse( attr2.remove( nullStringValue, binaryValue1 ) );
+        assertEquals( 2, attr2.size() );
+
+        attr2.clear();
+        attr2.add( BYTES1, ( byte[] ) null, BYTES2 );
+        attr2.add( "c" );
+        assertEquals( 4, attr2.size() );
+        assertFalse( attr2.remove( nullStringValue, binaryValue1, stringValue3 ) );
+        assertEquals( 3, attr2.size() );
+    }
+
+
+    /**
+     * Test method remove( byte... )
+     */
+    @Test
+    public void testRemoveByteArray() throws Exception
+    {
+        Attribute attr1 = new DefaultAttribute( atPwd );
+
+        assertFalse( attr1.remove( BYTES1 ) );
+
+        attr1.add( BYTES1, BYTES2, BYTES3 );
+        assertTrue( attr1.remove( BYTES1 ) );
+        assertEquals( 2, attr1.size() );
+
+        assertTrue( attr1.remove( BYTES2, BYTES3 ) );
+        assertEquals( 0, attr1.size() );
+
+        assertFalse( attr1.remove( BYTES4 ) );
+
+        attr1.clear();
+        attr1.add( BYTES1, BYTES2, BYTES3 );
+        assertFalse( attr1.remove( BYTES3, BYTES4 ) );
+        assertEquals( 2, attr1.size() );
+
+        attr1.clear();
+        attr1.add( BYTES1, ( byte[] ) null, BYTES2 );
+        assertTrue( attr1.remove( ( byte[] ) null, BYTES1 ) );
+        assertEquals( 1, attr1.size() );
+    }
+
+
+    /**
+     * Test method remove( String... )
+     */
+    @Test
+    public void testRemoveStringArray() throws Exception
+    {
+        Attribute attr1 = new DefaultAttribute( atEMail );
+
+        assertFalse( attr1.remove( "a" ) );
+
+        attr1.add( "a", "b", "c" );
+        assertTrue( attr1.remove( "a" ) );
+        assertEquals( 2, attr1.size() );
+
+        assertTrue( attr1.remove( "b", "c" ) );
+        assertEquals( 0, attr1.size() );
+
+        assertFalse( attr1.remove( "d" ) );
+
+        attr1.clear();
+        attr1.add( "a", "b", "c" );
+        assertFalse( attr1.remove( "b", "e" ) );
+        assertEquals( 2, attr1.size() );
+
+        attr1.clear();
+        attr1.add( "a", ( String ) null, "b" );
+        assertTrue( attr1.remove( ( String ) null, "a" ) );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+
+        assertFalse( attr2.remove( ( String ) null ) );
+        assertTrue( attr2.remove( "ab", "c" ) );
+        assertFalse( attr2.remove( "d" ) );
+    }
+
+
+    /**
+     * Test method iterator()
+     */
+    @Test
+    public void testIterator() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atCN );
+        attr1.add( "a", "b", "c" );
+
+        Iterator<Value<?>> iter = attr1.iterator();
+
+        assertTrue( iter.hasNext() );
+
+        String[] values = new String[]
+            { "a", "b", "c" };
+        int pos = 0;
+
+        for ( Value<?> val : attr1 )
+        {
+            assertTrue( val instanceof StringValue );
+            assertEquals( values[pos++], val.getString() );
+        }
+    }
+
+
+    /**
+     * Test method toString
+     */
+    @Test
+    public void testToString() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( atEMail );
+
+        assertEquals( "email: (null)", attr.toString() );
+
+        attr.setUpId( "EMail" );
+        assertEquals( "EMail: (null)", attr.toString() );
+
+        attr.add( ( String ) null );
+        assertEquals( "EMail: ''", attr.toString() );
+
+        attr.clear();
+        attr.add( "a", "b" );
+        assertEquals( "EMail: a\nEMail: b", attr.toString() );
+    }
+
+
+    /**
+     * Test method instanceOf()
+     */
+    @Test
+    public void testInstanceOf() throws Exception
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        assertTrue( attr.isInstanceOf( atCN ) );
+        assertTrue( attr.isInstanceOf( atName ) );
+        assertFalse( attr.isInstanceOf( atSN ) );
+    }
+
+
+    /**
+     * Test method setUpId( String, AttributeType )
+     */
+    @Test
+    public void testSetUpIdStringAttributeType() throws Exception
+    {
+        Attribute attr = new DefaultAttribute( atSN );
+
+        attr.setUpId( null, atCN );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        attr.setUpId( "  ", atCN );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        attr.setUpId( "  CN  ", atCN );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "  CN  ", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        attr.setUpId( "  CommonName  ", atCN );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "  CommonName  ", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        attr.setUpId( "  2.5.4.3  ", atCN );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "  2.5.4.3  ", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        // Check with wrong IDs
+        try
+        {
+            attr.setUpId( "sn", atCN );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            attr.setUpId( "  2.5.4.4  ", atCN );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test method setUpId( String ) inherited from ClientAttribute
+     */
+    @Test
+    public void testSetUpIdString() throws Exception
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        attr.setUpId( "cn" );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        attr.setUpId( "  CN  " );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "  CN  ", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        attr.setUpId( "  CommonName  " );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "  CommonName  ", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        attr.setUpId( "  2.5.4.3  " );
+        assertEquals( "  2.5.4.3  ", attr.getUpId() );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        // Now check wrong IDs
+        attr = new DefaultAttribute( atCN );
+
+        try
+        {
+            attr.setUpId( "sn" );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        try
+        {
+            attr.setUpId( "  SN  " );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        try
+        {
+            attr.setUpId( "  surname  " );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+
+        try
+        {
+            attr.setUpId( "  2.5.4.4  " );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+    }
+
+
+    /**
+     * Test method setAttributeType( AttributeType )
+     */
+    @Test
+    public void testSetAttributeType() throws Exception
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        try
+        {
+            attr.apply( null );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        attr.apply( atSN );
+
+        assertTrue( attr.isInstanceOf( atSN ) );
+        assertEquals( "2.5.4.4", attr.getId() );
+        assertEquals( "sn", attr.getUpId() );
+    }
+
+
+    /**
+     * Test method getAttributeType()
+     */
+    @Test
+    public void testGetAttributeType() throws Exception
+    {
+        Attribute attr = new DefaultAttribute( atSN );
+        assertEquals( atSN, attr.getAttributeType() );
+    }
+
+
+    /**
+     * Test constructor DefaultEntryAttribute( AttributeType )
+     */
+    @Test
+    public void testDefaultServerAttributeAttributeType()
+    {
+        Attribute attr = new DefaultAttribute( atCN );
+
+        assertTrue( attr.isHumanReadable() );
+        assertEquals( 0, attr.size() );
+        assertEquals( "2.5.4.3", attr.getId() );
+        assertEquals( "cn", attr.getUpId() );
+        assertEquals( atCN, attr.getAttributeType() );
+    }
+
+
+    /**
+     * Test constructor DefaultEntryAttribute( String, AttributeType )
+     */
+    @Test
+    public void testDefaultServerAttributeStringAttributeType()
+    {
+        Attribute attr1 = new DefaultAttribute( "cn", atCN );
+
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( 0, attr1.size() );
+        assertEquals( "2.5.4.3", attr1.getId() );
+        assertEquals( "cn", attr1.getUpId() );
+        assertEquals( atCN, attr1.getAttributeType() );
+
+        Attribute attr2 = new DefaultAttribute( "  CommonName  ", atCN );
+
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( 0, attr2.size() );
+        assertEquals( "2.5.4.3", attr2.getId() );
+        assertEquals( "  CommonName  ", attr2.getUpId() );
+        assertEquals( atCN, attr2.getAttributeType() );
+
+        Attribute attr3 = new DefaultAttribute( "  ", atCN );
+
+        assertTrue( attr3.isHumanReadable() );
+        assertEquals( 0, attr3.size() );
+        assertEquals( "2.5.4.3", attr3.getId() );
+        assertEquals( "cn", attr3.getUpId() );
+        assertEquals( atCN, attr3.getAttributeType() );
+    }
+
+
+    /**
+     * Test constructor DefaultEntryAttribute( AttributeType, Value... )
+     */
+    @Test
+    public void testDefaultServerAttributeAttributeTypeValueArray() throws Exception
+    {
+        Attribute attr1 = new DefaultAttribute( atDC, stringValue1, stringValue2, nullStringValue );
+
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( 3, attr1.size() );
+        assertEquals( "0.9.2342.19200300.100.1.25", attr1.getId() );
+        assertEquals( "dc", attr1.getUpId() );
+        assertEquals( atDC, attr1.getAttributeType() );
+        assertTrue( attr1.contains( "a", "b" ) );
+        assertTrue( attr1.contains( nullStringValue ) );
+
+        Attribute attr2 = new DefaultAttribute( atDC, stringValue1, binaryValue2, nullStringValue );
+
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( 2, attr2.size() );
+        assertEquals( "0.9.2342.19200300.100.1.25", attr2.getId() );
+        assertEquals( "dc", attr2.getUpId() );
+        assertEquals( atDC, attr2.getAttributeType() );
+        assertTrue( attr2.contains( "a" ) );
+        assertTrue( attr2.contains( nullStringValue ) );
+    }
+
+
+    /**
+     * Test constructor DefaultEntryAttribute( String, AttributeType, Value... )
+     */
+    @Test
+    public void testDefaultServerAttributeStringAttributeTypeValueArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "dc", atDC, stringValue1, stringValue2, nullStringValue );
+
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( 3, attr1.size() );
+        assertEquals( "0.9.2342.19200300.100.1.25", attr1.getId() );
+        assertEquals( "dc", attr1.getUpId() );
+        assertEquals( atDC, attr1.getAttributeType() );
+        assertTrue( attr1.contains( "a", "b" ) );
+        assertTrue( attr1.contains( nullStringValue ) );
+
+        Attribute attr2 = new DefaultAttribute( atDC, stringValue1, binaryValue2, nullStringValue );
+
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( 2, attr2.size() );
+        assertEquals( "0.9.2342.19200300.100.1.25", attr2.getId() );
+        assertEquals( "dc", attr2.getUpId() );
+        assertEquals( atDC, attr2.getAttributeType() );
+        assertTrue( attr2.contains( "a" ) );
+        assertTrue( attr2.contains( nullStringValue ) );
+
+        Attribute attr3 = new DefaultAttribute( "DomainComponent", atDC, stringValue1, stringValue2,
+            nullStringValue );
+
+        assertTrue( attr3.isHumanReadable() );
+        assertEquals( 3, attr3.size() );
+        assertEquals( "0.9.2342.19200300.100.1.25", attr3.getId() );
+        assertEquals( "DomainComponent", attr3.getUpId() );
+        assertEquals( atDC, attr3.getAttributeType() );
+        assertTrue( attr3.contains( "a", "b" ) );
+        assertTrue( attr3.contains( nullStringValue ) );
+
+        Attribute attr4 = new DefaultAttribute( " 0.9.2342.19200300.100.1.25 ", atDC, stringValue1, stringValue2,
+            nullStringValue );
+
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( 3, attr4.size() );
+        assertEquals( "0.9.2342.19200300.100.1.25", attr4.getId() );
+        assertEquals( " 0.9.2342.19200300.100.1.25 ", attr4.getUpId() );
+        assertEquals( atDC, attr4.getAttributeType() );
+        assertTrue( attr4.contains( "a", "b" ) );
+        assertTrue( attr4.contains( nullStringValue ) );
+    }
+
+
+    /**
+     * Test constructor DefaultEntryAttribute( AttributeType, String... )
+     */
+    @Test
+    public void testDefaultServerAttributeAttributeTypeStringArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atEMail, "a", "b", ( String ) null );
+
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( 3, attr1.size() );
+        assertEquals( "1.2.840.113549.1.9.1", attr1.getId() );
+        assertEquals( "email", attr1.getUpId() );
+        assertEquals( atEMail, attr1.getAttributeType() );
+        assertTrue( attr1.contains( "a", "b" ) );
+        assertTrue( attr1.contains( nullStringValue ) );
+
+        Attribute attr2 = new DefaultAttribute( atEMail, stringValue1, binaryValue2, nullStringValue );
+
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( 2, attr2.size() );
+        assertEquals( "1.2.840.113549.1.9.1", attr2.getId() );
+        assertEquals( "email", attr2.getUpId() );
+        assertEquals( atEMail, attr2.getAttributeType() );
+        assertTrue( attr2.contains( "a" ) );
+        assertTrue( attr2.contains( nullStringValue ) );
+    }
+
+
+    /**
+     * Test constructor DefaultEntryAttribute( String, AttributeType, String... )
+     */
+    @Test
+    public void testDefaultServerAttributeStringAttributeTypeStringArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "email", atEMail, "a", "b", ( String ) null );
+
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( 3, attr1.size() );
+        assertEquals( "1.2.840.113549.1.9.1", attr1.getId() );
+        assertEquals( "email", attr1.getUpId() );
+        assertEquals( atEMail, attr1.getAttributeType() );
+        assertTrue( attr1.contains( "a", "b" ) );
+        assertTrue( attr1.contains( nullStringValue ) );
+
+        Attribute attr2 = new DefaultAttribute( "EMail", atEMail, "a", "b", ( String ) null );
+
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( 3, attr2.size() );
+        assertEquals( "1.2.840.113549.1.9.1", attr2.getId() );
+        assertEquals( "EMail", attr2.getUpId() );
+        assertEquals( atEMail, attr2.getAttributeType() );
+        assertTrue( attr2.contains( "a", "b" ) );
+        assertTrue( attr2.contains( nullStringValue ) );
+
+        Attribute attr3 = new DefaultAttribute( " 1.2.840.113549.1.9.1 ", atEMail, "a", "b",
+            ( String ) null );
+
+        assertTrue( attr3.isHumanReadable() );
+        assertEquals( 3, attr3.size() );
+        assertEquals( "1.2.840.113549.1.9.1", attr3.getId() );
+        assertEquals( " 1.2.840.113549.1.9.1 ", attr3.getUpId() );
+        assertEquals( atEMail, attr3.getAttributeType() );
+        assertTrue( attr3.contains( "a", "b" ) );
+        assertTrue( attr3.contains( nullStringValue ) );
+    }
+
+
+    /**
+     * Test method DefaultEntryAttribute( AttributeType, byte[]... )
+     */
+    @Test
+    public void testDefaultServerAttributeAttributeTypeByteArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( atPwd, BYTES1, BYTES2, ( byte[] ) null );
+
+        assertFalse( attr1.isHumanReadable() );
+        assertEquals( 3, attr1.size() );
+        assertEquals( "2.5.4.35", attr1.getId() );
+        assertEquals( "userPassword", attr1.getUpId() );
+        assertEquals( atPwd, attr1.getAttributeType() );
+        assertTrue( attr1.contains( BYTES1, BYTES2 ) );
+        assertTrue( attr1.contains( nullBinaryValue ) );
+
+        Attribute attr2 = new DefaultAttribute( atPwd, stringValue1, binaryValue2, nullBinaryValue );
+
+        assertFalse( attr2.isHumanReadable() );
+        assertEquals( 2, attr2.size() );
+        assertEquals( "2.5.4.35", attr2.getId() );
+        assertEquals( "userPassword", attr2.getUpId() );
+        assertEquals( atPwd, attr2.getAttributeType() );
+        assertTrue( attr2.contains( BYTES2 ) );
+        assertTrue( attr2.contains( nullBinaryValue ) );
+    }
+
+
+    /**
+     * Test method DefaultEntryAttribute( String, AttributeType, byte[]... )
+     */
+    @Test
+    public void testDefaultServerAttributeStringAttributeTypeByteArray() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "userPassword", atPwd, BYTES1, BYTES2, ( byte[] ) null );
+
+        assertFalse( attr1.isHumanReadable() );
+        assertEquals( 3, attr1.size() );
+        assertEquals( "2.5.4.35", attr1.getId() );
+        assertEquals( "userPassword", attr1.getUpId() );
+        assertEquals( atPwd, attr1.getAttributeType() );
+        assertTrue( attr1.contains( BYTES1, BYTES2 ) );
+        assertTrue( attr1.contains( nullBinaryValue ) );
+
+        Attribute attr2 = new DefaultAttribute( "2.5.4.35", atPwd, stringValue1, binaryValue2, nullBinaryValue );
+
+        assertFalse( attr2.isHumanReadable() );
+        assertEquals( 2, attr2.size() );
+        assertEquals( "2.5.4.35", attr2.getId() );
+        assertEquals( "2.5.4.35", attr2.getUpId() );
+        assertEquals( atPwd, attr2.getAttributeType() );
+        assertTrue( attr2.contains( BYTES2 ) );
+        assertTrue( attr2.contains( nullBinaryValue ) );
+    }
+
+
+    /**
+     * Test method testClone()
+     */
+    @Test
+    public void testClone() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( atDC );
+
+        Attribute clone = attr.clone();
+
+        assertEquals( attr, clone );
+        attr.setUpId( "DomainComponent" );
+        assertEquals( "0.9.2342.19200300.100.1.25", clone.getId() );
+
+        attr.add( "a", ( String ) null, "b" );
+        clone = attr.clone();
+        assertEquals( attr, clone );
+
+        attr.remove( "a" );
+        assertNotSame( attr, clone );
+
+        clone = attr.clone();
+        assertEquals( attr, clone );
+    }
+
+
+    /**
+     * Test the copy constructor of a EntryAttribute
+     */
+    @Test
+    public void testCopyConstructorServerAttribute() throws LdapException
+    {
+        Attribute attribute = new DefaultAttribute( atCN );
+
+        Attribute copy = new DefaultAttribute( atCN, attribute );
+
+        assertEquals( copy, attribute );
+
+        Attribute attribute2 = new DefaultAttribute( atCN, "test" );
+
+        Attribute copy2 = new DefaultAttribute( atCN, attribute2 );
+
+        assertEquals( copy2, attribute2 );
+        attribute2.add( "test2" );
+        assertNotSame( copy2, attribute2 );
+        assertEquals( "test", copy2.getString() );
+    }
+
+
+    /**
+     * Test the copy constructor of a ClientAttribute
+     */
+    @Test
+    public void testCopyConstructorClientAttribute() throws LdapException
+    {
+        Attribute attribute = new DefaultAttribute( "commonName" );
+        attribute.add( "test" );
+
+        Attribute copy = new DefaultAttribute( atCN, attribute );
+
+        assertEquals( atCN, copy.getAttributeType() );
+        assertEquals( "test", copy.getString() );
+        assertTrue( copy.isHumanReadable() );
+
+        attribute.add( "test2" );
+        assertFalse( copy.contains( "test2" ) );
+    }
+
+
+    /**
+     * Test the conversion method
+     */
+    @Test
+    public void testToClientAttribute() throws LdapException
+    {
+        Attribute attribute = new DefaultAttribute( atCN, "test", "test2" );
+
+        Attribute clientAttribute = attribute.clone();
+
+        assertTrue( clientAttribute instanceof Attribute );
+
+        assertTrue( clientAttribute.contains( "test", "test2" ) );
+        assertEquals( "2.5.4.3", clientAttribute.getId() );
+
+        attribute.remove( "test", "test2" );
+        assertTrue( clientAttribute.contains( "test", "test2" ) );
+    }
+
+
+    /**
+     * Test the serialization of a complete server attribute
+     */
+    @Test
+    public void testSerializeCompleteAttribute() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dsa = new DefaultAttribute( atCN );
+        dsa.setUpId( "CommonName" );
+        dsa.add( "test1", "test2" );
+
+        DefaultAttribute dsaSer = deserializeValue( serializeValue( dsa ), atCN );
+        assertEquals( dsa.toString(), dsaSer.toString() );
+        assertEquals( "2.5.4.3", dsaSer.getId() );
+        assertEquals( "CommonName", dsaSer.getUpId() );
+        assertEquals( "test1", dsaSer.getString() );
+        assertTrue( dsaSer.contains( "test2", "test1" ) );
+        assertTrue( dsaSer.isHumanReadable() );
+    }
+
+
+    /**
+     * Test the serialization of a server attribute with no value
+     */
+    @Test
+    public void testSerializeAttributeWithNoValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dsa = new DefaultAttribute( atCN );
+        dsa.setUpId( "cn" );
+
+        DefaultAttribute dsaSer = deserializeValue( serializeValue( dsa ), atCN );
+        assertEquals( dsa.toString(), dsaSer.toString() );
+        assertEquals( "2.5.4.3", dsaSer.getId() );
+        assertEquals( "cn", dsaSer.getUpId() );
+        assertEquals( 0, dsaSer.size() );
+        assertTrue( dsaSer.isHumanReadable() );
+    }
+
+
+    /**
+     * Test the serialization of a server attribute with a null value
+     */
+    @Test
+    public void testSerializeAttributeNullValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dsa = new DefaultAttribute( atDC );
+        dsa.setUpId( "DomainComponent" );
+        dsa.add( ( String ) null );
+
+        DefaultAttribute dsaSer = deserializeValue( serializeValue( dsa ), atDC );
+        assertEquals( dsa.toString(), dsaSer.toString() );
+        assertEquals( "0.9.2342.19200300.100.1.25", dsaSer.getId() );
+        assertEquals( "DomainComponent", dsaSer.getUpId() );
+        assertEquals( "", dsaSer.getString() );
+        assertEquals( 1, dsaSer.size() );
+        assertTrue( dsaSer.contains( ( String ) null ) );
+        assertTrue( dsaSer.isHumanReadable() );
+    }
+
+
+    /**
+     * Test the serialization of a server attribute with a binary value
+     */
+    @Test
+    public void testSerializeAttributeBinaryValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dsa = new DefaultAttribute( atPwd );
+        byte[] password = Strings.getBytesUtf8( "secret" );
+        dsa.add( password );
+
+        DefaultAttribute dsaSer = deserializeValue( serializeValue( dsa ), atPwd );
+        assertEquals( dsa.toString(), dsaSer.toString() );
+        assertEquals( "2.5.4.35", dsaSer.getId() );
+        assertEquals( "userPassword", dsaSer.getUpId() );
+        assertTrue( Arrays.equals( dsa.getBytes(), dsaSer.getBytes() ) );
+        assertEquals( 1, dsaSer.size() );
+        assertTrue( dsaSer.contains( password ) );
+        assertFalse( dsaSer.isHumanReadable() );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareEntrySerializationTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareEntrySerializationTest.java
new file mode 100644
index 0000000..4946277
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareEntrySerializationTest.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Entry Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaAwareEntrySerializationTest
+{
+    private static SchemaManager schemaManager;
+
+
+    /**
+     * Initialize OIDs maps for normalization
+     */
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    @Test
+    public void testEntryFullSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry(
+            schemaManager,
+            "dc=example, dc=com",
+            "ObjectClass: top",
+            "ObjectClass: domain",
+            "dc: example",
+            "l: test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry( schemaManager );
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertTrue( entry2.contains( "2.5.4.0", "top", "domain" ) );
+    }
+
+
+    @Test
+    public void testEntryNoDnSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry(
+            schemaManager,
+            "",
+            "ObjectClass: top",
+            "ObjectClass: domain",
+            "dc: example",
+            "l: test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry( schemaManager );
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertTrue( entry2.contains( "ObjectClass", "top", "domain" ) );
+        assertEquals( "", entry2.getDn().toString() );
+    }
+
+
+    @Test
+    public void testEntryNoAttributesSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry( schemaManager, "dc=example, dc=com" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry( schemaManager );
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertEquals( 0, entry2.size() );
+    }
+
+
+    @Test
+    public void testEntryNoAttributesNoDnSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry( schemaManager, "" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry( schemaManager );
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertEquals( 0, entry2.size() );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareEntryTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareEntryTest.java
new file mode 100644
index 0000000..f8256d1
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareEntryTest.java
@@ -0,0 +1,1268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test class for the DefaultEntry class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaAwareEntryTest
+{
+    private static Dn exampleDn;
+    private static final byte[] BYTES1 = new byte[]
+        { 'a', 'b' };
+    private static final byte[] BYTES2 = new byte[]
+        { 'b' };
+    private static final byte[] BYTES3 = new byte[]
+        { 'c' };
+
+    private static SchemaManager schemaManager;
+
+
+    /**
+     * Helper method which creates an entry with 4 attributes.
+     */
+    private Entry createEntry()
+    {
+        try
+        {
+            Entry entry = new DefaultEntry( exampleDn );
+
+            Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+            Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+            Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+            Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+            entry.put( attrOC, attrCN, attrSN, attrPWD );
+
+            return entry;
+        }
+        catch ( LdapException ne )
+        {
+            // Do nothing
+            return null;
+        }
+    }
+
+
+    /**
+     * Serialize a ClientEntry
+     */
+    private ByteArrayOutputStream serializeValue( Entry value ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+            oOut.writeObject( value );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a ClientEntry
+     */
+    private Entry deserializeValue( ByteArrayOutputStream out ) throws IOException, ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+
+            Entry value = ( Entry ) oIn.readObject();
+
+            return value;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception
+    {
+        exampleDn = new Dn( "dc=example,dc=com" );
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    /**
+     * Test method for DefaultEntry()
+     */
+    @Test
+    public void testDefaultClientEntry()
+    {
+        Entry entry = new DefaultEntry();
+
+        assertNotNull( entry );
+        assertEquals( Dn.EMPTY_DN, entry.getDn() );
+        assertEquals( 0, entry.size() );
+    }
+
+
+    /**
+     * Test method for DefaultEntry()
+     */
+    @Test
+    public void testDefaultClientEntryLdif() throws Exception
+    {
+        Entry entry = new DefaultEntry(
+            "ou=example, dc=com",
+            "ObjectClass: top",
+            "ObjectClass: person",
+            "cn: test",
+            "sn: test" );
+
+        assertNotNull( entry );
+        assertEquals( "ou=example, dc=com", entry.getDn().toString() );
+        assertEquals( 3, entry.size() );
+        assertTrue( entry.contains( "objectClass", "top", "person" ) );
+        assertTrue( entry.contains( "cn", "test" ) );
+        assertTrue( entry.contains( "sn", "test" ) );
+    }
+
+
+    /**
+     * Test method for DefaultEntry( Dn )
+     */
+    @Test
+    public void testDefaultClientEntryLdapDN()
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertNotNull( entry );
+        assertNotNull( entry.getDn() );
+        assertEquals( exampleDn, entry.getDn() );
+        assertEquals( 0, entry.size() );
+    }
+
+
+    /**
+     * Test method for add( EntryAttribute... )
+     */
+    @Test
+    public void testAddEntryAttributeArray() throws LdapException
+    {
+        Entry entry = createEntry();
+
+        assertEquals( 4, entry.size() );
+        assertTrue( entry.containsAttribute( "ObjectClass" ) );
+        assertTrue( entry.containsAttribute( "CN" ) );
+        assertTrue( entry.containsAttribute( "  sn  " ) );
+        assertTrue( entry.containsAttribute( "userPassword" ) );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertEquals( 2, attr.size() );
+
+        Attribute attrCN2 = new DefaultAttribute( "cn", "test1", "test3" );
+        entry.add( attrCN2 );
+        assertEquals( 4, entry.size() );
+        attr = entry.get( "cn" );
+        assertEquals( 3, attr.size() );
+        assertTrue( attr.contains( "test1", "test2", "test3" ) );
+
+        // Check adding some byte[] values (they will not be transformed to Strings)
+        attrCN2.clear();
+        attrCN2.add( BYTES1, BYTES2 );
+        entry.add( attrCN2 );
+        assertEquals( 4, entry.size() );
+        attr = entry.get( "cn" );
+        assertEquals( 3, attr.size() );
+        assertTrue( attr.contains( "test1", "test2", "test3" ) );
+        assertFalse( attr.contains( "ab", "b" ) );
+    }
+
+
+    /**
+     * Test method for add( String, byte[]... )
+     */
+    @Test
+    public void testAddStringByteArrayArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        entry.add( "userPassword", ( byte[] ) null );
+        assertEquals( 1, entry.size() );
+        Attribute attributePWD = entry.get( "userPassword" );
+        assertEquals( 1, attributePWD.size() );
+        assertNotNull( attributePWD.get() );
+        assertNull( attributePWD.get().getValue() );
+
+        entry.add( "jpegPhoto", BYTES1, BYTES1, BYTES2 );
+        assertEquals( 2, entry.size() );
+        Attribute attributeJPG = entry.get( "jpegPhoto" );
+        assertEquals( 2, attributeJPG.size() );
+        assertNotNull( attributeJPG.get() );
+        assertTrue( attributeJPG.contains( BYTES1 ) );
+        assertTrue( attributeJPG.contains( BYTES2 ) );
+    }
+
+
+    /**
+     * Test method for add( String, String... )
+     */
+    @Test
+    public void testAddStringStringArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        entry.add( "cn", ( String ) null );
+        assertEquals( 1, entry.size() );
+        Attribute attributeCN = entry.get( "cn" );
+        assertEquals( 1, attributeCN.size() );
+        assertNotNull( attributeCN.get() );
+        assertNull( attributeCN.get().getValue() );
+
+        entry.add( "sn", "test", "test", "TEST" );
+        assertEquals( 2, entry.size() );
+        Attribute attributeSN = entry.get( "sn" );
+        assertEquals( 2, attributeSN.size() );
+        assertNotNull( attributeSN.get() );
+        assertTrue( attributeSN.contains( "test" ) );
+        assertTrue( attributeSN.contains( "TEST" ) );
+    }
+
+
+    /**
+     * Test method for add( String, Value<?>... )
+     */
+    @Test
+    public void testAddStringValueArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        Value<String> value = new StringValue( ( String ) null );
+
+        entry.add( "cn", value );
+        assertEquals( 1, entry.size() );
+        Attribute attributeCN = entry.get( "cn" );
+        assertEquals( 1, attributeCN.size() );
+        assertNotNull( attributeCN.get() );
+        assertNull( attributeCN.get().getValue() );
+
+        Value<String> value1 = new StringValue( "test1" );
+        Value<String> value2 = new StringValue( "test2" );
+        Value<String> value3 = new StringValue( "test1" );
+
+        entry.add( "sn", value1, value2, value3 );
+        assertEquals( 2, entry.size() );
+        Attribute attributeSN = entry.get( "sn" );
+        assertEquals( 2, attributeSN.size() );
+        assertNotNull( attributeSN.get() );
+        assertTrue( attributeSN.contains( value1 ) );
+        assertTrue( attributeSN.contains( value2 ) );
+
+        Value<byte[]> value4 = new BinaryValue( BYTES1 );
+        entry.add( "l", value1, value4 );
+        assertEquals( 3, entry.size() );
+        Attribute attributeL = entry.get( "l" );
+        assertEquals( 2, attributeL.size() );
+        assertNotNull( attributeL.get() );
+        assertTrue( attributeL.contains( value1 ) );
+
+        // The byte[] value must have been transformed to a String
+        assertTrue( attributeL.contains( "ab" ) );
+    }
+
+
+    /**
+     * Test method for clear()
+     */
+    @Test
+    public void testClear() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertEquals( 0, entry.size() );
+        assertNull( entry.get( "ObjectClass" ) );
+        entry.clear();
+        assertEquals( 0, entry.size() );
+        assertNull( entry.get( "ObjectClass" ) );
+
+        entry.add( "ObjectClass", "top", "person" );
+        assertEquals( 1, entry.size() );
+        assertNotNull( entry.get( "ObjectClass" ) );
+
+        entry.clear();
+        assertEquals( 0, entry.size() );
+        assertNull( entry.get( "ObjectClass" ) );
+    }
+
+
+    /**
+     * Test method for clone()
+     */
+    @Test
+    public void testClone() throws LdapException
+    {
+        Entry entry1 = new DefaultEntry();
+
+        Entry entry2 = entry1.clone();
+
+        assertEquals( entry1, entry2 );
+        entry2.setDn( exampleDn );
+
+        assertEquals( Dn.EMPTY_DN, entry1.getDn() );
+
+        entry1.setDn( exampleDn );
+        entry2 = entry1.clone();
+        assertEquals( entry1, entry2 );
+
+        entry1.add( "objectClass", "top", "person" );
+        entry1.add( "cn", "test1", "test2" );
+
+        entry2 = entry1.clone();
+        assertEquals( entry1, entry2 );
+
+        entry1.add( "cn", "test3" );
+        assertEquals( 2, entry2.get( "cn" ).size() );
+        assertFalse( entry2.contains( "cn", "test3" ) );
+
+        entry1.add( "sn", ( String ) null );
+        assertFalse( entry2.containsAttribute( "sn" ) );
+    }
+
+
+    /**
+     * Test method for contains( EntryAttribute... )
+     */
+    @Test
+    public void testContainsEntryAttributeArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        assertFalse( entry.contains( attrOC, attrCN ) );
+
+        entry.add( attrOC, attrCN );
+
+        assertTrue( entry.contains( attrOC, attrCN ) );
+        assertFalse( entry.contains( attrOC, attrCN, attrSN ) );
+
+        entry.add( attrSN, attrPWD );
+
+        assertTrue( entry.contains( attrSN, attrPWD ) );
+    }
+
+
+    /**
+     * Test method for contains( String, byte[]... )
+     */
+    @Test
+    public void testContainsStringByteArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertFalse( entry.containsAttribute( "objectClass" ) );
+
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, ( byte[] ) null, BYTES2 );
+
+        entry.add( attrPWD );
+
+        assertTrue( entry.contains( "  userPASSWORD  ", BYTES1, BYTES2 ) );
+        assertTrue( entry.contains( "  userPASSWORD  ", ( byte[] ) null ) );
+
+        // We can search for byte[] using Strings. the strings will be converted to byte[]
+        assertTrue( entry.contains( "  userPASSWORD  ", "ab", "b" ) );
+
+        assertFalse( entry.contains( "  userPASSWORD  ", "ab", "b", "d" ) );
+    }
+
+
+    /**
+     * Test method for contains( String, String... )
+     */
+    @Test
+    public void testContainsStringStringArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertFalse( entry.containsAttribute( "objectClass" ) );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2", ( String ) null );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        entry.add( attrOC, attrCN, attrSN, attrPWD );
+
+        assertTrue( entry.contains( "OBJECTCLASS", "top", "person" ) );
+        assertTrue( entry.contains( " cn ", "test1", "test2" ) );
+        assertTrue( entry.contains( "Sn", "Test1", "Test2", ( String ) null ) );
+        assertTrue( entry.contains( "  userPASSWORD  ", "ab", "b" ) );
+
+        assertFalse( entry.contains( "OBJECTCLASS", "PERSON" ) );
+        assertFalse( entry.contains( " cn ", "test1", "test3" ) );
+        assertFalse( entry.contains( "Sn", "Test" ) );
+        assertFalse( entry.contains( "  userPASSWORD  ", ( String ) null ) );
+    }
+
+
+    /**
+     * Test method for contains( Sring, Value<?>... )
+     */
+    @Test
+    public void testContainsStringValueArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertFalse( entry.containsAttribute( "objectClass" ) );
+
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2", ( String ) null );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2, ( byte[] ) null );
+
+        entry.add( attrCN, attrPWD );
+
+        Value<String> strValue1 = new StringValue( "test1" );
+        Value<String> strValue2 = new StringValue( "test2" );
+        Value<String> strValue3 = new StringValue( "test3" );
+        Value<String> strNullValue = new StringValue( ( String ) null );
+
+        Value<byte[]> binValue1 = new BinaryValue( BYTES1 );
+        Value<byte[]> binValue2 = new BinaryValue( BYTES2 );
+        Value<byte[]> binValue3 = new BinaryValue( BYTES3 );
+        Value<byte[]> binNullValue = new BinaryValue( ( byte[] ) null );
+
+        assertTrue( entry.contains( "CN", strValue1, strValue2, strNullValue ) );
+        assertTrue( entry.contains( "userpassword", binValue1, binValue2, binNullValue ) );
+
+        assertFalse( entry.contains( "cn", strValue3 ) );
+        assertFalse( entry.contains( "UserPassword", binValue3 ) );
+    }
+
+
+    /**
+     * Test method for containsAttribute( String )
+     */
+    @Test
+    public void testContainsAttribute() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertFalse( entry.containsAttribute( "objectClass" ) );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        entry.add( attrOC, attrCN, attrSN, attrPWD );
+
+        assertTrue( entry.containsAttribute( "OBJECTCLASS" ) );
+        assertTrue( entry.containsAttribute( " cn " ) );
+        assertTrue( entry.containsAttribute( "Sn" ) );
+        assertTrue( entry.containsAttribute( "  userPASSWORD  " ) );
+
+        entry.clear();
+
+        assertFalse( entry.containsAttribute( "OBJECTCLASS" ) );
+        assertFalse( entry.containsAttribute( " cn " ) );
+        assertFalse( entry.containsAttribute( "Sn" ) );
+        assertFalse( entry.containsAttribute( "  userPASSWORD  " ) );
+    }
+
+
+    /**
+     * Test method for equals()
+     */
+    @Test
+    public void testEqualsObject() throws LdapException
+    {
+        Entry entry1 = new DefaultEntry();
+        Entry entry2 = new DefaultEntry();
+
+        assertEquals( entry1, entry2 );
+
+        entry1.setDn( exampleDn );
+        assertNotSame( entry1, entry2 );
+
+        entry2.setDn( exampleDn );
+        assertEquals( entry1, entry2 );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        entry1.put( attrOC, attrCN, attrSN, attrPWD );
+        entry2.put( attrOC, attrCN, attrSN );
+        assertNotSame( entry1, entry2 );
+
+        entry2.put( attrPWD );
+        assertEquals( entry1, entry2 );
+
+        Attribute attrL1 = new DefaultAttribute( "l", "Paris", "New-York" );
+        Attribute attrL2 = new DefaultAttribute( "l", "Paris", "Tokyo" );
+
+        entry1.put( attrL1 );
+        entry2.put( attrL1 );
+        assertEquals( entry1, entry2 );
+
+        entry1.add( "l", "London" );
+        assertNotSame( entry1, entry2 );
+
+        entry2.add( attrL2 );
+        assertNotSame( entry1, entry2 );
+
+        entry1.clear();
+        entry2.clear();
+        assertEquals( entry1, entry2 );
+    }
+
+
+    /**
+     * Test method for get( String )
+     */
+    @Test
+    public void testGet() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertNull( entry.get( "objectClass" ) );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        entry.add( attrOC, attrCN, attrSN, attrPWD );
+
+        assertNotNull( entry.get( "  CN  " ) );
+        Attribute attribute = entry.get( "cN" );
+
+        assertEquals( attribute, attrCN );
+
+        assertNull( entry.get( ( String ) null ) );
+        assertNull( entry.get( "  " ) );
+        assertNull( entry.get( "l" ) );
+    }
+
+
+    /**
+     * Test method for getDN()
+     */
+    @Test
+    public void testGetDn() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertEquals( exampleDn, entry.getDn() );
+
+        Dn testDn = new Dn( "cn=test" );
+        entry.setDn( testDn );
+
+        assertEquals( testDn, entry.getDn() );
+    }
+
+
+    /**
+     * Test method for hashcode()
+     */
+    @Test
+    public void testHashCode() throws LdapException, LdapException
+    {
+        Entry entry1 = new DefaultEntry( exampleDn );
+        Entry entry2 = new DefaultEntry( exampleDn );
+
+        assertEquals( entry1.hashCode(), entry2.hashCode() );
+
+        entry2.setDn( new Dn( "ou=system,dc=com" ) );
+        assertNotSame( entry1.hashCode(), entry2.hashCode() );
+
+        entry2.setDn( exampleDn );
+        assertEquals( entry1.hashCode(), entry2.hashCode() );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        entry1.add( attrOC, attrCN, attrSN, attrPWD );
+        entry2.add( attrOC, attrCN, attrSN, attrPWD );
+
+        assertEquals( entry1.hashCode(), entry2.hashCode() );
+
+        Entry entry3 = new DefaultEntry( exampleDn );
+        entry3.add( attrOC, attrSN, attrCN, attrPWD );
+
+        assertEquals( entry1.hashCode(), entry3.hashCode() );
+    }
+
+
+    /**
+     * Test method for hasObjectClass( String )
+     */
+    @Test
+    public void testHasObjectClass() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertFalse( entry.containsAttribute( "objectClass" ) );
+        assertFalse( entry.hasObjectClass( "top" ) );
+
+        entry.add( new DefaultAttribute( "objectClass", "top", "person" ) );
+
+        assertTrue( entry.hasObjectClass( "top" ) );
+        assertTrue( entry.hasObjectClass( "person" ) );
+        assertFalse( entry.hasObjectClass( "inetorgperson" ) );
+        assertFalse( entry.hasObjectClass( ( String ) null ) );
+        assertFalse( entry.hasObjectClass( "" ) );
+    }
+
+
+    /**
+     * Test method for Iterator()
+     */
+    @Test
+    public void testIterator() throws LdapException
+    {
+        Entry entry = createEntry();
+
+        Iterator<Attribute> iterator = entry.iterator();
+
+        assertTrue( iterator.hasNext() );
+
+        Set<String> expectedIds = new HashSet<String>();
+        expectedIds.add( "objectclass" );
+        expectedIds.add( "cn" );
+        expectedIds.add( "sn" );
+        expectedIds.add( "userpassword" );
+
+        while ( iterator.hasNext() )
+        {
+            Attribute attribute = iterator.next();
+
+            String id = attribute.getId();
+            assertTrue( expectedIds.contains( id ) );
+            expectedIds.remove( id );
+        }
+
+        assertEquals( 0, expectedIds.size() );
+    }
+
+
+    /**
+     * Test method for put( EntryAttribute... )
+     */
+    @Test
+    public void testPutEntryAttributeArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        List<Attribute> removed = entry.put( attrOC, attrCN, attrSN, attrPWD );
+
+        assertEquals( 4, entry.size() );
+        assertEquals( 0, removed.size() );
+        assertTrue( entry.containsAttribute( "ObjectClass" ) );
+        assertTrue( entry.containsAttribute( "CN" ) );
+        assertTrue( entry.containsAttribute( "  sn  " ) );
+        assertTrue( entry.containsAttribute( "userPassword" ) );
+
+        Attribute attrCN2 = new DefaultAttribute( "cn", "test3", "test4" );
+        removed = entry.put( attrCN2 );
+        assertEquals( 4, entry.size() );
+        assertEquals( 1, removed.size() );
+        assertTrue( entry.containsAttribute( "CN" ) );
+        assertTrue( entry.contains( "cn", "test3", "test4" ) );
+    }
+
+
+    /**
+     * Test method for put( String, byte[]... )
+     */
+    @Test
+    public void testPutStringByteArrayArray()
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        try
+        {
+            entry.put( ( String ) null, BYTES1 );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            entry.put( "   ", BYTES1 );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        entry.put( "userPassword", ( byte[] ) null );
+        assertEquals( 1, entry.size() );
+        assertNotNull( entry.get( "userPassword" ) );
+        assertEquals( 1, entry.get( "userPassword" ).size() );
+        assertNull( entry.get( "userPassword" ).get().getValue() );
+
+        entry.put( "jpegPhoto", BYTES1, BYTES2, BYTES1 );
+        assertEquals( 2, entry.size() );
+        assertNotNull( entry.get( "jpegPhoto" ) );
+        assertEquals( 2, entry.get( "JPEGPhoto" ).size() );
+        Attribute attribute = entry.get( "jpegPhoto" );
+        assertTrue( attribute.contains( BYTES1 ) );
+        assertTrue( attribute.contains( BYTES2 ) );
+        assertEquals( "jpegphoto", attribute.getId() );
+        assertEquals( "jpegPhoto", attribute.getUpId() );
+    }
+
+
+    /**
+     * Test method for put( String, String... )
+     */
+    @Test
+    public void testPutStringStringArray()
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        try
+        {
+            entry.put( ( String ) null, "a" );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            entry.put( "   ", "a" );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        entry.put( "sn", ( String ) null );
+        assertEquals( 1, entry.size() );
+        assertNotNull( "sn", entry.get( "sn" ) );
+        assertEquals( 1, entry.get( "sn" ).size() );
+        assertNull( entry.get( "sn" ).get().getValue() );
+
+        entry.put( "ObjectClass", "top", "person", "top" );
+        assertEquals( 2, entry.size() );
+        assertNotNull( "objectclass", entry.get( "sn" ) );
+        assertEquals( 2, entry.get( "OBJECTCLASS" ).size() );
+        Attribute attribute = entry.get( "objectClass" );
+        assertTrue( attribute.contains( "top" ) );
+        assertTrue( attribute.contains( "person" ) );
+        assertEquals( "objectclass", attribute.getId() );
+        assertEquals( "ObjectClass", attribute.getUpId() );
+    }
+
+
+    /**
+     * Test method for pu( String, Value<?>... )
+     */
+    @Test
+    public void testPutStringValueArray()
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        Value<String> strValueTop = new StringValue( "top" );
+        Value<String> strValuePerson = new StringValue( "person" );
+        Value<String> strValueTop2 = new StringValue( "top" );
+        Value<String> strNullValue = new StringValue( ( String ) null );
+
+        Value<byte[]> binValue1 = new BinaryValue( BYTES1 );
+        Value<byte[]> binValue2 = new BinaryValue( BYTES2 );
+        Value<byte[]> binValue3 = new BinaryValue( BYTES1 );
+        Value<byte[]> binNullValue = new BinaryValue( ( byte[] ) null );
+
+        try
+        {
+            entry.put( ( String ) null, strValueTop );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            entry.put( "   ", strValueTop );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        entry.put( "sn", strNullValue );
+        assertEquals( 1, entry.size() );
+        assertNotNull( "sn", entry.get( "sn" ) );
+        assertEquals( 1, entry.get( "sn" ).size() );
+        assertNull( entry.get( "sn" ).get().getValue() );
+
+        entry.clear();
+
+        entry.put( "ObjectClass", strValueTop, strValuePerson, strValueTop2, strNullValue );
+        assertEquals( 1, entry.size() );
+        assertNotNull( "objectclass", entry.get( "objectclass" ) );
+        assertEquals( 3, entry.get( "OBJECTCLASS" ).size() );
+        Attribute attribute = entry.get( "objectClass" );
+        assertTrue( attribute.contains( "top" ) );
+        assertTrue( attribute.contains( "person" ) );
+        assertTrue( attribute.contains( ( String ) null ) );
+        assertEquals( "objectclass", attribute.getId() );
+        assertEquals( "ObjectClass", attribute.getUpId() );
+
+        entry.clear();
+
+        entry.put( "userpassword", strNullValue );
+        assertEquals( 1, entry.size() );
+        assertNotNull( "userpassword", entry.get( "userpassword" ) );
+        assertEquals( 1, entry.get( "userpassword" ).size() );
+        assertNull( entry.get( "userpassword" ).get().getValue() );
+
+        entry.clear();
+
+        entry.put( "userPassword", binValue1, binValue2, binValue3, binNullValue );
+        assertEquals( 1, entry.size() );
+        assertNotNull( "userpassword", entry.get( "userpassword" ) );
+        assertEquals( 3, entry.get( "userpassword" ).size() );
+        attribute = entry.get( "userpassword" );
+        assertTrue( attribute.contains( BYTES1 ) );
+        assertTrue( attribute.contains( BYTES2 ) );
+        assertTrue( attribute.contains( ( byte[] ) null ) );
+        assertEquals( "userpassword", attribute.getId() );
+        assertEquals( "userPassword", attribute.getUpId() );
+    }
+
+
+    /**
+     * Test method for removeAttributes( String... )
+     */
+    @Test
+    public void testRemoveAttributesStringArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        entry.put( attrOC, attrCN, attrSN, attrPWD );
+
+        entry.removeAttributes( "CN", "SN" );
+
+        assertFalse( entry.containsAttribute( "cn", "sn" ) );
+        assertTrue( entry.containsAttribute( "objectclass", "userpassword" ) );
+
+        entry.removeAttributes( "badId" );
+
+        entry.removeAttributes( ( String ) null );
+    }
+
+
+    /**
+     * Test method for remove( EntryAttribute... )
+     */
+    @Test
+    public void testRemoveEntryAttributeArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        Attribute attrOC = new DefaultAttribute( "objectClass", "top", "person" );
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2" );
+        Attribute attrSN = new DefaultAttribute( "sn", "Test1", "Test2" );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2 );
+
+        entry.put( attrOC, attrCN, attrSN, attrPWD );
+
+        List<Attribute> removed = entry.remove( attrSN, attrPWD );
+
+        assertEquals( 2, removed.size() );
+        assertEquals( 2, entry.size() );
+        assertTrue( removed.contains( attrSN ) );
+        assertTrue( removed.contains( attrPWD ) );
+        assertTrue( entry.contains( "objectClass", "top", "person" ) );
+        assertTrue( entry.contains( "cn", "test1", "test2" ) );
+        assertFalse( entry.containsAttribute( "sn" ) );
+        assertFalse( entry.containsAttribute( "userPassword" ) );
+
+        removed = entry.remove( attrSN, attrPWD );
+
+        assertEquals( 0, removed.size() );
+    }
+
+
+    /**
+     * Test method for remove(String, byte[]... )
+     */
+    @Test
+    public void testRemoveStringByteArrayArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, ( byte[] ) null, BYTES2 );
+
+        entry.put( attrPWD );
+        assertTrue( entry.remove( "userPassword", ( byte[] ) null ) );
+        assertTrue( entry.remove( "userPassword", BYTES1, BYTES2 ) );
+        assertFalse( entry.containsAttribute( "userPassword" ) );
+
+        entry.add( "userPassword", BYTES1, ( byte[] ) null, BYTES2 );
+        assertTrue( entry.remove( "userPassword", ( byte[] ) null ) );
+        assertEquals( 2, entry.get( "userPassword" ).size() );
+        assertTrue( entry.remove( "userPassword", BYTES1, BYTES3 ) );
+        assertEquals( 1, entry.get( "userPassword" ).size() );
+        assertTrue( Arrays.equals( BYTES2, entry.get( "userPassword" ).getBytes() ) );
+
+        assertFalse( entry.remove( "userPassword", BYTES3 ) );
+        assertFalse( entry.remove( "void", "whatever" ) );
+    }
+
+
+    /**
+     * Test method for remove( String, String... )
+     */
+    @Test
+    public void testRemoveStringStringArray() throws LdapException
+    {
+        Entry entry = createEntry();
+
+        assertTrue( entry.remove( "cn", "test1" ) );
+        assertTrue( entry.remove( "cn", "test2" ) );
+        assertFalse( entry.containsAttribute( "cn" ) );
+
+        entry.add( "cn", "test1", ( String ) null, "test2" );
+        assertTrue( entry.remove( "cn", ( String ) null ) );
+        assertEquals( 2, entry.get( "cn" ).size() );
+        assertTrue( entry.remove( "cn", "test1", "test3" ) );
+        assertEquals( 1, entry.get( "cn" ).size() );
+        assertEquals( "test2", entry.get( "cn" ).get().getString() );
+
+        assertFalse( entry.remove( "cn", "test3" ) );
+        assertFalse( entry.remove( "void", "whatever" ) );
+    }
+
+
+    /**
+     * Test method for remove(String, Value<?>... )
+     */
+    @Test
+    public void testRemoveStringValueArray() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        Attribute attrCN = new DefaultAttribute( "cn", "test1", "test2", ( String ) null );
+        Attribute attrPWD = new DefaultAttribute( "userPassword", BYTES1, BYTES2, ( byte[] ) null );
+
+        entry.add( attrCN, attrPWD );
+
+        Value<String> strValue1 = new StringValue( "test1" );
+        Value<String> strValue2 = new StringValue( "test2" );
+        Value<String> strValue3 = new StringValue( "test3" );
+        Value<String> strNullValue = new StringValue( ( String ) null );
+
+        Value<byte[]> binValue1 = new BinaryValue( BYTES1 );
+        Value<byte[]> binValue2 = new BinaryValue( BYTES2 );
+        Value<byte[]> binValue3 = new BinaryValue( BYTES3 );
+        Value<byte[]> binNullValue = new BinaryValue( ( byte[] ) null );
+
+        assertTrue( entry.remove( "cn", strValue1, strNullValue ) );
+        assertTrue( entry.contains( "cn", strValue2 ) );
+        assertFalse( entry.remove( "cn", strValue3 ) );
+        assertTrue( entry.remove( "cn", strValue2 ) );
+        assertFalse( entry.containsAttribute( "cn" ) );
+
+        entry.add( attrCN, attrPWD );
+
+        assertTrue( entry.remove( "userpassword", binValue1, binNullValue ) );
+        assertTrue( entry.contains( "userpassword", binValue2 ) );
+        assertFalse( entry.remove( "userpassword", binValue3 ) );
+        assertTrue( entry.remove( "userpassword", binValue2 ) );
+        assertFalse( entry.containsAttribute( "userpassword" ) );
+    }
+
+
+    /**
+     * Test method for setDN( Dn )
+     */
+    @Test
+    public void testSetDn()
+    {
+        Entry entry = new DefaultEntry();
+
+        assertEquals( Dn.EMPTY_DN, entry.getDn() );
+
+        entry.setDn( exampleDn );
+        assertEquals( exampleDn, entry.getDn() );
+    }
+
+
+    /**
+     * Test method for size()
+     */
+    @Test
+    public void testSize() throws LdapException
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertEquals( 0, entry.size() );
+        entry.add( "ObjectClass", "top", "person" );
+        entry.add( "cn", "test" );
+        entry.add( "sn", "Test" );
+
+        assertEquals( 3, entry.size() );
+
+        entry.clear();
+        assertEquals( 0, entry.size() );
+    }
+
+
+    /**
+     * Test method for for {@link org.apache.directory.api.ldap.model.entry.DefaultEntry#toString()}.
+     */
+    @Test
+    public void testToString()
+    {
+        Entry entry = new DefaultEntry( exampleDn );
+
+        assertEquals( "Entry\n    dn: dc=example,dc=com\n\n", entry.toString() );
+
+        Value<String> strValueTop = new StringValue( "top" );
+        Value<String> strValuePerson = new StringValue( "person" );
+        Value<String> strNullValue = new StringValue( ( String ) null );
+
+        Value<byte[]> binValue1 = new BinaryValue( BYTES1 );
+        Value<byte[]> binValue2 = new BinaryValue( BYTES2 );
+        Value<byte[]> binNullValue = new BinaryValue( ( byte[] ) null );
+
+        entry.put( "ObjectClass", strValueTop, strValuePerson, strNullValue );
+        entry.put( "UserPassword", binValue1, binValue2, binNullValue );
+
+        String expected =
+            "Entry\n"
+                + "    dn: dc=example,dc=com\n"
+                + "    ObjectClass: top\n"
+                + "    ObjectClass: person\n"
+                + "    ObjectClass: ''\n"
+                + "    UserPassword: 0x61 0x62 \n"
+                + "    UserPassword: 0x62 \n"
+                + "    UserPassword: ''\n";
+
+        assertEquals( expected, entry.toString() );
+    }
+
+
+    /**
+     * Test the serialization of a complete entry
+     */
+    @Test
+    public void testSerializeCompleteEntry() throws LdapException, IOException, ClassNotFoundException
+    {
+        Dn dn = new Dn( "ou=system" );
+
+        dn.apply( schemaManager );
+
+        byte[] password = Strings.getBytesUtf8( "secret" );
+        Entry entry = new DefaultEntry( dn );
+        entry.add( "ObjectClass", "top", "person" );
+        entry.add( "cn", "test1" );
+        entry.add( "userPassword", password );
+
+        Entry entrySer = deserializeValue( serializeValue( entry ) );
+
+        assertEquals( entry, entrySer );
+    }
+
+
+    /**
+     * Test the serialization of an entry with no Dn
+     */
+    @Test
+    public void testSerializeEntryWithNoDN() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] password = Strings.getBytesUtf8( "secret" );
+        Entry entry = new DefaultEntry();
+        entry.add( "ObjectClass", "top", "person" );
+        entry.add( "cn", "test1" );
+        entry.add( "userPassword", password );
+
+        Entry entrySer = deserializeValue( serializeValue( entry ) );
+
+        assertEquals( entry, entrySer );
+    }
+
+
+    /**
+     * Test the serialization of an entry with no attribute and no Dn
+     */
+    @Test
+    public void testSerializeEntryWithNoDNNoAttribute() throws LdapException, IOException, ClassNotFoundException
+    {
+        Entry entry = new DefaultEntry();
+
+        Entry entrySer = deserializeValue( serializeValue( entry ) );
+
+        assertEquals( entry, entrySer );
+    }
+
+
+    /**
+     * Test the serialization of an entry with no attribute
+     */
+    @Test
+    public void testSerializeEntryWithNoAttribute() throws LdapException, IOException, ClassNotFoundException
+    {
+        Dn dn = new Dn( "ou=system" );
+
+        dn.apply( schemaManager );
+
+        Entry entry = new DefaultEntry( dn );
+
+        Entry entrySer = deserializeValue( serializeValue( entry ) );
+
+        assertEquals( entry, entrySer );
+    }
+
+
+    /**
+     * Test method for userCertificate;binary AT
+     */
+    @Test
+    public void testUserCertificateBinary() throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+        entry.add( "objectClass", "top", "person", "inetorgPerson" );
+        entry.add( "cn", "test1", "test2" );
+        entry.add( "sn", "Test1", "Test2" );
+        entry.add( "userPassword", BYTES1, BYTES2 );
+
+        entry.add( "userCertificate;binary", Strings.getBytesUtf8( "secret" ) );
+        assertTrue( entry.containsAttribute( "userCertificate;binary" ) );
+        assertTrue( entry.containsAttribute( "userCertificate" ) );
+
+        entry.removeAttributes( "userCertificate;binary" );
+        assertFalse( entry.containsAttribute( "userCertificate;binary" ) );
+        assertFalse( entry.containsAttribute( "userCertificate" ) );
+
+        entry.add( "userCertificate", Strings.getBytesUtf8( "secret" ) );
+        assertTrue( entry.containsAttribute( "userCertificate;binary" ) );
+        assertTrue( entry.containsAttribute( "userCertificate" ) );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareModificationSerializationTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareModificationSerializationTest.java
new file mode 100644
index 0000000..ecbebd9
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareModificationSerializationTest.java
@@ -0,0 +1,238 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the DefaultModification class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaAwareModificationSerializationTest
+{
+    private static SchemaManager schemaManager;
+    private static AttributeType cnAT;
+
+
+    /**
+     * Initialize OIDs maps for normalization
+     */
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+        cnAT = schemaManager.getAttributeType( "cn" );
+    }
+
+
+    /**
+     * Serialize a DefaultModification
+     */
+    private ByteArrayOutputStream serializeValue( Modification modification ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+
+            modification.writeExternal( oOut );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a DefaultModification
+     */
+    private Modification deserializeValue( ByteArrayOutputStream out ) throws IOException, ClassNotFoundException,
+        LdapInvalidAttributeValueException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+            Modification modification = new DefaultModification();
+            modification.readExternal( oIn );
+
+            Attribute attribute = modification.getAttribute();
+
+            if ( ( attribute != null ) && ( schemaManager != null ) )
+            {
+                AttributeType attributeType = schemaManager.getAttributeType( attribute.getId() );
+
+                modification.apply( attributeType );
+            }
+
+            return modification;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    @Test
+    public void testCreateServerModification() throws LdapException
+    {
+        Attribute attribute = new DefaultAttribute( "cn", cnAT );
+        attribute.add( "test1", "test2" );
+
+        Modification mod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attribute );
+        Modification clone = mod.clone();
+
+        attribute.remove( "test2" );
+
+        Attribute clonedAttribute = clone.getAttribute();
+
+        assertEquals( 1, mod.getAttribute().size() );
+        assertTrue( mod.getAttribute().contains( "TEST1" ) );
+
+        assertEquals( 2, clonedAttribute.size() );
+        assertTrue( clone.getAttribute().contains( "test1" ) );
+        assertTrue( clone.getAttribute().contains( "test2" ) );
+    }
+
+
+    @Test
+    public void testSerializationModificationADD() throws ClassNotFoundException, IOException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute = new DefaultAttribute( "cn", cnAT );
+        attribute.add( "test1", "test2" );
+
+        DefaultModification mod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attribute );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+
+
+    @Test
+    public void testSerializationModificationREPLACE() throws ClassNotFoundException, IOException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute = new DefaultAttribute( "cn", cnAT );
+        attribute.add( "test1", "test2" );
+
+        DefaultModification mod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+
+
+    @Test
+    public void testSerializationModificationREMOVE() throws ClassNotFoundException, IOException,
+        LdapInvalidAttributeValueException
+    {
+        Attribute attribute = new DefaultAttribute( "cn", cnAT );
+        attribute.add( "test1", "test2" );
+
+        DefaultModification mod = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attribute );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+
+
+    @Test
+    public void testSerializationModificationNoAttribute() throws ClassNotFoundException, IOException,
+        LdapInvalidAttributeValueException
+    {
+        DefaultModification mod = new DefaultModification();
+
+        mod.setOperation( ModificationOperation.ADD_ATTRIBUTE );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareValueSerializationTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareValueSerializationTest.java
new file mode 100644
index 0000000..ccf7dcb
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/SchemaAwareValueSerializationTest.java
@@ -0,0 +1,340 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.entry;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.StringConstants;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Value Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaAwareValueSerializationTest
+{
+    private static final byte[] DATA = new byte[]
+        { 0x01, 0x02, 0x03, 0x04 };
+    private static BinaryValue bv1;
+    private static BinaryValue bv2;
+    private static BinaryValue bv3;
+    private static BinaryValue bv1n;
+    private static BinaryValue bv2n;
+    private static BinaryValue bv3n;
+    private static StringValue sv1;
+    private static StringValue sv2;
+    private static StringValue sv3;
+    private static StringValue sv1n;
+    private static StringValue sv2n;
+    private static StringValue sv3n;
+
+    private static SchemaManager schemaManager;
+    private static AttributeType cn = null;
+    private static AttributeType dc = null;
+    private static AttributeType userCertificate = null;
+
+
+    /**
+     * Initialize OIDs maps for normalization
+     */
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+        cn = schemaManager.getAttributeType( "cn" );
+        dc = schemaManager.getAttributeType( "dc" );
+        userCertificate = schemaManager.getAttributeType( "userCertificate" );
+
+        bv1 = new BinaryValue( userCertificate, DATA );
+        bv2 = new BinaryValue( userCertificate, StringConstants.EMPTY_BYTES );
+        bv3 = new BinaryValue( userCertificate, null );
+        bv1n = new BinaryValue( userCertificate, DATA );
+        bv2n = new BinaryValue( userCertificate, StringConstants.EMPTY_BYTES );
+        bv3n = new BinaryValue( userCertificate, null );
+        sv1 = new StringValue( cn, "test" );
+        sv2 = new StringValue( dc, "" );
+        sv3 = new StringValue( dc, ( String ) null );
+        sv1n = new StringValue( cn, "test" );
+        sv2n = new StringValue( dc, "" );
+        sv3n = new StringValue( dc, ( String ) null );
+    }
+
+
+    @Test
+    public void testBinaryValueWithDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        bv1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = BinaryValue.deserialize( in );
+
+        assertEquals( bv1, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueWithEmptyDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        bv2.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = BinaryValue.deserialize( in );
+
+        assertEquals( bv2, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueNoDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        bv3.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = BinaryValue.deserialize( in );
+
+        assertEquals( bv3, bvDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        sv1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = StringValue.deserialize( in );
+
+        assertEquals( sv1, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithEmptyDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        sv2.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = StringValue.deserialize( in );
+
+        assertEquals( sv2, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueNoDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        sv3.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = StringValue.deserialize( in );
+
+        assertEquals( sv3, svDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueWithDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        BinaryValue value = new BinaryValue( userCertificate, bv1n.getBytes() );
+
+        value.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = BinaryValue.deserialize( userCertificate, in );
+
+        assertEquals( value, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueWithEmptyDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        BinaryValue value = new BinaryValue( userCertificate, bv2n.getBytes() );
+
+        value.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = BinaryValue.deserialize( userCertificate, in );
+
+        assertEquals( value, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueNoDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        BinaryValue value = new BinaryValue( userCertificate, bv3n.getBytes() );
+
+        value.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = BinaryValue.deserialize( userCertificate, in );
+
+        assertEquals( value, bvDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        StringValue value = new StringValue( cn, sv1n.getString() );
+
+        value.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = StringValue.deserialize( cn, in );
+
+        assertEquals( value, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithEmptyDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        StringValue value = new StringValue( dc, sv2n.getString() );
+
+        value.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = StringValue.deserialize( dc, in );
+
+        assertEquals( value, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueNoDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        StringValue value = new StringValue( dc, sv3n.getString() );
+
+        value.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = StringValue.deserialize( dc, in );
+
+        assertEquals( value, svDeser );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/TestEntryUtils.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/TestEntryUtils.java
new file mode 100644
index 0000000..6eb312d
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/entry/TestEntryUtils.java
@@ -0,0 +1,297 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.entry;
+
+
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Some common declaration used by the serverEntry tests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class TestEntryUtils
+{
+    /**
+     * A local Syntax class for tests
+     */
+    static class AT extends AttributeType
+    {
+        private static final long serialVersionUID = 0L;
+
+
+        protected AT( String oid )
+        {
+            super( oid );
+        }
+    }
+
+
+    public static MatchingRule matchingRuleFactory( String oid )
+    {
+        MatchingRule matchingRule = new MatchingRule( oid );
+
+        return matchingRule;
+    }
+
+    /**
+     * A local MatchingRule class for tests
+     */
+    static class MR extends MatchingRule
+    {
+        /** The mandatory serialVersionUID field */
+        public static final long serialVersionUID = 1L;
+
+
+        protected MR( String oid )
+        {
+            super( oid );
+        }
+    }
+
+
+    /**
+     * A local Syntax class used for the tests
+     */
+    public static LdapSyntax syntaxFactory( String oid, boolean humanReadable )
+    {
+        LdapSyntax ldapSyntax = new LdapSyntax( oid );
+
+        ldapSyntax.setHumanReadable( humanReadable );
+
+        return ldapSyntax;
+    }
+
+    static class S extends LdapSyntax
+    {
+        private static final long serialVersionUID = 0L;
+
+
+        public S( String oid, boolean humanReadible )
+        {
+            super( oid, "", humanReadible );
+        }
+    }
+
+
+    /* no protection*/
+    static AttributeType getCaseIgnoringAttributeNoNumbersType()
+    {
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.3.1" );
+        LdapSyntax syntax = new LdapSyntax( "1.1.1.1", "", true );
+
+        syntax.setSyntaxChecker( new SyntaxChecker( "1.1.2.1" )
+        {
+            /** The mandatory serialVersionUID field */
+            public static final long serialVersionUID = 1L;
+
+
+            public boolean isValidSyntax( Object value )
+            {
+                if ( !( value instanceof String ) )
+                {
+                    return false;
+                }
+
+                String strval = ( String ) value;
+
+                for ( char c : strval.toCharArray() )
+                {
+                    if ( Character.isDigit( c ) )
+                    {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        } );
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.2.1" );
+        matchingRule.setSyntax( syntax );
+
+        matchingRule.setLdapComparator( new LdapComparator<String>( matchingRule.getOid() )
+        {
+            /** The mandatory serialVersionUID field */
+            public static final long serialVersionUID = 1L;
+
+
+            public int compare( String o1, String o2 )
+            {
+                return ( o1 == null ? ( o2 == null ? 0 : -1 ) : ( o2 == null ? 1 : o1.compareTo( o2 ) ) );
+            }
+        } );
+
+        Normalizer normalizer = new Normalizer( "1.1.1" )
+        {
+            /** The mandatory serialVersionUID field */
+            public static final long serialVersionUID = 1L;
+
+
+            public Value<?> normalize( Value<?> value ) throws LdapException
+            {
+                if ( value.isHumanReadable() )
+                {
+                    return new StringValue( Strings.toLowerCase( value.getString() ) );
+                }
+
+                throw new IllegalStateException();
+            }
+
+
+            public String normalize( String value ) throws LdapException
+            {
+                return Strings.toLowerCase( value );
+            }
+        };
+
+        matchingRule.setNormalizer( normalizer );
+
+        attributeType.setEquality( matchingRule );
+        attributeType.setSyntax( syntax );
+
+        return attributeType;
+    }
+
+
+    /* no protection*/static AttributeType getIA5StringAttributeType()
+    {
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1" );
+        attributeType.addName( "1.1" );
+        LdapSyntax syntax = new LdapSyntax( "1.1.1", "", true );
+
+        syntax.setSyntaxChecker( new SyntaxChecker( "1.1.2" )
+        {
+            /** The mandatory serialVersionUID field */
+            public static final long serialVersionUID = 1L;
+
+
+            public boolean isValidSyntax( Object value )
+            {
+                return ( ( String ) value == null ) || ( ( ( String ) value ).length() < 7 );
+            }
+        } );
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.2" );
+        matchingRule.setSyntax( syntax );
+
+        matchingRule.setLdapComparator( new LdapComparator<String>( matchingRule.getOid() )
+        {
+            /** The mandatory serialVersionUID field */
+            public static final long serialVersionUID = 1L;
+
+
+            public int compare( String o1, String o2 )
+            {
+                return ( ( o1 == null ) ? ( o2 == null ? 0 : -1 ) : ( o2 == null ? 1 : o1.compareTo( o2 ) ) );
+            }
+        } );
+
+        matchingRule.setNormalizer( new DeepTrimToLowerNormalizer( matchingRule.getOid() ) );
+
+        attributeType.setEquality( matchingRule );
+        attributeType.setSyntax( syntax );
+
+        return attributeType;
+    }
+
+
+    /* No protection */static AttributeType getBytesAttributeType()
+    {
+        MutableAttributeType attributeType = new MutableAttributeType( "1.2" );
+        LdapSyntax syntax = new LdapSyntax( "1.2.1", "", true );
+
+        syntax.setSyntaxChecker( new SyntaxChecker( "1.2.1" )
+        {
+            /** The mandatory serialVersionUID field */
+            public static final long serialVersionUID = 1L;
+
+
+            public boolean isValidSyntax( Object value )
+            {
+                return ( value == null ) || ( ( ( byte[] ) value ).length < 5 );
+            }
+        } );
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.2.2" );
+        matchingRule.setSyntax( syntax );
+
+        matchingRule.setLdapComparator( new ByteArrayComparator( "1.2.2" ) );
+
+        matchingRule.setNormalizer( new Normalizer( "1.1.1" )
+        {
+            /** The mandatory serialVersionUID field */
+            public static final long serialVersionUID = 1L;
+
+
+            public Value<?> normalize( Value<?> value ) throws LdapException
+            {
+                if ( !value.isHumanReadable() )
+                {
+                    byte[] val = value.getBytes();
+
+                    // each byte will be changed to be > 0, and spaces will be trimmed
+                    byte[] newVal = new byte[val.length];
+
+                    int i = 0;
+
+                    for ( byte b : val )
+                    {
+                        newVal[i++] = ( byte ) ( b & 0x007F );
+                    }
+
+                    return new BinaryValue( Strings.trim( newVal ) );
+                }
+
+                throw new IllegalStateException();
+            }
+
+
+            public String normalize( String value ) throws LdapException
+            {
+                throw new IllegalStateException();
+            }
+        } );
+
+        attributeType.setEquality( matchingRule );
+        attributeType.setSyntax( syntax );
+
+        return attributeType;
+    }
+
+
+    private TestEntryUtils()
+    {
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/AvaTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/AvaTest.java
new file mode 100644
index 0000000..ba280c2
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/AvaTest.java
@@ -0,0 +1,405 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the class AttributeTypeAndValue
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AvaTest
+{
+    private static SchemaManager schemaManager;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    /**
+     * Test a null AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueNull()
+    {
+        Ava atav = new Ava( schemaManager );
+        assertEquals( "", atav.toString() );
+        assertEquals( "", atav.getName() );
+    }
+
+
+    /**
+     * Test a null type for an AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueNullType() throws LdapException
+    {
+        try
+        {
+            new Ava( schemaManager, null, ( String ) null );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+
+    }
+
+
+    /**
+     * Test an invalid type for an AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueInvalidType() throws LdapException
+    {
+        try
+        {
+            new Ava( schemaManager, "  ", ( String ) null );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test a valid type for an AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueValidType() throws LdapException
+    {
+        Ava ava = new Ava( schemaManager, "CN", " " );
+        assertEquals( "CN=\\ ", ava.toString() );
+        assertEquals( "2.5.4.3=\\ ", ava.getNormName() );
+        assertEquals( "CN=\\ ", ava.getName() );
+
+        ava = new Ava( schemaManager, "  CN  ", " " );
+        assertEquals( "  CN  =\\ ", ava.toString() );
+        assertEquals( "2.5.4.3=\\ ", ava.getNormName() );
+        assertEquals( "  CN  =\\ ", ava.getName() );
+
+        ava = new Ava( schemaManager, "cn", " " );
+        assertEquals( "cn=\\ ", ava.toString() );
+        assertEquals( "2.5.4.3=\\ ", ava.getNormName() );
+        assertEquals( "cn=\\ ", ava.getName() );
+
+        ava = new Ava( schemaManager, "  cn  ", " " );
+        assertEquals( "  cn  =\\ ", ava.toString() );
+        assertEquals( "2.5.4.3=\\ ", ava.getNormName() );
+        assertEquals( "  cn  =\\ ", ava.getName() );
+    }
+
+
+    /**
+     * test an empty AttributeTypeAndValue
+     */
+    @Test
+    public void testAvaEmpty()
+    {
+        try
+        {
+            new Ava( schemaManager, "", "" );
+            fail( "Should not occurs ... " );
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a simple AttributeTypeAndValue : a = b
+     */
+    @Test
+    public void testAvaSimple() throws LdapException
+    {
+        Ava atav = new Ava( schemaManager, "cn", "b" );
+        assertEquals( "cn=b", atav.toString() );
+        assertEquals( "2.5.4.3=b", atav.getNormName() );
+        assertEquals( "cn=b", atav.getName() );
+    }
+
+
+    /**
+     * test a simple AttributeTypeAndValue : a = b
+     */
+    @Test
+    public void testAvaSimpleNorm() throws LdapException
+    {
+        Ava atav = new Ava( schemaManager, " CommonName ", " This is    a TEST " );
+        assertEquals( " CommonName =\\ This is    a TEST\\ ", atav.toString() );
+        assertEquals( "2.5.4.3=this is a test", atav.getNormName() );
+        assertEquals( " CommonName =\\ This is    a TEST\\ ", atav.getName() );
+    }
+
+
+    /**
+     * Compares two equals atavs
+     */
+    @Test
+    public void testEqualsSameAva() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "cn", "b" );
+        Ava atav2 = new Ava( schemaManager, "cn", "b" );
+
+        assertTrue( atav1.equals( atav2 ) );
+    }
+
+
+    /**
+     * Compares two equals atavs but with a type in different case
+     */
+    @Test
+    public void testEqualsUpperCaseAT() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "cn", "b" );
+        Ava atav2 = new Ava( schemaManager, "CN", "b" );
+
+        assertTrue( atav1.equals( atav2 ) );
+    }
+
+
+    /**
+     * Compares two equals atavs but with a type in different case
+     */
+    @Test
+    public void testEqualsSameValues() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "cn", "  B  a" );
+        Ava atav2 = new Ava( schemaManager, "CN", "b a" );
+
+        assertTrue( atav1.equals( atav2 ) );
+    }
+    
+    
+    /**
+     * Test the returned values for Ava. \u00E4 is the unicode char for "ä", encoded
+     * \C3\A4 in UTF8
+     */
+    @Test
+    public void testAvaValuesNoSchema() throws LdapException
+    {
+        String errors = null;
+        
+        Ava ava = new Ava( "OU", "Exemple + Rdn\u00E4 " );
+        
+        if ( !"ou=Exemple \\+ Rdn\u00E4\\ ".equals( ava.getNormName() ) )
+        {
+            errors = "\nAva.getNormName fails '" + ava.getNormName() + "'";
+        }
+        
+        if ( !"ou".equals( ava.getNormType() ) )
+        {
+            errors += "\nAva.getNormType fails '" + ava.getNormType() + "'";
+        }
+        
+        if ( !"Exemple + Rdn\u00E4 ".equals( ava.getValue().getNormValue().toString() ) )
+        {
+            errors += "\nAva.getNormValue fails '" + ava.getValue().getNormValue().toString() + "'";
+        }
+        
+        if ( !"OU=Exemple \\+ Rdn\u00E4\\ ".equals( ava.getName() ) )
+        {
+            errors += "\nAva.getUpName fails '" + ava.getName() + "'";
+        }
+        
+        if ( !"OU".equals( ava.getType() ) )
+        {
+            errors += "\nAva.getUpType fails '" + ava.getType() + "'";
+        }
+        
+        if ( !"Exemple + Rdn\u00E4 ".equals( ava.getValue().getString() ) )
+        {
+            errors += "\nAva.getUpValue fails '" + ava.getValue() .getString() + "'";
+        }
+        
+        if ( !"ou=Exemple \\+ Rdn\u00E4\\ ".equals( ava.normalize() ) )
+        {
+            errors += "\nAva.normalize fails '" + ava.normalize() + "'";
+        }
+        
+        if ( !"OU=Exemple \\+ Rdn\u00E4\\ ".equals( ava.toString() ) )
+        {
+            errors += "\nAva.toString fails '" + ava.toString() + "'";
+        }
+        
+        assertEquals( null, errors );
+    }
+    
+    
+    /**
+     * Test the returned values for a schema aware Ava.
+     * \u00E4 is the unicode char for "ä", encoded \C3\A4 in UTF8
+     */
+    @Test
+    public void testAvaValuesSchemaAware() throws LdapException
+    {
+        String errors = null;
+        
+        Ava ava = new Ava( schemaManager, "OU", "Exemple + Rdn\u002B " );
+        
+        if ( !"2.5.4.11=exemple \\+ rdn\\+".equals( ava.getNormName() ) )
+        {
+            errors = "\nAva.getNormName fails '" + ava.getNormName() + "'";
+        }
+        
+        if ( !"2.5.4.11".equals( ava.getNormType() ) )
+        {
+            errors += "\nAva.getNormType fails '" + ava.getNormType() + "'";
+        }
+        
+        if ( !"exemple + rdn\u002B".equals( ava.getValue().getNormValue().toString() ) )
+        {
+            errors += "\nAva.getNormValue fails '" + ava.getValue().getNormValue().toString() + "'";
+        }
+        
+        if ( !"OU=Exemple \\+ Rdn\\+\\ ".equals( ava.getName() ) )
+        {
+            errors += "\nAva.getUpName fails '" + ava.getName() + "'";
+        }
+        
+        if ( !"OU".equals( ava.getType() ) )
+        {
+            errors += "\nAva.getUpType fails '" + ava.getType() + "'";
+        }
+        
+        if ( !"Exemple + Rdn\u002B ".equals( ava.getValue().getString() ) )
+        {
+            errors += "\nAva.getUpValue fails '" + ava.getValue().getString() + "'";
+        }
+        
+        if ( !"2.5.4.11=exemple \\+ rdn\\+".equals( ava.normalize() ) )
+        {
+            errors += "\nAva.normalize fails '" + ava.normalize() + "'";
+        }
+        
+        if ( !"OU=Exemple \\+ Rdn\\+\\ ".equals( ava.toString() ) )
+        {
+            errors += "\nAva.toString fails '" + ava.toString() + "'";
+        }
+        
+        assertEquals( null, errors );
+    }
+    
+    
+    @Test
+    public void testCompareToSameAva() throws LdapInvalidDnException
+    {
+        Ava atav1 = new Ava( schemaManager, "cn", "b" );
+        Ava atav2 = new Ava( schemaManager, "cn", "b" );
+        Ava atav3 = new Ava( schemaManager, "commonName", "b" );
+        Ava atav4 = new Ava( schemaManager, "2.5.4.3", "  B  " );
+
+        // 1 with others
+        assertEquals( 0, atav1.compareTo( atav1 ) );
+        assertEquals( 0, atav1.compareTo( atav2 ) );
+        assertEquals( 0, atav1.compareTo( atav3 ) );
+        assertEquals( 0, atav1.compareTo( atav4 ) );
+        
+        // 2 with others
+        assertEquals( 0, atav2.compareTo( atav1 ) );
+        assertEquals( 0, atav2.compareTo( atav2 ) );
+        assertEquals( 0, atav2.compareTo( atav3 ) );
+        assertEquals( 0, atav2.compareTo( atav4 ) );
+        
+        // 3 with others
+        assertEquals( 0, atav3.compareTo( atav1 ) );
+        assertEquals( 0, atav3.compareTo( atav2 ) );
+        assertEquals( 0, atav3.compareTo( atav3 ) );
+        assertEquals( 0, atav3.compareTo( atav4 ) );
+        
+        // 4 with others
+        assertEquals( 0, atav4.compareTo( atav1 ) );
+        assertEquals( 0, atav4.compareTo( atav2 ) );
+        assertEquals( 0, atav4.compareTo( atav3 ) );
+        assertEquals( 0, atav4.compareTo( atav4 ) );
+    }
+    
+    
+    @Test
+    public void testCompareAvaOrder() throws LdapInvalidDnException
+    {
+        Ava atav1 = new Ava( schemaManager, "cn", "  B  " );
+        Ava atav2 = new Ava( schemaManager, "sn", "  c" );
+        
+        // atav1 should be before atav2
+        assertEquals( -1, atav1.compareTo( atav2 ) );
+        assertEquals( 1, atav2.compareTo( atav1 ) );
+
+        Ava atav3 = new Ava( schemaManager, "2.5.4.3", "A " );
+        
+        // Atav1 shoud be after atav3
+        assertEquals( 1, atav1.compareTo( atav3 ) );
+        assertEquals( -1, atav3.compareTo( atav1 ) );
+    }
+    
+    
+    @Test
+    public void testSortAva() throws LdapInvalidDnException
+    {
+        Ava atav1 = new Ava( schemaManager, "cn", "  B  " );
+        Ava atav2 = new Ava( schemaManager, "sn", "  c" );
+        Ava atav3 = new Ava( schemaManager, "2.5.4.3", "A " );
+        Ava atav4 = new Ava( schemaManager, "2.5.4.11", " C  " );
+        Ava atav5 = new Ava( schemaManager, "ou", "B " );
+        Ava atav6 = new Ava( schemaManager, "ou", "D " );
+        Ava atav7 = new Ava( schemaManager, "CN", " " );
+
+        Ava[] avas = new Ava[] { atav1, atav2, atav3, atav4, atav5, atav6, atav7 };
+        
+        Arrays.sort( avas );
+        
+        assertEquals( atav5, avas[0] );
+        assertEquals( atav4, avas[1] );
+        assertEquals( atav6, avas[2] );
+        assertEquals( atav7, avas[3] );
+        assertEquals( atav3, avas[4] );
+        assertEquals( atav1, avas[5] );
+        assertEquals( atav2, avas[6] );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/DnTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/DnTest.java
new file mode 100644
index 0000000..5a54385
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/DnTest.java
@@ -0,0 +1,2992 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the class Dn
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DnTest
+{
+    private static SchemaManager schemaManager;
+
+
+    /**
+     * Initialize OIDs maps for normalization
+     */
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    // ------------------------------------------------------------------------------------
+    // CONSTRUCTOR functions --------------------------------------------------
+
+    /**
+     * Test a null Dn
+     */
+    @Test
+    public void testDnNull()
+    {
+        Dn dn = new Dn();
+        assertEquals( "", dn.getName() );
+        assertEquals( "", dn.getNormName() );
+        assertTrue( dn.isEmpty() );
+    }
+
+
+    /**
+     * test an empty Dn
+     */
+    @Test
+    public void testDnEmpty() throws LdapException
+    {
+        Dn dn = new Dn( "" );
+        assertEquals( "", dn.getName() );
+        assertTrue( dn.isEmpty() );
+    }
+
+
+    /**
+     * test a simple Dn : a = b
+     */
+    @Test
+    public void testDnSimple() throws LdapException
+    {
+        Dn dn = new Dn( "a = b" );
+
+        assertTrue( Dn.isValid( "a = b" ) );
+        assertEquals( "a = b", dn.getName() );
+        assertEquals( "a=b", dn.getNormName() );
+    }
+
+
+    /**
+     * test a simple Dn with some spaces : "a = b  "
+     */
+    @Test
+    public void testDnSimpleWithSpaces() throws LdapException
+    {
+        Dn dn = new Dn( "a = b  " );
+
+        assertTrue( Dn.isValid( "a = b  " ) );
+        assertEquals( "a = b  ", dn.getName() );
+        assertEquals( "a=b", dn.getNormName() );
+    }
+
+
+    /**
+     * test a composite Dn : a = b, d = e
+     */
+    @Test
+    public void testDnComposite() throws LdapException
+    {
+        Dn dn = new Dn( "a = b, c = d" );
+
+        assertTrue( Dn.isValid( "a = b, c = d" ) );
+        assertEquals( "a=b,c=d", dn.getNormName() );
+        assertEquals( "a = b, c = d", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with spaces : a = b  , d = e
+     */
+    @Test
+    public void testDnCompositeWithSpaces() throws LdapException
+    {
+        Dn dn = new Dn( "a = b  , c = d" );
+
+        assertTrue( Dn.isValid( "a = b  , c = d" ) );
+        assertEquals( "a=b,c=d", dn.getNormName() );
+        assertEquals( "a = b  , c = d", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with or without spaces: a=b, a =b, a= b, a = b, a = b
+     */
+    @Test
+    public void testDnCompositeWithSpace() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, a =b, a= b, a = b, a  =  b" );
+
+        assertTrue( Dn.isValid( "a=b, a =b, a= b, a = b, a  =  b" ) );
+        assertEquals( "a=b,a=b,a=b,a=b,a=b", dn.getNormName() );
+        assertEquals( "a=b, a =b, a= b, a = b, a  =  b", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with differents separators : a=b;c=d,e=f It should
+     * return a=b,c=d,e=f (the ';' is replaced by a ',')
+     */
+    @Test
+    public void testDnCompositeSepators() throws LdapException
+    {
+        Dn dn = new Dn( "a=b;c=d,e=f" );
+
+        assertTrue( Dn.isValid( "a=b;c=d,e=f" ) );
+        assertEquals( "a=b,c=d,e=f", dn.getNormName() );
+        assertEquals( "a=b;c=d,e=f", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with multiple NameComponents : a = b + c = d
+     */
+    @Test
+    public void testDnSimpleMultivaluedAttribute() throws LdapException
+    {
+        Dn dn = new Dn( "a = b + c = d" );
+
+        assertTrue( Dn.isValid( "a = b + c = d" ) );
+        assertEquals( "a=b+c=d", dn.getNormName() );
+        assertEquals( "a = b + c = d", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with multiple NC and separators : a=b+c=d, e=f + g=h +
+     * i=j
+     */
+    @Test
+    public void testDnCompositeMultivaluedAttribute() throws LdapException
+    {
+        Dn dn = new Dn( "a=b+c=d, e=f + g=h + i=j" );
+
+        assertTrue( Dn.isValid( "a=b+c=d, e=f + g=h + i=j" ) );
+        assertEquals( "a=b+c=d,e=f+g=h+i=j", dn.getNormName() );
+        assertEquals( "a=b+c=d, e=f + g=h + i=j", dn.getName() );
+    }
+
+
+    /**
+    * Test to see if a Dn with multiRdn values is preserved after an addAll.
+    */
+    @Test
+    public void testAddAllWithMultivaluedAttribute() throws LdapException
+    {
+        Dn dn = new Dn( "cn=Kate Bush+sn=Bush,ou=system" );
+        Dn target = new Dn();
+
+        assertTrue( Dn.isValid( "cn=Kate Bush+sn=Bush,ou=system" ) );
+        target = target.add( dn );
+        assertEquals( "cn=Kate Bush+sn=Bush,ou=system", target.toString() );
+        assertEquals( "cn=Kate Bush+sn=Bush,ou=system", target.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with an oid prefix (uppercase) : OID.12.34.56 = azerty
+     */
+    @Test
+    public void testDnOidUpper() throws LdapException
+    {
+        Dn dn = new Dn( "OID.12.34.56 = azerty" );
+
+        assertTrue( Dn.isValid( "OID.12.34.56 = azerty" ) );
+        assertEquals( "oid.12.34.56=azerty", dn.getNormName() );
+        assertEquals( "OID.12.34.56 = azerty", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with an oid prefix (lowercase) : oid.12.34.56 = azerty
+     */
+    @Test
+    public void testDnOidLower() throws LdapException
+    {
+        Dn dn = new Dn( "oid.12.34.56 = azerty" );
+
+        assertTrue( Dn.isValid( "oid.12.34.56 = azerty" ) );
+        assertEquals( "oid.12.34.56=azerty", dn.getNormName() );
+        assertEquals( "oid.12.34.56 = azerty", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with an oid attribut without oid prefix : 12.34.56 =
+     * azerty
+     */
+    @Test
+    public void testDnOidWithoutPrefix() throws LdapException
+    {
+        Dn dn = new Dn( "12.34.56 = azerty" );
+
+        assertTrue( Dn.isValid( "12.34.56 = azerty" ) );
+        assertEquals( "12.34.56=azerty", dn.getNormName() );
+        assertEquals( "12.34.56 = azerty", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with an oid attribut wiithout oid prefix : 12.34.56 =
+     * azerty; 7.8 = test
+     */
+    @Test
+    public void testDnCompositeOidWithoutPrefix() throws LdapException
+    {
+        Dn dn = new Dn( "12.34.56 = azerty; 7.8 = test" );
+
+        assertTrue( Dn.isValid( "12.34.56 = azerty; 7.8 = test" ) );
+        assertEquals( "12.34.56=azerty,7.8=test", dn.getNormName() );
+        assertEquals( "12.34.56 = azerty; 7.8 = test", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with pair char attribute value : a = \,\=\+\<\>\#\;\\\"\C4\8D"
+     */
+    @Test
+    public void testDnPairCharAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\\C4\\8D" );
+
+        assertTrue( Dn.isValid( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\\C4\\8D" ) );
+        assertEquals( "a=\\,\\=\\+\\<\\>#\\;\\\\\\\"\u010d", dn.getNormName() );
+        assertEquals( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\\C4\\8D", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with pair char attribute value : "SN=Lu\C4\8Di\C4\87"
+     */
+    @Test
+    public void testDnRFC253_Lucic() throws LdapException
+    {
+        Dn dn = new Dn( "SN=Lu\\C4\\8Di\\C4\\87" );
+
+        assertTrue( Dn.isValid( "SN=Lu\\C4\\8Di\\C4\\87" ) );
+        assertEquals( "sn=Lu\u010di\u0107", dn.getNormName() );
+        assertEquals( "SN=Lu\\C4\\8Di\\C4\\87", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with hexString attribute value : a = #0010A0AAFF
+     */
+    @Test
+    public void testDnHexStringAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = #0010A0AAFF" );
+
+        assertTrue( Dn.isValid( "a = #0010A0AAFF" ) );
+        assertEquals( "a=#0010A0AAFF", dn.getNormName() );
+        assertEquals( "a = #0010A0AAFF", dn.getName() );
+    }
+
+
+    /**
+     * Test for DIRSTUDIO-589, DIRSTUDIO-591, DIRSHARED-38
+     *
+     * Check escaped sharp followed by a hex sequence
+     * (without the ESC it would be a valid hexstring).
+     */
+    @Test
+    public void testDnEscSharpNumber() throws LdapException, LdapException
+    {
+        Dn dn = new Dn( "a = \\#123456" );
+
+        assertTrue( Dn.isValid( "a = \\#123456" ) );
+        assertEquals( "a=\\#123456", dn.getNormName() );
+        assertEquals( "a = \\#123456", dn.getName() );
+
+        Rdn rdn = dn.getRdn();
+        assertEquals( "a = \\#123456", rdn.getName() );
+
+        assertTrue( Dn.isValid( "a = \\#00" ) );
+        assertTrue( Dn.isValid( "a = \\#11" ) );
+        assertTrue( Dn.isValid( "a = \\#99" ) );
+        assertTrue( Dn.isValid( "a = \\#AA" ) );
+        assertTrue( Dn.isValid( "a = \\#FF" ) );
+
+        assertTrue( Dn.isValid( "uid=\\#123456" ) );
+        assertTrue( Dn.isValid( "cn=\\#ACL_AD-Projects_Author,ou=Notes_Group,o=Contacts,c=DE" ) );
+        assertTrue( Dn.isValid( "cn=\\#Abraham" ) );
+    }
+
+
+    /**
+     * Test for DIRSTUDIO-589, DIRSTUDIO-591, DIRSHARED-38
+     *
+     * Check escaped sharp followed by a hex sequence
+     * (without the ESC it would be a valid hexstring).
+     */
+    @Test
+    public void testDnEscValue() throws LdapException, LdapException
+    {
+        Dn dn = new Dn( "cn = Exa\\+mple  one " );
+
+        assertTrue( Dn.isValid( "cn = Exa\\+mple  one " ) );
+        assertEquals( "cn=Exa\\+mple  one", dn.getNormName() );
+        assertEquals( "cn = Exa\\+mple  one ", dn.getName() );
+
+        Dn dn2 = new Dn( schemaManager, "cn = Exa\\+mple  one " );
+
+        assertEquals( "2.5.4.3=exa\\+mple one", dn2.getNormName() );
+        assertEquals( "cn = Exa\\+mple  one ", dn2.getName() );
+    }
+
+
+    /**
+      * test a simple Dn with a # on first position
+      */
+    @Test
+    public void testDnSharpFirst() throws LdapException, LdapException
+    {
+        Dn dn = new Dn( "a = \\#this is a sharp" );
+
+        assertTrue( Dn.isValid( "a = \\#this is a sharp" ) );
+        assertEquals( "a=\\#this is a sharp", dn.getNormName() );
+        assertEquals( "a = \\#this is a sharp", dn.getName() );
+
+        Rdn rdn = dn.getRdn();
+        assertEquals( "a = \\#this is a sharp", rdn.getName() );
+    }
+
+
+    /**
+     * Normalize a simple Dn with a # on first position
+     */
+    @Test
+    public void testNormalizeDnSharpFirst() throws LdapException, LdapException
+    {
+        Dn dn = new Dn( "ou = \\#this is a sharp" );
+
+        assertTrue( Dn.isValid( "ou = \\#this is a sharp" ) );
+        assertEquals( "ou=\\#this is a sharp", dn.getNormName() );
+        assertEquals( "ou = \\#this is a sharp", dn.getName() );
+
+        // Check the normalization now
+        Dn ndn = dn.apply( schemaManager );
+
+        assertEquals( "ou = \\#this is a sharp", ndn.getName() );
+        assertEquals( "2.5.4.11=\\#this is a sharp", ndn.getNormName() );
+    }
+
+
+    /**
+     * Normalize a Dn with sequence ESC ESC HEX HEX (\\C3\\A4).
+     * This is a corner case for the parser and normalizer.
+     */
+    @Test
+    public void testNormalizeDnEscEscHexHexEscSpecial() throws LdapException
+    {
+        Dn dn = new Dn( "ou = AC\\\\C3\\2B" );
+        assertTrue( Dn.isValid( "ou = AC\\\\C3\\2B" ) );
+        assertEquals( "ou=AC\\\\C3\\+", dn.getNormName() );
+        assertEquals( "ou = AC\\\\C3\\2B", dn.getName() );
+
+        // Check the normalization now
+        Dn ndn = dn.apply( schemaManager );
+        assertEquals( "ou = AC\\\\C3\\2B", ndn.getName() );
+        assertEquals( "2.5.4.11=ac\\\\c3\\+", ndn.getNormName() );
+    }
+
+    /**
+     * Normalize a Dn with sequence ESC ESC HEX HEX (\\DC).
+     * This is a corner case for the parser and normalizer.
+     */
+    @Test
+    public void testNormalizeDnEscEscHexHex() throws LdapException
+    {
+        Dn dn = new Dn( "ou = AC\\\\DC" );
+        assertTrue( Dn.isValid( "ou = AC\\\\DC" ) );
+        assertEquals( "ou=AC\\\\DC", dn.getNormName() );
+        assertEquals( "ou = AC\\\\DC", dn.getName() );
+
+        // Check the normalization now
+        Dn ndn = dn.apply( schemaManager );
+        assertEquals( "ou = AC\\\\DC", ndn.getName() );
+        assertEquals( "2.5.4.11=ac\\\\dc", ndn.getNormName() );
+    }
+
+
+    /**
+     * test a simple Dn with a wrong hexString attribute value : a = #0010Z0AAFF
+     */
+    @Test
+    public void testDnWrongHexStringAttributeValue()
+    {
+        try
+        {
+            new Dn( "a = #0010Z0AAFF" );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+
+            assertFalse( Dn.isValid( "a = #0010Z0AAFF" ) );
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a simple Dn with a wrong hexString attribute value : a = #AABBCCDD3
+     */
+    @Test
+    public void testDnWrongHexStringAttributeValue2()
+    {
+        try
+        {
+            new Dn( "a = #AABBCCDD3" );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertFalse( Dn.isValid( "a = #AABBCCDD3" ) );
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a simple Dn with a quote in attribute value : a = quoted \"value\"
+     */
+    @Test
+    public void testDnQuoteInAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = quoted \\\"value\\\"" );
+
+        assertTrue( Dn.isValid( "a = quoted \\\"value\\\"" ) );
+        assertEquals( "a=quoted \\\"value\\\"", dn.getNormName() );
+        assertEquals( "a = quoted \\\"value\\\"", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with quoted attribute value : a = \" quoted value \"
+     */
+    @Test
+    public void testDnQuotedAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = \\\" quoted value \\\"" );
+
+        assertTrue( Dn.isValid( "a = \\\" quoted value \\\"" ) );
+        assertEquals( "a=\\\" quoted value \\\"", dn.getNormName() );
+        assertEquals( "a = \\\" quoted value \\\"", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with a comma at the end
+     */
+    @Test
+    public void testDnComaAtEnd()
+    {
+        assertFalse( Dn.isValid( "a = b," ) );
+        assertFalse( Dn.isValid( "a = b, " ) );
+
+        try
+        {
+            new Dn( "a = b," );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    // REMOVE operation -------------------------------------------------------
+
+    /**
+     * test a remove from position 0
+     *
+    @Test
+    public void testDnRemove0() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d, e=f" );
+
+        assertTrue( Dn.isValid("a=b, c=d, e=f") );
+        // now remove method returns a modified cloned Dn
+        dn = dn.remove( 0 );
+        assertEquals( "a=b,c=d", dn.getNormName() );
+        assertEquals( "a=b, c=d", dn.getName() );
+    }
+
+
+    /**
+     * test a remove from position 1
+     *
+    @Test
+    public void testDnRemove1() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d, e=f" );
+
+        assertTrue( Dn.isValid("a=b, c=d, e=f") );
+        assertEquals( "a=b, c=d, e=f", dn.getName() );
+    }
+
+
+    /**
+     * test a remove from position 2
+     *
+    @Test
+    public void testDnRemove2() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d, e=f" );
+
+        assertTrue( Dn.isValid("a=b, c=d, e=f") );
+        dn = dn.remove( 2 );
+        assertEquals( " c=d, e=f", dn.getName() );
+    }
+
+
+    /**
+     * test a remove from position 1 whith semi colon
+     *
+    @Test
+    public void testDnRemove1WithSemiColon() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d; e=f" );
+
+        assertTrue( Dn.isValid("a=b, c=d; e=f") );
+        dn = dn.remove( 1 );
+        assertEquals( "a=b, e=f", dn.getName() );
+    }
+
+
+    /**
+     * test a remove out of bound
+     *
+    @Test
+    public void testDnRemoveOutOfBound() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d; e=f" );
+
+        assertTrue( Dn.isValid("a=b, c=d; e=f") );
+
+        try
+        {
+            dn.remove( 4 );
+            // We whould never reach this point
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aoobe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    // SIZE operations
+    /**
+     * test a 0 size
+     */
+    @Test
+    public void testDnSize0()
+    {
+        Dn dn = new Dn();
+
+        assertTrue( Dn.isValid( "" ) );
+        assertEquals( 0, dn.size() );
+    }
+
+
+    /**
+     * test a 1 size
+     */
+    @Test
+    public void testDnSize1() throws LdapException
+    {
+        Dn dn = new Dn( "a=b" );
+
+        assertTrue( Dn.isValid( "a=b" ) );
+        assertEquals( 1, dn.size() );
+    }
+
+
+    /**
+     * test a 3 size
+     */
+    @Test
+    public void testDnSize3() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d, e=f" );
+
+        assertTrue( Dn.isValid( "a=b, c=d, e=f" ) );
+        assertEquals( 3, dn.size() );
+    }
+
+
+    /**
+     * test a 3 size with NameComponents
+     */
+    @Test
+    public void testDnSize3NC() throws LdapException
+    {
+        Dn dn = new Dn( "a=b+c=d, c=d, e=f" );
+
+        assertTrue( Dn.isValid( "a=b+c=d, c=d, e=f" ) );
+        assertEquals( 3, dn.size() );
+    }
+
+
+    /**
+     * test size after operations
+     */
+    @Test
+    public void testLdapResizing() throws LdapException
+    {
+        Dn dn = new Dn();
+        assertEquals( 0, dn.size() );
+
+        dn = dn.add( "e = f" );
+        assertEquals( 1, dn.size() );
+
+        dn = dn.add( "c = d" );
+        assertEquals( 2, dn.size() );
+
+        dn = dn.getParent();
+        assertEquals( 1, dn.size() );
+
+        dn = dn.getParent();
+        assertEquals( 0, dn.size() );
+    }
+
+
+    // ADD Operations
+    /**
+     * test Add on a new Dn
+     */
+    @Test
+    public void testLdapEmptyAdd() throws LdapException
+    {
+        Dn dn = new Dn();
+
+        dn = dn.add( "e = f" );
+        assertEquals( "e=f", dn.getNormName() );
+        assertEquals( "e = f", dn.getName() );
+        assertEquals( 1, dn.size() );
+    }
+
+
+    /**
+     * test Add to an existing Dn
+     */
+    @Test
+    public void testDnAdd() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d" );
+
+        dn = dn.add( "e = f" );
+        assertEquals( "e=f,a=b,c=d", dn.getNormName() );
+        assertEquals( "e = f,a=b, c=d", dn.getName() );
+        assertEquals( 3, dn.size() );
+    }
+
+
+    /**
+     * test Add a composite Rdn to an existing Dn
+     */
+    @Test
+    public void testDnAddComposite() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d" );
+
+        dn = dn.add( "e = f + g = h" );
+
+        // Warning ! The order of AVAs has changed during the parsing
+        // This has no impact on the correctness of the Dn, but the
+        // String used to do the comparizon should be inverted.
+        assertEquals( "e=f+g=h,a=b,c=d", dn.getNormName() );
+        assertEquals( 3, dn.size() );
+    }
+
+
+    /**
+     * test Add at the end of an existing Dn
+     */
+    @Test
+    public void testDnAddEnd() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d" );
+
+        dn = dn.add( "e = f" );
+        assertEquals( "e = f,a=b, c=d", dn.getName() );
+        assertEquals( 3, dn.size() );
+    }
+
+
+    // ADD ALL Operations
+    /**
+     * Test AddAll
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testDnAddAll() throws LdapException
+    {
+        Dn dn = new Dn( "a = b" );
+        Dn dn2 = new Dn( "c = d" );
+        dn = dn.add( dn2 );
+        assertEquals( "c = d,a = b", dn.getName() );
+    }
+
+
+    /**
+     * Test AddAll with an empty added name
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testDnAddAllAddedNameEmpty() throws LdapException
+    {
+        Dn dn = new Dn( "a = b" );
+        Dn dn2 = new Dn();
+        dn = dn.add( dn2 );
+        assertEquals( "a=b", dn.getNormName() );
+        assertEquals( "a = b", dn.getName() );
+    }
+
+
+    /**
+     * Test AddAll to an empty name
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testDnAddAllNameEmpty() throws LdapException
+    {
+        Dn dn = new Dn();
+        Dn dn2 = new Dn( "a = b" );
+        dn = dn.add( dn2 );
+        assertEquals( "a = b", dn.getName() );
+    }
+
+
+    /**
+     * Test AddAll at position 0
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testDnAt0AddAll() throws LdapException
+    {
+        Dn dn = new Dn( "a = b" );
+        Dn dn2 = new Dn( "c = d" );
+        dn = dn2.add( dn );
+        assertEquals( "a = b,c = d", dn.getName() );
+    }
+
+
+    /**
+     * Test AddAll at position 1
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testDnAt1AddAll() throws LdapException
+    {
+        Dn dn = new Dn( "a = b" );
+        Dn dn2 = new Dn( "c = d" );
+        dn = dn.add( dn2 );
+        assertEquals( "c = d,a = b", dn.getName() );
+    }
+
+
+    /**
+     * Test AddAll with an empty added name at position 0
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testDnAddAllAt0AddedNameEmpty() throws LdapException
+    {
+        Dn dn = new Dn( "a = b" );
+        Dn dn2 = new Dn();
+        dn = dn.add( dn2 );
+        assertEquals( "a=b", dn.getNormName() );
+        assertEquals( "a = b", dn.getName() );
+    }
+
+
+    /**
+     * Test AddAll to an empty name at position 0
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testDnAddAllAt0NameEmpty() throws LdapException
+    {
+        Dn dn = new Dn();
+        Dn dn2 = new Dn( "a = b" );
+        dn = dn.add( dn2 );
+        assertEquals( "a = b", dn.getName() );
+    }
+
+
+    // GET PREFIX actions
+    /**
+     * Get the prefix at pos 0
+     */
+    @Test
+    public void testDnGetPrefixPos0() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getAncestorOf( "" ) );
+        assertEquals( "a=b, c=d,e = f", newDn.getName() );
+    }
+
+
+    /**
+     * Get the prefix at pos 1
+     */
+    @Test
+    public void testDnGetPrefixPos1() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getAncestorOf( "a=b" ) );
+        assertEquals( " c=d,e = f", newDn.getName() );
+    }
+
+
+    /**
+     * Get the prefix at pos 2
+     */
+    @Test
+    public void testDnGetPrefixPos2() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getAncestorOf( "a=b, c=d" ) );
+        assertEquals( "e = f", newDn.getName() );
+    }
+
+
+    /**
+     * Get the prefix at pos 3
+     */
+    @Test
+    public void testDnGetPrefixPos3() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getAncestorOf( "a=b, c=d,e = f" ) );
+        assertEquals( "", newDn.getName() );
+    }
+
+
+    /**
+     * Get the prefix out of bound
+     */
+    @Test(expected = LdapInvalidDnException.class)
+    public void testDnGetPrefixPos4() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+
+        dn.getAncestorOf( "a=z" );
+    }
+
+
+    /**
+     * Get the prefix of an empty LdapName
+     */
+    @Test
+    public void testDnGetPrefixEmptyDN() throws LdapInvalidDnException
+    {
+        Dn dn = new Dn();
+        Dn newDn = ( dn.getAncestorOf( "" ) );
+        assertEquals( "", newDn.getName() );
+    }
+
+
+    // GET SUFFIX operations
+    /**
+     * Get the suffix at pos 0
+     */
+    @Test
+    public void testDnGetSuffixPos0() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getDescendantOf( "" ) );
+        assertEquals( "a=b, c=d,e = f", newDn.getName() );
+    }
+
+
+    /**
+     * Get the suffix at pos 1
+     */
+    @Test
+    public void testDnGetSuffixPos1() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getDescendantOf( "e=f" ) );
+        assertEquals( "a=b, c=d", newDn.getName() );
+    }
+
+
+    /**
+     * Get the suffix at pos 2
+     */
+    @Test
+    public void testDnGetSuffixPos2() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getDescendantOf( "c=d,e=f" ) );
+        assertEquals( "a=b", newDn.getName() );
+    }
+
+
+    /**
+     * Get the suffix at pos 3
+     */
+    @Test
+    public void testDnGetSuffixPos3() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        Dn newDn = ( dn.getDescendantOf( "a=b, c=d, e=f" ) );
+        assertEquals( "", newDn.getName() );
+    }
+
+
+    /**
+     * Get the suffix out of bound
+     */
+    @Test
+    public void testDnGetSuffixPos4() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+
+        try
+        {
+            dn.getDescendantOf( "i=j, a=b, c=d, e=f" );
+            // We should not reach this point.
+            fail();
+        }
+        catch ( ArrayIndexOutOfBoundsException aoobe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Get the suffix of an empty LdapName
+     *
+    @Test
+    public void testDnGetSuffixEmptyDN()
+    {
+        Dn dn = new Dn();
+        Dn newDn = ( dn.getSuffix( 0 ) );
+        assertEquals( "", newDn.getName() );
+    }
+
+
+    // IS EMPTY operations
+    /**
+     * Test that a Dn is empty
+     */
+    @Test
+    public void testDnIsEmpty()
+    {
+        Dn dn = new Dn();
+        assertEquals( true, dn.isEmpty() );
+    }
+
+
+    /**
+     * Test that a Dn is empty
+     */
+    @Test
+    public void testDnNotEmpty() throws LdapException
+    {
+        Dn dn = new Dn( "a=b" );
+        assertEquals( false, dn.isEmpty() );
+    }
+
+
+    /**
+     * Test that a Dn is empty
+     *
+    @Test
+    public void testDnRemoveIsEmpty() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d" );
+        Dn clonedDn = dn.remove( 0 );
+
+        assertFalse( dn == clonedDn );
+
+        clonedDn = clonedDn.remove( 0 );
+
+        assertEquals( true, clonedDn.isEmpty() );
+    }
+
+
+    // STARTS WITH operations
+    /**
+     * Test a startsWith a null Dn
+     */
+    @Test
+    public void testDnStartsWithNull() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( true, dn.isDescendantOf( ( Dn ) null ) );
+    }
+
+
+    /**
+     * Test a startsWith an empty Dn
+     */
+    @Test
+    public void testDnStartsWithEmpty() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( true, dn.isDescendantOf( new Dn() ) );
+    }
+
+
+    /**
+     * Test a startsWith an simple Dn
+     */
+    @Test
+    public void testDnStartsWithSimple() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( true, dn.isDescendantOf( new Dn( "e=f" ) ) );
+    }
+
+
+    /**
+     * Test a startsWith a complex Dn
+     */
+    @Test
+    public void testDnStartsWithComplex() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( true, dn.isDescendantOf( new Dn( "c =  d, e =  f" ) ) );
+    }
+
+
+    /**
+     * Test a startsWith a complex Dn
+     */
+    @Test
+    public void testDnStartsWithComplexMixedCase() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( false, dn.isDescendantOf( new Dn( "c =  D, E =  f" ) ) );
+    }
+
+
+    /**
+     * Test a startsWith a full Dn
+     */
+    @Test
+    public void testDnStartsWithFull() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( true, dn.isDescendantOf( new Dn( "a=  b; c =  d, e =  f" ) ) );
+    }
+
+
+    /**
+     * Test a startsWith which returns false
+     */
+    @Test
+    public void testDnStartsWithWrong() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( false, dn.isDescendantOf( new Dn( "c =  t, e =  f" ) ) );
+    }
+
+
+    // ENDS WITH operations
+    /**
+     * Test a endsWith a null Dn
+     */
+    @Test
+    public void testDnEndsWithNull() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, c=d,e = f" );
+        assertEquals( true, dn.isDescendantOf( ( Dn ) null ) );
+    }
+
+
+    @Test
+    public void testAttributeEqualsIsCaseInSensitive() throws Exception
+    {
+        Dn name1 = new Dn( "cn=HomeDir" );
+        Dn name2 = new Dn( "CN=HomeDir" );
+
+        assertTrue( name1.equals( name2 ) );
+    }
+
+
+    @Test
+    public void testAttributeTypeEqualsIsCaseInsensitive() throws Exception
+    {
+        Dn name1 = new Dn( "cn=HomeDir+Sn=WorkDir" );
+        Dn name2 = new Dn( "cn=HomeDir+SN=WorkDir" );
+
+        assertTrue( name1.equals( name2 ) );
+    }
+
+
+    @Test
+    public void testNameEqualsIsInsensitiveToAttributesOrder() throws Exception
+    {
+
+        Dn name1 = new Dn( "cn=HomeDir+sn=WorkDir" );
+        Dn name2 = new Dn( "sn=WorkDir+cn=HomeDir" );
+
+        assertTrue( name1.equals( name2 ) );
+    }
+
+
+    @Test
+    public void testAttributeComparisonIsCaseInSensitive() throws Exception
+    {
+        Dn name1 = new Dn( "cn=HomeDir" );
+        Dn name2 = new Dn( "CN=HomeDir" );
+
+        assertEquals( name1, name2 );
+    }
+
+
+    @Test
+    public void testAttributeTypeComparisonIsCaseInsensitive() throws Exception
+    {
+        Dn name1 = new Dn( "cn=HomeDir+sn=WorkDir" );
+        Dn name2 = new Dn( "cn=HomeDir+SN=WorkDir" );
+
+        assertEquals( name1, name2 );
+    }
+
+
+    @Test
+    public void testNameComparisonIsInsensitiveToAttributesOrder() throws Exception
+    {
+
+        Dn name1 = new Dn( "cn=HomeDir+sn=WorkDir" );
+        Dn name2 = new Dn( "sn=WorkDir+cn=HomeDir" );
+
+        assertEquals( name1, name2 );
+    }
+
+
+    @Test
+    public void testNameComparisonIsInsensitiveToAttributesOrderFailure() throws Exception
+    {
+
+        Dn name1 = new Dn( "cn= HomeDir+sn=Workdir" );
+        Dn name2 = new Dn( "sn = Work+cn=HomeDir" );
+
+        assertNotSame( name1, name2 );
+    }
+
+
+    /**
+     * Test the encoding of a LdanDN
+     */
+    @Test
+    public void testNameToBytes() throws Exception
+    {
+        Dn dn = new Dn( "cn = John, ou = People, OU = Marketing" );
+
+        byte[] bytes = Dn.getBytes( dn );
+
+        assertEquals( 30, Dn.getNbBytes( dn ) );
+        assertEquals( "cn=John,ou=People,ou=Marketing", new String( bytes, "UTF-8" ) );
+    }
+
+
+    @Test
+    public void testStringParser() throws Exception
+    {
+        String dn = Strings.utf8ToString( new byte[]
+            { 'C', 'N', ' ', '=', ' ', 'E', 'm', 'm', 'a', 'n', 'u', 'e', 'l', ' ', ' ', 'L', ( byte ) 0xc3,
+                ( byte ) 0xa9, 'c', 'h', 'a', 'r', 'n', 'y' } );
+
+        Dn name = new Dn( dn );
+
+        assertEquals( dn, ( name ).getName() );
+        assertEquals( "cn=Emmanuel  L\u00e9charny", ( name ).getNormName() );
+    }
+
+
+    /**
+     * Class to test for void LdapName(String)
+     *
+     * @throws Exception
+     *             if anything goes wrong.
+     */
+    @Test
+    public void testLdapNameString() throws Exception
+    {
+        Dn name = new Dn( "" );
+        Dn name50 = new Dn();
+        assertEquals( name50, name );
+
+        Dn name0 = new Dn( "ou=Marketing,ou=East" );
+        Dn copy = new Dn( "ou=Marketing,ou=East" );
+        Dn name1 = new Dn( "cn=John,ou=Marketing,ou=East" );
+        Dn name2 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        Dn name3 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+        Dn name4 = new Dn( "cn=Website,cn=John,ou=Marketing,ou=West" );
+        Dn name5 = new Dn( "cn=Airline,cn=John,ou=Marketing,ou=West" );
+
+        assertEquals( name0, copy );
+        assertTrue( name0.isAncestorOf( name1 ) );
+        assertTrue( name0.isAncestorOf( name2 ) );
+        assertTrue( name1.isAncestorOf( name2 ) );
+        assertTrue( name2.isDescendantOf( name1 ) );
+        assertTrue( name2.isDescendantOf( name0 ) );
+        assertNotSame( name2, name3 );
+        assertNotSame( name2, name4 );
+        assertNotSame( name3, name4 );
+        assertNotSame( name3, name5 );
+        assertNotSame( name4, name5 );
+        assertNotSame( name2, name5 );
+    }
+
+
+    /**
+     * Class to test for void LdapName()
+     */
+    @Test
+    public void testLdapName()
+    {
+        Dn name = new Dn();
+        assertTrue( name.toString().equals( "" ) );
+    }
+
+
+    /**
+     * Class to test for Object clone()
+     *
+     * @throws Exception
+     *             if anything goes wrong.
+     *
+    @Test
+    public void testClone() throws Exception
+    {
+        String strName = "cn=HomeDir,cn=John,ou=Marketing,ou=East";
+        Dn name = new Dn( strName );
+        assertEquals( name, name.clone() );
+    }
+
+
+    /**
+     * Class to test for size
+     *
+     * @throws Exception
+     *             if anything goes wrong.
+     */
+    @Test
+    public void testSize() throws Exception
+    {
+        Dn name0 = new Dn( "" );
+        Dn name1 = new Dn( "ou=East" );
+        Dn name2 = new Dn( "ou=Marketing,ou=East" );
+        Dn name3 = new Dn( "cn=John,ou=Marketing,ou=East" );
+        Dn name4 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        Dn name5 = new Dn( "cn=Website,cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+        Dn name6 = new Dn( "cn=Airline,cn=Website,cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+
+        assertEquals( 0, name0.size() );
+        assertEquals( 1, name1.size() );
+        assertEquals( 2, name2.size() );
+        assertEquals( 3, name3.size() );
+        assertEquals( 4, name4.size() );
+        assertEquals( 5, name5.size() );
+        assertEquals( 6, name6.size() );
+    }
+
+
+    /**
+     * Class to test for isEmpty
+     *
+     * @throws Exception
+     *             if anything goes wrong.
+     */
+    @Test
+    public void testIsEmpty() throws Exception
+    {
+        Dn name0 = new Dn( "" );
+        Dn name1 = new Dn( "ou=East" );
+        Dn name2 = new Dn( "ou=Marketing,ou=East" );
+        Dn name3 = new Dn( "cn=John,ou=Marketing,ou=East" );
+        Dn name4 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        Dn name5 = new Dn( "cn=Website,cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+        Dn name6 = new Dn( "cn=Airline,cn=Website,cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+
+        assertEquals( true, name0.isEmpty() );
+        assertEquals( false, name1.isEmpty() );
+        assertEquals( false, name2.isEmpty() );
+        assertEquals( false, name3.isEmpty() );
+        assertEquals( false, name4.isEmpty() );
+        assertEquals( false, name5.isEmpty() );
+        assertEquals( false, name6.isEmpty() );
+    }
+
+
+    /**
+     * Class to test for getAll
+     *
+     * @throws Exception
+     *             if anything goes wrong.
+     *
+    @Test
+    public void testGetAll() throws Exception
+    {
+        Dn name0 = new Dn( "" );
+        Dn name1 = new Dn( "ou=East" );
+        Dn name2 = new Dn( "ou=Marketing,ou=East" );
+        Dn name3 = new Dn( "cn=John,ou=Marketing,ou=East" );
+        Dn name4 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        Dn name5 = new Dn( "cn=Website,cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+        Dn name6 = new Dn( "cn=Airline,cn=Website,cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+
+        Enumeration<String> enum0 = name0.getAll();
+        assertEquals( false, enum0.hasMoreElements() );
+
+        Enumeration<String> enum1 = name1.getAll();
+        assertEquals( true, enum1.hasMoreElements() );
+
+        for ( int i = 0; enum1.hasMoreElements(); i++ )
+        {
+            String element = ( String ) enum1.nextElement();
+
+            if ( i == 0 )
+            {
+                assertEquals( "ou=East", element );
+            }
+        }
+
+        Enumeration<String> enum2 = name2.getAll();
+        assertEquals( true, enum2.hasMoreElements() );
+
+        for ( int i = 0; enum2.hasMoreElements(); i++ )
+        {
+            String element = ( String ) enum2.nextElement();
+
+            if ( i == 0 )
+            {
+                assertEquals( "ou=East", element );
+            }
+
+            if ( i == 1 )
+            {
+                assertEquals( "ou=Marketing", element );
+            }
+        }
+
+        Enumeration<String> enum3 = name3.getAll();
+        assertEquals( true, enum3.hasMoreElements() );
+
+        for ( int i = 0; enum3.hasMoreElements(); i++ )
+        {
+            String element = ( String ) enum3.nextElement();
+
+            if ( i == 0 )
+            {
+                assertEquals( "ou=East", element );
+            }
+
+            if ( i == 1 )
+            {
+                assertEquals( "ou=Marketing", element );
+            }
+
+            if ( i == 2 )
+            {
+                assertEquals( "cn=John", element );
+            }
+        }
+
+        Enumeration<String> enum4 = name4.getAll();
+        assertEquals( true, enum4.hasMoreElements() );
+
+        for ( int i = 0; enum4.hasMoreElements(); i++ )
+        {
+            String element = ( String ) enum4.nextElement();
+
+            if ( i == 0 )
+            {
+                assertEquals( "ou=East", element );
+            }
+
+            if ( i == 1 )
+            {
+                assertEquals( "ou=Marketing", element );
+            }
+
+            if ( i == 2 )
+            {
+                assertEquals( "cn=John", element );
+            }
+
+            if ( i == 3 )
+            {
+                assertEquals( "cn=HomeDir", element );
+            }
+        }
+
+        Enumeration<String> enum5 = name5.getAll();
+        assertEquals( true, enum5.hasMoreElements() );
+
+        for ( int i = 0; enum5.hasMoreElements(); i++ )
+        {
+            String element = ( String ) enum5.nextElement();
+
+            if ( i == 0 )
+            {
+                assertEquals( "ou=West", element );
+            }
+
+            if ( i == 1 )
+            {
+                assertEquals( "ou=Marketing", element );
+            }
+
+            if ( i == 2 )
+            {
+                assertEquals( "cn=John", element );
+            }
+
+            if ( i == 3 )
+            {
+                assertEquals( "cn=HomeDir", element );
+            }
+
+            if ( i == 4 )
+            {
+                assertEquals( "cn=Website", element );
+            }
+        }
+
+        Enumeration<String> enum6 = name6.getAll();
+        assertEquals( true, enum6.hasMoreElements() );
+
+        for ( int i = 0; enum6.hasMoreElements(); i++ )
+        {
+            String element = ( String ) enum6.nextElement();
+
+            if ( i == 0 )
+            {
+                assertEquals( "ou=West", element );
+            }
+
+            if ( i == 1 )
+            {
+                assertEquals( "ou=Marketing", element );
+            }
+
+            if ( i == 2 )
+            {
+                assertEquals( "cn=John", element );
+            }
+
+            if ( i == 3 )
+            {
+                assertEquals( "cn=HomeDir", element );
+            }
+
+            if ( i == 4 )
+            {
+                assertEquals( "cn=Website", element );
+            }
+
+            if ( i == 5 )
+            {
+                assertEquals( "cn=Airline", element );
+            }
+        }
+    }
+
+
+    /**
+     * Class to test for getAllRdn
+     *
+     * @throws Exception
+     *             if anything goes wrong.
+     */
+    @Test
+    public void testIterator() throws Exception
+    {
+        Dn dn = new Dn( "cn=Airline,cn=Website,cn=HomeDir,cn=John,ou=Marketing,ou=West" );
+        String[] expected = new String[]
+            { "ou=West", "ou=Marketing", "cn=John", "cn=HomeDir", "cn=Website", "cn=Airline" };
+        int count = 0;
+
+        for ( Rdn rdn : dn )
+        {
+            assertEquals( expected[count], rdn.toString() );
+            count++;
+        }
+    }
+
+
+    /**
+     * Test the getRdn( int ) method
+     */
+    @Test
+    public void testGetRdn() throws Exception
+    {
+        Dn name = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        assertEquals( "cn=HomeDir", name.getRdn( 0 ).getName() );
+        assertEquals( "cn=John", name.getRdn( 1 ).getName() );
+        assertEquals( "ou=Marketing", name.getRdn( 2 ).getName() );
+        assertEquals( "ou=East", name.getRdn( 3 ).getName() );
+    }
+
+
+    /**
+     * Test the getRdns() method
+     */
+    @Test
+    public void testGetRdns() throws Exception
+    {
+        Dn dn = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+
+        String[] expected = new String[]
+            { "cn=HomeDir", "cn=John", "ou=Marketing", "ou=East" };
+
+        int i = 0;
+
+        for ( Rdn rdn : dn.getRdns() )
+        {
+            assertEquals( expected[i], rdn.getName() );
+            i++;
+        }
+    }
+
+
+    /**
+     * Class to test for getSuffix
+     *
+     * @throws Exception
+     *             anything goes wrong
+     */
+    @Test
+    public void testGetXSuffix() throws Exception
+    {
+        Dn name = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        assertEquals( "", name.getDescendantOf( "cn=HomeDir,cn=John,ou=Marketing,ou=East" ).toString() );
+        assertEquals( "cn=HomeDir", name.getDescendantOf( "cn=John,ou=Marketing,ou=East" ).toString() );
+        assertEquals( "cn=HomeDir,cn=John", name.getDescendantOf( "ou=Marketing,ou=East" ).toString() );
+        assertEquals( "cn=HomeDir,cn=John,ou=Marketing", name.getDescendantOf( "ou=East" ).toString() );
+        assertEquals( "cn=HomeDir,cn=John,ou=Marketing,ou=East", name.getDescendantOf( "" ).toString() );
+    }
+
+
+    /**
+     * Class to test for getPrefix
+     *
+     * @throws Exception
+     *             anything goes wrong
+     */
+    @Test
+    public void testGetPrefix() throws Exception
+    {
+        Dn name = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+
+        assertEquals( "cn=HomeDir,cn=John,ou=Marketing,ou=East", name.getAncestorOf( "" ).toString() );
+        assertEquals( "cn=John,ou=Marketing,ou=East", name.getAncestorOf( "cn=HomeDir" ).toString() );
+        assertEquals( "ou=Marketing,ou=East", name.getAncestorOf( "cn=HomeDir,cn=John" ).toString() );
+        assertEquals( "ou=East", name.getAncestorOf( "cn=HomeDir,cn=John,ou=Marketing" ).toString() );
+        assertEquals( "", name.getAncestorOf( "cn=HomeDir,cn=John,ou=Marketing,ou=East" ).toString() );
+    }
+
+
+    /**
+     * Class to test for startsWith
+     *
+     * @throws Exception
+     *             anything goes wrong
+     */
+    @Test
+    public void testStartsWith() throws Exception
+    {
+        Dn n0 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        Dn n1 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        Dn n2 = new Dn( "cn=John,ou=Marketing,ou=East" );
+        Dn n3 = new Dn( "ou=Marketing,ou=East" );
+        Dn n4 = new Dn( "ou=East" );
+        Dn n5 = new Dn( "" );
+
+        Dn n6 = new Dn( "cn=HomeDir" );
+        Dn n7 = new Dn( "cn=HomeDir,cn=John" );
+        Dn n8 = new Dn( "cn=HomeDir,cn=John,ou=Marketing" );
+
+        // Check with Dn
+        assertTrue( n0.isDescendantOf( n1 ) );
+        assertTrue( n0.isDescendantOf( n2 ) );
+        assertTrue( n0.isDescendantOf( n3 ) );
+        assertTrue( n0.isDescendantOf( n4 ) );
+        assertTrue( n0.isDescendantOf( n5 ) );
+
+        assertTrue( !n0.isDescendantOf( n6 ) );
+        assertTrue( !n0.isDescendantOf( n7 ) );
+        assertTrue( !n0.isDescendantOf( n8 ) );
+
+        Dn nn0 = new Dn( "cn=zero" );
+        Dn nn10 = new Dn( "cn=one,cn=zero" );
+        Dn nn210 = new Dn( "cn=two,cn=one,cn=zero" );
+        Dn nn3210 = new Dn( "cn=three,cn=two,cn=one,cn=zero" );
+
+        assertTrue( nn0.isDescendantOf( nn0 ) );
+        assertTrue( nn10.isDescendantOf( nn0 ) );
+        assertTrue( nn210.isDescendantOf( nn0 ) );
+        assertTrue( nn3210.isDescendantOf( nn0 ) );
+
+        assertTrue( nn10.isDescendantOf( nn10 ) );
+        assertTrue( nn210.isDescendantOf( nn10 ) );
+        assertTrue( nn3210.isDescendantOf( nn10 ) );
+
+        assertTrue( nn210.isDescendantOf( nn210 ) );
+        assertTrue( nn3210.isDescendantOf( nn210 ) );
+
+        assertTrue( nn3210.isDescendantOf( nn3210 ) );
+
+        assertTrue( "Starting Dn fails with ADS Dn",
+            new Dn( "ou=foo,dc=apache,dc=org" ).isDescendantOf( new Dn( "dc=apache,dc=org" ) ) );
+
+        assertTrue( "Starting Dn fails with Java LdapName",
+            new Dn( "ou=foo,dc=apache,dc=org" ).isDescendantOf( new Dn( "dc=apache,dc=org" ) ) );
+
+        assertTrue( "Starting Dn fails with Java LdapName",
+            new Dn( "dc=apache,dc=org" ).isDescendantOf( new Dn( "dc=apache,dc=org" ) ) );
+    }
+
+
+    /**
+     * Class to test for Dn addAll(Dn)
+     *
+     * @throws Exception
+     *             when anything goes wrong
+     */
+    @Test
+    public void testAddAllName0() throws Exception
+    {
+        Dn name = new Dn();
+        Dn name0 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        assertTrue( name0.equals( name.add( name0 ) ) );
+    }
+
+
+    /**
+     * Class to test for Dn addAll(Dn)
+     *
+     * @throws Exception
+     *             when anything goes wrong
+     */
+    @Test
+    public void testAddAllNameExisting0() throws Exception
+    {
+        Dn name1 = new Dn( "ou=Marketing,ou=East" );
+        Dn name2 = new Dn( "cn=HomeDir,cn=John" );
+        Dn nameAdded = new Dn( "cn=HomeDir,cn=John, ou=Marketing,ou=East" );
+        assertTrue( nameAdded.equals( name1.add( name2 ) ) );
+    }
+
+
+    /**
+     * Class to test for Dn addAll(Dn)
+     *
+     * @throws Exception
+     *             when anything goes wrong
+     */
+    @Test
+    public void testAddAllName1() throws Exception
+    {
+        Dn name = new Dn();
+        Dn name0 = new Dn( "ou=Marketing,ou=East" );
+        Dn name1 = new Dn( "cn=HomeDir,cn=John" );
+        Dn name2 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+
+        name = name.add( name0 );
+        assertTrue( name0.equals( name ) );
+        assertTrue( name2.equals( name.add( name1 ) ) );
+    }
+
+
+    /**
+     * Class to test for Dn addAll(int, Dn)
+     *
+     * @throws Exception
+     *             when something goes wrong
+     */
+    @Test
+    public void testAddAllintName0() throws Exception
+    {
+        Dn name = new Dn();
+        Dn name0 = new Dn( "ou=Marketing,ou=East" );
+        Dn name1 = new Dn( "cn=HomeDir,cn=John" );
+        Dn name2 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+
+        name = name.add( name0 );
+        assertTrue( name0.equals( name ) );
+        assertTrue( name2.equals( name.add( name1 ) ) );
+    }
+
+
+    /**
+     * Class to test for Dn add(String)
+     *
+     * @throws Exception when something goes wrong
+     */
+    @Test
+    public void testAddString() throws Exception
+    {
+        Dn name = new Dn( schemaManager );
+        assertEquals( name, new Dn( "" ) );
+
+        Dn name4 = new Dn( schemaManager, "ou=East" );
+
+        assertTrue( name.isSchemaAware() );
+
+        name = name.add( "ou=East" );
+
+        assertTrue( name.isSchemaAware() );
+
+        assertEquals( name4, name );
+
+        Dn name3 = new Dn( schemaManager, "ou=Marketing,ou=East" );
+        name = name.add( "ou=Marketing" );
+        assertEquals( name3, name );
+
+        Dn name2 = new Dn( schemaManager, "cn=John,ou=Marketing,ou=East" );
+        name = name.add( "cn=John" );
+        assertEquals( name2, name );
+
+        Dn name0 = new Dn( schemaManager, "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        name = name.add( "cn=HomeDir" );
+        assertEquals( name0, name );
+    }
+
+
+    /**
+     * Class to test for Name add(int, String)
+     *
+     * @throws Exception
+     *             if anything goes wrong
+     */
+    @Test
+    public void testAddintString() throws Exception
+    {
+        Dn name = new Dn();
+        assertEquals( name, new Dn( "" ) );
+
+        Dn name4 = new Dn( "ou=East" );
+        name = name.add( "ou=East" );
+        assertEquals( name4, name );
+
+        Dn name3 = new Dn( "ou=Marketing,ou=East" );
+        name = name.add( "ou=Marketing" );
+        assertEquals( name3, name );
+
+        Dn name2 = new Dn( "cn=John,ou=Marketing,ou=East" );
+        name = name.add( "cn=John" );
+        assertEquals( name2, name );
+
+        Dn name0 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
+        name = name.add( "cn=HomeDir" );
+        assertEquals( name0, name );
+    }
+
+
+    /**
+     * Class to test for String toString()
+     *
+     * @throws Exception if anything goes wrong
+     */
+    @Test
+    public void testToString() throws Exception
+    {
+        Dn name = new Dn();
+        assertEquals( "", name.toString() );
+
+        name = name.add( "ou=East" );
+        assertEquals( "ou=East", name.toString() );
+
+        name = name.add( "ou=Marketing" );
+        assertEquals( "ou=Marketing,ou=East", name.toString() );
+
+        name = name.add( "cn=John" );
+        assertEquals( "cn=John,ou=Marketing,ou=East", name.toString() );
+
+        name = name.add( "cn=HomeDir" );
+        assertEquals( "cn=HomeDir,cn=John,ou=Marketing,ou=East", name.toString() );
+    }
+
+
+    /**
+     * Tests getParent().
+     */
+    @Test
+    public void testGetParent() throws Exception
+    {
+        Dn empty = new Dn();
+        assertEquals( Dn.EMPTY_DN, empty.getParent() );
+
+        Dn one = new Dn( "cn=test" );
+        assertNotNull( one.getParent() );
+        assertTrue( one.getParent().isEmpty() );
+
+        Dn two = new Dn( "cn=test,o=acme" );
+        assertNotNull( two.getParent() );
+        assertFalse( two.getParent().isSchemaAware() );
+        assertFalse( two.getParent().isEmpty() );
+        assertEquals( "o=acme", two.getParent().getName() );
+
+        Dn three = new Dn( "cn=test,dc=example,dc=com" );
+        three.apply( schemaManager );
+        Dn threeParent = three.getParent();
+        assertNotNull( threeParent );
+        assertTrue( threeParent.isSchemaAware() );
+        assertFalse( threeParent.isEmpty() );
+        assertEquals( "dc=example,dc=com", threeParent.getName() );
+        assertEquals( 2, threeParent.getRdns().size() );
+
+        Dn five = new Dn( "uid=user1,ou=sales,ou=users,dc=example,dc=com" );
+        Dn fiveParent = five.getParent();
+        assertNotNull( fiveParent );
+        assertFalse( fiveParent.isSchemaAware() );
+        assertFalse( fiveParent.isEmpty() );
+        assertEquals( "ou=sales,ou=users,dc=example,dc=com", fiveParent.getName() );
+        assertEquals( 4, fiveParent.getRdns().size() );
+    }
+
+
+    /**
+     * Class to test for boolean equals(Object)
+     *
+     * @throws Exception
+     *             if anything goes wrong
+     */
+    @Test
+    public void testEqualsObject() throws Exception
+    {
+        assertTrue( new Dn( "ou=People" ).equals( new Dn( "ou=People" ) ) );
+
+        assertTrue( !new Dn( "ou=People,dc=example,dc=com" ).equals( new Dn( "ou=People" ) ) );
+        assertTrue( !new Dn( "ou=people" ).equals( new Dn( "ou=People" ) ) );
+        assertTrue( !new Dn( "ou=Groups" ).equals( new Dn( "ou=People" ) ) );
+    }
+
+
+    @Test
+    public void testNameFrenchChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', 0x4A, ( byte ) 0xC3, ( byte ) 0xA9, 0x72, ( byte ) 0xC3, ( byte ) 0xB4, 0x6D, 0x65 },
+            "UTF-8" );
+
+        Dn name = new Dn( cn );
+
+        assertEquals( "cn=J\u00e9r\u00f4me", name.toString() );
+    }
+
+
+    @Test
+    public void testNameGermanChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC3, ( byte ) 0x84, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3, ( byte ) 0x9C,
+                ( byte ) 0xC3, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0xA4, ( byte ) 0xC3, ( byte ) 0xB6,
+                ( byte ) 0xC3, ( byte ) 0xBC }, "UTF-8" );
+
+        Dn name = new Dn( cn );
+
+        assertEquals( "cn=\u00C4\u00D6\u00DC\u00DF\u00E4\u00F6\u00FC", name.toString() );
+    }
+
+
+    @Test
+    public void testNameTurkishChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC4, ( byte ) 0xB0, ( byte ) 0xC4, ( byte ) 0xB1, ( byte ) 0xC5, ( byte ) 0x9E,
+                ( byte ) 0xC5, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3, ( byte ) 0xB6,
+                ( byte ) 0xC3, ( byte ) 0x9C, ( byte ) 0xC3, ( byte ) 0xBC, ( byte ) 0xC4, ( byte ) 0x9E,
+                ( byte ) 0xC4, ( byte ) 0x9F }, "UTF-8" );
+
+        Dn name = new Dn( cn );
+
+        assertEquals( "cn=\u0130\u0131\u015E\u015F\u00D6\u00F6\u00DC\u00FC\u011E\u011F", name.toString() );
+    }
+
+
+    /**
+     * Class to test for toOid( Dn, Map)
+     */
+    @Test
+    public void testLdapNameToName() throws Exception
+    {
+        Dn name = new Dn( "ou= Some   People   ", "dc = eXample", "dc= cOm" );
+
+        assertTrue( name.getName().equals( "ou= Some   People   ,dc = eXample,dc= cOm" ) );
+
+        Dn result = name.apply( schemaManager );
+
+        assertEquals( "2.5.4.11=some people,0.9.2342.19200300.100.1.25=example,0.9.2342.19200300.100.1.25=com",
+            result.getNormName() );
+    }
+
+
+    @Test
+    public void testRdnGetTypeUpName() throws Exception
+    {
+        Dn name = new Dn( "ou= Some   People   ", "dc = eXample", "dc= cOm" );
+
+        assertTrue( name.getName().equals( "ou= Some   People   ,dc = eXample,dc= cOm" ) );
+
+        Rdn rdn = name.getRdn();
+
+        assertEquals( "ou= Some   People   ", rdn.getName() );
+        assertEquals( "ou", rdn.getNormType() );
+        assertEquals( "ou", rdn.getType() );
+
+        Dn result = name.apply( schemaManager );
+
+        assertTrue( result.getNormName().equals(
+            "2.5.4.11=some people,0.9.2342.19200300.100.1.25=example,0.9.2342.19200300.100.1.25=com" ) );
+        assertTrue( name.getName().equals( "ou= Some   People   ,dc = eXample,dc= cOm" ) );
+
+        Rdn rdn2 = result.getRdn();
+
+        assertEquals( "ou= Some   People   ", rdn2.getName() );
+        assertEquals( "2.5.4.11", rdn2.getNormType() );
+        assertEquals( "ou", rdn2.getType() );
+    }
+
+
+    /**
+     * Class to test for toOid( Dn, Map) with a NULL dn
+     */
+    @Test
+    public void testLdapNameToNameEmpty() throws Exception
+    {
+        Dn name = new Dn();
+
+        Dn result = name.apply( schemaManager );
+        assertTrue( result.toString().equals( "" ) );
+    }
+
+
+    /**
+     * Class to test for toOid( Dn, Map) with a multiple NameComponent
+     */
+    @Test
+    public void testLdapNameToNameMultiNC() throws Exception
+    {
+        Dn name = new Dn(
+            "2.5.4.11= Some   People   + 0.9.2342.19200300.100.1.25=  And   Some anImAls,0.9.2342.19200300.100.1.25 = eXample,dc= cOm" );
+
+        Dn result = name.apply( schemaManager );
+
+        assertEquals(
+            ( result ).getNormName(),
+            "0.9.2342.19200300.100.1.25=and some animals+2.5.4.11=some people,0.9.2342.19200300.100.1.25=example,0.9.2342.19200300.100.1.25=com" );
+        assertTrue( ( result )
+            .getName()
+            .equals(
+                "2.5.4.11= Some   People   + 0.9.2342.19200300.100.1.25=  And   Some anImAls,0.9.2342.19200300.100.1.25 = eXample,dc= cOm" ) );
+    }
+
+
+    /**
+     * Class to test for toOid( Dn, Map) with a multiple NameComponent
+     */
+    @Test
+    public void testLdapNameToNameAliasMultiNC() throws Exception
+    {
+        Dn name = new Dn(
+            "2.5.4.11= Some   People   + domainComponent=  And   Some anImAls,DomainComponent = eXample,0.9.2342.19200300.100.1.25= cOm" );
+
+        Dn result = name.apply( schemaManager );
+
+        assertTrue( result
+            .getNormName()
+            .equals(
+                "0.9.2342.19200300.100.1.25=and some animals+2.5.4.11=some people,0.9.2342.19200300.100.1.25=example,0.9.2342.19200300.100.1.25=com" ) );
+        assertTrue( result
+            .getName()
+            .equals(
+                "2.5.4.11= Some   People   + domainComponent=  And   Some anImAls,DomainComponent = eXample,0.9.2342.19200300.100.1.25= cOm" ) );
+    }
+
+
+    /**
+     * Class to test for hashCode().
+     */
+    @Test
+    public void testLdapNameHashCode() throws Exception
+    {
+        Dn name1 = new Dn(
+            schemaManager,
+            "2.5.4.11= Some   People   + domainComponent=  And   Some anImAls,DomainComponent = eXample,0.9.2342.19200300.100.1.25= cOm" );
+
+        Dn name2 = new Dn( schemaManager,
+            "2.5.4.11=some people+domainComponent=and some animals,DomainComponent=example,0.9.2342.19200300.100.1.25=com" );
+
+        assertEquals( name1.hashCode(), name2.hashCode() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191
+     */
+    @Test
+    public void testName() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new javax.naming.ldap.LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+        assertEquals( jName.toString(), "cn=four,cn=three,cn=two,cn=one" );
+        assertEquals( aName.toString(), "cn=four,cn=three,cn=two,cn=one" );
+        assertEquals( jName.toString(), aName.toString() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191
+     */
+    @Test
+    public void testGetPrefixName() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+
+        assertEquals( jName.getPrefix( 0 ).toString(), aName.getAncestorOf( "cn=four,cn=three,cn=two,cn=one" )
+            .toString() );
+        assertEquals( jName.getPrefix( 1 ).toString(), aName.getAncestorOf( "cn=four,cn=three,cn=two" ).toString() );
+        assertEquals( jName.getPrefix( 2 ).toString(), aName.getAncestorOf( "cn=four,cn=three" ).toString() );
+        assertEquals( jName.getPrefix( 3 ).toString(), aName.getAncestorOf( "cn=four" ).toString() );
+        assertEquals( jName.getPrefix( 4 ).toString(), aName.getAncestorOf( "" ).toString() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191
+     */
+    @Test
+    public void testGetSuffix() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+
+        assertEquals( jName.getSuffix( 0 ).toString(), aName.getDescendantOf( "" ).toString() );
+        assertEquals( jName.getSuffix( 1 ).toString(), aName.getDescendantOf( "cn=one" ).toString() );
+        assertEquals( jName.getSuffix( 2 ).toString(), aName.getDescendantOf( "cn=two,cn=one" ).toString() );
+        assertEquals( jName.getSuffix( 3 ).toString(), aName.getDescendantOf( "cn=three,cn=two,cn=one" ).toString() );
+        assertEquals( jName.getSuffix( 4 ).toString(), aName.getDescendantOf( "cn=four,cn=three,cn=two,cn=one" )
+            .toString() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191. The Dn is immutable, thus we can't add a new Rdn
+     * to a Dn, it simply creates a new one.
+     */
+    @Test
+    public void testAddStringName() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+
+        assertSame( jName, jName.add( "cn=five" ) );
+        assertNotSame( aName, aName.add( "cn=five" ) );
+        assertNotSame( jName.toString(), aName.toString() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191
+     */
+    @Test
+    public void testAddAllName() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+
+        assertSame( jName, jName.addAll( new LdapName( "cn=seven,cn=six" ) ) );
+        assertNotSame( aName, aName.add( new Dn( "cn=seven,cn=six" ) ) );
+        assertNotSame( jName.toString(), aName.toString() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191
+     */
+    @Test
+    public void testAddAllIntName() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+
+        assertSame( jName, jName.addAll( 0, new LdapName( "cn=zero,cn=zero.5" ) ) );
+        assertNotSame( aName, aName.add( new Dn( "cn=zero,cn=zero.5" ) ) );
+        assertNotSame( jName.toString(), aName.toString() );
+
+        assertSame( jName, jName.addAll( 2, new LdapName( "cn=zero,cn=zero.5" ) ) );
+        assertNotSame( aName, aName.add( new Dn( "cn=zero,cn=zero.5" ) ) );
+        assertNotSame( jName.toString(), aName.toString() );
+
+        assertSame( jName, jName.addAll( jName.size(), new LdapName( "cn=zero,cn=zero.5" ) ) );
+        assertNotSame( aName, aName.add( new Dn( "cn=zero,cn=zero.5" ) ) );
+        assertNotSame( jName.toString(), aName.toString() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191
+     */
+    @Test
+    public void testStartsWithName() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+
+        assertEquals( jName.startsWith( new LdapName( "cn=seven,cn=six,cn=five" ) ),
+            aName.isDescendantOf( new Dn( "cn=seven,cn=six,cn=five" ) ) );
+        assertEquals( jName.startsWith( new LdapName( "cn=three,cn=two,cn=one" ) ),
+            aName.isDescendantOf( new Dn( "cn=three,cn=two,cn=one" ) ) );
+    }
+
+
+    /**
+     * Test for DIRSERVER-191
+     *
+    @Test
+    public void testRemoveName() throws LdapException, InvalidNameException
+    {
+        LdapName jName = new LdapName( "cn=four,cn=three,cn=two,cn=one" );
+        Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
+        jName.remove( 0 );
+
+        assertEquals( jName.toString(), aName.remove( 0 ).toString() );
+        assertNotSame( jName.toString(), aName.toString() );
+
+        jName.remove( jName.size() - 1 );
+        assertEquals( jName.toString(), aName.getParent().remove( 0 ).toString() );
+        assertNotSame( jName.toString(), aName.toString() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-642
+     * @throws LdapException
+     */
+    @Test
+    public void testDoubleQuoteInNameDIRSERVER_642() throws LdapException, LdapException
+    {
+        Dn name1 = new Dn( "cn=\"Kylie Minogue\",dc=example,dc=com" );
+
+        String[] expected = new String[]
+            { "cn=\"Kylie Minogue\"", "dc=example", "dc=com" };
+
+        List<Rdn> j = name1.getRdns();
+        int count = 0;
+
+        for ( Rdn rdn : j )
+        {
+            assertEquals( expected[count], rdn.getName() );
+            count++;
+        }
+    }
+
+
+    /**
+     * Test for DIRSERVER-642
+     * @throws LdapException
+     */
+    @Test
+    public void testDoubleQuoteInNameDIRSERVER_642_1() throws LdapException
+    {
+        Dn dn = new Dn( "cn=\" Kylie Minogue \",dc=example,dc=com" );
+
+        assertEquals( "cn=\" Kylie Minogue \",dc=example,dc=com", dn.getName() );
+        assertEquals( "cn=\\ Kylie Minogue\\ ,dc=example,dc=com", dn.getNormName() );
+    }
+
+
+    /**
+     * Test for DIRSTUDIO-250
+     * @throws LdapException
+     */
+    @Test
+    public void testDoubleQuoteWithSpecialCharsInNameDIRSERVER_250() throws LdapException
+    {
+        Dn dn = new Dn( "a=\"b,c\"" );
+
+        assertEquals( "a=\"b,c\"", dn.getName() );
+        assertEquals( "a=b\\,c", dn.getNormName() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testLeadingAndTrailingSpacesDIRSERVER_184() throws LdapException
+    {
+        Dn name = new Dn( "dn= \\ four spaces leading and 3 trailing \\  " );
+
+        assertEquals( "dn=\\ four spaces leading and 3 trailing \\ ", name.getNormName() );
+        assertEquals( "dn= \\ four spaces leading and 3 trailing \\  ", name.getName() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testDIRSERVER_184_1()
+    {
+        try
+        {
+            new Dn( "dn=middle\\ spaces" );
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testDIRSERVER_184_2()
+    {
+        try
+        {
+            new Dn( "dn=# a leading pound" );
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testDIRSERVER_184_3() throws LdapException
+    {
+        Dn name = new Dn( "dn=\\# a leading pound" );
+
+        assertEquals( "dn=\\# a leading pound", name.toString() );
+        assertEquals( "dn=\\# a leading pound", name.getName() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testDIRSERVER_184_4() throws LdapException
+    {
+        Dn name = new Dn( "dn=a middle \\# pound" );
+
+        assertEquals( "dn=a middle # pound", name.getNormName() );
+        assertEquals( "dn=a middle \\# pound", name.getName() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testDIRSERVER_184_5() throws LdapException
+    {
+        Dn name = new Dn( "dn=a trailing pound \\#" );
+
+        assertEquals( "dn=a trailing pound #", name.getNormName() );
+        assertEquals( "dn=a trailing pound \\#", name.getName() );
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testDIRSERVER_184_6()
+    {
+        try
+        {
+            new Dn( "dn=a middle # pound" );
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test for DIRSERVER-184
+     * @throws LdapException
+     */
+    @Test
+    public void testDIRSERVER_184_7()
+    {
+        try
+        {
+            new Dn( "dn=a trailing pound #" );
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testDIRSERVER_631_1() throws LdapException
+    {
+        Dn name = new Dn( "cn=Bush\\, Kate,dc=example,dc=com" );
+
+        assertEquals( "cn=Bush\\, Kate,dc=example,dc=com", name.toString() );
+        assertEquals( "cn=Bush\\, Kate,dc=example,dc=com", name.getName() );
+
+    }
+
+
+    /**
+     * Added a test to check the parsing of a Dn with more than one Rdn
+     * which are OIDs, and with one Rdn which has more than one atav.
+     * @throws LdapException
+     */
+    @Test
+    public void testDNWithMultiOidsRDN() throws LdapException
+    {
+        Dn name = new Dn(
+            "0.9.2342.19200300.100.1.1=00123456789+2.5.4.3=pablo picasso,2.5.4.11=search,2.5.4.10=imc,2.5.4.6=us" );
+        assertEquals(
+            "0.9.2342.19200300.100.1.1=00123456789+2.5.4.3=pablo picasso,2.5.4.11=search,2.5.4.10=imc,2.5.4.6=us",
+            name.toString() );
+        assertEquals(
+            "0.9.2342.19200300.100.1.1=00123456789+2.5.4.3=pablo picasso,2.5.4.11=search,2.5.4.10=imc,2.5.4.6=us",
+            name.getName() );
+    }
+
+
+    @Test
+    public void testDNEquals() throws LdapException
+    {
+        Dn dn1 = new Dn( "a=b,c=d,e=f" );
+        Dn dn2 = new Dn( "a=b\\,c\\=d,e=f" );
+
+        assertFalse( dn1.getNormName().equals( dn2.getNormName() ) );
+    }
+
+
+    @Test
+    public void testDNAddEmptyString() throws LdapException
+    {
+        Dn dn = new Dn();
+        assertTrue( dn.size() == 0 );
+        assertTrue( dn.add( "" ).size() == 0 );
+    }
+
+
+    /**
+     * This leads to the bug in DIRSERVER-832.
+     */
+    @Test
+    public void testPreserveAttributeIdCase() throws LdapException
+    {
+        Dn dn = new Dn( "uID=kevin" );
+        assertEquals( "uID", dn.getRdn().getType() );
+    }
+
+
+    /**
+     * Tests the Dn.isValid() method.
+     */
+    @Test
+    public void testIsValid()
+    {
+        assertTrue( Dn.isValid( "" ) );
+
+        assertFalse( Dn.isValid( "a" ) );
+        assertFalse( Dn.isValid( "a " ) );
+
+        assertTrue( Dn.isValid( "a=" ) );
+        assertTrue( Dn.isValid( "a= " ) );
+
+        assertFalse( Dn.isValid( "=" ) );
+        assertFalse( Dn.isValid( " = " ) );
+        assertFalse( Dn.isValid( " = a" ) );
+    }
+
+
+    @Test
+    public void testCompositeRDN() throws LdapException
+    {
+        assertTrue( Dn.isValid( "a=b+c=d+e=f,g=h" ) );
+
+        Dn dn = new Dn( "a=b+c=d+e=f,g=h" );
+
+        assertEquals( "a=b+c=d+e=f,g=h", dn.toString() );
+    }
+
+
+    @Test
+    public void testCompositeRDNOids() throws LdapException
+    {
+        assertTrue( Dn
+            .isValid( "1.2.3.4.5=0+1.2.3.4.6=0+1.2.3.4.7=omnischmomni,2.5.4.3=subtree,0.9.2342.19200300.100.1.25=example,0.9.2342.19200300.100.1.25=com" ) );
+
+        Dn dn = new Dn(
+            "1.2.3.4.5=0+1.2.3.4.6=0+1.2.3.4.7=omnischmomni,2.5.4.3=subtree,0.9.2342.19200300.100.1.25=example,0.9.2342.19200300.100.1.25=com" );
+
+        assertEquals(
+            "1.2.3.4.5=0+1.2.3.4.6=0+1.2.3.4.7=omnischmomni,2.5.4.3=subtree,0.9.2342.19200300.100.1.25=example,0.9.2342.19200300.100.1.25=com",
+            dn.toString() );
+    }
+
+
+    /**
+     * Tests that AttributeTypeAndValues are correctly trimmed.
+     */
+    @Test
+    public void testTrimAtavs() throws LdapException
+    {
+        // antlr parser: string value with trailing spaces
+        Dn dn1 = new Dn( " cn = Amos\\,Tori , ou=system " );
+        assertEquals( " cn = Amos\\,Tori ", dn1.getRdn().getName() );
+        Ava atav1 = dn1.getRdn().getAva();
+        assertEquals( "cn", atav1.getType() );
+        assertEquals( "Amos\\,Tori", atav1.getValue().getValue() );
+
+        // antlr parser: hexstring with trailing spaces
+        Dn dn3 = new Dn( " cn = #414243 , ou=system " );
+        assertEquals( " cn = #414243 ", dn3.getRdn().getName() );
+        Ava atav3 = dn3.getRdn().getAva();
+        assertEquals( "cn", atav3.getType() );
+        assertTrue( Arrays.equals( Strings.getBytesUtf8( "ABC" ), (byte[])atav3.getValue().getValue() ) );
+        assertTrue( Arrays.equals( Strings.getBytesUtf8( "ABC" ), atav3.getValue().getBytes() ) );
+
+        // antlr parser:
+        Dn dn4 = new Dn( " cn = \\41\\42\\43 , ou=system " );
+        assertEquals( " cn = \\41\\42\\43 ", dn4.getRdn().getName() );
+        Ava atav4 = dn4.getRdn().getAva();
+        assertEquals( "cn", atav4.getType() );
+        assertEquals( "\\41\\42\\43", atav4.getValue().getValue() );
+        assertEquals( "ABC", atav4.getValue().getNormValue() );
+
+        // antlr parser: quotestring with trailing spaces
+        Dn dn5 = new Dn( " cn = \"ABC\" , ou=system " );
+        assertEquals( " cn = \"ABC\" ", dn5.getRdn().getName() );
+        Ava atav5 = dn5.getRdn().getAva();
+        assertEquals( "cn", atav5.getType() );
+        assertEquals( "\"ABC\"", atav5.getValue() .getValue());
+        assertEquals( "ABC", atav5.getValue().getNormValue() );
+
+        // fast parser: string value with trailing spaces
+        Dn dn2 = new Dn( " cn = Amos Tori , ou=system " );
+        assertEquals( " cn = Amos Tori ", dn2.getRdn().getName() );
+        Ava atav2 = dn2.getRdn().getAva();
+        assertEquals( "cn", atav2.getType() );
+        assertEquals( "Amos Tori", atav2.getValue().getValue() );
+    }
+
+
+    /**
+     * Test for DIRSHARED-39.
+     * (Trailing escaped space not parsed correctly by the Dn parser(
+     */
+    @Test
+    public void testTrailingEscapedSpace() throws Exception
+    {
+        Dn dn1 = new Dn( "ou=A\\ ,ou=system" );
+        dn1.apply( schemaManager );
+        assertEquals( "ou=A\\ ,ou=system", dn1.getName() );
+        assertEquals( "2.5.4.11=a\\ ,2.5.4.11=system", dn1.getNormName() );
+        assertEquals( "ou=A\\ ", dn1.getRdn().getName() );
+        assertEquals( "2.5.4.11=a\\ ", dn1.getRdn().getNormName() );
+
+        Dn dn2 = new Dn( "ou=A\\20,ou=system" );
+        dn2.apply( schemaManager );
+        assertEquals( "ou=A\\20,ou=system", dn2.getName() );
+        assertEquals( "2.5.4.11=a\\ ,2.5.4.11=system", dn2.getNormName() );
+        assertEquals( "ou=A\\20", dn2.getRdn().getName() );
+        assertEquals( "2.5.4.11=a\\ ", dn2.getRdn().getNormName() );
+
+        Dn dn3 = new Dn( "ou=\\ ,ou=system" );
+        dn3.apply( schemaManager );
+        assertEquals( "ou=\\ ,ou=system", dn3.getName() );
+        assertEquals( "2.5.4.11=\\ ,2.5.4.11=system", dn3.getNormName() );
+        assertEquals( "ou=\\ ", dn3.getRdn().getName() );
+        assertEquals( "2.5.4.11=\\ ", dn3.getRdn().getNormName() );
+
+        Dn dn4 = new Dn( "ou=\\20,ou=system" );
+        dn4.apply( schemaManager );
+        assertEquals( "ou=\\20,ou=system", dn4.getName() );
+        assertEquals( "2.5.4.11=\\ ,2.5.4.11=system", dn4.getNormName() );
+        assertEquals( "ou=\\20", dn4.getRdn().getName() );
+        assertEquals( "2.5.4.11=\\ ", dn4.getRdn().getNormName() );
+    }
+
+
+    /**
+     * Test for DIRSHARED-41, DIRSTUDIO-603.
+     * (Dn parser fails to parse names containing an numeric OID value)
+     */
+    @Test
+    public void testNumericOid() throws Exception
+    {
+        // numeric OID only
+        Dn dn1 = new Dn( "cn=loopback+ipHostNumber=127.0.0.1,ou=Hosts,dc=mygfs,dc=com" );
+        assertEquals( "cn=loopback+ipHostNumber=127.0.0.1,ou=Hosts,dc=mygfs,dc=com", dn1.getName() );
+        assertEquals( "cn=loopback+iphostnumber=127.0.0.1,ou=Hosts,dc=mygfs,dc=com", dn1.getNormName() );
+        assertEquals( "cn=loopback+ipHostNumber=127.0.0.1", dn1.getRdn().getName() );
+        assertEquals( "cn=loopback+iphostnumber=127.0.0.1", dn1.getRdn().getNormName() );
+        assertEquals( "127.0.0.1", dn1.getRdn().getAva( "ipHostNumber" ).getValue().getValue() );
+
+        // numeric OID with suffix
+        Dn dn2 = new Dn( "cn=loopback+ipHostNumber=X127.0.0.1,ou=Hosts,dc=mygfs,dc=com" );
+        assertEquals( "cn=loopback+ipHostNumber=X127.0.0.1,ou=Hosts,dc=mygfs,dc=com", dn2.getName() );
+        assertEquals( "cn=loopback+iphostnumber=X127.0.0.1,ou=Hosts,dc=mygfs,dc=com", dn2.getNormName() );
+        assertEquals( "cn=loopback+ipHostNumber=X127.0.0.1", dn2.getRdn().getName() );
+        assertEquals( "cn=loopback+iphostnumber=X127.0.0.1", dn2.getRdn().getNormName() );
+
+        // numeric OID with prefix
+        Dn dn3 = new Dn( "cn=loopback+ipHostNumber=127.0.0.1Y,ou=Hosts,dc=mygfs,dc=com" );
+        assertEquals( "cn=loopback+ipHostNumber=127.0.0.1Y,ou=Hosts,dc=mygfs,dc=com", dn3.getName() );
+        assertEquals( "cn=loopback+iphostnumber=127.0.0.1Y,ou=Hosts,dc=mygfs,dc=com", dn3.getNormName() );
+        assertEquals( "cn=loopback+ipHostNumber=127.0.0.1Y", dn3.getRdn().getName() );
+        assertEquals( "cn=loopback+iphostnumber=127.0.0.1Y", dn3.getRdn().getNormName() );
+
+        // numeric OID with special characters
+        Dn dn4 = new Dn( "cn=loopback+ipHostNumber=\\#127.0.0.1 Z,ou=Hosts,dc=mygfs,dc=com" );
+        assertEquals( "cn=loopback+ipHostNumber=\\#127.0.0.1 Z,ou=Hosts,dc=mygfs,dc=com", dn4.getName() );
+        assertEquals( "cn=loopback+iphostnumber=\\#127.0.0.1 Z,ou=Hosts,dc=mygfs,dc=com", dn4.getNormName() );
+        assertEquals( "cn=loopback+ipHostNumber=\\#127.0.0.1 Z", dn4.getRdn().getName() );
+        assertEquals( "cn=loopback+iphostnumber=\\#127.0.0.1 Z", dn4.getRdn().getNormName() );
+    }
+
+
+    @Test
+    public void testNormalizeAscii() throws Exception
+    {
+        Dn dn = new Dn( "  ou  =  Example ,  ou  =  COM " );
+
+        dn.apply( schemaManager );
+        assertEquals( "2.5.4.11=example,2.5.4.11=com", dn.getNormName() );
+        assertEquals( "  ou  =  Example ,  ou  =  COM ", dn.getName() );
+
+        Rdn rdn = dn.getRdn();
+        assertEquals( "2.5.4.11", rdn.getNormType() );
+        assertEquals( "example", rdn.getNormValue() );
+        assertEquals( "2.5.4.11=example", rdn.getNormName() );
+        assertEquals( "ou", rdn.getType() );
+        assertEquals( "Example", rdn.getValue() );
+        assertEquals( "  ou  =  Example ", rdn.getName() );
+
+        Ava atav = rdn.getAva();
+
+        assertEquals( "2.5.4.11=example", atav.getNormName() );
+        assertEquals( "2.5.4.11", atav.getNormType() );
+        assertEquals( "example", atav.getValue().getNormValue().toString() );
+
+        assertEquals( "ou", atav.getType() );
+        assertEquals( "Example", atav.getValue().getValue() );
+
+        assertEquals( "  ou  =  Example ", atav.getName() );
+    }
+
+
+    @Test
+    public void testNormalizeAsciiComposite() throws Exception
+    {
+        Dn dn = new Dn( "  ou  =  Example + cn = TEST ,  ou  =  COM " );
+
+        dn.apply( schemaManager );
+        assertEquals( "2.5.4.11=example+2.5.4.3=test,2.5.4.11=com", dn.getNormName() );
+        assertEquals( "  ou  =  Example + cn = TEST ,  ou  =  COM ", dn.getName() );
+
+        Rdn rdn = dn.getRdn();
+        assertEquals( "2.5.4.11", rdn.getNormType() );
+        assertEquals( "example", rdn.getNormValue() );
+        assertEquals( "2.5.4.11=example+2.5.4.3=test", rdn.getNormName() );
+        assertEquals( "ou", rdn.getType() );
+        assertEquals( "Example", rdn.getValue() );
+        assertEquals( "  ou  =  Example + cn = TEST ", rdn.getName() );
+
+        // The first ATAV
+        Ava atav = rdn.getAva();
+
+        assertEquals( "2.5.4.11=example", atav.getNormName() );
+        assertEquals( "2.5.4.11", atav.getNormType() );
+        assertEquals( "example", atav.getValue().getNormValue().toString() );
+
+        assertEquals( "ou", atav.getType() );
+        assertEquals( "Example", atav.getValue().getValue() );
+
+        assertEquals( "  ou  =  Example ", atav.getName() );
+
+        assertEquals( 2, rdn.size() );
+
+        // The second ATAV
+        for ( Ava ava : rdn )
+        {
+            if ( "example".equals( ava.getValue().getNormValue().toString() ) )
+            {
+                // Skip the first one
+                continue;
+            }
+
+            assertEquals( "2.5.4.3=test", ava.getNormName() );
+            assertEquals( "2.5.4.3", ava.getNormType() );
+            assertEquals( "test", ava.getValue().getNormValue().toString() );
+
+            assertEquals( "cn", ava.getType() );
+            assertEquals( "TEST", ava.getValue().getValue() );
+            assertEquals( " cn = TEST ", ava.getName() );
+        }
+    }
+
+
+    @Test
+    public void testNormalizeAsciiWithEscaped() throws Exception
+    {
+        Dn dn = new Dn( "  ou  =  Ex\\+mple " );
+
+        dn.apply( schemaManager );
+        assertEquals( "2.5.4.11=ex\\+mple", dn.getNormName() );
+        assertEquals( "  ou  =  Ex\\+mple ", dn.getName() );
+
+        Rdn rdn = dn.getRdn();
+        assertEquals( "2.5.4.11", rdn.getNormType() );
+        assertEquals( "ex+mple", rdn.getNormValue() );
+        assertEquals( "2.5.4.11=ex\\+mple", rdn.getNormName() );
+        assertEquals( "ou", rdn.getType() );
+        assertEquals( "Ex\\+mple", rdn.getValue() );
+        assertEquals( "  ou  =  Ex\\+mple ", rdn.getName() );
+
+        Ava atav = rdn.getAva();
+
+        assertEquals( "2.5.4.11=ex\\+mple", atav.getNormName() );
+        assertEquals( "2.5.4.11", atav.getNormType() );
+        assertEquals( "ex+mple", atav.getValue().getNormValue().toString() );
+
+        assertEquals( "ou", atav.getType() );
+        assertEquals( "Ex\\+mple", atav.getValue().getValue() );
+
+        assertEquals( "  ou  =  Ex\\+mple ", atav.getName() );
+    }
+
+
+    @Test
+    public void testNormalizeCompositeWithEscaped() throws Exception
+    {
+        Dn dn = new Dn( "  OU  =  Ex\\+mple + cn = T\\+ST\\  ,  ou  =  COM " );
+
+        // ------------------------------------------------------------------
+        // Before normalization
+        assertEquals( "  OU  =  Ex\\+mple + cn = T\\+ST\\  ,  ou  =  COM ", dn.getName() );
+        assertEquals( "ou=Ex\\+mple+cn=T\\+ST\\ ,ou=COM", dn.getNormName() );
+
+        // Check the first Rdn
+        Rdn rdn = dn.getRdn();
+        assertEquals( "  OU  =  Ex\\+mple + cn = T\\+ST\\  ", rdn.getName() );
+        assertEquals( "ou=Ex\\+mple+cn=T\\+ST\\ ", rdn.getNormName() );
+
+        assertEquals( "OU", rdn.getType() );
+        assertEquals( "ou", rdn.getNormType() );
+
+        assertEquals( "Ex\\+mple", rdn.getValue() );
+        assertEquals( "Ex+mple", rdn.getNormValue() );
+
+        // The first ATAV
+        Ava atav = rdn.getAva();
+
+        assertEquals( "  OU  =  Ex\\+mple ", atav.getName() );
+        assertEquals( "ou=Ex\\+mple", atav.getNormName() );
+
+        assertEquals( "ou", atav.getNormType() );
+        assertEquals( "OU", atav.getType() );
+
+        assertEquals( "Ex\\+mple", atav.getValue().getValue() );
+        assertEquals( "Ex+mple", atav.getValue().getNormValue().toString() );
+
+        assertEquals( 2, rdn.size() );
+
+        // The second ATAV
+        for ( Ava ava : rdn )
+        {
+            if ( "Ex+mple".equals( ava.getValue().getNormValue().toString() ) )
+            {
+                // Skip the first one
+                continue;
+            }
+
+            assertEquals( " cn = T\\+ST\\  ", ava.getName() );
+            assertEquals( "cn=T\\+ST\\ ", ava.getNormName() );
+
+            assertEquals( "cn", ava.getType() );
+            assertEquals( "cn", ava.getNormType() );
+
+            assertEquals( "T\\+ST\\ ", ava.getValue().getValue() );
+            assertEquals( "T+ST ", ava.getValue().getNormValue().toString() );
+        }
+
+        // ------------------------------------------------------------------
+        // Now normalize the Dn
+        dn.apply( schemaManager );
+
+        assertEquals( "  OU  =  Ex\\+mple + cn = T\\+ST\\  ,  ou  =  COM ", dn.getName() );
+        assertEquals( "2.5.4.11=ex\\+mple+2.5.4.3=t\\+st\\ ,2.5.4.11=com", dn.getNormName() );
+
+        // Check the first Rdn
+        rdn = dn.getRdn();
+        assertEquals( "  OU  =  Ex\\+mple + cn = T\\+ST\\  ", rdn.getName() );
+        assertEquals( "2.5.4.11=ex\\+mple+2.5.4.3=t\\+st\\ ", rdn.getNormName() );
+
+        assertEquals( "OU", rdn.getType() );
+        assertEquals( "2.5.4.11", rdn.getNormType() );
+
+        assertEquals( "Ex\\+mple", rdn.getValue() );
+        assertEquals( "ex+mple", rdn.getNormValue() );
+
+        // The first ATAV
+        atav = rdn.getAva();
+
+        assertEquals( "  OU  =  Ex\\+mple ", atav.getName() );
+        assertEquals( "2.5.4.11=ex\\+mple", atav.getNormName() );
+
+        assertEquals( "2.5.4.11", atav.getNormType() );
+        assertEquals( "OU", atav.getType() );
+
+        assertEquals( "Ex\\+mple", atav.getValue().getValue() );
+        assertEquals( "ex+mple", atav.getValue().getNormValue().toString() );
+
+        assertEquals( 2, rdn.size() );
+
+        // The second ATAV
+        for ( Ava ava : rdn )
+        {
+            if ( "ex+mple".equals( ava.getValue().getNormValue().toString() ) )
+            {
+                // Skip the first one
+                continue;
+            }
+
+            assertEquals( " cn = T\\+ST\\  ", ava.getName() );
+            assertEquals( "2.5.4.3=t\\+st\\ ", ava.getNormName() );
+
+            assertEquals( "cn", ava.getType() );
+            assertEquals( "2.5.4.3", ava.getNormType() );
+
+            assertEquals( "T\\+ST\\ ", ava.getValue().getValue() );
+            assertEquals( "t+st ", ava.getValue().getNormValue().toString() );
+        }
+    }
+
+
+    //-------------------------------------------------------------------------
+    // test the iterator
+    //-------------------------------------------------------------------------
+    @Test
+    public void testIteratorNullDN()
+    {
+        Dn dn = Dn.EMPTY_DN;
+
+        for ( Rdn rdn : dn )
+        {
+            fail( "Should not be there: rdn = " + rdn );
+        }
+
+        assertTrue( true );
+    }
+
+
+    @Test
+    public void testIteratorOneRDN() throws Exception
+    {
+        Dn dn = new Dn( "ou=example" );
+        int count = 0;
+
+        for ( Rdn rdn : dn )
+        {
+            count++;
+            assertEquals( "ou=example", rdn.getName() );
+        }
+
+        assertEquals( 1, count );
+    }
+
+
+    @Test
+    public void testIteratorMultipleRDN() throws Exception
+    {
+        Dn dn = new Dn( "sn=joe+cn=doe,dc=apache,dc=org" );
+        int count = 0;
+
+        String[] expected = new String[]
+            { "sn=joe+cn=doe", "dc=apache", "dc=org" };
+
+        for ( Rdn rdn : dn.getRdns() )
+        {
+            assertEquals( expected[count], rdn.getName() );
+            count++;
+        }
+
+        assertEquals( 3, count );
+    }
+
+
+    @Test
+    public void testIsParentOfTrue() throws Exception
+    {
+        Dn dn = new Dn( "ou=example, dc=apache, dc=org" );
+        Dn parent1 = new Dn( "ou=example,dc=apache, dc=org" );
+        Dn parent2 = new Dn( "dc=apache, dc=org" );
+        Dn parent3 = new Dn( "dc=org" );
+        Dn notParent = new Dn( "ou=example,dc=apache, dc=com" );
+
+        assertTrue( parent1.isAncestorOf( dn ) );
+        assertTrue( parent2.isAncestorOf( dn ) );
+        assertTrue( parent3.isAncestorOf( dn ) );
+        assertFalse( notParent.isAncestorOf( dn ) );
+    }
+
+
+    @Test
+    public void testIsDescendantOfTrue() throws Exception
+    {
+        Dn dn = new Dn( "ou=example, dc=apache, dc=org" );
+        Dn parent1 = new Dn( "ou=example,dc=apache, dc=org" );
+        Dn parent2 = new Dn( "dc=apache, dc=org" );
+        Dn parent3 = new Dn( "dc=org" );
+        Dn notParent = new Dn( "dc=apache, dc=com" );
+
+        assertTrue( dn.isDescendantOf( parent1 ) );
+        assertTrue( dn.isDescendantOf( parent2 ) );
+        assertTrue( dn.isDescendantOf( parent3 ) );
+        assertFalse( notParent.isDescendantOf( dn ) );
+    }
+
+
+    @Test
+    public void testNormalize() throws Exception
+    {
+        Dn dn = new Dn( "ou=system" );
+        assertFalse( dn.isSchemaAware() );
+
+        dn = dn.add( "ou=users" );
+        assertFalse( dn.isSchemaAware() );
+
+        dn.apply( schemaManager );
+        assertTrue( dn.isSchemaAware() );
+
+        dn = dn.add( "ou=x" );
+        assertTrue( dn.isSchemaAware() );
+
+        assertEquals( "2.5.4.11=x,2.5.4.11=users,2.5.4.11=system", dn.getNormName() );
+        assertEquals( "ou=x,ou=users,ou=system", dn.getName() );
+
+        dn.apply( schemaManager );
+        assertEquals( "2.5.4.11=x,2.5.4.11=users,2.5.4.11=system", dn.getNormName() );
+        assertEquals( "ou=x,ou=users,ou=system", dn.getName() );
+
+        Rdn rdn = new Rdn( "ou=system" );
+        dn = new Dn();
+        assertFalse( dn.isSchemaAware() );
+
+        dn = dn.add( rdn );
+        assertFalse( dn.isSchemaAware() );
+
+        dn.apply( schemaManager );
+        assertTrue( dn.isSchemaAware() );
+
+        Dn anotherDn = new Dn( "ou=x,ou=users" );
+
+        dn = dn.add( anotherDn );
+        assertTrue( dn.isSchemaAware() );
+
+        dn.apply( schemaManager );
+        assertTrue( dn.isSchemaAware() );
+    }
+
+
+    @Test
+    public void testParseDnWithSlash() throws Exception
+    {
+        String dnStr = "dc=/vehicles/v1/";
+
+        Dn dn = new Dn( dnStr );
+        dn.apply( schemaManager );
+
+        assertEquals( dnStr, dn.toString() );
+    }
+
+
+    @Test
+    public void testCreateDnFromRdnParent() throws Exception
+    {
+        String rdn = "cn=test";
+        String parentDn = "ou=apache,ou=org";
+
+        Dn dn = new Dn( rdn, parentDn );
+
+        assertEquals( "cn=test,ou=apache,ou=org", dn.getName() );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/MultiThreadedTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/MultiThreadedTest.java
new file mode 100644
index 0000000..5e86435
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/MultiThreadedTest.java
@@ -0,0 +1,138 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.junit.tools.MultiThreadedMultiInvoker;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Multi-threaded 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MultiThreadedTest
+{
+    @Rule
+    public MultiThreadedMultiInvoker i = new MultiThreadedMultiInvoker( 100, 1000 );
+
+    private static Dn referenceDn;
+    private static Dn sharedDn;
+    private static Rdn referenceRdn;
+    private static Rdn sharedRdn;
+    private static Ava referenceAva;
+    private static Ava sharedAva;
+
+    private static SchemaManager schemaManager;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+
+        referenceDn = new Dn( "dc=example,dc=com" );
+        referenceDn.apply( schemaManager );
+        sharedDn = new Dn( "dc=example,dc=com" );
+        sharedDn.apply( schemaManager );
+
+        referenceRdn = new Rdn( "ou=system" );
+        referenceRdn.apply( schemaManager );
+        sharedRdn = new Rdn( "ou=system" );
+        sharedRdn.apply( schemaManager );
+
+        referenceAva = new Ava( schemaManager, "ou", "System" );
+        sharedAva = new Ava( schemaManager, "ou", "System" );
+    }
+
+
+    @Test
+    public void testNormalize() throws Exception
+    {
+        sharedAva.normalize();
+
+        sharedRdn.apply( schemaManager );
+        assertTrue( sharedRdn.isSchemaAware() );
+
+        sharedDn.apply( schemaManager );
+        assertTrue( sharedDn.isSchemaAware() );
+    }
+
+
+    @Test
+    public void testNormalizeHashCode() throws Exception
+    {
+        assertEquals( referenceAva.hashCode(), sharedAva.hashCode() );
+
+        sharedRdn.apply( schemaManager );
+        assertEquals( referenceRdn.hashCode(), sharedRdn.hashCode() );
+
+        sharedDn.apply( schemaManager );
+        assertEquals( referenceDn.hashCode(), sharedDn.hashCode() );
+    }
+
+
+    @Test
+    public void testNormalizeEquals() throws Exception
+    {
+        assertEquals( referenceAva, sharedAva );
+        assertTrue( referenceAva.equals( sharedAva ) );
+        assertTrue( sharedAva.equals( referenceAva ) );
+
+        sharedRdn.apply( schemaManager );
+        assertEquals( referenceRdn, sharedRdn );
+        assertTrue( referenceRdn.equals( sharedRdn ) );
+        assertTrue( sharedRdn.equals( referenceRdn ) );
+
+        sharedDn.apply( schemaManager );
+        assertEquals( referenceDn, sharedDn );
+        assertTrue( referenceDn.equals( sharedDn ) );
+        assertTrue( sharedDn.equals( referenceDn ) );
+    }
+
+
+    @Test
+    public void testNormalizeCompare() throws Exception
+    {
+        assertTrue( sharedAva.equals( referenceAva ) );
+        assertTrue( referenceAva.equals( sharedAva ) );
+
+        assertTrue( referenceRdn.equals( sharedRdn ) );
+        assertTrue( sharedRdn.equals( referenceRdn ) );
+
+        assertEquals( referenceDn, sharedDn );
+        assertEquals( sharedDn, referenceDn );
+    }
+
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/RdnTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/RdnTest.java
new file mode 100644
index 0000000..8856760
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/RdnTest.java
@@ -0,0 +1,208 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+/**
+ * Tests for the schemaAware Rdn class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class RdnTest
+{
+    private static SchemaManager schemaManager;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+    
+    
+    @Test
+    public void testRdnValueSchemaAware() throws LdapException
+    {
+        String errors = null;
+        
+        Rdn rdn = new Rdn( schemaManager, "cn= TEST\\ " );
+        
+        if ( !"cn= TEST\\ ".equals( rdn.getName() ) )
+        {
+            errors += "\nRdn.getName fails '" + rdn.getName() + "'";
+        }
+        
+        if ( !"2.5.4.3=test\\ ".equals( rdn.getNormName() ) )
+        {
+            errors = "\nRdn.getNormName fails '" + rdn.getNormName() + "'";
+        }
+        
+        if ( !"test ".equals( rdn.getNormValue( "cn" ) ) )
+        {
+            errors += "\nRdn.getNormValue( 'cn' ) fails '" + ( String ) rdn.getNormValue( "cn" ) + "'";
+        }
+        
+        assertEquals( null, errors );
+    }
+
+    
+    @Test
+    public void testRdnValuesNoSchema() throws LdapException
+    {
+        String errors = null;
+        
+        Rdn rdn = new Rdn( "OU = Exemple \\+ Rdn\\C3\\A4\\ +cn= TEST" );
+        
+        if ( !"OU = Exemple \\+ Rdn\\C3\\A4\\ +cn= TEST".equals( rdn.getName() ) )
+        {
+            errors += "\nRdn.getName fails '" + rdn.getName() + "'";
+        }
+        
+        if ( !"ou=Exemple \\+ Rdn\u00E4\\ +cn=TEST" .equals( rdn.getNormName() ) )
+        {
+            errors = "\nRdn.getNormName fails '" + rdn.getNormName() + "'";
+        }
+        
+        if ( !"ou".equals( rdn.getNormType() ) )
+        {
+            errors += "\nRdn.getNormType fails '" + rdn.getNormType() + "'";
+        }
+        
+        if ( !"Exemple + Rdn\u00E4 ".equals( rdn.getNormValue() ) )
+        {
+            errors += "\nRdn.getNormValue fails '" + rdn.getNormValue() + "'";
+        }
+        
+        if ( !"OU".equals( rdn.getType() ) )
+        {
+            errors += "\nRdn.getUpType fails '" + rdn.getType() + "'";
+        }
+        
+        if ( !"Exemple + Rdn\u00E4 ".equals( rdn.getNormValue() ) )
+        {
+            errors += "\nRdn.getNormValue fails '" + rdn.getNormValue() + "'";
+        }
+        
+        if ( !"Exemple + Rdn\u00E4 ".equals( rdn.getNormValue( "ou" ) ) )
+        {
+            errors += "\nRdn.getNormValue( 'ou' ) fails '" + rdn.getNormValue( "ou" ) + "'";
+        }
+        
+        if ( !"TEST".equals( rdn.getValue( "cn" ) ) )
+        {
+            errors += "\nRdn.getValue( 'test' ) fails '" + rdn.getValue( "cn" ) + "'";
+        }
+        
+        if ( !"OU = Exemple \\+ Rdn\\C3\\A4\\ +cn= TEST".equals( rdn.toString() ) )
+        {
+            errors += "\nRdn.toString fails '" + rdn.toString() + "'";
+        }
+        
+        assertEquals( null, errors );
+    }
+    
+    
+    @Test
+    public void testRdnValuesSchemaAware() throws LdapException
+    {
+        String errors = null;
+        
+        Rdn rdn = new Rdn( schemaManager, "OU = Exemple \\+ Rdn\\C3\\A4\\ +cn= TEST" );
+        
+        if ( !"OU = Exemple \\+ Rdn\\C3\\A4\\ +cn= TEST".equals( rdn.getName() ) )
+        {
+            errors += "\nRdn.getName fails '" + rdn.getName() + "'";
+        }
+        
+        if ( !"2.5.4.11=exemple \\+ rdn\u00E4\\ +2.5.4.3=test" .equals( rdn.getNormName() ) )
+        {
+            errors = "\nRdn.getNormName fails '" + rdn.getNormName() + "'";
+        }
+        
+        if ( !"2.5.4.11".equals( rdn.getNormType() ) )
+        {
+            errors += "\nRdn.getNormType fails '" + rdn.getNormType() + "'";
+        }
+        
+        if ( !"exemple + rdn\u00E4 ".equals( rdn.getNormValue() ) )
+        {
+            errors += "\nRdn.getNormValue fails '" + rdn.getNormValue() + "'";
+        }
+        
+        if ( !"OU".equals( rdn.getType() ) )
+        {
+            errors += "\nRdn.getUpType fails '" + rdn.getType() + "'";
+        }
+        
+        if ( !"Exemple \\+ Rdn\\C3\\A4\\ ".equals( rdn.getValue() ) )
+        {
+            errors += "\nRdn.getUpValue fails '" + rdn.getValue() + "'";
+        }
+        
+        if ( !"exemple + rdn\u00E4 ".equals( rdn.getNormValue( "ou" ) ) )
+        {
+            errors += "\nRdn.getNormValue( 'ou' ) fails '" + ( String ) rdn.getNormValue( "ou" ) + "'";
+        }
+        
+        if ( !"test".equals( rdn.getNormValue( "cn" ) ) )
+        {
+            errors += "\nRdn.getNormValue( 'cn' ) fails '" + ( String ) rdn.getNormValue( "cn" ) + "'";
+        }
+        
+        if ( !"OU = Exemple \\+ Rdn\\C3\\A4\\ +cn= TEST".equals( rdn.toString() ) )
+        {
+            errors += "\nRdn.toString fails '" + rdn.toString() + "'";
+        }
+        
+        assertEquals( null, errors );
+    }
+    
+    
+    @Test
+    public void testRdnMultipleAvas() throws Exception
+    {
+        Rdn rdn1 = new Rdn( schemaManager, "cn=doe+gn=john" );
+        Rdn rdn2 = new Rdn( schemaManager, "gn=john+cn=doe" );
+        
+        assertEquals( rdn1, rdn2 );
+        assertEquals( rdn1.getNormName(), rdn2.getNormName() );
+    }
+    
+    
+    @Test
+    public void testRdnEscapedValue() throws Exception
+    {
+        Rdn rdn = new Rdn( schemaManager, "sn=\\46\\65\\72\\72\\79" );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareAvaSerializationTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareAvaSerializationTest.java
new file mode 100644
index 0000000..cc7446e
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareAvaSerializationTest.java
@@ -0,0 +1,513 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+/**
+ * Test the class AttributeTypeAndValue
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaAwareAvaSerializationTest
+{
+    private static SchemaManager schemaManager;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testStringAtavSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testStringAtavSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+
+        int pos1 = atav.serialize( buffer, 0 );
+
+        Ava atav2 = new Ava( schemaManager );
+        int pos2 = atav2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testBinaryAtavSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] normValue = Strings.getBytesUtf8( "Test" );
+
+        Ava atav = new Ava( schemaManager, "userPKCS12", normValue );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Ignore
+    @Test
+    public void testBinaryAtavSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        byte[] normValue = Strings.getBytesUtf8( "Test" );
+
+        Ava atav = new Ava( schemaManager, "userPKCS12", normValue );
+
+        int pos1 = atav.serialize( buffer, 0 );
+
+        Ava atav2 = new Ava( schemaManager );
+        int pos2 = atav2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testNullAtavSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testNullAtavSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager );
+
+        try
+        {
+            atav.serialize( buffer, 0 );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testNullUpValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "dc", ( String ) null );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            String message = ioe.getMessage();
+            assertEquals( "Cannot serialize a wrong ATAV, the value should not be null", message );
+        }
+    }
+
+
+    @Test
+    public void testNullUpValueSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager, "dc", ( String ) null );
+
+        try
+        {
+            atav.serialize( buffer, 0 );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            String message = ioe.getMessage();
+            assertEquals( "Cannot serialize an wrong ATAV, the value should not be null", message );
+        }
+    }
+
+
+    @Test
+    public void testEmptyNormValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "DC", "" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testEmptyNormValueSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager, "DC", "" );
+
+        int pos1 = atav.serialize( buffer, 0 );
+
+        Ava atav2 = new Ava( schemaManager );
+        int pos2 = atav2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testStringAtavStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testStringAtavStaticSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+
+        int pos1 = atav.serialize( buffer, 0 );
+
+        Ava atav2 = new Ava( schemaManager );
+        int pos2 = atav2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testBinaryAtavStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] upValue = Strings.getBytesUtf8( "  Test  " );
+
+        Ava atav = new Ava( schemaManager, "userPKCS12", upValue );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Ignore
+    @Test
+    public void testBinaryAtavStaticSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        byte[] upValue = Strings.getBytesUtf8( "  Test  " );
+
+        Ava atav = new Ava( schemaManager, "userPKCS12", upValue );
+
+        int pos1 = atav.serialize( buffer, 0 );
+
+        Ava atav2 = new Ava( schemaManager );
+        int pos2 = atav2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test static serialization of a simple ATAV
+     */
+    @Test
+    public void testNullAtavStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test static serialization of a simple ATAV
+     */
+    @Test
+    public void testNullAtavStaticSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager );
+
+        try
+        {
+            atav.serialize( buffer, 0 );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test(expected = IOException.class)
+    public void testNullNormValueStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager, "DC", ( String ) null );
+
+        atav.serialize( buffer, 0 );
+        fail();
+    }
+
+
+    @Test(expected = IOException.class)
+    public void testNullNormValueStaticSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "DC", ( String ) null );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+        fail();
+    }
+
+
+    @Test
+    public void testEmptyNormValueStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "DC", "" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testEmptyNormValueStaticSerializationBytes() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        Ava atav = new Ava( schemaManager, "DC", "" );
+
+        int pos1 = atav.serialize( buffer, 0 );
+
+        Ava atav2 = new Ava( schemaManager );
+        int pos2 = atav2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Ignore
+    @Test
+    public void testStringAtavSerializationPerf() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+        Ava atav2 = new Ava( schemaManager );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 10000000; i++ )
+        {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream out = new ObjectOutputStream( baos );
+
+            atav.writeExternal( out );
+
+            ObjectInputStream in = null;
+
+            byte[] data = baos.toByteArray();
+            in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+            atav2.readExternal( in );
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        System.out.println( "Delta ser slow = " + ( t1 - t0 ) );
+    }
+
+
+    @Ignore
+    @Test
+    public void testStringAtavSerializationBytesPerf() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+        Ava atav2 = new Ava( schemaManager );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 10000000; i++ )
+        {
+            byte[] buffer = new byte[128];
+            atav.serialize( buffer, 0 );
+            atav2.deserialize( buffer, 0 );
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        System.out.println( "Delta ser fast = " + ( t1 - t0 ) );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareDnSerializationTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareDnSerializationTest.java
new file mode 100644
index 0000000..3f7416d
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareDnSerializationTest.java
@@ -0,0 +1,276 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Dn Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaAwareDnSerializationTest
+{
+    private static SchemaManager schemaManager;
+
+
+    /**
+     * Initialize OIDs maps for normalization
+     */
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    @Test
+    public void testDnFullSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Dn dn1 = new Dn( schemaManager, "gn=john + cn=doe, dc=example, dc=com" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn( schemaManager );
+        dn2.readExternal( in );
+
+        assertEquals( dn1, dn2 );
+    }
+
+
+    @Test
+    public void testDnEmptySerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Dn dn1 = new Dn( schemaManager );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn( schemaManager );
+        dn2.readExternal( in );
+
+        assertEquals( dn1, dn2 );
+    }
+
+
+    @Test
+    public void testDnSimpleSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Dn dn1 = new Dn( schemaManager, "Cn = Doe" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn( schemaManager );
+        dn2.readExternal( in );
+
+        assertEquals( dn1, dn2 );
+        assertEquals( "Cn = Doe", dn2.getName() );
+        assertEquals( "2.5.4.3=doe", dn2.getNormName() );
+    }
+
+
+    /**
+     * Test the serialization of a Dn
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testNameSerialization() throws Exception
+    {
+        Dn dn = new Dn( "ou= Some   People   + dc=  And   Some anImAls,dc = eXample,dc= cOm" );
+        dn.apply( schemaManager );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn.writeExternal( out );
+
+        byte[] data = baos.toByteArray();
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn( schemaManager );
+        dn2.readExternal( in );
+
+        assertEquals( dn, dn2 );
+    }
+
+
+    @Test
+    public void testSerializeEmptyDN() throws Exception
+    {
+        Dn dn = Dn.EMPTY_DN;
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn.writeExternal( out );
+
+        byte[] data = baos.toByteArray();
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn( schemaManager );
+        dn2.readExternal( in );
+
+        assertEquals( dn, dn2 );
+    }
+
+
+    /**
+     * Test the serialization of a Dn
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testNameStaticSerialization() throws Exception
+    {
+        Dn dn = new Dn( "ou= Some   People   + dc=  And   Some anImAls,dc = eXample,dc= cOm" );
+        dn.apply( schemaManager );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn.writeExternal( out );
+
+        byte[] data = baos.toByteArray();
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn( schemaManager );
+        dn2.readExternal( in );
+
+        assertEquals( dn, dn2 );
+    }
+
+
+    @Ignore
+    @Test
+    public void testSerializationPerfs() throws Exception
+    {
+        Dn dn = new Dn( "ou= Some   People   + dc=  And   Some anImAls,dc = eXample,dc= cOm" );
+        dn.apply( schemaManager );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 1000; i++ )
+        {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream out = new ObjectOutputStream( baos );
+
+            dn.writeExternal( out );
+
+            byte[] data = baos.toByteArray();
+            ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+            Dn dn1 = new Dn( schemaManager );
+            dn1.readExternal( in );
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        System.out.println( "delta :" + ( t1 - t0 ) );
+
+        long t2 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 1000000; i++ )
+        {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream out = new ObjectOutputStream( baos );
+
+            dn.writeExternal( out );
+
+            byte[] data = baos.toByteArray();
+            ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+            Dn dn1 = new Dn( schemaManager );
+            dn1.readExternal( in );
+
+            dn.apply( schemaManager );
+        }
+
+        long t3 = System.currentTimeMillis();
+
+        System.out.println( "delta :" + ( t3 - t2 ) );
+
+        //assertEquals( dn, DnSerializer.deserialize( in ) );
+    }
+
+
+    @Test
+    public void testStaticSerializeEmptyDN() throws Exception
+    {
+        Dn dn = Dn.EMPTY_DN;
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn.writeExternal( out );
+
+        byte[] data = baos.toByteArray();
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn( schemaManager );
+        dn2.readExternal( in );
+
+        assertEquals( dn, dn2 );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareRdnSerializationTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareRdnSerializationTest.java
new file mode 100644
index 0000000..51bd06c
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareRdnSerializationTest.java
@@ -0,0 +1,235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Rdn Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaAwareRdnSerializationTest
+{
+    private static SchemaManager schemaManager;
+
+
+    /**
+     * Initialize OIDs maps for normalization
+     */
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    @Test
+    public void testRdnFullSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, "gn=john + cn=doe" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn1, rdn2 );
+    }
+
+
+    @Test
+    public void testRdnFullSerializationBytes() throws IOException, LdapException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[256];
+        Rdn rdn1 = new Rdn( schemaManager, "gn=john + cn=doe" );
+
+        int pos1 = rdn1.serialize( buffer, 0 );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        int pos2 = rdn2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( rdn1, rdn2 );
+    }
+
+
+    @Test
+    public void testRdnEmptySerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn( schemaManager );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn1, rdn2 );
+    }
+
+
+    @Test
+    public void testRdnEmptySerializationBytes() throws IOException, LdapException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[256];
+        Rdn rdn1 = new Rdn( schemaManager );
+
+        int pos1 = rdn1.serialize( buffer, 0 );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        int pos2 = rdn2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( rdn1, rdn2 );
+    }
+
+
+    @Test
+    public void testRdnSimpleSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, "cn=Doe" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn1, rdn2 );
+        assertEquals( "Doe", rdn2.getValue( "cn" ) );
+        assertEquals( "doe", rdn2.getNormValue( "cn" ) );
+        assertEquals( "Doe", rdn2.getValue() );
+    }
+
+
+    @Test
+    public void testRdnSimpleSerializationBytes() throws IOException, LdapException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[256];
+        Rdn rdn1 = new Rdn( schemaManager, "cn=Doe" );
+
+        int pos1 = rdn1.serialize( buffer, 0 );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        int pos2 = rdn2.deserialize( buffer, 0 );
+
+        assertEquals( pos1, pos2 );
+        assertEquals( rdn1, rdn2 );
+        assertEquals( "Doe", rdn2.getValue( "cn" ) );
+        assertEquals( "doe", rdn2.getNormValue( "cn" ) );
+        assertEquals( "Doe", rdn2.getValue() );
+    }
+
+
+    @Ignore
+    @Test
+    public void testRdnFullSerializationPerf() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, "gn=john + cn=doe" );
+        Rdn rdn2 = new Rdn( schemaManager );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 5000000; i++ )
+        {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream out = new ObjectOutputStream( baos );
+
+            rdn1.writeExternal( out );
+
+            ObjectInputStream in = null;
+
+            byte[] data = baos.toByteArray();
+            in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+            rdn2.readExternal( in );
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        System.out.println( "Delta ser slow = " + ( t1 - t0 ) );
+    }
+
+
+    @Ignore
+    @Test
+    public void testRdnFullSerializationBytesPerf() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, "gn=john + cn=doe" );
+        Rdn rdn2 = new Rdn( schemaManager );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 5000000; i++ )
+        {
+            byte[] buffer = new byte[256];
+            rdn1.serialize( buffer, 0 );
+            rdn2.deserialize( buffer, 0 );
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        System.out.println( "Delta ser fast = " + ( t1 - t0 ) );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareRdnTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareRdnTest.java
new file mode 100644
index 0000000..96b4a3f
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/model/name/SchemaAwareRdnTest.java
@@ -0,0 +1,1257 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Iterator;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Schema aware Rdn class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaAwareRdnTest
+{
+    /** A null schemaManager used in tests */
+    private static SchemaManager schemaManager;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        schemaManager = new DefaultSchemaManager();
+    }
+
+
+    /**
+     * Test a null Rdn
+     */
+    @Test
+    public void testRdnNull()
+    {
+        assertEquals( "", new Rdn( schemaManager ).toString() );
+    }
+
+
+    /**
+     * test an empty Rdn
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnEmpty() throws LdapException
+    {
+        assertEquals( "", new Rdn( schemaManager, "" ).toString() );
+    }
+
+
+    /**
+     * test a simple Rdn : cn = b
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnSimple() throws LdapException
+    {
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn = b" ).getNormName() );
+    }
+
+
+    /**
+     * test a composite Rdn : cn = b, sn = e
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnComposite() throws LdapException
+    {
+        assertEquals( "2.5.4.3=b+2.5.4.4=d", new Rdn( schemaManager, "cn = b + sn = d" ).getNormName() );
+    }
+
+
+    /**
+     * test a composite Rdn with or without spaces: cn=b, cn =b, cn= b, cn = b, cn =
+     * b
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnCompositeWithSpace() throws LdapException
+    {
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn=b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn=b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn =b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn= b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn=b " ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn =b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn= b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn=b " ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn = b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn =b " ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn= b " ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn = b" ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn =b " ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn= b " ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, "cn = b " ).getNormName() );
+        assertEquals( "2.5.4.3=b", new Rdn( schemaManager, " cn = b " ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with differents separators : cn = b + sn = d
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnSimpleMultivaluedAttribute() throws LdapException
+    {
+        String result = new Rdn( schemaManager, "cn = b + sn = d" ).getNormName();
+        assertEquals( "2.5.4.3=b+2.5.4.4=d", result );
+    }
+
+
+    /**
+     * test a composite Rdn with differents separators : cn=b+sn=d, gn=f + l=h +
+     * c=j
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnCompositeMultivaluedAttribute() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn =b+sn=d + gn=f + l  =h + c =j " );
+
+        // NameComponent are not ordered
+        assertEquals( "b", rdn.getValue( "CommonName" ) );
+        assertEquals( "d", rdn.getValue( "2.5.4.4" ) );
+        assertEquals( "f", rdn.getValue( "  gn  " ) );
+        assertEquals( "h", rdn.getValue( "L" ) );
+        assertEquals( "j", rdn.getValue( "c" ) );
+    }
+
+
+    /**
+     * test a simple Rdn with an oid prefix (uppercase) : OID.2.5.4.3 = azerty
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnOidUpper() throws LdapException
+    {
+        assertEquals( "2.5.4.3=azerty", new Rdn( schemaManager, "OID.2.5.4.3 =  azerty" ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with an oid prefix (lowercase) : oid.12.34.56 = azerty
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnOidLower() throws LdapException
+    {
+        assertEquals( "2.5.4.3=azerty", new Rdn( schemaManager, "oid.2.5.4.3 = azerty" ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with an oid attribut wiithout oid prefix : 2.5.4.3 =
+     * azerty
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnOidWithoutPrefix() throws LdapException
+    {
+        assertEquals( "2.5.4.3=azerty", new Rdn( schemaManager, "2.5.4.3 = azerty" ).getNormName() );
+    }
+
+
+    /**
+     * test a composite Rdn with an oid attribut wiithout oid prefix : 2.5.4.3 =
+     * azerty; 2.5.4.4 = test
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnCompositeOidWithoutPrefix() throws LdapException
+    {
+        String result = new Rdn( schemaManager, "2.5.4.3 = azerty + 2.5.4.4 = test" ).getNormName();
+        assertEquals( "2.5.4.3=azerty+2.5.4.4=test", result );
+    }
+
+
+    /**
+     * test a simple Rdn with pair char attribute value : l = \,\=\+\<\>\#\;\\\"\C3\A9"
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnPairCharAttributeValue() throws LdapException
+    {
+        String rdn = Strings.utf8ToString( new byte[]
+            {
+                'l',
+                '=',
+                '\\',
+                ',',
+                '\\',
+                '=',
+                '\\',
+                '+',
+                '\\',
+                '<',
+                '\\',
+                '>',
+                '#',
+                '\\',
+                ';',
+                '\\',
+                '\\',
+                '\\',
+                '"',
+                '\\',
+                'C',
+                '3',
+                '\\',
+                'A',
+                '9' } );
+        assertEquals( "2.5.4.7=\\,\\=\\+\\<\\>#\\;\\\\\\\"\u00e9", new Rdn( schemaManager, rdn ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with hexString attribute value : userCertificate = #0010A0AAFF
+     */
+    @Test
+    public void testRdnHexStringAttributeValue() throws LdapException
+    {
+        assertEquals( "2.5.4.36=#0010A0AAFF", new Rdn( schemaManager, "userCertificate = #0010A0AAFF" ).getNormName() );
+    }
+
+
+    /**
+     * test exception from illegal hexString attribute value : cn=#zz.
+     */
+    @Test
+    public void testBadRdnHexStringAttributeValue() throws LdapException
+    {
+        try
+        {
+            new Rdn( schemaManager, "cn=#zz" );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a simple Rdn with quoted attribute value : cn = "quoted \"value"
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnQuotedAttributeValue() throws LdapException
+    {
+        assertEquals( "2.5.4.3=quoted \\\"value", new Rdn( schemaManager, "cn = quoted \\\"value" ).getNormName() );
+    }
+
+
+    /**
+     * Test the clone method for a Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCloningOneNameComponent() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "CN", "B" );
+
+        Rdn rdnClone = rdn.clone();
+
+        rdn = new Rdn( schemaManager, "cn=d" );
+
+        assertEquals( "b", rdnClone.getNormValue( "Cn" ) );
+    }
+
+
+    /**
+     * Test the creation of a new Rdn
+     * 
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException
+     */
+    @Test
+    public void testRDNCreation() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "CN", "  b  " );
+        assertEquals( "2.5.4.3=b", rdn.getNormName() );
+        assertEquals( "CN=  b  ", rdn.getName() );
+    }
+
+
+    /**
+     * Test the clone method for a Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCloningTwoNameComponent() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn = b + sn = bb" );
+
+        Rdn rdnClone = rdn.clone();
+
+        rdn.clear();
+        rdn = new Rdn( schemaManager, "l=d" );
+
+        assertEquals( "b", rdnClone.getValue( "2.5.4.3" ) );
+        assertEquals( "bb", rdnClone.getValue( "SN" ) );
+        assertEquals( "", rdnClone.getValue( "l" ) );
+    }
+
+
+    /**
+     * Test the equals method for a Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNull() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + sn = d + l = f + gn = h " );
+        Rdn rdn2 = null;
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NC to a single NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NC() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + sn = d + l = f + gn = h " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b " );
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a single NC to a composite NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NCS() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " sn = b " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b + sn = d + l = f + gn = h " );
+
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NCS to a composite NCS in the same order.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NCSOrdered() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + sn = d + gn = f + l = h " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b + sn = d + gn = f + l = h " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NCS to a composite NCS in a different order.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NCSUnordered() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + gn = f + l = h + sn = d " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b + sn = d + gn = f + l = h " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NCS to a different composite NCS.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NCSNotEquals() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = f + sn = h + l = d " );
+        Rdn rdn2 = new Rdn( schemaManager, " l = d + cn = h + sn = h " );
+
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-2.
+     * The first ATAV is equal, the second or following ATAV differs.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareSecondAtav() throws LdapException
+    {
+        // the second ATAV differs
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + sn = d " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b + sn = y " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+
+        // the third ATAV differs
+        Rdn rdn3 = new Rdn( schemaManager, " cn = b + sn = d + l = f " );
+        Rdn rdn4 = new Rdn( schemaManager, " cn = b + sn = d + l = y " );
+        assertFalse( rdn3.equals( rdn4 ) );
+        assertFalse( rdn4.equals( rdn3 ) );
+
+        // the second ATAV differs in value only
+        Rdn rdn5 = new Rdn( schemaManager, " cn = b + sn = c " );
+        Rdn rdn6 = new Rdn( schemaManager, " cn = b + sn = y " );
+        assertFalse( rdn5.equals( rdn6 ) );
+        assertFalse( rdn6.equals( rdn5 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-2.
+     * The compare operation should return a correct value (1 or -1)
+     * depending on the ATAVs, not on their position.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareIndependentFromOrder() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + sn = d " );
+        Rdn rdn2 = new Rdn( schemaManager, " sn = d + cn = b " );
+        assertTrue( rdn1.equals( rdn2 ) );
+
+        rdn1 = new Rdn( schemaManager, " cn = b + sn = e " );
+        rdn2 = new Rdn( schemaManager, " sn = d + cn = b " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+
+        rdn1 = new Rdn( schemaManager, " cn = b + sn = d " );
+        rdn2 = new Rdn( schemaManager, " l = f + gn = h " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for single-valued RDNs.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareInvertableNC2NC() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = c " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for multi-valued RDNs with different values.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareInvertableNCS2NCSDifferentValues() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + sn = c " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b + sn = y " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for multi-valued RDNs with different types.
+     * 
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException
+     */
+    @Test
+    public void testCompareInvertableNCS2NCSDifferentTypes() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b + sn = d  " );
+        Rdn rdn2 = new Rdn( schemaManager, " l = f + gn = h " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for multi-valued RDNs with different order.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareInvertableNCS2NCSUnordered() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " sn = d + cn = b " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b + l = f " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Compares with a null Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNullRdn() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b " );
+
+        assertFalse( rdn1.equals( null ) );
+    }
+
+
+    /**
+     * Compares a simple NC to a simple NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NC() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b " );
+        Rdn rdn2 = new Rdn( schemaManager, " cn = b " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a simple NC to a simple NC in UperCase.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NCUperCase() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b " );
+        Rdn rdn2 = new Rdn( schemaManager, " CN = b " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a simple NC to a different simple NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NCNotEquals() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, " cn = b " );
+        Rdn rdn2 = new Rdn( schemaManager, " CN = d " );
+
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * 
+     * Test the getValue method.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testGetValue() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, " cn = b + sn = f + gn = h + l = d " );
+
+        assertEquals( "b", rdn.getNormValue() );
+    }
+
+
+    /**
+     * 
+     * Test the getType method.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testGetType() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, " cn = b + sn = f + gn = h + l = d " );
+
+        assertEquals( "2.5.4.3", rdn.getNormType() );
+    }
+
+
+    /**
+     * Test the getSize method.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testGetSize() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, " cn = b + sn = f + gn = h + l = d " );
+
+        assertEquals( 4, rdn.size() );
+    }
+
+
+    /**
+     * Test the getSize method.
+     *
+     */
+    @Test
+    public void testGetSize0()
+    {
+        Rdn rdn = new Rdn( schemaManager );
+
+        assertEquals( 0, rdn.size() );
+    }
+
+
+    /**
+     * Test the equals method
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testEquals() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn=b + sn=d + gn=f" );
+
+        assertFalse( rdn.equals( null ) );
+        assertFalse( rdn.equals( "test" ) );
+        assertFalse( rdn.equals( new Rdn( schemaManager, "cn=c + sn=d + gn=f" ) ) );
+        assertFalse( rdn.equals( new Rdn( schemaManager, "cn=b" ) ) );
+        assertTrue( rdn.equals( new Rdn( schemaManager, "cn=b + sn=d + gn=f" ) ) );
+        assertTrue( rdn.equals( new Rdn( schemaManager, "cn=b + SN=d + GN=f" ) ) );
+        assertTrue( rdn.equals( new Rdn( schemaManager, "sn=d + gn=f + CN=b" ) ) );
+    }
+
+
+    @Test
+    public void testUnescapeValueHexa()
+    {
+        byte[] res = ( byte[] ) Rdn.unescapeValue( "#fF" );
+
+        assertEquals( "0xFF ", Strings.dumpBytes( res ) );
+
+        res = ( byte[] ) Rdn.unescapeValue( "#0123456789aBCDEF" );
+        assertEquals( "0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF ", Strings.dumpBytes( res ) );
+    }
+
+
+    @Test
+    public void testUnescapeValueHexaWrong()
+    {
+        try
+        {
+            Rdn.unescapeValue( "#fF1" );
+            fail(); // Should not happen
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testUnescapeValueString()
+    {
+        String res = ( String ) Rdn.unescapeValue( "azerty" );
+
+        assertEquals( "azerty", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringSpecial()
+    {
+        String res = ( String ) Rdn.unescapeValue( "\\\\\\#\\,\\+\\;\\<\\>\\=\\\"\\ " );
+
+        assertEquals( "\\#,+;<>=\" ", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithSpaceInTheMiddle()
+    {
+        String res = ( String ) Rdn.unescapeValue( "a b" );
+
+        assertEquals( "a b", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithSpaceInAtTheBeginning()
+    {
+        String res = ( String ) Rdn.unescapeValue( "\\ a b" );
+
+        assertEquals( " a b", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithSpaceInAtTheEnd()
+    {
+        String res = ( String ) Rdn.unescapeValue( "a b\\ " );
+
+        assertEquals( "a b ", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithPoundInTheMiddle()
+    {
+        String res = ( String ) Rdn.unescapeValue( "a#b" );
+
+        assertEquals( "a#b", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithPoundAtTheEnd()
+    {
+        String res = ( String ) Rdn.unescapeValue( "ab#" );
+
+        assertEquals( "ab#", res );
+    }
+
+
+    @Test
+    public void testEscapeValueString()
+    {
+        String res = Rdn.escapeValue( Strings.getBytesUtf8( "azerty" ) );
+
+        assertEquals( "azerty", res );
+    }
+
+
+    @Test
+    public void testEscapeValueStringSpecial()
+    {
+        String res = Rdn.escapeValue( Strings.getBytesUtf8( "\\#,+;<>=\" " ) );
+
+        assertEquals( "\\\\#\\,\\+\\;\\<\\>\\=\\\"\\ ", res );
+    }
+
+
+    @Test
+    public void testEscapeValueNumeric()
+    {
+        String res = Rdn.escapeValue( new byte[]
+            { '-', 0x00, '-', 0x1F, '-', 0x7F, '-' } );
+
+        assertEquals( "-\\00-\\1F-\\7F-", res );
+    }
+
+
+    @Test
+    public void testEscapeValueMix()
+    {
+        String res = Rdn.escapeValue( new byte[]
+            { '\\', 0x00, '-', '+', '#', 0x7F, '-' } );
+
+        assertEquals( "\\\\\\00-\\+#\\7F-", res );
+    }
+
+
+    @Test
+    public void testDIRSERVER_703() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn=Kate Bush+sn=Bush" );
+        assertEquals( "cn=Kate Bush+sn=Bush", rdn.getName() );
+    }
+
+
+    @Test
+    public void testMultiValuedIterator() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn=Kate Bush+sn=Bush" );
+        Iterator<Ava> iterator = rdn.iterator();
+        assertNotNull( iterator );
+        assertTrue( iterator.hasNext() );
+        assertNotNull( iterator.next() );
+        assertTrue( iterator.hasNext() );
+        assertNotNull( iterator.next() );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    @Test
+    public void testSingleValuedIterator() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn=Kate Bush" );
+        Iterator<Ava> iterator = rdn.iterator();
+        assertNotNull( iterator );
+        assertTrue( iterator.hasNext() );
+        assertNotNull( iterator.next() );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    @Test
+    public void testEmptyIterator()
+    {
+        Rdn rdn = new Rdn( schemaManager );
+        Iterator<Ava> iterator = rdn.iterator();
+        assertNotNull( iterator );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    @Test
+    public void testRdnWithSpaces() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn=a\\ b\\ c" );
+        assertEquals( "2.5.4.3=a b c", rdn.getNormName() );
+    }
+
+
+    @Test
+    public void testEscapedSpaceInValue() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, "cn=a b c" );
+        Rdn rdn2 = new Rdn( schemaManager, "cn=a\\ b\\ c" );
+        assertEquals( "2.5.4.3=a b c", rdn1.getNormName() );
+        assertEquals( "2.5.4.3=a b c", rdn2.getNormName() );
+        assertTrue( rdn1.equals( rdn2 ) );
+
+        Rdn rdn3 = new Rdn( schemaManager, "cn=\\ a b c\\ " );
+        Rdn rdn4 = new Rdn( schemaManager, "cn=\\ a\\ b\\ c\\ " );
+        assertEquals( "2.5.4.3=\\ a b c\\ ", rdn3.getNormName() );
+        assertEquals( "cn=\\ a b c\\ ", rdn3.getName() );
+        assertEquals( "2.5.4.3=\\ a b c\\ ", rdn4.getNormName() );
+        assertEquals( "cn=\\ a\\ b\\ c\\ ", rdn4.getName() );
+        assertTrue( rdn3.equals( rdn4 ) );
+    }
+
+
+    @Test
+    public void testEscapedHashInValue() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( schemaManager, "cn=a#b#c" );
+        Rdn rdn2 = new Rdn( schemaManager, "cn=a\\#b\\#c" );
+        assertEquals( "2.5.4.3=a#b#c", rdn1.getNormName() );
+        assertEquals( "2.5.4.3=a#b#c", rdn2.getNormName() );
+        assertTrue( rdn1.equals( rdn2 ) );
+
+        Rdn rdn3 = new Rdn( schemaManager, "cn=\\#a#b#c\\#" );
+        Rdn rdn4 = new Rdn( schemaManager, "cn=\\#a\\#b\\#c\\#" );
+        assertEquals( "2.5.4.3=\\#a#b#c#", rdn3.getNormName() );
+        assertEquals( "2.5.4.3=\\#a#b#c#", rdn4.getNormName() );
+        assertTrue( rdn3.equals( rdn4 ) );
+    }
+
+
+    @Test
+    public void testEscapedAttributeValue()
+    {
+        // space doesn't need to be escaped in the middle of a string
+        assertEquals( "a b", Rdn.escapeValue( "a b" ) );
+        assertEquals( "\u00e4 b c", Rdn.escapeValue( "\u00e4 b c" ) );
+        assertEquals( "a b c d", Rdn.escapeValue( "a b c d" ) );
+
+        // space must be escaped at the beginning and the end of a string
+        assertEquals( "\\ a b", Rdn.escapeValue( " a b" ) );
+        assertEquals( "a b\\ ", Rdn.escapeValue( "a b " ) );
+        assertEquals( "\\ a b\\ ", Rdn.escapeValue( " a b " ) );
+        assertEquals( "\\  a  b \\ ", Rdn.escapeValue( "  a  b  " ) );
+
+        // hash doesn't need to be escaped in the middle and the end of a string
+        assertEquals( "a#b", Rdn.escapeValue( "a#b" ) );
+        assertEquals( "a#b#", Rdn.escapeValue( "a#b#" ) );
+        assertEquals( "a#b#c", Rdn.escapeValue( "a#b#c" ) );
+        assertEquals( "a#b#c#", Rdn.escapeValue( "a#b#c#" ) );
+        assertEquals( "a#b#c#d", Rdn.escapeValue( "a#b#c#d" ) );
+        assertEquals( "a#b#c#d#", Rdn.escapeValue( "a#b#c#d#" ) );
+
+        // hash must be escaped at the beginning of a string
+        assertEquals( "\\#a#b", Rdn.escapeValue( "#a#b" ) );
+        assertEquals( "\\##a#b", Rdn.escapeValue( "##a#b" ) );
+
+        // other characters that need to be escaped
+        // '"', '+', ',', ';', '<', '>', '\', the null (U+0000) character
+        assertEquals( "\\\"\\+\\,\\;\\<\\>\\\\\\00", Rdn.escapeValue( "\"+,;<>\\\u0000" ) );
+
+        // unicode characters don't need to be escaped
+        // \u00e9 - e with acute - 2 bytes in UTF-8
+        // \u20ac - Euro character - 3 bytes in UTF-8
+        // \uD83D\uDE08 - Smiley - 4 bytes in UTF-8
+        assertEquals( "\u00e9\u20AC\uD83D\uDE08", Rdn.escapeValue( "\u00e9\u20AC\uD83D\uDE08" ) );
+    }
+
+
+    /** Serialization tests ------------------------------------------------- */
+
+    /**
+     * Test serialization of an empty Rdn
+     */
+    @Test
+    public void testEmptyRDNSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager, "" );
+
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    @Test
+    public void testNullRdnSerialization() throws IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager );
+
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn
+     */
+    @Test
+    public void testSimpleRdnSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager, "cn=b" );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn
+     */
+    @Test
+    public void testSimpleRdn2Serialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager, " CN  = DEF " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with no value
+     */
+    @Test
+    public void testSimpleRdnNoValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager, " DC  =" );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with one value
+     */
+    @Test
+    public void testSimpleRdnOneValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager, " CN  = def " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with three values
+     */
+    @Test
+    public void testSimpleRdnThreeValuesSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager, " CN = a + SN = b + GN = c " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with three unordered values
+     */
+    @Test
+    public void testSimpleRdnThreeValuesUnorderedSerialization() throws LdapException, IOException,
+        ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( schemaManager, " CN = b + SN = a + GN = c " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn( schemaManager );
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * test an Rdn with empty value
+     */
+    @Test
+    public void testRdnWithEmptyValue() throws LdapException
+    {
+        assertTrue( Rdn.isValid( "dc=" ) );
+        assertTrue( Rdn.isValid( "dc=\"\"" ) );
+        assertEquals( "0.9.2342.19200300.100.1.25=", new Rdn( schemaManager, "dc=" ).getNormName() );
+        assertEquals( "0.9.2342.19200300.100.1.25=", new Rdn( schemaManager, "dc=\"\"" ).getNormName() );
+    }
+
+
+    /**
+     * test an Rdn with escaped comma
+     */
+    @Test
+    public void testRdnWithEscapedComa() throws LdapException
+    {
+        assertTrue( Rdn.isValid( "cn=b\\,c" ) );
+        assertEquals( "2.5.4.3=b\\,c", new Rdn( schemaManager, "cn=b\\,c" ).getNormName() );
+
+        assertTrue( Rdn.isValid( "cn=\"b,c\"" ) );
+        assertEquals( "2.5.4.3=b\\,c", new Rdn( schemaManager, "cn=\"b,c\"" ).getNormName() );
+        assertEquals( "cn=\"b,c\"", new Rdn( schemaManager, "cn=\"b,c\"" ).getName() );
+
+        assertTrue( Rdn.isValid( "cn=\"b\\,c\"" ) );
+        Rdn rdn = new Rdn( schemaManager, "cn=\"b\\,c\"" );
+        assertEquals( "cn=\"b\\,c\"", rdn.getName() );
+        assertEquals( "2.5.4.3=b\\,c", rdn.getNormName() );
+    }
+
+
+    /**
+     * Tests the equals and equals results of cloned multi-valued RDNs.
+     * Test for DIRSHARED-9.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testComparingOfClonedMultiValuedRDNs() throws LdapException
+    {
+        // Use upper case attribute types to test if normalized types are used
+        // for comparison
+        Rdn rdn = new Rdn( schemaManager, " CN = b + SN = d" );
+        Rdn clonedRdn = rdn.clone();
+
+        assertTrue( rdn.equals( clonedRdn ) );
+    }
+
+
+    /**
+     * Tests the equals and equals results of copy constructed multi-valued RDNs.
+     * Test for DIRSHARED-9.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testComparingOfCopyConstructedMultiValuedRDNs() throws LdapException
+    {
+        // Use upper case attribute types to test if normalized types are used
+        // for comparison
+        Rdn rdn = new Rdn( schemaManager, " CN = b + SN = d" );
+        Rdn copiedRdn = new Rdn( rdn );
+
+        assertTrue( rdn.equals( copiedRdn ) );
+    }
+
+
+    /**
+     * test the UpName method on a Rdn with more than one atav
+     */
+    @Test
+    public void testGetUpNameMultipleAtav() throws LdapException
+    {
+        Rdn rdn = new Rdn( schemaManager, " CN = b + SN = d " );
+
+        assertEquals( " CN = b + SN = d ", rdn.getName() );
+    }
+
+
+    @Test
+    public void testSchemaAware() throws LdapException
+    {
+        Rdn rdn = new Rdn( "cn=John" );
+
+        assertFalse( rdn.isSchemaAware() );
+
+        rdn.apply( schemaManager );
+
+        assertTrue( rdn.isSchemaAware() );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/schema/syntaxCheckers/ACIItemSyntaxCheckerTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/schema/syntaxCheckers/ACIItemSyntaxCheckerTest.java
new file mode 100644
index 0000000..521453e
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/schema/syntaxCheckers/ACIItemSyntaxCheckerTest.java
@@ -0,0 +1,295 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.syntaxCheckers;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.aci.ACIItemSyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test cases for ACIItemSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ACIItemSyntaxCheckerTest
+{
+    private static ACIItemSyntaxChecker checker;
+
+
+    @BeforeClass
+    public static void init() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+        schemaManager.loadAllEnabled();
+        checker = new org.apache.directory.api.ldap.aci.ACIItemSyntaxChecker();
+        checker.setSchemaManager( schemaManager );
+    }
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.1", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+    }
+
+
+    /**
+     * Tests the checker with an ACIItem of ItemFirst main component.
+     */
+    @Test
+    public void testItemFirst()
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { entry  , attributeType { 1.2.3    , ou }  , "
+            + " attributeValue { ou=people  , cn=Ersin  }  , rangeOfValues (cn=ErsinEr) , "
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    /**
+     * Tests the checker with an ACIItem of UserFirst main component.
+     */
+    @Test
+    public void testUserFirst()
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {cn=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testAllowAddAllUsers()
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testCombo()
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers, name { \"ou=blah\" } }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testOrderOfProtectedItemsDoesNotMatter()
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testOrderOfUserClassesDoesNotMatter()
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  name { \"ou=people,cn=ersin\" }, allUsers, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {cn=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testItemPermissionComponentsOrderDoesNotMatter()
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { grantsAndDenials  {  denyCompare  , grantModify }, userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"2.5.4.3=y,dc=t\"  , \"cn=b,dc=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testUserPermissionComponentsOrderDoesNotMatter()
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { grantsAndDenials { grantBrowse }, protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {cn=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  } } }  }   ";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testOrderOfMainACIComponentsDoesNotMatter()
+    {
+        String spec = "{   itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {cn=y,sn=n,dc=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }, "
+            + " identificationTag \"id2\"   , authenticationLevel none, precedence 14 }   ";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testRestrictedValueComponentsOrderDoesNotMatter()
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\"}, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , "
+            + "maxValueCount { { type 10.11.12, maxCount 10 }, { maxCount 20, type 11.12.13  } } "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    @Test
+    public void testMaxValueCountComponentsOrderDoesNotMatter()
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , "
+            + "restrictedBy { { type 10.11.12, valuesIn ou }, { valuesIn cn, type 11.12.13  } } "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        assertTrue( checker.isValidSyntax( spec ) );
+    }
+
+
+    /**
+     * Test case for DIRSERVER-891
+     */
+    @Test
+    public void testInvalidAttributeValue()
+    {
+        String spec;
+
+        // no name-value-pair
+        spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue { must_be_a_name_value_pair } , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ minimum 7, maximum 9, base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + " maximum   2, minimum  1 } } }  }  }   ";
+        assertFalse( checker.isValidSyntax( spec ) );
+
+        // no name-value-pair
+        spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue { x=y,m=n,k=l,x } , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ minimum 7, maximum 9, base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + " maximum   2, minimum  1 } } }  }  }   ";
+        assertFalse( checker.isValidSyntax( spec ) );
+    }
+
+
+    /**
+     * Test case for DIRSERVER-891
+     */
+    @Test
+    public void testIncomplete()
+    {
+        String spec;
+
+        spec = "{ }";
+        assertFalse( checker.isValidSyntax( spec ) );
+
+        spec = "{ identificationTag \"id2\" }";
+        assertFalse( checker.isValidSyntax( spec ) );
+
+        spec = "{ identificationTag \"id2\", precedence 14 } ";
+        assertFalse( checker.isValidSyntax( spec ) );
+
+        spec = "{ identificationTag \"id2\", precedence 14, authenticationLevel none } ";
+        assertFalse( checker.isValidSyntax( spec ) );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/schema/syntaxCheckers/SubtreeSpecificationSyntaxCheckerTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/schema/syntaxCheckers/SubtreeSpecificationSyntaxCheckerTest.java
new file mode 100644
index 0000000..d1ab96b
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/schema/syntaxCheckers/SubtreeSpecificationSyntaxCheckerTest.java
@@ -0,0 +1,297 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.syntaxCheckers;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.SubtreeSpecificationSyntaxChecker;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for SubtreeSpecificationSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SubtreeSpecificationSyntaxCheckerTest
+{
+    private static SubtreeSpecificationSyntaxChecker checker;
+
+
+    /**
+     * Initialization
+     */
+    @BeforeClass
+    public static void init() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadAllEnabled();
+
+        checker = new SubtreeSpecificationSyntaxChecker();
+        checker.setSchemaManager( schemaManager );
+    }
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.45", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+    }
+
+    /** A valid empty specification with single white space between brackets */
+    private static final String EMPTY_SPEC = "{ }";
+
+    /** A valid specification only with base set */
+    private static final String SPEC_WITH_BASE = "{ base \"ou=system\" }";
+
+    /** An invalid specification with missing white space and base set */
+    private static final String INVALID_SPEC_WITH_BASE_AND_MISSING_WS = "{ base\"ou=system\"}";
+
+    /** A valid specification with some specific exclusions set */
+    private static final String SPEC_WITH_SPECIFICEXCLUSIONS = "{ specificExclusions { chopAfter:\"ef=gh\", chopBefore:\"ab=cd\" } }";
+
+    /** A valid specification with empty specific exclusions set */
+    private static final String SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS = "{ specificExclusions { } }";
+
+    /** A valid specification with minimum and maximum set */
+    private static final String SPEC_WITH_MINIMUM_AND_MAXIMUM = "{ minimum 1, maximum 2 }";
+
+    /** A valid specification with base and minimum and maximum set */
+    private static final String SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM = "{ base \"ou=ORGANIZATION UNIT\", minimum  1, maximum   2 }";
+
+    /**
+     * A valid specification with base and specific exclusions and minimum and
+     * maximum set
+     */
+    private static final String SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM = "{ base \"ou=people\", specificExclusions { chopBefore:\"x=y\""
+        + ", chopAfter:\"k=l\", chopBefore:\"y=z\", chopAfter:\"l=m\" }, minimum   7, maximum 77 }";
+
+    /** A valid specification with refinement set */
+    private static final String SPEC_WITH_REFINEMENT = "{ base \"ou=system\", specificationFilter and:{ and:{ item:1.2.3"
+        + ", or:{ item:4.5.6, item:person-7 } }, not: item:10.11.12 } }";
+
+    /** A valid specification with base and an empty refinement set */
+    private static final String SPEC_WITH_BASE_AND_EMPTY_REFINEMENT = "{ base \"ou=system\", specificationFilter and:{ } }";
+
+    /** A valid specification with ALL IN ONE */
+    private static final String SPEC_WITH_ALL_IN_ONE = "{ base    \"ou=departments\""
+        + ", specificExclusions { chopBefore:\"x=y\", chopAfter:\"k=l\", chopBefore:\"y=z\", chopAfter:\"l=m\" }"
+        + ", minimum 7, maximum   77"
+        + ", specificationFilter     and:{ and:{ item:1.2.3, or:{ item:4.5.6, item:7.8.9 } }, not: item:10.11.12 } }";
+
+    /** An valid specification with unordinary component order */
+    private static final String SPEC_ORDER_OF_COMPONENTS_DOES_NOT_MATTER = "{ base \"ou=system\", minimum 3, specificExclusions { chopBefore:\"x=y\" } }";
+
+    /** An invalid specification with completely unrelated content */
+    private static final String INVALID_SILLY_THING = "How much wood would a wood chuck chuck if a wood chuck would chuck wood?";
+
+    /** A valid specification with filter expression */
+    private static final String SPEC_WITH_FILTER = "{ base \"ou=system\", specificationFilter (&(cn=test)(sn=test)) }";
+
+
+    /**
+     * Tests the parser with a valid empty specification.
+     */
+    @Test
+    public void testEmptySpec() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( EMPTY_SPEC ) );
+
+        // try a second time
+        assertTrue( checker.isValidSyntax( EMPTY_SPEC ) );
+
+        // try a third time
+        assertTrue( checker.isValidSyntax( EMPTY_SPEC ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base set.
+     */
+    @Test
+    public void testSpecWithBase() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_BASE ) );
+    }
+
+
+    /**
+     * Tests the parser with an invalid specification with missing white spaces
+     * and base set.
+     */
+    @Test
+    public void testInvalidSpecWithBaseAndMissingWS() throws Exception
+    {
+        assertFalse( checker.isValidSyntax( INVALID_SPEC_WITH_BASE_AND_MISSING_WS ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with some specific exclusions
+     * set.
+     */
+    @Test
+    public void testSpecWithSpecificExclusions() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_SPECIFICEXCLUSIONS ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with an empty specific
+     * exclusions set.
+     */
+    @Test
+    public void testSpecWithEmptySpecificExclusions() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with minimum and maximum set.
+     */
+    @Test
+    public void testSpecWithMinimumAndMaximum() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_MINIMUM_AND_MAXIMUM ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and minimum and
+     * maximum set.
+     */
+    @Test
+    public void testWithBaseAndMinimumAndMaximum() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and specific
+     * exclusions and minimum and maximum set.
+     */
+    @Test
+    public void testSpecWithBaseAndSpecificExclusionsAndMinimumAndMaximum() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with refinement set.
+     */
+    @Test
+    public void testSpecWithRefinement() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_REFINEMENT ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and empty
+     * refinement set.
+     */
+    @Test
+    public void testSpecWithBaseAndEmptyRefinement() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_BASE_AND_EMPTY_REFINEMENT ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with all components set.
+     */
+    @Test
+    public void testSpecWithAllInOne() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_ALL_IN_ONE ) );
+
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with unordinary component
+     * order.
+     */
+    @Test
+    public void testSpecOrderOfComponentsDoesNotMatter() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_ORDER_OF_COMPONENTS_DOES_NOT_MATTER ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with unordinary component
+     * order.
+     */
+    @Test
+    public void testBadAssertion() throws Exception
+    {
+        assertFalse( checker.isValidSyntax( INVALID_SILLY_THING ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with refinement set.
+     */
+    @Test
+    public void testSpecWithFilter() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( SPEC_WITH_FILTER ) );
+    }
+}
diff --git a/trunk/integ/src/test/java/org/apache/directory/api/ldap/subtree/SubtreeSpecificationParserTest.java b/trunk/integ/src/test/java/org/apache/directory/api/ldap/subtree/SubtreeSpecificationParserTest.java
new file mode 100644
index 0000000..b1315a7
--- /dev/null
+++ b/trunk/integ/src/test/java/org/apache/directory/api/ldap/subtree/SubtreeSpecificationParserTest.java
@@ -0,0 +1,489 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.subtree;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.subtree.AndRefinement;
+import org.apache.directory.api.ldap.model.subtree.ItemRefinement;
+import org.apache.directory.api.ldap.model.subtree.NotRefinement;
+import org.apache.directory.api.ldap.model.subtree.OrRefinement;
+import org.apache.directory.api.ldap.model.subtree.Refinement;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecificationParser;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class for Subtree Specification parser (wrapper).
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SubtreeSpecificationParserTest
+{
+    /** the ss parser wrapper */
+    private static SubtreeSpecificationParser parser;
+
+    /** A valid empty specification with single white space between brackets */
+    private static final String EMPTY_SPEC = "{ }";
+
+    /** A valid specification only with base set */
+    private static final String SPEC_WITH_BASE = "{ base \"ou=system\" }";
+
+    /** An invalid specification with missing white space and base set */
+    private static final String INVALID_SPEC_WITH_BASE_AND_MISSING_WS = "{ base\"ou=system\"}";
+
+    /** A valid specification with some specific exclusions set */
+    private static final String SPEC_WITH_SPECIFICEXCLUSIONS = "{ specificExclusions { chopAfter:\"cn=gh\", chopBefore:\"cn=cd\" } }";
+
+    /** A valid specification with empty specific exclusions set */
+    private static final String SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS = "{ specificExclusions { } }";
+
+    /** A valid specification with minimum and maximum set */
+    private static final String SPEC_WITH_MINIMUM_AND_MAXIMUM = "{ minimum 1, maximum 2 }";
+
+    /** A valid specification with base and minimum and maximum set */
+    private static final String SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM = "{ base \"ou=ORGANIZATION UNIT\", minimum  1, maximum   2 }";
+
+    /**
+     * A valid specification with base and specific exclusions and minimum and
+     * maximum set
+     */
+    private static final String SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM = "{ base \"ou=people\", specificExclusions { chopBefore:\"cn=y\""
+        + ", chopAfter:\"sn=l\", chopBefore:\"c=z\", chopAfter:\"l=m\" }, minimum   7, maximum 77 }";
+
+    /** A valid specification with refinement set */
+    private static final String SPEC_WITH_REFINEMENT = "{ base \"ou=system\", specificationFilter and:{ and:{ item:2.5.6.0"
+        + ", or:{ item:2.5.6.1, item:person } }, not: item:2.5.6.2 } }";
+
+    /** A valid specification with base and an empty refinement set */
+    private static final String SPEC_WITH_BASE_AND_EMPTY_REFINEMENT = "{ base \"ou=system\", specificationFilter and:{ } }";
+
+    /** A valid specification with ALL IN ONE */
+    private static final String SPEC_WITH_ALL_IN_ONE = "{ base    \"ou=departments\""
+        + ", specificExclusions { chopBefore:\"cn=y\", chopAfter:\"sn=l\", chopBefore:\"c=z\", chopAfter:\"l=m\" }"
+        + ", minimum 7, maximum   77"
+        + ", specificationFilter     and:{ and:{ item:2.5.6.0, or:{ item:2.5.6.1, item:2.5.6.2 } }, not: item:2.5.6.3 } }";
+
+    /** An valid specification with unordinary component order */
+    private static final String SPEC_ORDER_OF_COMPONENTS_DOES_NOT_MATTER = "{ base \"ou=system\", minimum 3, specificExclusions { chopBefore:\"cn=y\" } }";
+
+    /** An invalid specification with completely unrelated content */
+    private static final String INVALID_SILLY_THING = "How much wood would a wood chuck chuck if a wood chuck would chuck wood?";
+
+    /** holds multithreaded success value */
+    boolean isSuccessMultithreaded = true;
+
+    /** The schema manager */
+    private static SchemaManager schemaManager;
+
+    /** Some global OC */
+    private static ObjectClass topOC; // 2.5.6.0
+    private static ObjectClass aliasOC; // 2.5.6.1
+    private static ObjectClass countryOC; // 2.5.6.2
+    private static ObjectClass personOC; // 2.5.6.6
+
+
+    /**
+     * Initialization
+     */
+    @BeforeClass
+    public static void init() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+        schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadAllEnabled();
+
+        parser = new SubtreeSpecificationParser( schemaManager );
+
+        topOC = schemaManager.lookupObjectClassRegistry( "top" );
+        aliasOC = schemaManager.lookupObjectClassRegistry( "alias" );
+        countryOC = schemaManager.lookupObjectClassRegistry( "country" );
+        personOC = schemaManager.lookupObjectClassRegistry( "person" );
+    }
+
+
+    /**
+     * Tests the parser with a valid empty specification.
+     */
+    @Test
+    public void testEmptySpec() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( EMPTY_SPEC );
+        assertNotNull( ss );
+
+        // try a second time
+        ss = parser.parse( EMPTY_SPEC );
+        assertNotNull( ss );
+
+        // try a third time
+        ss = parser.parse( EMPTY_SPEC );
+        assertNotNull( ss );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base set.
+     */
+    @Test
+    public void testSpecWithBase() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE );
+        assertNotNull( ss );
+
+        assertEquals( "ou=system", ss.getBase().toString() );
+    }
+
+
+    /**
+     * Tests the parser with an invalid specification with missing white spaces
+     * and base set.
+     */
+    @Test
+    public void testInvalidSpecWithBaseAndMissingWS() throws Exception
+    {
+        try
+        {
+            parser.parse( INVALID_SPEC_WITH_BASE_AND_MISSING_WS );
+            fail( "testInvalidSpecWithBaseAndMissingWS() should never come here..." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with some specific exclusions
+     * set.
+     */
+    @Test
+    public void testSpecWithSpecificExclusions() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
+        assertFalse( ss.getChopBeforeExclusions().isEmpty() );
+        assertFalse( ss.getChopAfterExclusions().isEmpty() );
+        assertTrue( ss.getChopBeforeExclusions().contains( new Dn( schemaManager, "cn=cd" ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new Dn( schemaManager, "cn=gh" ) ) );
+
+        // try a second time
+        ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
+        assertFalse( ss.getChopBeforeExclusions().isEmpty() );
+        assertFalse( ss.getChopAfterExclusions().isEmpty() );
+        assertTrue( ss.getChopBeforeExclusions().contains( new Dn( schemaManager, "cn=cd" ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new Dn( schemaManager, "cn=gh" ) ) );
+
+        // try a third time
+        ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
+        assertFalse( ss.getChopBeforeExclusions().isEmpty() );
+        assertFalse( ss.getChopAfterExclusions().isEmpty() );
+        assertTrue( ss.getChopBeforeExclusions().contains( new Dn( schemaManager, "cn=cd" ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new Dn( schemaManager, "cn=gh" ) ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with an empty specific
+     * exclusions set.
+     */
+    @Test
+    public void testSpecWithEmptySpecificExclusions() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS );
+        assertNotNull( ss );
+
+        assertTrue( ss.getChopBeforeExclusions().isEmpty() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with minimum and maximum set.
+     */
+    @Test
+    public void testSpecWithMinimumAndMaximum() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
+        assertEquals( 1, ss.getMinBaseDistance() );
+        assertEquals( 2, ss.getMaxBaseDistance() );
+
+        // try a second time
+        ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
+        assertEquals( 1, ss.getMinBaseDistance() );
+        assertEquals( 2, ss.getMaxBaseDistance() );
+
+        // try a third time
+        ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
+        assertEquals( 1, ss.getMinBaseDistance() );
+        assertEquals( 2, ss.getMaxBaseDistance() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and minimum and
+     * maximum set.
+     */
+    @Test
+    public void testWithBaseAndMinimumAndMaximum() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM );
+
+        assertEquals( new Dn( "ou=ORGANIZATION UNIT" ).getName(), ss.getBase().getName() );
+        assertEquals( 1, ss.getMinBaseDistance() );
+        assertEquals( 2, ss.getMaxBaseDistance() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and specific
+     * exclusions and minimum and maximum set.
+     */
+    @Test
+    public void testSpecWithBaseAndSpecificExclusionsAndMinimumAndMaximum() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM );
+        assertNotNull( ss );
+
+        assertEquals( "ou=people", ss.getBase().toString() );
+        assertTrue( ss.getChopBeforeExclusions().contains( new Dn( "cn=y" ).apply( schemaManager ) ) );
+        assertTrue( ss.getChopBeforeExclusions().contains( new Dn( "c=z" ).apply( schemaManager ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new Dn( "sn=l" ).apply( schemaManager ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new Dn( "l=m" ).apply( schemaManager ) ) );
+        assertEquals( 7, ss.getMinBaseDistance() );
+        assertEquals( 77, ss.getMaxBaseDistance() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with refinement set.
+     */
+    @Test
+    public void testSpecWithRefinement() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_REFINEMENT );
+
+        // The items
+        Refinement topItem = new ItemRefinement( topOC );
+        Refinement aliasItem = new ItemRefinement( aliasOC );
+        Refinement personItem = new ItemRefinement( personOC );
+        Refinement countryItem = new ItemRefinement( countryOC );
+
+        // The inner OR refinement or:{item:2.5.6.1, item:person}
+        List<Refinement> orList = new ArrayList<Refinement>();
+        orList.add( aliasItem );
+        orList.add( personItem );
+
+        Refinement orRefinement = new OrRefinement( orList );
+
+        // The inner AND refinement and:{ item:2.5.6.0, or:... }
+        List<Refinement> innerAndList = new ArrayList<Refinement>();
+        innerAndList.add( topItem );
+        innerAndList.add( orRefinement );
+
+        Refinement innerAndRefinement = new AndRefinement( innerAndList );
+
+        // The NOT refinement not:item:2.5.6.2
+        Refinement notRefinement = new NotRefinement( countryItem );
+
+        // The outer AND refinement and:{and:..., not:...}
+        List<Refinement> outerAndList = new ArrayList<Refinement>();
+        outerAndList.add( innerAndRefinement );
+        outerAndList.add( notRefinement );
+
+        StringBuilder buffer = new StringBuilder();
+        ss.getRefinement().printRefinementToBuffer( buffer );
+
+        //assertEquals( outerAndRefinement.toString(), buffer );
+        assertEquals( "and: { and: { item: 2.5.6.0, or: { item: 2.5.6.1, item: person } }, not: item: 2.5.6.2 }",
+            buffer.toString() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and empty
+     * refinement set.
+     */
+    @Test
+    public void testSpecWithBaseAndEmptyRefinement() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_EMPTY_REFINEMENT );
+
+        assertEquals( "ou=system", ss.getBase().toString() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with all components set.
+     */
+    @Test
+    public void testSpecWithAllInOne() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_ALL_IN_ONE );
+        assertNotNull( ss );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with unordinary component
+     * order.
+     */
+    @Test
+    public void testSpecOrderOfComponentsDoesNotMatter() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_ORDER_OF_COMPONENTS_DOES_NOT_MATTER );
+        assertNotNull( ss );
+    }
+
+
+    /**
+     * Tests the parser with an invalid specification with silly things in.
+     */
+    @Test
+    public void testInvalidSillyThing() throws Exception
+    {
+        try
+        {
+            parser.parse( INVALID_SILLY_THING );
+            fail( "testInvalidSillyThing() should never come here..." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    /**
+     * Test reusability, especially if the state is resetted.
+     */
+    @Test
+    public void testReusabiltiy() throws Exception
+    {
+        Dn firstDn = new Dn( schemaManager, "cn=l" );
+        String firstExclusion = "{ specificExclusions { chopAfter:\"cn=l\" } }";
+        SubtreeSpecification firstSpec = parser.parse( firstExclusion );
+        assertEquals( 1, firstSpec.getChopAfterExclusions().size() );
+        assertEquals( firstDn, firstSpec.getChopAfterExclusions().iterator().next() );
+
+        Dn secondDn = new Dn( schemaManager, "l=y" );
+        String secondExclusion = "{ specificExclusions { chopAfter:\"l=y\" } }";
+        SubtreeSpecification secondSpec = parser.parse( secondExclusion );
+        assertEquals( 1, secondSpec.getChopAfterExclusions().size() );
+        assertEquals( secondDn, secondSpec.getChopAfterExclusions().iterator().next() );
+
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws Exception
+    {
+        // start up and track all threads (40 threads)
+        List<Thread> threads = new ArrayList<Thread>();
+        for ( int ii = 0; ii < 10; ii++ )
+        {
+            Thread t0 = new Thread( new ParseSpecification( EMPTY_SPEC ) );
+            Thread t1 = new Thread( new ParseSpecification( SPEC_WITH_SPECIFICEXCLUSIONS ) );
+            Thread t2 = new Thread( new ParseSpecification( SPEC_WITH_MINIMUM_AND_MAXIMUM ) );
+            Thread t3 = new Thread( new ParseSpecification( SPEC_WITH_ALL_IN_ONE ) );
+            threads.add( t0 );
+            threads.add( t1 );
+            threads.add( t2 );
+            threads.add( t3 );
+            t0.start();
+            t1.start();
+            t2.start();
+            t3.start();
+        }
+
+        // wait until all threads have died
+        boolean hasLiveThreads = false;
+        do
+        {
+            hasLiveThreads = false;
+
+            for ( int ii = 0; ii < threads.size(); ii++ )
+            {
+                Thread t = threads.get( ii );
+                hasLiveThreads = hasLiveThreads || t.isAlive();
+            }
+        }
+        while ( hasLiveThreads );
+
+        // check that no one thread failed to parse and generate a SS object
+        assertTrue( isSuccessMultithreaded );
+    }
+
+    /**
+     * Used to test multithreaded use of a single parser.
+     */
+    class ParseSpecification implements Runnable
+    {
+        private final String specStr;
+
+        SubtreeSpecification result;
+
+
+        public ParseSpecification( String specStr )
+        {
+            this.specStr = specStr;
+        }
+
+
+        public void run()
+        {
+            try
+            {
+                result = parser.parse( specStr );
+            }
+            catch ( ParseException e )
+            {
+                e.printStackTrace();
+            }
+
+            isSuccessMultithreaded = isSuccessMultithreaded && ( result != null );
+        }
+    }
+}
diff --git a/trunk/integ/src/test/resources/log4j.properties b/trunk/integ/src/test/resources/log4j.properties
new file mode 100644
index 0000000..7c79176
--- /dev/null
+++ b/trunk/integ/src/test/resources/log4j.properties
@@ -0,0 +1,22 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=ERROR, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+log4j.org.apache.directory.api.ldap.codec.standalone.StandaloneLdapCodecService=DEBUG
diff --git a/trunk/ldap/client/all/pom.xml b/trunk/ldap/client/all/pom.xml
new file mode 100644
index 0000000..68f27e3
--- /dev/null
+++ b/trunk/ldap/client/all/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-client-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-client-all</artifactId>
+  <name>Apache Directory LDAP API Client All</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-ber</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-client-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-standalone</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-schema-data</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+              <createDependencyReducedPom>true</createDependencyReducedPom>
+              <createSourcesJar>true</createSourcesJar>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/client/all/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/client/all/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/client/all/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/client/all/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/client/all/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/client/all/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/client/api/pom.xml b/trunk/ldap/client/api/pom.xml
new file mode 100644
index 0000000..da14f47
--- /dev/null
+++ b/trunk/ldap/client/api/pom.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-client-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+
+  <artifactId>api-ldap-client-api</artifactId>
+  <name>Apache Directory LDAP API Client API</name>
+  <packaging>bundle</packaging>
+  <inceptionYear>2009</inceptionYear>
+
+  <issueManagement>
+    <system>jira</system>
+    <url>http://issues.apache.org/jira/browse/DIRAPI</url>
+  </issueManagement>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/directory/clients/ldap/tags/1.0.0-M32/ldap/trunk/ldap-client-api</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/directory/clients/ldap/tags/1.0.0-M32/ldap/trunk/ldap-client-api</developerConnection>
+    <url>http://svn.apache.org/viewvc/directory/clients/ldap/tags/1.0.0-M32/ldap/trunk/ldap-client-api</url>
+  </scm>
+
+  <description>
+    LDAP Client API
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-schema-data</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-aci</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-pool</groupId>
+      <artifactId>commons-pool</artifactId>
+    </dependency>
+   
+    <dependency>
+      <groupId>org.apache.mina</groupId>
+      <artifactId>mina-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.10.19</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/Abstract*</exclude>
+            <exclude>**/*RegressionTest*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+            <mainClass>LdifAnonymizer.java.LdifAnonymizer</mainClass>
+          </archive>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.client.api</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.ldap.client.api;version=${project.version};-noimport:=true,
+              org.apache.directory.ldap.client.api.callback;version=${project.version};-noimport:=true,
+              org.apache.directory.ldap.client.api.exception;version=${project.version};-noimport:=true,
+              org.apache.directory.ldap.client.api.future;version=${project.version};-noimport:=true,
+              org.apache.directory.ldap.client.api.search;version=${project.version};-noimport:=true,
+              org.apache.directory.ldap.client.template;version=${project.version};-noimport:=true,
+              org.apache.directory.ldap.client.template.exception;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.commons.pool;version=${commons.pool.version},
+              org.apache.commons.pool.impl;version=${commons.pool.version},
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.asn1.util;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.aci;version=${project.version},
+              org.apache.directory.api.ldap.aci.protectedItem;version=${project.version},
+              org.apache.directory.api.ldap.codec.api;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.ppolicy_impl;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.ppolicy;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.vlv_impl;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.vlv;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.startTls;version=${project.version},
+              org.apache.directory.api.ldap.model.constants;version=${project.version},
+              org.apache.directory.api.ldap.model.cursor;version=${project.version},
+              org.apache.directory.api.ldap.model.entry;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.ldif.anonymizer;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.message.controls;version=${project.version},
+              org.apache.directory.api.ldap.model.message.extended;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.schema;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.parsers;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.registries;version=${project.version},
+              org.apache.directory.api.ldap.schema.manager.impl;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.apache.mina.core.filterchain;version=${mina.core.version},
+              org.apache.mina.core.future;version=${mina.core.version},
+              org.apache.mina.core.service;version=${mina.core.version},
+              org.apache.mina.core.session;version=${mina.core.version},
+              org.apache.mina.filter.codec;version=${mina.core.version},
+              org.apache.mina.filter.ssl;version=${mina.core.version},
+              org.apache.mina.transport.socket;version=${mina.core.version},
+              org.apache.mina.transport.socket.nio;version=${mina.core.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              javax.security.auth.login,
+              javax.security.auth.callback,
+              javax.security.sasl,
+              javax.net.ssl
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+
diff --git a/trunk/ldap/client/api/src/checkstyle/suppressions.xml b/trunk/ldap/client/api/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..64a81cb
--- /dev/null
+++ b/trunk/ldap/client/api/src/checkstyle/suppressions.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+
+  <suppress files="org.apache.directory.ldap.client.api.LdapNetworkConnection" checks="FileLength"/>
+
+</suppressions>
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractLdapConnection.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractLdapConnection.java
new file mode 100644
index 0000000..4923803
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractLdapConnection.java
@@ -0,0 +1,171 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import static org.apache.directory.api.ldap.model.message.ResultCodeEnum.processResponse;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An abstract LdapConnection class gathering the common behavior of LdapConnection
+ * concrete classes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractLdapConnection extends IoHandlerAdapter implements LdapConnection
+{
+    /** logger for reporting errors that might not be handled properly upstream */
+    private static final Logger LOG = LoggerFactory.getLogger( AbstractLdapConnection.class );
+
+    /** the schema manager */
+    protected SchemaManager schemaManager;
+
+    /** A Message ID which is incremented for each operation */
+    protected AtomicInteger messageId;
+
+    /** the ldap codec service */
+    protected LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of an AbstractLdapConnection
+     */
+    protected AbstractLdapConnection()
+    {
+        this( LdapApiServiceFactory.getSingleton() );
+    }
+
+    protected AbstractLdapConnection( LdapApiService codec )
+    {
+        messageId = new AtomicInteger( 0 );
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind( Dn name ) throws LdapException
+    {
+        byte[] credBytes = StringConstants.EMPTY_BYTES;
+
+        BindRequest bindRequest = new BindRequestImpl();
+        bindRequest.setDn( name );
+        bindRequest.setCredentials( credBytes );
+
+        BindResponse bindResponse = bind( bindRequest );
+
+        processResponse( bindResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind( String name ) throws LdapException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        bind( new Dn( schemaManager, name ), null );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind( String name, String credentials ) throws LdapException
+    {
+        bind( new Dn( schemaManager, name ), credentials );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind( Dn name, String credentials ) throws LdapException
+    {
+        byte[] credBytes = ( credentials == null ? StringConstants.EMPTY_BYTES : Strings.getBytesUtf8( credentials ) );
+
+        BindRequest bindRequest = new BindRequestImpl();
+        bindRequest.setDn( name );
+        bindRequest.setCredentials( credBytes );
+
+        BindResponse bindResponse = bind( bindRequest );
+
+        processResponse( bindResponse );
+    }
+
+
+    /**
+     * Create a complete BindRequest ready to be sent.
+     */
+    protected BindRequest createBindRequest( String name, byte[] credentials, String saslMechanism, Control... controls )
+        throws LdapException
+    {
+        // Set the new messageId
+        BindRequest bindRequest = new BindRequestImpl();
+
+        // Set the version
+        bindRequest.setVersion3( true );
+
+        // Set the name
+        bindRequest.setName( name );
+
+        // Set the credentials
+        if ( Strings.isEmpty( saslMechanism ) )
+        {
+            // Simple bind
+            bindRequest.setSimple( true );
+            bindRequest.setCredentials( credentials );
+        }
+        else
+        {
+            // SASL bind
+            bindRequest.setSimple( false );
+            bindRequest.setCredentials( credentials );
+            bindRequest.setSaslMechanism( saslMechanism );
+        }
+
+        // Add the controls
+        if ( ( controls != null ) && ( controls.length != 0 ) )
+        {
+            bindRequest.addAllControls( controls );
+        }
+
+        return bindRequest;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractPoolableLdapConnectionFactory.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractPoolableLdapConnectionFactory.java
new file mode 100644
index 0000000..68457d1
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/AbstractPoolableLdapConnectionFactory.java
@@ -0,0 +1,175 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import java.lang.reflect.Constructor;
+
+import org.apache.commons.pool.PoolableObjectFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An abstract class implementing the PoolableObjectFactory, for LdapConnections.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractPoolableLdapConnectionFactory implements PoolableObjectFactory<LdapConnection>
+{
+    /** This class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AbstractPoolableLdapConnectionFactory.class );
+
+    /** The factory to use to create a new connection */
+    protected LdapConnectionFactory connectionFactory;
+
+    /** The validator to use */
+    protected LdapConnectionValidator validator = new LookupLdapConnectionValidator();
+
+    /**
+     * {@inheritDoc}
+     * 
+     * There is nothing to do to activate a connection.
+     */
+    public void activateObject( LdapConnection connection ) throws LdapException
+    {
+        LOG.debug( "Activating {}", connection );
+        if ( !connection.isConnected() || !connection.isAuthenticated() )
+        {
+            LOG.debug( "rebind due to connection dropped on {}", connection );
+            connectionFactory.bindConnection( connection );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * Destroying a connection will unbind it which will result on a shutdown
+     * of teh underlying protocol.
+     */
+    public void destroyObject( LdapConnection connection ) throws LdapException
+    {
+        LOG.debug( "Destroying {}", connection );
+
+        try
+        {
+            // https://tools.ietf.org/html/rfc2251#section-4.3
+            // unbind closes the connection so no need to close
+            connection.unBind();
+        }
+        catch ( LdapException e )
+        {
+            LOG.error( "unable to unbind connection: {}", e.getMessage() );
+            LOG.debug( "unable to unbind connection:", e );
+        }
+    }
+
+
+    /**
+     * Returns the LdapApiService instance used by this factory.
+     *
+     * @return The LdapApiService instance used by this factory
+     */
+    public LdapApiService getLdapApiService()
+    {
+        return connectionFactory.getLdapApiService();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * Specifically, we are creating a new connection based on the LdapConnection Factory
+     * we used to create this pool of connections. The default is to create bound connections.
+     * 
+     * @throws LdapException If unable to connect.
+     */
+    public LdapConnection makeObject() throws LdapException
+    {
+        LOG.debug( "Creating a LDAP connection" );
+        return connectionFactory.newLdapConnection();
+    }
+
+
+    protected static LdapConnectionFactory newLdapConnectionFactory(
+        LdapConnectionConfig config,
+        Class<? extends LdapConnectionFactory> connectionFactoryClass )
+    {
+        try
+        {
+            Constructor<? extends LdapConnectionFactory> constructor =
+                connectionFactoryClass.getConstructor( LdapConnectionConfig.class );
+            return constructor.newInstance( config );
+        }
+        catch ( Exception e )
+        {
+            throw new IllegalArgumentException( "unable to create LdapConnectionFactory" + e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * We don't do anything with the connection. It remains in the state it was before
+     * being used.
+     * 
+     * @throws LdapException If unable to reconfigure and rebind.
+     */
+    public void passivateObject( LdapConnection connection ) throws LdapException
+    {
+        LOG.debug( "Passivating {}", connection );
+    }
+  
+    
+    /**
+     * Sets the validator to use when validation occurs.  Note that validation
+     * will only occur if the connection pool was configured to validate.  This
+     * means one of:
+     * <ul>
+     * <li>{@link org.apache.commons.pool.impl.GenericObjectPool#setTestOnBorrow setTestOnBorrow}</li>
+     * <li>{@link org.apache.commons.pool.impl.GenericObjectPool#setTestWhileIdle setTestWhileIdle}</li>
+     * <li>{@link org.apache.commons.pool.impl.GenericObjectPool#setTestOnReturn setTestOnReturn}</li>
+     * </ul>
+     * must have been set to true on the pool.  The default validator is 
+     * {@link LookupLdapConnectionValidator}.
+     *
+     * @param validator The validator
+     */
+    public void setValidator( LdapConnectionValidator validator ) 
+    {
+        this.validator = validator;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * Validating a connection is done by checking the connection status.
+     */
+    public boolean validateObject( LdapConnection connection )
+    {
+        LOG.debug( "Validating {}", connection );
+        return validator.validate( connection );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ConnectionClosedEventListener.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ConnectionClosedEventListener.java
new file mode 100644
index 0000000..ca66e88
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ConnectionClosedEventListener.java
@@ -0,0 +1,36 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+/**
+ * A listener class intended for notifying the classes using LdapNetworkConnection
+ * in the event of any network failure
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ConnectionClosedEventListener
+{
+    /**
+     * called when the LdapNetworkConnection is unable to reach the server it is connected to
+     */
+    void connectionClosed();
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultLdapConnectionFactory.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultLdapConnectionFactory.java
new file mode 100755
index 0000000..4a4f794
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultLdapConnectionFactory.java
@@ -0,0 +1,150 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The default implementation of LdapConnectionFactory. Allows for the 
+ * setting of timeout and {@link LdapApiService} as well as the standard 
+ * {@link LdapConnectionConfig}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultLdapConnectionFactory implements LdapConnectionFactory
+{
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultLdapConnectionFactory.class );
+
+    private LdapApiService apiService;
+    private LdapConnectionConfig connectionConfig;
+    private long timeout;
+
+
+    /**
+     * Creates a new instance of DefaultLdapConnectionFactory.
+     *
+     * @param config The connection config.
+     */
+    public DefaultLdapConnectionFactory( LdapConnectionConfig config )
+    {
+        this.connectionConfig = config;
+        this.timeout = config.getTimeout();
+    }
+
+
+    @Override
+    public LdapConnection bindConnection( LdapConnection connection ) throws LdapException
+    {
+        try
+        {
+            connection.bind( connectionConfig.getName(), connectionConfig.getCredentials() );
+        }
+        catch ( LdapException e )
+        {
+            LOG.error( "unable to bind connection: {}", e.getMessage() );
+            LOG.debug( "unable to bind connection:", e );
+
+            try
+            {
+                connection.close();
+            }
+            catch ( IOException ioe )
+            {
+                LOG.error( "unable to close failed bind connection: {}", e.getMessage() );
+                LOG.debug( "unable to close failed bind connection:", e );
+            }
+
+            throw e;
+        }
+
+        return connection;
+    }
+
+
+    @Override
+    public LdapConnection configureConnection( LdapConnection connection )
+    {
+        connection.setTimeOut( timeout );
+        connection.setBinaryAttributeDetector( connectionConfig.getBinaryAttributeDetector() );
+        return connection;
+    }
+
+
+    @Override
+    public LdapApiService getLdapApiService()
+    {
+        return apiService;
+    }
+
+
+    @Override
+    public LdapConnection newLdapConnection() throws LdapException
+    {
+        return bindConnection( newUnboundLdapConnection() );
+    }
+
+
+    @Override
+    public LdapConnection newUnboundLdapConnection()
+    {
+        if ( apiService == null )
+        {
+            return configureConnection( new LdapNetworkConnection( connectionConfig ) );
+        }
+        else
+        {
+            return configureConnection( new LdapNetworkConnection( connectionConfig, apiService ) );
+        }
+    }
+
+
+    /**
+     * Sets the LdapApiService (codec) to be used by the connections created
+     * by this factory.
+     *
+     * @param apiService The codec to used by connections created by this 
+     * factory
+     */
+    public void setLdapApiService( LdapApiService apiService )
+    {
+        this.apiService = apiService;
+    }
+
+
+    /**
+     * Sets the timeout that will be used by all connections created by this
+     * factory.
+     *
+     * @param timeout The timeout in millis.
+     * 
+     * @see LdapConnection#setTimeOut(long)
+     */
+    public void setTimeOut( long timeout )
+    {
+        this.timeout = timeout;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultLdapConnectionValidator.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultLdapConnectionValidator.java
new file mode 100755
index 0000000..7b881c7
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultLdapConnectionValidator.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+/**
+ * An implementation of {@link LdapConnectionValidator} that checks to see that
+ * the connection <code>isConnected()</code> and <code>isAuthenticated()</code>.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DefaultLdapConnectionValidator implements LdapConnectionValidator
+{
+    /**
+     * Returns true if <code>connection</code> is connected, and authenticated.
+     * 
+     * @param connection The connection to validate
+     * @return True, if the connection is still valid
+     */
+    public boolean validate( LdapConnection connection )
+    {
+        return connection.isConnected() && connection.isAuthenticated();
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultPoolableLdapConnectionFactory.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultPoolableLdapConnectionFactory.java
new file mode 100644
index 0000000..39766ac
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultPoolableLdapConnectionFactory.java
@@ -0,0 +1,72 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+
+
+/**
+ * A factory for creating LdapConnection objects managed by LdapConnectionPool. The connections are
+ * not validated when they are pulled from the pool : we just check if they are still connected, using
+ * their internal flag. We don't either re-bind when we push back teh connection into the pool.
+ * <br/>
+ * It's up to the users to be careful with the way they deal with connectiosn -especially when using
+ * the StartTLS extended operation -.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultPoolableLdapConnectionFactory extends AbstractPoolableLdapConnectionFactory
+{
+    /**
+     * Creates a new instance of PoolableLdapConnectionFactory.
+     *
+     * @param config the configuration for creating LdapConnections
+     */
+    public DefaultPoolableLdapConnectionFactory( LdapConnectionConfig config )
+    {
+        this( new DefaultLdapConnectionFactory( config ) );
+    }
+    
+    
+    /**
+     * Creates a new instance of PoolableLdapConnectionFactory using an instance
+     * of the supplied class as its LdapConnection factory.
+     *
+     * @param config the configuration for creating LdapConnections
+     * @param connectionFactoryClass the class used as a factory for connections
+     */
+    public DefaultPoolableLdapConnectionFactory( LdapConnectionConfig config,
+        Class<? extends LdapConnectionFactory> connectionFactoryClass )
+    {
+        this( newLdapConnectionFactory( config, connectionFactoryClass ) );
+    }
+
+
+    /**
+     * Creates a new instance of PoolableLdapConnectionFactory.
+     *
+     * @param connectionFactory the connection factory for creating LdapConnections
+     */
+    public DefaultPoolableLdapConnectionFactory( LdapConnectionFactory connectionFactory )
+    {
+        this.connectionFactory = connectionFactory;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultSchemaLoader.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultSchemaLoader.java
new file mode 100644
index 0000000..0631bff
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/DefaultSchemaLoader.java
@@ -0,0 +1,1165 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.AttributesFactory;
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.api.ldap.model.schema.NameForm;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
+import org.apache.directory.api.ldap.model.schema.parsers.AttributeTypeDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.DitContentRuleDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.DitStructureRuleDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapSyntaxDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleUseDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.NameFormDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.ObjectClassDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader;
+import org.apache.directory.api.ldap.model.schema.registries.DefaultSchema;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.ldap.client.api.exception.InvalidConnectionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A schema loader which uses LdapConnection to load schema from a ApacheDS serveur
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultSchemaLoader extends AbstractSchemaLoader
+{
+    private static final String DEFAULT_APACHEDS_VENDOR_NAME = "Apache Software Foundation";
+
+    /** the logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaLoader.class );
+
+    /** the connection to the ldap server */
+    private LdapConnection connection;
+
+    /** the subschemaSubentry DN */
+    private Dn subschemaSubentryDn;
+
+    /** The SubschemaSubentry descriptions parsers */
+    private static final AttributeTypeDescriptionSchemaParser AT_DESCR_SCHEMA_PARSER = new AttributeTypeDescriptionSchemaParser();
+    private static final DitStructureRuleDescriptionSchemaParser DSR_DESCR_SCHEMA_PARSER = new DitStructureRuleDescriptionSchemaParser();
+    private static final DitContentRuleDescriptionSchemaParser DCR_DESCR_SCHEMA_PARSER = new DitContentRuleDescriptionSchemaParser();
+    private static final MatchingRuleDescriptionSchemaParser MR_DESCR_SCHEMA_PARSER = new MatchingRuleDescriptionSchemaParser();
+    private static final MatchingRuleUseDescriptionSchemaParser MRU_DESCR_SCHEMA_PARSER = new MatchingRuleUseDescriptionSchemaParser();
+    private static final NameFormDescriptionSchemaParser NF_DESCR_SCHEMA_PARSER = new NameFormDescriptionSchemaParser();
+    private static final ObjectClassDescriptionSchemaParser OC_DESCR_SCHEMA_PARSER = new ObjectClassDescriptionSchemaParser();
+    private static final LdapSyntaxDescriptionSchemaParser LS_DESCR_SCHEMA_PARSER = new LdapSyntaxDescriptionSchemaParser();
+
+    private static final LdapComparatorDescriptionSchemaParser C_DESCR_SCHEMA_PARSER = new LdapComparatorDescriptionSchemaParser();
+    private static final NormalizerDescriptionSchemaParser N_DESCR_SCHEMA_PARSER = new NormalizerDescriptionSchemaParser();
+    private static final SyntaxCheckerDescriptionSchemaParser SC_DESCR_SCHEMA_PARSER = new SyntaxCheckerDescriptionSchemaParser();
+
+
+    /**
+     * Creates a new instance of DefaultSchemaLoader.
+     *
+     * @param connection the LDAP connection
+     * @throws Exception if the connection is not authenticated or if there are any problems
+     *                   while loading the schema entries
+     */
+    public DefaultSchemaLoader( LdapConnection connection ) throws LdapException
+    {
+        this( connection, false );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultSchemaLoader.
+     *
+     * @param connection the LDAP connection
+     * @param initial setting for the relaxed mode
+     * @throws Exception if the connection is not authenticated or if there are any problems
+     *                   while loading the schema entries
+     */
+    public DefaultSchemaLoader( LdapConnection connection, boolean relaxed ) throws LdapException
+    {
+        if ( connection == null )
+        {
+            throw new InvalidConnectionException( "Cannot connect on the server, the connection is null" );
+        }
+
+        this.connection = connection;
+        setRelaxed( relaxed );
+        setQuirksMode( relaxed );
+
+        // Flagging if the connection was already connected
+        boolean wasConnected = connection.isConnected();
+
+        try
+        {
+            // Connecting (if needed)
+            if ( !wasConnected )
+            {
+                connection.connect();
+            }
+
+            // Getting the subschemaSubentry DN from the rootDSE
+            Entry rootDse = connection.lookup( Dn.ROOT_DSE, SchemaConstants.SUBSCHEMA_SUBENTRY_AT,
+                SchemaConstants.VENDOR_NAME_AT );
+
+            if ( rootDse != null )
+            {
+                // Checking if this is an ApacheDS server
+                if ( isApacheDs( rootDse ) )
+                {
+                    // Getting the subSchemaSubEntry attribute
+                    Attribute subschemaSubentryAttribute = rootDse.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
+
+                    if ( ( subschemaSubentryAttribute != null ) && ( subschemaSubentryAttribute.size() > 0 ) )
+                    {
+                        subschemaSubentryDn = new Dn( connection.getSchemaManager(),
+                            subschemaSubentryAttribute.getString() );
+
+                        loadSchemas();
+                    }
+                }
+                else
+                {
+                    try
+                    {
+                        // No matter what, first try to search the schema from the rootDSE
+                        // Getting the subSchemaSubEntry attribute
+                        Attribute subschemaSubentryAttribute = rootDse.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
+
+                        if ( ( subschemaSubentryAttribute != null ) && ( subschemaSubentryAttribute.size() > 0 ) )
+                        {
+                            subschemaSubentryDn = new Dn( connection.getSchemaManager(),
+                                subschemaSubentryAttribute.getString() );
+
+                            loadSchemas();
+                        }
+                    }
+                    catch ( LdapException le )
+                    {
+                        // TODO : if we can't read the schema from the rootDSE, just try to read the 
+                        // schema from cn=schema
+                        throw le;
+                    }
+                }
+            }
+        }
+        finally
+        {
+            // Checking if the connection needs to be closed
+            if ( ( !wasConnected ) && ( connection.isConnected() ) )
+            {
+                try
+                {
+                    connection.close();
+                }
+                catch ( IOException e )
+                {
+                    throw new LdapException( e );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Indicates if the given Root DSE corresponds to an ApacheDS server.
+     *
+     * @param rootDse the Root DSE
+     * @return <code>true</code> if this is an ApacheDS server,
+     *         <code>false</code> if not.
+     * @throws LdapInvalidAttributeValueException
+     */
+    private boolean isApacheDs( Entry rootDse ) throws LdapInvalidAttributeValueException
+    {
+        if ( rootDse != null )
+        {
+            Attribute vendorNameAttribute = rootDse.get( SchemaConstants.VENDOR_NAME_AT );
+
+            if ( ( vendorNameAttribute != null ) && vendorNameAttribute.size() == 1 )
+            {
+                return DEFAULT_APACHEDS_VENDOR_NAME.equalsIgnoreCase( vendorNameAttribute.getString() );
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Creates a new instance of NetworkSchemaLoader.
+     *
+     * @param connection the LDAP connection
+     * @throws Exception if the connection is not authenticated or if there are any problems
+     *                   while loading the schema entries
+     */
+    public DefaultSchemaLoader( LdapConnection connection, Dn subschemaSubentryDn ) throws Exception
+    {
+        if ( !connection.isAuthenticated() )
+        {
+            throw new IllegalArgumentException( "connection is not authenticated" );
+        }
+
+        this.connection = connection;
+        this.subschemaSubentryDn = subschemaSubentryDn;
+
+        loadSchemas();
+    }
+
+
+    /**
+     * Load all the schemas.
+     * 
+     * @param subschemaSubentryDn
+     * @throws Exception
+     */
+    private void loadSchemas() throws LdapException
+    {
+        LOG.debug( "initializing schemas" );
+
+        // Load all the elements from the SubschemaSubentry
+        Entry subschemaSubentry = connection.lookup( subschemaSubentryDn,
+            SchemaConstants.ATTRIBUTE_TYPES_AT,
+            SchemaConstants.COMPARATORS_AT,
+            SchemaConstants.DIT_CONTENT_RULES_AT,
+            SchemaConstants.DIT_STRUCTURE_RULES_AT,
+            SchemaConstants.LDAP_SYNTAXES_AT,
+            SchemaConstants.MATCHING_RULES_AT,
+            SchemaConstants.MATCHING_RULE_USE_AT,
+            SchemaConstants.NAME_FORMS_AT,
+            SchemaConstants.NORMALIZERS_AT,
+            SchemaConstants.OBJECT_CLASSES_AT,
+            SchemaConstants.SYNTAX_CHECKERS_AT
+            );
+
+        // Load all the AT
+        Attribute attributeTypes = subschemaSubentry.get( SchemaConstants.ATTRIBUTE_TYPES_AT );
+        loadAttributeTypes( attributeTypes );
+
+        // Load all the C
+        Attribute comparators = subschemaSubentry.get( SchemaConstants.COMPARATORS_AT );
+        loadComparators( comparators );
+
+        // Load all the DCR
+        Attribute ditContentRules = subschemaSubentry.get( SchemaConstants.DIT_CONTENT_RULES_AT );
+        loadDitContentRules( ditContentRules );
+
+        // Load all the DSR
+        Attribute ditStructureRules = subschemaSubentry.get( SchemaConstants.DIT_STRUCTURE_RULES_AT );
+        loadDitStructureRules( ditStructureRules );
+
+        // Load all the LS
+        Attribute ldapSytaxes = subschemaSubentry.get( SchemaConstants.LDAP_SYNTAXES_AT );
+        loadLdapSyntaxes( ldapSytaxes );
+
+        // Load all the MR
+        Attribute matchingRules = subschemaSubentry.get( SchemaConstants.MATCHING_RULES_AT );
+        loadMatchingRules( matchingRules );
+
+        // Load all the MRU
+        Attribute matchingRuleUse = subschemaSubentry.get( SchemaConstants.MATCHING_RULE_USE_AT );
+        loadMatchingRuleUses( matchingRuleUse );
+
+        // Load all the N
+        Attribute normalizers = subschemaSubentry.get( SchemaConstants.NORMALIZERS_AT );
+        loadNormalizers( normalizers );
+
+        // Load all the NF
+        Attribute nameForms = subschemaSubentry.get( SchemaConstants.NAME_FORMS_AT );
+        loadNameForms( nameForms );
+
+        // Load all the OC
+        Attribute objectClasses = subschemaSubentry.get( SchemaConstants.OBJECT_CLASSES_AT );
+        loadObjectClasses( objectClasses );
+
+        // Load all the SC
+        Attribute syntaxCheckers = subschemaSubentry.get( SchemaConstants.SYNTAX_CHECKERS_AT );
+        loadSyntaxCheckers( syntaxCheckers );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadAttributeTypes( Attribute attributeTypes ) throws LdapException
+    {
+        if ( attributeTypes == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : attributeTypes )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                AttributeType attributeType = AT_DESCR_SCHEMA_PARSER.parseAttributeTypeDescription( desc );
+
+                updateSchemas( attributeType );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadComparators( Attribute comparators ) throws LdapException
+    {
+        if ( comparators == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : comparators )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                LdapComparatorDescription comparator = C_DESCR_SCHEMA_PARSER.parseComparatorDescription( desc );
+
+                updateSchemas( comparator );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadDitContentRules( Attribute ditContentRules ) throws LdapException
+    {
+        if ( ditContentRules == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : ditContentRules )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                DitContentRule ditContentRule = DCR_DESCR_SCHEMA_PARSER.parseDITContentRuleDescription( desc );
+
+                updateSchemas( ditContentRule );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadDitStructureRules( Attribute ditStructureRules ) throws LdapException
+    {
+        if ( ditStructureRules == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : ditStructureRules )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                DitStructureRule ditStructureRule = DSR_DESCR_SCHEMA_PARSER.parseDITStructureRuleDescription( desc );
+
+                updateSchemas( ditStructureRule );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadLdapSyntaxes( Attribute ldapSyntaxes ) throws LdapException
+    {
+        if ( ldapSyntaxes == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : ldapSyntaxes )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                LdapSyntax ldapSyntax = LS_DESCR_SCHEMA_PARSER.parseLdapSyntaxDescription( desc );
+
+                updateSchemas( ldapSyntax );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadMatchingRules( Attribute matchingRules ) throws LdapException
+    {
+        if ( matchingRules == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : matchingRules )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                MatchingRule matchingRule = MR_DESCR_SCHEMA_PARSER.parseMatchingRuleDescription( desc );
+
+                updateSchemas( matchingRule );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadMatchingRuleUses( Attribute matchingRuleUses ) throws LdapException
+    {
+        if ( matchingRuleUses == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : matchingRuleUses )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                MatchingRuleUse matchingRuleUse = MRU_DESCR_SCHEMA_PARSER.parseMatchingRuleUseDescription( desc );
+
+                updateSchemas( matchingRuleUse );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadNameForms( Attribute nameForms ) throws LdapException
+    {
+        if ( nameForms == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : nameForms )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                NameForm nameForm = NF_DESCR_SCHEMA_PARSER.parseNameFormDescription( desc );
+
+                updateSchemas( nameForm );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadNormalizers( Attribute normalizers ) throws LdapException
+    {
+        if ( normalizers == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : normalizers )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                NormalizerDescription normalizer = N_DESCR_SCHEMA_PARSER.parseNormalizerDescription( desc );
+
+                updateSchemas( normalizer );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadObjectClasses( Attribute objectClasses ) throws LdapException
+    {
+        if ( objectClasses == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : objectClasses )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                ObjectClass objectClass = OC_DESCR_SCHEMA_PARSER.parseObjectClassDescription( desc );
+
+                updateSchemas( objectClass );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void loadSyntaxCheckers( Attribute syntaxCheckers ) throws LdapException
+    {
+        if ( syntaxCheckers == null )
+        {
+            return;
+        }
+
+        for ( Value<?> value : syntaxCheckers )
+        {
+            String desc = value.getString();
+
+            try
+            {
+                SyntaxCheckerDescription syntaxChecker = SC_DESCR_SCHEMA_PARSER.parseSyntaxCheckerDescription( desc );
+
+                updateSchemas( syntaxChecker );
+            }
+            catch ( ParseException pe )
+            {
+                throw new LdapException( pe );
+            }
+        }
+    }
+
+
+    private void updateSchemas( SchemaObject schemaObject )
+    {
+        String schemaName = schemaObject.getSchemaName();
+        Schema schema = null;
+
+        if ( Strings.isEmpty( schemaName ) || Strings.equals( "null", schemaName ) )
+        {
+            schemaName = "default";
+            schema = schemaMap.get( schemaName );
+        }
+        else
+        {
+            schema = schemaMap.get( schemaName );
+        }
+
+        if ( schema == null )
+        {
+            schema = new DefaultSchema( schemaName );
+
+            schemaMap.put( schemaName, schema );
+        }
+
+        schema.getContent().add( new SchemaObjectWrapper( schemaObject ) );
+
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> attributeTypeEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return attributeTypeEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof AttributeType )
+                {
+                    AttributeType attributeType = ( AttributeType ) schemaObject;
+
+                    Entry attributeTypeEntry = factory.convert( attributeType, schema, null );
+
+                    attributeTypeEntries.add( attributeTypeEntry );
+                }
+            }
+        }
+
+        return attributeTypeEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> comparatorEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return comparatorEntries;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof LdapComparatorDescription )
+                {
+                    LdapComparatorDescription ldapComparatorDescription = ( LdapComparatorDescription ) schemaObject;
+                    Entry lcEntry = getEntry( ldapComparatorDescription );
+
+                    comparatorEntries.add( lcEntry );
+                }
+            }
+        }
+
+        return comparatorEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> ditContentRuleEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return ditContentRuleEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof DitContentRule )
+                {
+                    DitContentRule ditContentRule = ( DitContentRule ) schemaObject;
+
+                    Entry ditContentRuleEntry = factory.convert( ditContentRule, schema, null );
+
+                    ditContentRuleEntries.add( ditContentRuleEntry );
+                }
+            }
+        }
+
+        return ditContentRuleEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> ditStructureRuleEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return ditStructureRuleEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof DitStructureRule )
+                {
+                    DitStructureRule ditStructureRule = ( DitStructureRule ) schemaObject;
+
+                    Entry ditStructureRuleEntry = factory.convert( ditStructureRule, schema, null );
+
+                    ditStructureRuleEntries.add( ditStructureRuleEntry );
+                }
+            }
+        }
+
+        return ditStructureRuleEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> matchingRuleUseEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return matchingRuleUseEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof MatchingRuleUse )
+                {
+                    MatchingRuleUse matchingRuleUse = ( MatchingRuleUse ) schemaObject;
+
+                    Entry matchingRuleUseEntry = factory.convert( matchingRuleUse, schema, null );
+
+                    matchingRuleUseEntries.add( matchingRuleUseEntry );
+                }
+            }
+        }
+
+        return matchingRuleUseEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> matchingRuleEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return matchingRuleEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof MatchingRule )
+                {
+                    MatchingRule matchingRule = ( MatchingRule ) schemaObject;
+
+                    Entry matchingRuleEntry = factory.convert( matchingRule, schema, null );
+
+                    matchingRuleEntries.add( matchingRuleEntry );
+                }
+            }
+        }
+
+        return matchingRuleEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> nameFormEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return nameFormEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof NameForm )
+                {
+                    NameForm nameForm = ( NameForm ) schemaObject;
+
+                    Entry nameFormEntry = factory.convert( nameForm, schema, null );
+
+                    nameFormEntries.add( nameFormEntry );
+                }
+            }
+        }
+
+        return nameFormEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> normalizerEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return normalizerEntries;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof NormalizerDescription )
+                {
+                    NormalizerDescription normalizerDescription = ( NormalizerDescription ) schemaObject;
+                    Entry normalizerEntry = getEntry( normalizerDescription );
+
+                    normalizerEntries.add( normalizerEntry );
+                }
+            }
+        }
+
+        return normalizerEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> objectClassEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return objectClassEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof ObjectClass )
+                {
+                    ObjectClass objectClass = ( ObjectClass ) schemaObject;
+
+                    Entry objectClassEntry = factory.convert( objectClass, schema, null );
+
+                    objectClassEntries.add( objectClassEntry );
+                }
+            }
+        }
+
+        return objectClassEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> syntaxCheckerEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return syntaxCheckerEntries;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof SyntaxCheckerDescription )
+                {
+                    SyntaxCheckerDescription syntaxCheckerDescription = ( SyntaxCheckerDescription ) schemaObject;
+                    Entry syntaxCheckerEntry = getEntry( syntaxCheckerDescription );
+
+                    syntaxCheckerEntries.add( syntaxCheckerEntry );
+                }
+            }
+        }
+
+        return syntaxCheckerEntries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> syntaxEntries = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return syntaxEntries;
+        }
+
+        AttributesFactory factory = new AttributesFactory();
+
+        for ( Schema schema : schemas )
+        {
+            Set<SchemaObjectWrapper> schemaObjectWrappers = schema.getContent();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjectWrappers )
+            {
+                SchemaObject schemaObject = schemaObjectWrapper.get();
+
+                if ( schemaObject instanceof LdapSyntax )
+                {
+                    LdapSyntax ldapSyntax = ( LdapSyntax ) schemaObject;
+
+                    Entry ldapSyntaxEntry = factory.convert( ldapSyntax, schema, null );
+
+                    syntaxEntries.add( ldapSyntaxEntry );
+                }
+            }
+        }
+
+        return syntaxEntries;
+    }
+
+
+    private Entry getEntry( LdapComparatorDescription comparatorDescription )
+    {
+        Entry entry = new DefaultEntry();
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT,
+            SchemaConstants.TOP_OC,
+            MetaSchemaConstants.META_TOP_OC,
+            MetaSchemaConstants.META_COMPARATOR_OC );
+
+        entry.put( MetaSchemaConstants.M_OID_AT, comparatorDescription.getOid() );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, comparatorDescription.getFqcn() );
+
+        if ( comparatorDescription.getBytecode() != null )
+        {
+            entry.put( MetaSchemaConstants.M_BYTECODE_AT,
+                Base64.decode( comparatorDescription.getBytecode().toCharArray() ) );
+        }
+
+        if ( comparatorDescription.getDescription() != null )
+        {
+            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, comparatorDescription.getDescription() );
+        }
+
+        return entry;
+    }
+
+
+    private Entry getEntry( SyntaxCheckerDescription syntaxCheckerDescription )
+    {
+        Entry entry = new DefaultEntry();
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT,
+            SchemaConstants.TOP_OC,
+            MetaSchemaConstants.META_TOP_OC,
+            MetaSchemaConstants.META_SYNTAX_CHECKER_OC );
+
+        entry.put( MetaSchemaConstants.M_OID_AT, syntaxCheckerDescription.getOid() );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, syntaxCheckerDescription.getFqcn() );
+
+        if ( syntaxCheckerDescription.getBytecode() != null )
+        {
+            entry.put( MetaSchemaConstants.M_BYTECODE_AT,
+                Base64.decode( syntaxCheckerDescription.getBytecode().toCharArray() ) );
+        }
+
+        if ( syntaxCheckerDescription.getDescription() != null )
+        {
+            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, syntaxCheckerDescription.getDescription() );
+        }
+
+        return entry;
+    }
+
+
+    private Entry getEntry( NormalizerDescription normalizerDescription )
+    {
+        Entry entry = new DefaultEntry();
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT,
+            SchemaConstants.TOP_OC,
+            MetaSchemaConstants.META_TOP_OC,
+            MetaSchemaConstants.META_NORMALIZER_OC );
+
+        entry.put( MetaSchemaConstants.M_OID_AT, normalizerDescription.getOid() );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, normalizerDescription.getFqcn() );
+
+        if ( normalizerDescription.getBytecode() != null )
+        {
+            entry.put( MetaSchemaConstants.M_BYTECODE_AT,
+                Base64.decode( normalizerDescription.getBytecode().toCharArray() ) );
+        }
+
+        if ( normalizerDescription.getDescription() != null )
+        {
+            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, normalizerDescription.getDescription() );
+        }
+
+        return entry;
+    }
+
+
+    /**
+     * Sets the quirks mode for all the internal parsers.
+     *
+     * If enabled the parser accepts non-numeric OIDs and some
+     * special characters in descriptions.
+     *
+     * @param enabled the new quirks mode
+     */
+    public void setQuirksMode( boolean enabled )
+    {
+        AT_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        C_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        DCR_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        DSR_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        LS_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        MR_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        MRU_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        N_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        NF_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        OC_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+        SC_DESCR_SCHEMA_PARSER.setQuirksMode( enabled );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/EntryCursorImpl.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/EntryCursorImpl.java
new file mode 100644
index 0000000..3635ea2
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/EntryCursorImpl.java
@@ -0,0 +1,309 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
+import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapReferralException;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An implementation of Cursor based on the underlying SearchFuture instance.
+ * 
+ * Note: This is a forward only cursor hence the only valid operations are next(), get() and close() 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EntryCursorImpl extends AbstractCursor<Entry> implements EntryCursor
+{
+    /** A dedicated log for cursors */
+    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
+
+    /** a reference to hold the retrieved SearchResponse object from SearchFuture */
+    private Response response;
+
+    /** The encapsulated search cursor */
+    private SearchCursor searchCursor;
+
+    /** The underlying messageId */
+    private int messageId;
+
+
+    /**
+     * Instantiates a new search cursor, embedding a SearchCursor.
+     *
+     * @param searchCursor the embedded SearchResponse cursor
+     */
+    public EntryCursorImpl( SearchCursor searchCursor )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Creating EntryCursorImpl {}", this );
+        }
+
+        this.searchCursor = searchCursor;
+        messageId = -1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean next() throws LdapException, CursorException
+    {
+        if ( !searchCursor.next() )
+        {
+            return false;
+        }
+
+        try
+        {
+
+            do
+            {
+                response = searchCursor.get();
+
+                if ( response == null )
+                {
+                    throw new LdapException( LdapNetworkConnection.TIME_OUT_ERROR );
+                }
+
+                messageId = response.getMessageId();
+
+                if ( response instanceof SearchResultEntry )
+                {
+                    return true;
+                }
+
+                if ( response instanceof SearchResultReference )
+                {
+                    return true;
+                }
+            }
+            while ( !( response instanceof SearchResultDone ) );
+
+            return false;
+        }
+        catch ( Exception e )
+        {
+            LdapException ldapException = new LdapException( LdapNetworkConnection.NO_RESPONSE_ERROR );
+            ldapException.initCause( e );
+
+            // close the cursor
+            close( ldapException );
+
+            throw ldapException;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry get() throws CursorException
+    {
+        if ( !searchCursor.available() )
+        {
+            throw new InvalidCursorPositionException();
+        }
+
+        try
+        {
+            do
+            {
+                if ( response instanceof SearchResultEntry )
+                {
+                    return ( ( SearchResultEntry ) response ).getEntry();
+                }
+
+                if ( response instanceof SearchResultReference )
+                {
+                    throw new LdapReferralException( ( ( SearchResultReference ) response ).getReferral().getLdapUrls() );
+                }
+            }
+            while ( next() && !( response instanceof SearchResultDone ) );
+        }
+        catch ( LdapReferralException lre )
+        {
+            throw new CursorLdapReferralException( lre );
+        }
+        catch ( Exception e )
+        {
+            throw new CursorException( e );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchResultDone getSearchResultDone()
+    {
+        return searchCursor.getSearchResultDone();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean available()
+    {
+        return searchCursor.available();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close()
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing EntryCursorImpl {}", this );
+        }
+
+        searchCursor.close();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close( Exception cause )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing EntryCursorImpl {}", this );
+        }
+
+        searchCursor.close( cause );
+    }
+
+
+    // rest of all operations will throw UnsupportedOperationException
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void after( Entry element ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "after( Response element )" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void afterLast() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "afterLast()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void before( Entry element ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "before( Response element )" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void beforeFirst() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "beforeFirst()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public boolean first() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "first()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public boolean last() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "last()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public boolean previous() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "previous()" ) ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getMessageId()
+    {
+        return messageId;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/Krb5LoginConfiguration.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/Krb5LoginConfiguration.java
new file mode 100644
index 0000000..5cf50bd
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/Krb5LoginConfiguration.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import java.util.HashMap;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+import javax.security.auth.login.Configuration;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Krb5LoginConfiguration extends Configuration
+{
+
+    /** The list with configuration entries. */
+    private static AppConfigurationEntry[] configList = new AppConfigurationEntry[1];
+
+
+    /**
+     * Creates a new instance of Krb5LoginConfiguration.
+     */
+    public Krb5LoginConfiguration()
+    {
+        String loginModule = "com.sun.security.auth.module.Krb5LoginModule";
+
+        HashMap<String, Object> options = new HashMap<String, Object>();
+
+        // TODO: this only works for Sun JVM
+        options.put( "refreshKrb5Config", "true" );
+
+        LoginModuleControlFlag flag = LoginModuleControlFlag.REQUIRED;
+        configList[0] = new AppConfigurationEntry( loginModule, flag, options );
+    }
+
+
+    /**
+     * Interface method requiring us to return all the LoginModules we know about.
+     *
+     * @param applicationName the application name
+     * @return the configuration entry
+     */
+    public AppConfigurationEntry[] getAppConfigurationEntry( String applicationName )
+    {
+        // We will ignore the applicationName, since we want all apps to use Kerberos V5
+        return configList;
+    }
+
+
+    /**
+     * Interface method for reloading the configuration.  We don't need this.
+     */
+    public void refresh()
+    {
+        // Right now this is a load once scheme and we will not implement the refresh method
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapAsyncConnection.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapAsyncConnection.java
new file mode 100644
index 0000000..f621389
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapAsyncConnection.java
@@ -0,0 +1,256 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.ldap.client.api.future.AddFuture;
+import org.apache.directory.ldap.client.api.future.BindFuture;
+import org.apache.directory.ldap.client.api.future.CompareFuture;
+import org.apache.directory.ldap.client.api.future.DeleteFuture;
+import org.apache.directory.ldap.client.api.future.ExtendedFuture;
+import org.apache.directory.ldap.client.api.future.ModifyDnFuture;
+import org.apache.directory.ldap.client.api.future.ModifyFuture;
+import org.apache.directory.ldap.client.api.future.SearchFuture;
+
+
+/**
+ * Root interface for all asynchronous LDAP connections.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface LdapAsyncConnection extends LdapConnection
+{
+
+    /**
+     * Add an entry to the server asynchronously. This is a non blocking add :
+     * the user has to get for the response from the returned Future.
+     * 
+     * @param entry The entry to add
+     * @return the add operation's future
+     * @throws LdapException if some error occurred
+     */
+    AddFuture addAsync( Entry entry ) throws LdapException;
+
+
+    /**
+     * Add an entry present in the AddRequest to the server.
+     * 
+     * @param addRequest the request object containing an entry and controls(if any)
+     * @return the add operation's future
+     * @throws LdapException if some error occurred
+     */
+    AddFuture addAsync( AddRequest addRequest ) throws LdapException;
+
+
+    /**
+     * Asynchronous Bind on a server, using the LdapConnectionConfig informations.
+     *
+     * @return the bind operation's future
+     * @throws LdapException if some error occurred
+     * @throws IOException if some IO error occurred
+     */
+    BindFuture bindAsync() throws LdapException, IOException;
+
+
+    /**
+     * Anonymous asynchronous Bind on a server.
+     *
+     * @return the bind operation's future
+     * @throws LdapException if some error occurred
+     * @throws IOException if some IO error occurred
+     */
+    BindFuture anonymousBindAsync() throws LdapException, IOException;
+
+
+    /**
+     * Simple asynchronous Bind on a server.
+     *
+     * @param name The name we use to authenticate the user, it must be a valid Dn
+     * @param credentials The password, it can't be null
+     * @return the bind operation's future
+     * @throws LdapException if some error occurred
+     * @throws IOException if some IO error occurred
+     */
+    BindFuture bindAsync( String name, String credentials ) throws LdapException, IOException;
+
+
+    /**
+     * Simple asynchronous Bind on a server.
+     *
+     * @param name The name we use to authenticate the user, it must be a valid Dn
+     * @param credentials The password, it can't be null
+     * @return the bind operation's future
+     * @throws LdapException if some error occurred
+     * @throws IOException if some IO error occurred
+     */
+    BindFuture bindAsync( Dn name, String credentials ) throws LdapException, IOException;
+
+
+    /**
+     * Do an asynchronous bind, based on a BindRequest.
+     *
+     * @param bindRequest The BindRequest to send
+     * @return the bind operation's future
+     * @throws LdapException if some error occurred
+     * @throws IOException if some IO error occurred
+     */
+    BindFuture bindAsync( BindRequest bindRequest ) throws LdapException, IOException;
+
+
+    /**
+     * Do an asynchronous search, on the base object, using the given filter. The
+     * SearchRequest parameters default to :
+     * <pre>
+     * Scope : ONE
+     * DerefAlias : ALWAYS
+     * SizeLimit : none
+     * TimeLimit : none
+     * TypesOnly : false
+     * Attributes : all the user's attributes.
+     * This method is blocking.
+     * </pre>
+     * 
+     * @param baseDn The base for the search, it must be a valid Dn, and can't be emtpy
+     * @param filter The filter to use for this search, it can't be empty
+     * @param scope The search scope : OBJECT, ONELEVEL or SUBTREE
+     * @param attributes The attributes for this search
+     * @return the search operation's future
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if some error occurred
+     */
+    SearchFuture searchAsync( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException;
+
+
+    /**
+     * Do an asynchronous search, on the base object, using the given filter. The
+     * SearchRequest parameters default to :
+     * <pre>
+     * Scope : ONE
+     * DerefAlias : ALWAYS
+     * SizeLimit : none
+     * TimeLimit : none
+     * TypesOnly : false
+     * Attributes : all the user's attributes.
+     * This method is blocking.
+     * </pre>
+     * 
+     * @param baseDn The base for the search, it must be a valid Dn, and can't be empty
+     * @param filter The filter to use for this search, it can't be empty
+     * @param scope The search scope : OBJECT, ONELEVEL or SUBTREE
+     * @param attributes The attributes for this search
+     * @return the search operation's future
+     * @throws LdapException if some error occurred
+     */
+    SearchFuture searchAsync( Dn baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException;
+
+
+    /**
+     * Do a search, on the base object, using the given filter. The
+     * SearchRequest parameters default to :
+     * <pre>
+     * Scope : ONE
+     * DerefAlias : ALWAYS
+     * SizeLimit : none
+     * TimeLimit : none
+     * TypesOnly : false
+     * Attributes : all the user's attributes.
+     * This method is blocking.
+     * </pre>
+     * 
+     * @param searchRequest The search request to send to the server
+     * @return the search operation's future
+     * @throws LdapException if some error occurred
+     */
+    SearchFuture searchAsync( SearchRequest searchRequest ) throws LdapException;
+
+
+    /**
+     * Performs an asynchronous modify operation based on the modifications present in
+     * the ModifyRequest.
+     *
+     * @param modRequest the request for modify operation
+     * @return the modify operation's future
+     * @throws LdapException in case of modify operation failure or timeout happens
+     */
+    ModifyFuture modifyAsync( ModifyRequest modRequest ) throws LdapException;
+
+
+    /**
+     * Performs the modifyDn operation based on the given ModifyDnRequest.
+     *
+     * @param modDnRequest the request
+     * @return modifyDn operation's future
+     * @throws LdapException if some error occurred
+     */
+    ModifyDnFuture modifyDnAsync( ModifyDnRequest modDnRequest ) throws LdapException;
+
+
+    /**
+     * Performs an asynchronous delete operation based on the delete request object.
+     * 
+     * @param delRequest the delete operation's request
+     * @return delete operation's future
+     * @throws LdapException If the Dn is not valid or if the deletion failed
+     */
+    DeleteFuture deleteAsync( DeleteRequest delRequest ) throws LdapException;
+
+
+    /**
+     * Asynchronously compares an entry's attribute's value with that of the given value
+     * 
+     * @param compareRequest the CompareRequest which contains the target Dn, attribute name and value
+     * @return compare operation's future
+     * @throws LdapException if some error occurred
+     */
+    CompareFuture compareAsync( CompareRequest compareRequest ) throws LdapException;
+
+
+    /**
+     * Asynchronously requests the server to perform an extended operation based on the given request.
+     *
+     * @param extendedRequest the object containing the details of the extended operation to be performed
+     * @return extended operation's Future
+     * @throws LdapException if some error occurred
+     */
+    ExtendedFuture extendedAsync( ExtendedRequest extendedRequest ) throws LdapException;
+
+
+    /**
+     * Configuration of LdapNetworkConnection
+     * 
+     * @return the configuration of the LDAP connection
+     */
+    LdapConnectionConfig getConfig();
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnection.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnection.java
new file mode 100644
index 0000000..f0b66ee
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnection.java
@@ -0,0 +1,844 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.codec.api.BinaryAttributeDetector;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+// TODO: all the SASL bind methods are not declared in this interface, but implemented in LdapNetworkConnection. Is that intended?
+// TODO: why does connect() return a boolean? What is the difference between false and an Exception?
+// TODO: think about usage of abbrevisions (Dn/Rdn) vs. spelled out (relative distinguished name) in javadoc
+// TODO: describe better which type of LdapException are thrown in which case?
+// TODO: remove the "we" language in javadoc
+// TODO: does method getCodecService() belong into the interface? It returns a LdapApiService, should it be renamed?
+// TODO: does method doesFutureExistFor() belong into the interface? Move to LdapAsyncConnection?
+
+/**
+ * The root interface for all the LDAP connection implementations. All operations defined in this interface are blocking (synchronous).
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface LdapConnection extends Closeable
+{
+    /**
+     * Check if we are connected.
+     *
+     * @return <code>true</code> if we are connected.
+     */
+    boolean isConnected();
+
+
+    /**
+     * Check if we are authenticated.
+     *
+     * @return <code>true</code> if we are connected.
+     */
+    boolean isAuthenticated();
+
+
+    /**
+     * Connect to the remote LDAP server.
+     *
+     * @return <code>true</code> if the connection is established, false otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean connect() throws LdapException;
+
+
+    /**
+     * Disconnect from the remote LDAP server.
+     *
+     * @throws IOException if some I/O error occurs
+     */
+    void close() throws IOException;
+
+
+    //------------------------ The LDAP operations ------------------------//
+    // Add operations                                                      //
+    //---------------------------------------------------------------------//
+    /**
+     * Add an entry to the server.
+     *
+     * @param entry The entry to add
+     * @throws LdapException if some error occurred
+     */
+    void add( Entry entry ) throws LdapException;
+
+
+    /**
+     * Add an entry present in the {@link AddRequest} to the server.
+     *
+     * @param addRequest the request object containing an entry and controls (if any)
+     * @return the add operation's response
+     * @throws LdapException if some error occurred
+     */
+    AddResponse add( AddRequest addRequest ) throws LdapException;
+
+
+    /**
+     * Abandons a request submitted to the server for performing a particular operation.
+     *
+     * The abandonRequest is always non-blocking, because no response is expected
+     *
+     * @param messageId the ID of the request message sent to the server
+     */
+    void abandon( int messageId );
+
+
+    /**
+     * An abandon request essentially with the request message ID of the operation to be canceled
+     * and/or potentially some controls and timeout (the controls and timeout are not mandatory).
+     *
+     * The abandonRequest is always non-blocking, because no response is expected.
+     *
+     * @param abandonRequest the abandon operation's request
+     */
+    void abandon( AbandonRequest abandonRequest );
+
+
+    /**
+     * Bind on a server, using the {@link LdapConnectionConfig} information of this connection.
+     *
+     * @throws LdapException if some error occurred
+     * @throws IOException if an I/O exception occurred
+     */
+    void bind() throws LdapException;
+
+
+    /**
+     * Anonymous bind on a server.
+     *
+     * @throws LdapException if some error occurred
+     */
+    void anonymousBind() throws LdapException;
+
+
+    /**
+     * Unauthenticated authentication bind on a server.
+     *
+     * @param name The name we use to authenticate the user. It must be a
+     * valid {@link Dn}
+     * @throws LdapException if some error occurred
+     */
+    void bind( String name ) throws LdapException;
+
+
+    /**
+     * Simple bind on a server.
+     *
+     * @param name The name we use to authenticate the user. It must be a
+     * valid {@link Dn}
+     * @param credentials The password, it can't be <code>null</code>
+     * @throws LdapException if some error occurred
+     */
+    void bind( String name, String credentials ) throws LdapException;
+
+
+    /**
+     * SASL PLAIN Bind on a server.
+     *
+     * @param authcid The Authentication identity
+     * @param credentials The password, it can't be null
+     * @return The BindResponse LdapResponse
+     * @throws LdapException if some error occurred
+     */
+    // Not yet available on the CoreConnection
+    //BindResponse bindSaslPlain( String authcid, String credentials ) throws LdapException;
+
+    /**
+     * SASL PLAIN Bind on a server.
+     *
+     * @param authzid The Authorization identity
+     * @param authcid The Authentication identity
+     * @param credentials The password. It can't be null
+     * @return The BindResponse LdapResponse
+     * @throws LdapException if some error occurred
+     */
+    // Not yet available on the CoreConnection
+    //BindResponse bindSaslPlain( String authzid, String authcid, String credentials ) throws LdapException;
+
+    /**
+     * Unauthenticated authentication bind on a server.
+     *
+     * @param name The name we use to authenticate the user.
+     * @throws LdapException if some error occurred
+     */
+    void bind( Dn name ) throws LdapException;
+
+
+    /**
+     * Simple bind on a server.
+     *
+     * @param name The name we use to authenticate the user.
+     * @param credentials The password, it can't be null
+     * @throws LdapException if some error occurred
+     */
+    void bind( Dn name, String credentials ) throws LdapException;
+
+
+    /**
+     * Bind to the server using a bind request object.
+     *
+     * @param bindRequest The bind request object containing all the needed parameters
+     * @return A {@link BindResponse} containing the result
+     * @throws LdapException if some error occurred
+     */
+    BindResponse bind( BindRequest bindRequest ) throws LdapException;
+
+
+    /**
+     * Do a search, on the base object, using the given filter and scope. The
+     * SearchRequest parameters default to
+     * <ul>
+     * <li> DerefAlias : ALWAYS
+     * <li> SizeLimit : none
+     * <li> TimeLimit : none
+     * <li> TypesOnly : false
+     * </ul>
+     * 
+     * @param baseDn The base for the search. It must be a valid distinguished name and can't be emtpy
+     * @param filter The filter to use for this search. It can't be empty
+     * @param scope The search scope : OBJECT, ONELEVEL or SUBTREE
+     * @param attributes The attributes to use for this search
+     * @return An {@link EntryCursor} on the result.
+     * @throws LdapException if some error occurred
+     */
+    EntryCursor search( Dn baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException;
+
+
+    /**
+     * Do a search, on the base object, using the given filter and scope. The
+     * SearchRequest parameters default to
+     * <ul>
+     * <li> DerefAlias : ALWAYS
+     * <li> SizeLimit : none
+     * <li> TimeLimit : none
+     * <li> TypesOnly : false
+     * </ul>
+     *
+     * @param baseDn The base for the search. It must be a valid distinguished name, and can't be emtpy
+     * @param filter The filter to use for this search. It can't be empty
+     * @param scope The search scope : OBJECT, ONELEVEL or SUBTREE
+     * @param attributes The attributes to use for this search
+     * @return An {@link EntryCursor} on the result.
+     * @throws LdapException if some error occurred
+     */
+    EntryCursor search( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException;
+
+
+    /**
+     * Performs search using a search request object.
+     *
+     * @param searchRequest The search request object containing all the needed information
+     * @return a search cursor on the result.
+     * @throws LdapException if some error occurred
+     */
+    SearchCursor search( SearchRequest searchRequest ) throws LdapException;
+
+
+    //------------------------ The LDAP operations ------------------------//
+    // Unbind operations                                                   //
+    //---------------------------------------------------------------------//
+    /**
+     * UnBind from a server. This is a request which expects no response.
+     * 
+     * @throws LdapException if some error occurred
+     */
+    void unBind() throws LdapException;
+
+
+    /**
+     * Set the timeout for the responses. We won't wait longer than this
+     * value.
+     *
+     * @param timeOut The timeout, in milliseconds
+     */
+    void setTimeOut( long timeOut );
+
+
+    /**
+     * Applies all the modifications to the entry specified by its distinguished name.
+     *
+     * @param dn The entry's distinguished name
+     * @param modifications The list of modifications to be applied
+     * @throws LdapException in case of modify operation failure or timeout happens
+     */
+    void modify( Dn dn, Modification... modifications ) throws LdapException;
+
+
+    /**
+     * Applies all the modifications to the entry specified by its distinguished name.
+     *
+     * @param dn The entry's distinguished name, it must be a valid {@link Dn}
+     * @param modifications The list of modifications to be applied
+     * @return the modify operation's response
+     * @throws LdapException in case of modify operation failure or timeout happens
+     */
+    void modify( String dn, Modification... modifications ) throws LdapException;
+
+
+    /**
+     * Modifies all the attributes present in the entry by applying the same operation.
+     *
+     * @param entry the entry with the attributes to be modified
+     * @param modOp the operation to be applied on all the attributes of the above entry
+     * @return the modify operation's response
+     * @throws LdapException in case of modify operation failure or timeout happens
+     */
+    void modify( Entry entry, ModificationOperation modOp ) throws LdapException;
+
+
+    /**
+     * Performs an modify operation based on the modifications present in
+     * the modify request.
+     *
+     * @param modRequest the modify request object
+     * @return the modify operation's response
+     * @throws LdapException in case of modify operation failure or timeout happens
+     */
+    ModifyResponse modify( ModifyRequest modRequest ) throws LdapException;
+
+
+    /**
+     * Renames the given entryDn with new Rdn and deletes the old Rdn.
+     *
+     * @param entryDn the target Dn
+     * @param newRdn new Rdn for the target Dn
+     * @throws LdapException if some error occurred
+     * @see #rename(String, String, boolean)
+     */
+    void rename( String entryDn, String newRdn ) throws LdapException;
+
+
+    /**
+     * Renames the given entryDn with new Rdn and deletes the old Rdn.
+     *
+     * @param entryDn the target Dn
+     * @param newRdn new Rdn for the target Dn
+     * @throws LdapException if some error occurred
+     * @see #rename(Dn, Rdn, boolean)
+     */
+    void rename( Dn entryDn, Rdn newRdn ) throws LdapException;
+
+
+    /**
+     * Renames the given entryDn with new Rdn and deletes the old Rdn if
+     * deleteOldRdn is set to true.
+     *
+     * @param entryDn the target Dn
+     * @param newRdn new Rdn for the target Dn
+     * @param deleteOldRdn flag to indicate whether to delete the old Rdn
+     * @throws LdapException if some error occurred
+     * @see #rename(Dn, Rdn, boolean)
+     */
+    void rename( String entryDn, String newRdn, boolean deleteOldRdn ) throws LdapException;
+
+
+    /**
+     * Renames the given entryDn with new Rdn and deletes the old Rdn if
+     * deleteOldRdn is set to true.
+     *
+     * @param entryDn the target Dn
+     * @param newRdn new Rdn for the target Dn
+     * @param deleteOldRdn flag to indicate whether to delete the old Rdn
+     * @return modifyDn operation's response
+     * @throws LdapException if some error occurred
+     */
+    void rename( Dn entryDn, Rdn newRdn, boolean deleteOldRdn ) throws LdapException;
+
+
+    /**
+     * Moves the given entry Dn under the new superior Dn.
+     *
+     * @param entryDn the Dn of the target entry
+     * @param newSuperiorDn Dn of the new parent/superior
+     * @throws LdapException if some error occurred
+     * @see #move(Dn, Dn)
+     */
+    void move( String entryDn, String newSuperiorDn ) throws LdapException;
+
+
+    /**
+     * Moves the given entry Dn under the new superior Dn.
+     *
+     * @param entryDn the Dn of the target entry
+     * @param newSuperiorDn Dn of the new parent/superior
+     * @throws LdapException if some error occurred
+     */
+    void move( Dn entryDn, Dn newSuperiorDn ) throws LdapException;
+
+
+    /**
+     * Moves and renames the given entryDn. The old Rdn will be deleted.
+     *
+     * @param entryDn The original entry Dn
+     * @param newDn The new entry Dn
+     * @throws LdapException if some error occurred
+     * @see #moveAndRename(Dn, Dn, boolean)
+     */
+    void moveAndRename( Dn entryDn, Dn newDn ) throws LdapException;
+
+
+    /**
+     * Moves and renames the given entryDn.The old Rdn will be deleted
+     *
+     * @param entryDn The original entry Dn
+     * @param newDn The new entry Dn
+     * @throws LdapException if some error occurred
+     * @see #moveAndRename(Dn, Dn, boolean)
+     */
+    void moveAndRename( String entryDn, String newDn ) throws LdapException;
+
+
+    /**
+     * Moves and renames the given entryDn. The old Rdn will be deleted if requested.
+     *
+     * @param entryDn The original entry Dn
+     * @param newDn The new entry Dn
+     * @param deleteOldRdn Tells if the old Rdn must be removed
+     * @throws LdapException if some error occurred
+     */
+    void moveAndRename( Dn entryDn, Dn newDn, boolean deleteOldRdn ) throws LdapException;
+
+
+    /**
+     * Moves and renames the given entryDn. The old Rdn will be deleted if requested.
+     *
+     * @param entryDn The original entry Dn
+     * @param newDn The new entry Dn
+     * @param deleteOldRdn Tells if the old Rdn must be removed
+     * @throws LdapException if some error occurred
+     */
+    void moveAndRename( String entryDn, String newDn, boolean deleteOldRdn )
+        throws LdapException;
+
+
+    /**
+     * Performs the modifyDn operation based on the given request object.
+     *
+     * @param modDnRequest the request object
+     * @return modifyDn operation's response
+     * @throws LdapException if some error occurred
+     */
+    ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest ) throws LdapException;
+
+
+    /**
+     * Deletes the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name, it must be a valid {@link Dn}
+     * @throws LdapException If the Dn is not valid or if the deletion failed
+     */
+    void delete( String dn ) throws LdapException;
+
+
+    /**
+     * Deletes the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name
+     * @throws LdapException If the Dn is not valid or if the deletion failed
+     */
+    void delete( Dn dn ) throws LdapException;
+
+
+    /**
+     * Performs a delete operation based on the delete request object.
+     *
+     * @param deleteRequest the delete operation's request
+     * @return delete operation's response
+     * @throws LdapException If the Dn is not valid or if the deletion failed
+     */
+    DeleteResponse delete( DeleteRequest deleteRequest ) throws LdapException;
+
+
+    /**
+     * Compares whether a given attribute's value matches that of the
+     * existing value of the attribute present in the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name, it must be a valid {@link Dn}
+     * @param attributeName the attribute's name
+     * @param value a String value with which the target entry's attribute value to be compared with
+     * @return <code>true</code> if the value matches, <code>false</code> otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean compare( String dn, String attributeName, String value ) throws LdapException;
+
+
+    /**
+     * Compares whether a given attribute's value matches that of the
+     * existing value of the attribute present in the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name, it must be a valid {@link Dn}
+     * @param attributeName the attribute's name
+     * @param value a byte[] value with which the target entry's attribute value to be compared with
+     * @return <code>true</code> if the value matches, <code>false</code> otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean compare( String dn, String attributeName, byte[] value ) throws LdapException;
+
+
+    /**
+     * Compares whether a given attribute's value matches that of the
+     * existing value of the attribute present in the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name, it must be a valid {@link Dn}
+     * @param attributeName the attribute's name
+     * @param value a Value<?> value with which the target entry's attribute value to be compared with
+     * @return <code>true</code> if the value matches, <code>false</code> otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean compare( String dn, String attributeName, Value<?> value ) throws LdapException;
+
+
+    /**
+     * Compares whether a given attribute's value matches that of the
+     * existing value of the attribute present in the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name
+     * @param attributeName the attribute's name
+     * @param value a String value with which the target entry's attribute value to be compared with
+     * @return <code>true</code> if the value matches, <code>false</code> otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean compare( Dn dn, String attributeName, String value ) throws LdapException;
+
+
+    /**
+     * Compares whether a given attribute's value matches that of the
+     * existing value of the attribute present in the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name
+     * @param attributeName the attribute's name
+     * @param value a byte[] value with which the target entry's attribute value to be compared with
+     * @return <code>true</code> if the value matches, <code>false</code> otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean compare( Dn dn, String attributeName, byte[] value ) throws LdapException;
+
+
+    /**
+     * Compares whether a given attribute's value matches that of the
+     * existing value of the attribute present in the entry with the given distinguished name.
+     *
+     * @param dn the target entry's distinguished name
+     * @param attributeName the attribute's name
+     * @param value a Value<?> value with which the target entry's attribute value to be compared with
+     * @return <code>true</code> if the value matches, <code>false</code> otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean compare( Dn dn, String attributeName, Value<?> value ) throws LdapException;
+
+
+    /**
+     * Compares an entry's attribute's value with that of the given value.
+     *
+     * @param compareRequest the compare request which contains the target Dn, attribute name and value
+     * @return compare operation's response
+     * @throws LdapException if some error occurred
+     */
+    CompareResponse compare( CompareRequest compareRequest ) throws LdapException;
+
+
+    /**
+     * Sends a extended operation request to the server with the given OID and no value.
+     *
+     * @param oid the object identifier of the extended operation
+     * @return extended operation's response
+     * @throws LdapException if some error occurred
+     * @see #extended(org.apache.directory.api.asn1.util.Oid, byte[])
+     */
+    ExtendedResponse extended( String oid ) throws LdapException;
+
+
+    /**
+     * Sends a extended operation request to the server with the given OID and value.
+     *
+     * @param oid the object identifier of the extended operation
+     * @param value value to be used by the extended operation, can be a null value
+     * @return extended operation's response
+     * @throws LdapException if some error occurred
+     * @see #extended(org.apache.directory.api.asn1.util.Oid, byte[])
+     */
+    ExtendedResponse extended( String oid, byte[] value ) throws LdapException;
+
+
+    /**
+     * Sends a extended operation request to the server with the given OID and no value.
+     *
+     * @param oid the object identifier of the extended operation
+     * @return extended operation's response
+     * @throws LdapException if some error occurred
+     * @see #extended(org.apache.directory.api.asn1.util.Oid, byte[])
+     */
+    ExtendedResponse extended( Oid oid ) throws LdapException;
+
+
+    /**
+     * Sends a extended operation request to the server with the given OID and value.
+     *
+     * @param oid the object identifier of the extended operation
+     * @param value value to be used by the extended operation, can be a null value
+     * @return extended operation's response
+     * @throws LdapException if some error occurred
+     */
+    ExtendedResponse extended( Oid oid, byte[] value ) throws LdapException;
+
+
+    /**
+     * Performs an extended operation based on the extended request object.
+     *
+     * @param extendedRequest the extended operation's request
+     * @return Extended operation's response
+     * @throws LdapException if the extended operation failed
+     */
+    ExtendedResponse extended( ExtendedRequest extendedRequest ) throws LdapException;
+
+
+    /**
+     * Tells if an entry exists in the server.
+     * 
+     * @param dn The distinguished name of the entry we want to check the existence, must be a valid {@link Dn}
+     * @return <code>true</code> if the entry exists, <code>false</code> otherwise.
+     * Note that if the entry exists but if the user does not have the permission to
+     * read it, <code>false</code> will also be returned
+     * @throws LdapException if some error occurred
+     */
+    boolean exists( String dn ) throws LdapException;
+
+
+    /**
+     * Tells if an Entry exists in the server.
+     * 
+     * @param dn The distinguished name of the entry we want to check the existence
+     * @return <code>true</code> if the entry exists, <code>false</code> otherwise.
+     * Note that if the entry exists but if the user does not have the permission to
+     * read it, <code>false</code> will also be returned
+     * @throws LdapException if some error occurred
+     */
+    boolean exists( Dn dn ) throws LdapException;
+
+
+    /**
+     * Get back the RooDSE from the connected server. Only the user attributes are returned.
+     * 
+     * @return The Entry containing all the information about the rootDSE
+     * @throws LdapException If the rootDSE can't be read
+     */
+    Entry getRootDse() throws LdapException;
+
+
+    /**
+     * Get back the RooDSE from the connected server. The user can provide the
+     * list of attributes he wants to get back. Sending "*" will return all the
+     * user attributes, sending "+" will return all the operational attributes.
+     * 
+     * @param attributes The list of attributes to return
+     * @return The Entry containing all the information about the rootDSE
+     * @throws LdapException If the rootDSE can't be read
+     */
+    Entry getRootDse( String... attributes ) throws LdapException;
+
+
+    /**
+     * Searches for an entry having the given Dn.
+     *
+     * @param dn the Dn of the entry to be fetched
+     * @return the Entry with the given Dn or null if no entry exists with that Dn
+     * @throws LdapException in case of any problems while searching for the Dn or if the returned response contains a referral
+     * @see #lookup(org.apache.directory.api.ldap.model.name.Dn, String...)
+     */
+    Entry lookup( Dn dn ) throws LdapException;
+
+
+    /**
+     * Searches for an entry having the given Dn.
+     *
+     * @param dn the Dn of the entry to be fetched
+     * @return the Entry with the given Dn or null if no entry exists with that Dn
+     * @throws LdapException in case of any problems while searching for the Dn or if the returned response contains a referral
+     * @see #lookup(String, String...)
+     */
+    Entry lookup( String dn ) throws LdapException;
+
+
+    /**
+     * Searches for an entry having the given Dn.
+     *
+     * @param dn the Dn of the entry to be fetched
+     * @param attributes the attributes to be returned along with entry
+     * @return the Entry with the given Dn or null if no entry exists with that Dn
+     * @throws LdapException in case of any problems while searching for the Dn or if the returned response contains a referral
+     */
+    Entry lookup( Dn dn, String... attributes ) throws LdapException;
+
+
+    /**
+     * Searches for an entry having the given Dn.
+     *
+     * @param dn the Dn of the entry to be fetched
+     * @param controls the controls to use
+     * @param attributes the attributes to be returned along with entry
+     * @return the Entry with the given Dn or null if no entry exists with that Dn
+     * @throws LdapException in case of any problems while searching for the Dn or if the returned response contains a referral
+     */
+    Entry lookup( Dn dn, Control[] controls, String... attributes ) throws LdapException;
+
+
+    /**
+     * Searches for an entry having the given Dn.
+     *
+     * @param dn the Dn of the entry to be fetched
+     * @param attributes the attributes to be returned along with entry
+     * @return the Entry with the given Dn or null if no entry exists with that Dn
+     * @throws LdapException in case of any problems while searching for the Dn or if the returned response contains a referral
+     * @see #lookup(org.apache.directory.api.ldap.model.name.Dn, String...)
+     */
+    Entry lookup( String dn, String... attributes ) throws LdapException;
+
+
+    /**
+     * Searches for an entry having the given Dn.
+     *
+     * @param dn the Dn of the entry to be fetched
+     * @param controls the controls to use
+     * @param attributes the attributes to be returned along with entry
+     * @return the Entry with the given Dn or null if no entry exists with that Dn
+     * @throws LdapException in case of any problems while searching for the Dn or if the returned response contains a referral
+     * @see #lookup(org.apache.directory.api.ldap.model.name.Dn, String...)
+     */
+    Entry lookup( String dn, Control[] controls, String... attributes ) throws LdapException;
+
+
+    /**
+     * Checks if a control with the given OID is supported.
+     *
+     * @param controlOID the OID of the control
+     * @return true if the control is supported, false otherwise
+     * @throws LdapException if some error occurred
+     */
+    boolean isControlSupported( String controlOID ) throws LdapException;
+
+
+    /**
+     * Get the Controls supported by server.
+     *
+     * @return a list of control OIDs supported by server
+     * @throws LdapException if some error occurred
+     */
+    List<String> getSupportedControls() throws LdapException;
+
+
+    /**
+     * Loads all the default schemas that are bundled with the API.<br><br>
+     * <b>Note:</b> This method enables <b>all</b> schemas prior to loading.
+     * 
+     * @throws LdapException in case of problems while loading the schema
+     */
+    void loadSchema() throws LdapException;
+
+
+    /**
+     * Loads all the default schemas that are bundled with the API, in a relaxed mode.<br><br>
+     * <b>Note:</b> This method enables <b>all</b> schemas prior to loading.<br/>
+     * The relaxed mode will allow inconsistencies in the schema.
+     * 
+     * @throws LdapException in case of problems while loading the schema
+     */
+    void loadSchemaRelaxed() throws LdapException;
+
+
+    /**
+     * @return The SchemaManager associated with this LdapConection if any
+     */
+    SchemaManager getSchemaManager();
+
+
+    /**
+     * Gets the LDAP CODEC service responsible for encoding and decoding
+     * messages.
+     * 
+     * @return The LDAP CODEC service.
+     */
+    LdapApiService getCodecService();
+
+
+    /**
+     * Checks if there is a ResponseFuture associated with the given message ID.
+     *
+     * @param messageId ID of the request
+     * @return true if there is a non-null future exists, false otherwise
+     */
+    boolean doesFutureExistFor( int messageId );
+
+
+    /**
+     * @return the object responsible for the detection of binary attributes
+     */
+    BinaryAttributeDetector getBinaryAttributeDetector();
+
+
+    /**
+     * Sets the object responsible for the detection of binary attributes.
+     */
+    void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetecter );
+
+
+    /**
+     * sets a SchemaManager to be used by this connection
+     */
+    void setSchemaManager( SchemaManager schemaManager );
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionConfig.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionConfig.java
new file mode 100644
index 0000000..d109f3a
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionConfig.java
@@ -0,0 +1,544 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.directory.api.ldap.codec.api.BinaryAttributeDetector;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class to hold the configuration for creating an LdapConnection.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapConnectionConfig
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( LdapConnectionConfig.class );
+
+    /** Default ports for LDAP */
+    public static final int DEFAULT_LDAP_PORT = 389;
+
+    /** Default port for LDAPS */
+    public static final int DEFAULT_LDAPS_PORT = 636;
+
+    /** The default host : localhost */
+    public static final String DEFAULT_LDAP_HOST = "localhost";
+
+    /** The LDAP version */
+    public static final int LDAP_V3 = 3;
+
+    /** The default timeout for operation : 30 seconds */
+    public static final long DEFAULT_TIMEOUT = 30000L;
+
+    /** the default protocol used for creating SSL context */
+    public static final String DEFAULT_SSL_PROTOCOL = "TLS";
+
+    // --- private members ----
+    /** A flag indicating if we are using SSL or not, default value is false */
+    private boolean useSsl = false;
+
+    /** The session timeout */
+    private long timeout = DEFAULT_TIMEOUT;
+
+    /** A flag indicating if we are using TLS or not, default value is false */
+    private boolean useTls = false;
+
+    /** The selected LDAP port */
+    private int ldapPort;
+
+    /** the remote LDAP host */
+    private String ldapHost;
+
+    /** a valid Dn to authenticate the user */
+    private String name;
+
+    /** user's credentials ( current implementation supports password only); it must be a non-null value */
+    private String credentials;
+
+    /** an array of key managers, if set, will be used while initializing the SSL context */
+    private KeyManager[] keyManagers;
+
+    /** an instance of SecureRandom, if set, will be used while initializing the SSL context */
+    private SecureRandom secureRandom;
+
+    /** an array of certificate trust managers, if set, will be used while initializing the SSL context */
+    private TrustManager[] trustManagers;
+
+    /** an array of cipher suites which are enabled, if set, will be used while initializing the SSL context */
+    private String[] enabledCipherSuites;
+
+    /** an array of protocols which are enabled, if set, will be used while initializing the SSL context */
+    private String[] enabledProtocols;
+
+    /** name of the protocol used for creating SSL context, default value is "TLS" */
+    private String sslProtocol = DEFAULT_SSL_PROTOCOL;
+
+    /** The class used to detect if an attribute is HR or not */
+    private BinaryAttributeDetector binaryAttributeDetector;
+
+    /** The Service to use internally when creating connections */
+    private LdapApiService ldapApiService;
+
+
+    /**
+     * Creates a default LdapConnectionConfig instance
+     */
+    public LdapConnectionConfig()
+    {
+        setDefaultTrustManager();
+    }
+
+
+    /**
+     * sets the default trust manager based on the SunX509 trustManagement algorithm
+     */
+    private void setDefaultTrustManager()
+    {
+        String trustMgmtAlgo = TrustManagerFactory.getDefaultAlgorithm();
+
+        try
+        {
+            TrustManagerFactory tmFactory = TrustManagerFactory.getInstance( trustMgmtAlgo );
+            tmFactory.init( ( KeyStore ) null );
+
+            TrustManager[] factoryTrustManagers = tmFactory.getTrustManagers();
+
+            for ( int i = 0; i < factoryTrustManagers.length; i++ )
+            {
+                if ( factoryTrustManagers[i] instanceof X509TrustManager )
+                {
+                    trustManagers = new TrustManager[]
+                        { factoryTrustManagers[i] };
+                    LOG.debug( "found X509TrustManager {}", factoryTrustManagers[i] );
+                    break;
+                }
+            }
+        }
+        catch ( NoSuchAlgorithmException e )
+        {
+            LOG.warn( "couldn't find any default X509 TrustManager with algorithm {}", trustMgmtAlgo );
+        }
+        catch ( KeyStoreException e )
+        {
+            LOG.warn( "couldn't initialize TrustManagerFactory with keystore {}", KeyStore.getDefaultType() );
+        }
+    }
+
+
+    /**
+     * Checks if SSL (ldaps://) is used.
+     *
+     * @return true, if SSL is used
+     */
+    public boolean isUseSsl()
+    {
+        return useSsl;
+    }
+
+
+    /**
+     * Sets whether SSL should be used.
+     *
+     * @param useSsl true to use SSL
+     */
+    public void setUseSsl( boolean useSsl )
+    {
+        this.useSsl = useSsl;
+    }
+
+
+    /**
+     * Gets the LDAP port.
+     *
+     * @return the LDAP port
+     */
+    public int getLdapPort()
+    {
+        return ldapPort;
+    }
+
+
+    /**
+     * Sets the LDAP port.
+     *
+     * @param ldapPort the new LDAP port
+     */
+    public void setLdapPort( int ldapPort )
+    {
+        this.ldapPort = ldapPort;
+    }
+
+
+    /**
+     * Gets the LDAP host.
+     *
+     * @return the LDAP host
+     */
+    public String getLdapHost()
+    {
+        return ldapHost;
+    }
+
+
+    /**
+     * Sets the LDAP host.
+     *
+     * @param ldapHost the new LDAP host
+     */
+    public void setLdapHost( String ldapHost )
+    {
+        this.ldapHost = ldapHost;
+    }
+
+
+    /**
+     * Gets the name that is used to authenticate the user.
+     *
+     * @return the name
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * Sets the name which is used to authenticate the user.
+     *
+     * @param name the new name
+     */
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Gets the credentials.
+     *
+     * @return the credentials
+     */
+    public String getCredentials()
+    {
+        return credentials;
+    }
+
+
+    /**
+     * Sets the credentials.
+     *
+     * @param credentials the new credentials
+     */
+    public void setCredentials( String credentials )
+    {
+        this.credentials = credentials;
+    }
+
+
+    /**
+     * Gets the default LDAP port.
+     *
+     * @return the default LDAP port
+     */
+    public int getDefaultLdapPort()
+    {
+        return DEFAULT_LDAP_PORT;
+    }
+
+
+    /**
+     * Gets the default LDAPS port.
+     *
+     * @return the default LDAPS port
+     */
+    public int getDefaultLdapsPort()
+    {
+        return DEFAULT_LDAPS_PORT;
+    }
+
+
+    /**
+     * Gets the default LDAP host.
+     *
+     * @return the default LDAP host
+     */
+    public String getDefaultLdapHost()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostName();
+        }
+        catch ( UnknownHostException uhe )
+        {
+            return DEFAULT_LDAP_HOST;
+        }
+    }
+
+
+    /**
+     * Gets the default timeout.
+     *
+     * @return the default timeout
+     */
+    public long getDefaultTimeout()
+    {
+        return DEFAULT_TIMEOUT;
+    }
+
+
+    /**
+     * Gets the timeout.
+     *
+     * @return the timeout
+     */
+    public long getTimeout()
+    {
+        return timeout;
+    }
+
+
+    /**
+     * Sets the timeout.
+     *
+     * @return the timeout
+     */
+    public void setTimeout( long timeout )
+    {
+        this.timeout = timeout;
+    }
+
+
+    /**
+     * Gets the supported LDAP version.
+     *
+     * @return the supported LDAP version
+     */
+    public int getSupportedLdapVersion()
+    {
+        return LDAP_V3;
+    }
+
+
+    /**
+     * Gets the trust managers.
+     *
+     * @return the trust managers
+     */
+    public TrustManager[] getTrustManagers()
+    {
+        return trustManagers;
+    }
+
+
+    /**
+     * Sets the trust managers.
+     *
+     * @param trustManagers the new trust managers
+     */
+    public void setTrustManagers( TrustManager... trustManagers )
+    {
+        this.trustManagers = trustManagers;
+    }
+
+
+    /**
+     * Gets the SSL protocol.
+     *
+     * @return the SSL protocol
+     */
+    public String getSslProtocol()
+    {
+        return sslProtocol;
+    }
+
+
+    /**
+     * Sets the SSL protocol.
+     *
+     * @param sslProtocol the new SSL protocol
+     */
+    public void setSslProtocol( String sslProtocol )
+    {
+        this.sslProtocol = sslProtocol;
+    }
+
+
+    /**
+     * Gets the key managers.
+     *
+     * @return the key managers
+     */
+    public KeyManager[] getKeyManagers()
+    {
+        return keyManagers;
+    }
+
+
+    /**
+     * Sets the key managers.
+     *
+     * @param keyManagers the new key managers
+     */
+    public void setKeyManagers( KeyManager[] keyManagers )
+    {
+        this.keyManagers = keyManagers;
+    }
+
+
+    /**
+     * Gets the secure random.
+     *
+     * @return the secure random
+     */
+    public SecureRandom getSecureRandom()
+    {
+        return secureRandom;
+    }
+
+
+    /**
+     * Sets the secure random.
+     *
+     * @param secureRandom the new secure random
+     */
+    public void setSecureRandom( SecureRandom secureRandom )
+    {
+        this.secureRandom = secureRandom;
+    }
+
+
+    /**
+     * Gets the cipher suites which are enabled.
+     * 
+     * @return the cipher suites which are enabled
+     */
+    public String[] getEnabledCipherSuites()
+    {
+        return enabledCipherSuites;
+    }
+
+
+    /**
+     * Sets the cipher suites which are enabled
+     * 
+     * @param enabledCipherSuites the cipher suites which are enabled
+     */
+    public void setEnabledCipherSuites( String[] enabledCipherSuites )
+    {
+        this.enabledCipherSuites = enabledCipherSuites;
+    }
+
+
+    /**
+     * Gets the protocols which are enabled.
+     * 
+     * @return the protocol which are enabled
+     */
+    public String[] getEnabledProtocols()
+    {
+        return enabledProtocols;
+    }
+
+
+    /**
+     * Sets the protocols which are enabled
+     * 
+     * @param enabledProtocols the protocols which are enabled
+     */
+    public void setEnabledProtocols( String... enabledProtocols )
+    {
+        this.enabledProtocols = enabledProtocols;
+    }
+
+
+    /**
+     * @return the binaryAttributeDetector
+     */
+    public BinaryAttributeDetector getBinaryAttributeDetector()
+    {
+        return binaryAttributeDetector;
+    }
+
+
+    /**
+     * @param binaryAttributeDetector the binaryAttributeDetector to set
+     */
+    public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector )
+    {
+        this.binaryAttributeDetector = binaryAttributeDetector;
+    }
+
+
+    /**
+     * Checks if TLS is used.
+     *
+     * @return true, if TLS is used
+     */
+    public boolean isUseTls()
+    {
+        return useTls;
+    }
+
+
+    /**
+     * Sets whether TLS should be used.
+     *
+     * @param useTls true to use TLS
+     */
+    public void setUseTls( boolean useTls )
+    {
+        this.useTls = useTls;
+    }
+
+
+    /**
+     * @return the ldapApiService
+     */
+    public LdapApiService getLdapApiService()
+    {
+        return ldapApiService;
+    }
+
+
+    /**
+     * @param ldapApiService the ldapApiService to set
+     */
+    public void setLdapApiService( LdapApiService ldapApiService )
+    {
+        this.ldapApiService = ldapApiService;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionFactory.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionFactory.java
new file mode 100755
index 0000000..3b0f2ba
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionFactory.java
@@ -0,0 +1,97 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * A factory that creates {@link LdapConnection} objects using the provided
+ * {@link LdapConnectionConfig}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface LdapConnectionFactory
+{
+    /**
+     * Issues a bind request on the supplied connection using the name and
+     * credentials from the LdapConnectionConfg supplied to the constructor.
+     * Returns the connection supplied for chaining.
+     * 
+     * @param connection
+     *            The connection to bind with the configuration credentials.
+     * @return The connection supplied.
+     * @throws LdapException
+     *             If the bind fails.
+     */
+    LdapConnection bindConnection( LdapConnection connection ) throws LdapException;
+
+
+    /**
+     * Applies the following configuration settings from the
+     * LdapConnectionConfig to the supplied connection:
+     * <ul>
+     * <li>timeOut</li>
+     * <li>binaryAttributeDetector</li>
+     * </ul>
+     * This method is called by newLdapConnection, so there is no need to call
+     * this on a newly created connection. This should be used for pooling where
+     * the returned connection could have been modified by the borrower in order
+     * to ensure the next borrower gets a correctly configured connection.
+     * Returns the supplied connection for chaining.
+     * 
+     * @param connection
+     *            The connection to configure
+     * @return The supplied connection.
+     */
+    LdapConnection configureConnection( LdapConnection connection );
+
+
+    /**
+     * Returns the LdapApiService instance used by this factory.
+     *
+     * @return The LdapApiService instance used by this factory
+     */
+    LdapApiService getLdapApiService();
+
+
+    /**
+     * Returns a newly created, configured, and authenticated connection. This
+     * method should be used by a connection pool to manufacture the pooled
+     * instances.
+     * 
+     * @return A newly created, configured, and authenticated LdapConnection.
+     * @throws LdapException
+     */
+    LdapConnection newLdapConnection() throws LdapException;
+
+
+    /**
+     * Returns a newly created connection, that has not been bound (bind) that
+     * otherwise respects LdapConnectionConfig supplied to the constructor. This
+     * is useful for authentication purposes where the consumer will use a bind
+     * operation.
+     * 
+     * @return A newly created and configured LdapConnection.
+     */
+    LdapConnection newUnboundLdapConnection();
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionPool.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionPool.java
new file mode 100644
index 0000000..3ca2ecc
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionPool.java
@@ -0,0 +1,189 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.commons.pool.PoolableObjectFactory;
+import org.apache.commons.pool.impl.GenericObjectPool;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A pool implementation for LdapConnection objects.
+ * 
+ * This class is just a wrapper around the commons GenericObjectPool, and has
+ * a more meaningful name to represent the pool type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapConnectionPool extends GenericObjectPool<LdapConnection>
+{
+    private static final Logger LOG = LoggerFactory.getLogger( LdapConnectionPool.class );
+
+    private PoolableObjectFactory<LdapConnection> factory;
+
+
+    /**
+     * Instantiates a new LDAP connection pool.
+     *
+     * @param connectionConfig The connection configuration
+     * @param apiService The api service (codec)
+     * @param timeout The connection timeout in millis
+     */
+    public LdapConnectionPool( LdapConnectionConfig connectionConfig,
+        LdapApiService apiService, long timeout )
+    {
+        this( connectionConfig, apiService, timeout, null );
+    }
+
+
+    /**
+     * Instantiates a new LDAP connection pool.
+     *
+     * @param connectionConfig The connection configuration
+     * @param apiService The api service (codec)
+     * @param timeout The connection timeout in millis
+     * @param poolConfig The pool configuration
+     */
+    public LdapConnectionPool( LdapConnectionConfig connectionConfig,
+        LdapApiService apiService, long timeout, Config poolConfig )
+    {
+        this( newPoolableConnectionFactory( connectionConfig, apiService, timeout ), poolConfig );
+    }
+
+
+    /**
+     * Instantiates a new LDAP connection pool.
+     *
+     * @param factory The LDAP connection factory
+     */
+    public LdapConnectionPool( PoolableObjectFactory<LdapConnection> factory )
+    {
+        this( factory, null );
+    }
+
+
+    /**
+     * Instantiates a new LDAP connection pool.
+     *
+     * @param factory The LDAP connection factory
+     * @param poolConfig The pool configuration
+     */
+    public LdapConnectionPool( PoolableObjectFactory<LdapConnection> factory, Config poolConfig )
+    {
+        super( factory, poolConfig == null ? new Config() : poolConfig );
+        this.factory = factory;
+    }
+
+
+    /**
+     * Returns the LdapApiService instance used by this connection pool.
+     *
+     * @return The LdapApiService instance used by this connection pool.
+     */
+    public LdapApiService getLdapApiService()
+    {
+        return ( ( AbstractPoolableLdapConnectionFactory ) factory ).getLdapApiService();
+    }
+
+
+    /**
+     * Gives a LdapConnection fetched from the pool.
+     *
+     * @return an LdapConnection object from pool
+     * @throws Exception if an error occurs while obtaining a connection from the factory
+     */
+    public LdapConnection getConnection() throws LdapException
+    {
+        LdapConnection connection;
+
+        try
+        {
+            connection = super.borrowObject();
+            LOG.trace( "borrowed connection {}", connection );
+        }
+        catch ( LdapException e )
+        {
+            throw ( e );
+        }
+        catch ( RuntimeException e )
+        {
+            throw ( e );
+        }
+        catch ( Exception e )
+        {
+            // wrap in runtime, but this should NEVER happen per published 
+            // contract as it only throws what the makeObject throws and our 
+            // PoolableLdapConnectionFactory only throws LdapException
+            LOG.error( "An unexpected exception was thrown: ", e );
+            throw new RuntimeException( e );
+        }
+
+        return connection;
+    }
+
+
+    private static ValidatingPoolableLdapConnectionFactory newPoolableConnectionFactory(
+        LdapConnectionConfig connectionConfig, LdapApiService apiService,
+        long timeout )
+    {
+        DefaultLdapConnectionFactory connectionFactory =
+            new DefaultLdapConnectionFactory( connectionConfig );
+        connectionFactory.setLdapApiService( apiService );
+        connectionFactory.setTimeOut( timeout );
+        return new ValidatingPoolableLdapConnectionFactory( connectionFactory );
+    }
+
+
+    /**
+     * Places the given LdapConnection back in the pool.
+     * 
+     * @param connection the LdapConnection to be released
+     * @throws Exception if an error occurs while releasing the connection
+     */
+    public void releaseConnection( LdapConnection connection ) throws LdapException
+    {
+        try
+        {
+            super.returnObject( connection );
+            LOG.trace( "returned connection {}", connection );
+        }
+        catch ( LdapException e )
+        {
+            throw ( e );
+        }
+        catch ( RuntimeException e )
+        {
+            throw ( e );
+        }
+        catch ( Exception e )
+        {
+            // wrap in runtime, but this should NEVER happen as it only throws 
+            // what the passivateObject throws and our 
+            // PoolableLdapConnectionFactory only throws LdapException
+            LOG.error( "An unexpected exception was thrown: ", e );
+            throw new RuntimeException( e );
+        }
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionValidator.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionValidator.java
new file mode 100755
index 0000000..252a088
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionValidator.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+/**
+ * An LdapConnection validator intended to be used by a GenericObjectPool to
+ * determine whether or not a conneciton is still <i>usable</i>.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface LdapConnectionValidator
+{
+    /**
+     * Return true if the connection is still valid.  This means that if this
+     * connections is handed out to a user, it <i>should</i> allow for 
+     * successful communication with the server.
+     *
+     * @param ldapConnection The connection to test
+     * @return True, if the connection is still valid
+     */
+    boolean validate( LdapConnection ldapConnection );
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionWrapper.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionWrapper.java
new file mode 100755
index 0000000..32b7649
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapConnectionWrapper.java
@@ -0,0 +1,579 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.codec.api.BinaryAttributeDetector;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * Provides a base implementation of a {@link Wrapper} for {@link LdapConnection}
+ * objects.  All methods are passed through to the wrapped 
+ * <code>LdapConnection</code>.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapConnectionWrapper implements LdapConnection, Wrapper<LdapConnection>
+{
+    protected LdapConnection connection;
+
+
+    protected LdapConnectionWrapper( LdapConnection connection )
+    {
+        this.connection = connection;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapConnection wrapped()
+    {
+        return connection;
+    }
+
+
+    @Override
+    public boolean isConnected()
+    {
+        return connection.isConnected();
+    }
+
+
+    @Override
+    public boolean isAuthenticated()
+    {
+        return connection.isAuthenticated();
+    }
+
+
+    @Override
+    public boolean connect() throws LdapException
+    {
+        return connection.connect();
+    }
+
+
+    @Override
+    public void close() throws IOException
+    {
+        connection.close();
+    }
+
+
+    @Override
+    public void add( Entry entry ) throws LdapException
+    {
+        connection.add( entry );
+    }
+
+
+    @Override
+    public AddResponse add( AddRequest addRequest ) throws LdapException
+    {
+        return connection.add( addRequest );
+    }
+
+
+    @Override
+    public void abandon( int messageId )
+    {
+        connection.abandon( messageId );
+    }
+
+
+    @Override
+    public void abandon( AbandonRequest abandonRequest )
+    {
+        connection.abandon( abandonRequest );
+    }
+
+
+    @Override
+    public void bind() throws LdapException
+    {
+        connection.bind();
+    }
+
+
+    @Override
+    public void anonymousBind() throws LdapException
+    {
+        connection.anonymousBind();
+    }
+
+
+    @Override
+    public void bind( String name ) throws LdapException
+    {
+        connection.bind( name );
+    }
+
+
+    @Override
+    public void bind( String name, String credentials ) throws LdapException
+    {
+        connection.bind( name, credentials );
+    }
+
+
+    @Override
+    public void bind( Dn name ) throws LdapException
+    {
+        connection.bind( name );
+    }
+
+
+    @Override
+    public void bind( Dn name, String credentials ) throws LdapException
+    {
+        connection.bind( name, credentials );
+    }
+
+
+    @Override
+    public BindResponse bind( BindRequest bindRequest ) throws LdapException
+    {
+        return connection.bind( bindRequest );
+    }
+
+
+    @Override
+    public EntryCursor search( Dn baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        return connection.search( baseDn, filter, scope, attributes );
+    }
+
+
+    @Override
+    public EntryCursor search( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        return connection.search( baseDn, filter, scope, attributes );
+    }
+
+
+    @Override
+    public SearchCursor search( SearchRequest searchRequest ) throws LdapException
+    {
+        return connection.search( searchRequest );
+    }
+
+
+    @Override
+    public void unBind() throws LdapException
+    {
+        connection.unBind();
+    }
+
+
+    @Override
+    public void setTimeOut( long timeOut )
+    {
+        connection.setTimeOut( timeOut );
+    }
+
+
+    @Override
+    public void modify( Dn dn, Modification... modifications ) throws LdapException
+    {
+        connection.modify( dn, modifications );
+    }
+
+
+    @Override
+    public void modify( String dn, Modification... modifications ) throws LdapException
+    {
+        connection.modify( dn, modifications );
+    }
+
+
+    @Override
+    public void modify( Entry entry, ModificationOperation modOp ) throws LdapException
+    {
+        connection.modify( entry, modOp );
+    }
+
+
+    @Override
+    public ModifyResponse modify( ModifyRequest modRequest ) throws LdapException
+    {
+        return connection.modify( modRequest );
+    }
+
+
+    @Override
+    public void rename( String entryDn, String newRdn ) throws LdapException
+    {
+        connection.rename( entryDn, newRdn );
+    }
+
+
+    @Override
+    public void rename( Dn entryDn, Rdn newRdn ) throws LdapException
+    {
+        connection.rename( entryDn, newRdn );
+    }
+
+
+    @Override
+    public void rename( String entryDn, String newRdn, boolean deleteOldRdn ) throws LdapException
+    {
+        connection.rename( entryDn, newRdn, deleteOldRdn );
+    }
+
+
+    @Override
+    public void rename( Dn entryDn, Rdn newRdn, boolean deleteOldRdn ) throws LdapException
+    {
+        connection.rename( entryDn, newRdn, deleteOldRdn );
+    }
+
+
+    @Override
+    public void move( String entryDn, String newSuperiorDn ) throws LdapException
+    {
+        connection.move( entryDn, newSuperiorDn );
+    }
+
+
+    @Override
+    public void move( Dn entryDn, Dn newSuperiorDn ) throws LdapException
+    {
+        connection.move( entryDn, newSuperiorDn );
+    }
+
+
+    @Override
+    public void moveAndRename( Dn entryDn, Dn newDn ) throws LdapException
+    {
+        connection.moveAndRename( entryDn, newDn );
+    }
+
+
+    @Override
+    public void moveAndRename( String entryDn, String newDn ) throws LdapException
+    {
+        connection.moveAndRename( entryDn, newDn );
+    }
+
+
+    @Override
+    public void moveAndRename( Dn entryDn, Dn newDn, boolean deleteOldRdn ) throws LdapException
+    {
+        connection.moveAndRename( entryDn, newDn, deleteOldRdn );
+    }
+
+
+    @Override
+    public void moveAndRename( String entryDn, String newDn, boolean deleteOldRdn ) throws LdapException
+    {
+        connection.moveAndRename( entryDn, newDn, deleteOldRdn );
+    }
+
+
+    @Override
+    public ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest ) throws LdapException
+    {
+        return connection.modifyDn( modDnRequest );
+    }
+
+
+    @Override
+    public void delete( String dn ) throws LdapException
+    {
+        connection.delete( dn );
+    }
+
+
+    @Override
+    public void delete( Dn dn ) throws LdapException
+    {
+        connection.delete( dn );
+    }
+
+
+    @Override
+    public DeleteResponse delete( DeleteRequest deleteRequest ) throws LdapException
+    {
+        return connection.delete( deleteRequest );
+    }
+
+
+    @Override
+    public boolean compare( String dn, String attributeName, String value ) throws LdapException
+    {
+        return connection.compare( dn, attributeName, value );
+    }
+
+
+    @Override
+    public boolean compare( String dn, String attributeName, byte[] value ) throws LdapException
+    {
+        return connection.compare( dn, attributeName, value );
+    }
+
+
+    @Override
+    public boolean compare( String dn, String attributeName, Value<?> value ) throws LdapException
+    {
+        return connection.compare( dn, attributeName, value );
+    }
+
+
+    @Override
+    public boolean compare( Dn dn, String attributeName, String value ) throws LdapException
+    {
+        return connection.compare( dn, attributeName, value );
+    }
+
+
+    @Override
+    public boolean compare( Dn dn, String attributeName, byte[] value ) throws LdapException
+    {
+        return connection.compare( dn, attributeName, value );
+    }
+
+
+    @Override
+    public boolean compare( Dn dn, String attributeName, Value<?> value ) throws LdapException
+    {
+        return connection.compare( dn, attributeName, value );
+    }
+
+
+    @Override
+    public CompareResponse compare( CompareRequest compareRequest ) throws LdapException
+    {
+        return connection.compare( compareRequest );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( String oid ) throws LdapException
+    {
+        return connection.extended( oid );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( String oid, byte[] value ) throws LdapException
+    {
+        return connection.extended( oid, value );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( Oid oid ) throws LdapException
+    {
+        return connection.extended( oid );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( Oid oid, byte[] value ) throws LdapException
+    {
+        return connection.extended( oid, value );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( ExtendedRequest extendedRequest ) throws LdapException
+    {
+        return connection.extended( extendedRequest );
+    }
+
+
+    @Override
+    public boolean exists( String dn ) throws LdapException
+    {
+        return connection.exists( dn );
+    }
+
+
+    @Override
+    public boolean exists( Dn dn ) throws LdapException
+    {
+        return connection.exists( dn );
+    }
+
+
+    @Override
+    public Entry getRootDse() throws LdapException
+    {
+        return connection.getRootDse();
+    }
+
+
+    @Override
+    public Entry getRootDse( String... attributes ) throws LdapException
+    {
+        return connection.getRootDse( attributes );
+    }
+
+
+    @Override
+    public Entry lookup( Dn dn ) throws LdapException
+    {
+        return connection.lookup( dn );
+    }
+
+
+    @Override
+    public Entry lookup( String dn ) throws LdapException
+    {
+        return connection.lookup( dn );
+    }
+
+
+    @Override
+    public Entry lookup( Dn dn, String... attributes ) throws LdapException
+    {
+        return connection.lookup( dn, attributes );
+    }
+
+
+    @Override
+    public Entry lookup( Dn dn, Control[] controls, String... attributes ) throws LdapException
+    {
+        return connection.lookup( dn, controls, attributes );
+    }
+
+
+    @Override
+    public Entry lookup( String dn, String... attributes ) throws LdapException
+    {
+        return connection.lookup( dn, attributes );
+    }
+
+
+    @Override
+    public Entry lookup( String dn, Control[] controls, String... attributes ) throws LdapException
+    {
+        return connection.lookup( dn, controls, attributes );
+    }
+
+
+    @Override
+    public boolean isControlSupported( String controlOID ) throws LdapException
+    {
+        return connection.isControlSupported( controlOID );
+    }
+
+
+    @Override
+    public List<String> getSupportedControls() throws LdapException
+    {
+        return connection.getSupportedControls();
+    }
+
+
+    @Override
+    public void loadSchema() throws LdapException
+    {
+        connection.loadSchema();
+    }
+
+
+    @Override
+    public SchemaManager getSchemaManager()
+    {
+        return connection.getSchemaManager();
+    }
+
+
+    @Override
+    public LdapApiService getCodecService()
+    {
+        return connection.getCodecService();
+    }
+
+
+    @Override
+    public boolean doesFutureExistFor( int messageId )
+    {
+        return connection.doesFutureExistFor( messageId );
+    }
+
+
+    @Override
+    public BinaryAttributeDetector getBinaryAttributeDetector()
+    {
+        return connection.getBinaryAttributeDetector();
+    }
+
+
+    @Override
+    public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetecter )
+    {
+        connection.setBinaryAttributeDetector( binaryAttributeDetecter );
+    }
+
+
+    @Override
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        connection.setSchemaManager( schemaManager );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void loadSchemaRelaxed() throws LdapException
+    {
+        connection.loadSchemaRelaxed();
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
new file mode 100644
index 0000000..c092512
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
@@ -0,0 +1,4261 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import static org.apache.directory.api.ldap.model.message.ResultCodeEnum.processResponse;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.nio.channels.UnresolvedAddressException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.net.ssl.SSLContext;
+import javax.security.auth.Subject;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.codec.api.BinaryAttributeDetector;
+import org.apache.directory.api.ldap.codec.api.DefaultConfigurableBinaryAttributeDetector;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.api.LdapDecoder;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.api.MessageEncoderException;
+import org.apache.directory.api.ldap.codec.api.SchemaBinaryAttributeDetector;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequestImpl;
+import org.apache.directory.api.ldap.model.constants.LdapConstants;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.cursor.Cursor;
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
+import org.apache.directory.api.ldap.model.exception.LdapOperationException;
+import org.apache.directory.api.ldap.model.exception.LdapOtherException;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddRequestImpl;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareRequestImpl;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.ldap.model.message.IntermediateResponseImpl;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.Request;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.message.UnbindRequest;
+import org.apache.directory.api.ldap.model.message.UnbindRequestImpl;
+import org.apache.directory.api.ldap.model.message.controls.ManageDsaITImpl;
+import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.api.ldap.model.message.extended.AddNoDResponse;
+import org.apache.directory.api.ldap.model.message.extended.BindNoDResponse;
+import org.apache.directory.api.ldap.model.message.extended.CompareNoDResponse;
+import org.apache.directory.api.ldap.model.message.extended.DeleteNoDResponse;
+import org.apache.directory.api.ldap.model.message.extended.ExtendedNoDResponse;
+import org.apache.directory.api.ldap.model.message.extended.ModifyDnNoDResponse;
+import org.apache.directory.api.ldap.model.message.extended.ModifyNoDResponse;
+import org.apache.directory.api.ldap.model.message.extended.NoticeOfDisconnect;
+import org.apache.directory.api.ldap.model.message.extended.SearchNoDResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.parsers.OpenLdapSchemaParser;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.ldap.client.api.callback.SaslCallbackHandler;
+import org.apache.directory.ldap.client.api.exception.InvalidConnectionException;
+import org.apache.directory.ldap.client.api.future.AddFuture;
+import org.apache.directory.ldap.client.api.future.BindFuture;
+import org.apache.directory.ldap.client.api.future.CompareFuture;
+import org.apache.directory.ldap.client.api.future.DeleteFuture;
+import org.apache.directory.ldap.client.api.future.ExtendedFuture;
+import org.apache.directory.ldap.client.api.future.ModifyDnFuture;
+import org.apache.directory.ldap.client.api.future.ModifyFuture;
+import org.apache.directory.ldap.client.api.future.ResponseFuture;
+import org.apache.directory.ldap.client.api.future.SearchFuture;
+import org.apache.mina.core.filterchain.IoFilter;
+import org.apache.mina.core.future.CloseFuture;
+import org.apache.mina.core.future.ConnectFuture;
+import org.apache.mina.core.future.IoFuture;
+import org.apache.mina.core.future.IoFutureListener;
+import org.apache.mina.core.future.WriteFuture;
+import org.apache.mina.core.service.IoConnector;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.mina.filter.codec.ProtocolEncoderException;
+import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.transport.socket.SocketSessionConfig;
+import org.apache.mina.transport.socket.nio.NioSocketConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class is the base for every operations sent or received to and
+ * from a LDAP server.
+ *
+ * A connection instance is necessary to send requests to the server. The connection
+ * is valid until either the client closes it, the server closes it or the
+ * client does an unbind.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapNetworkConnection extends AbstractLdapConnection implements LdapAsyncConnection
+{
+    /** logger for reporting errors that might not be handled properly upstream */
+    private static final Logger LOG = LoggerFactory.getLogger( LdapNetworkConnection.class );
+
+    /** The timeout used for response we are waiting for */
+    private long timeout = LdapConnectionConfig.DEFAULT_TIMEOUT;
+
+    /** configuration object for the connection */
+    private LdapConnectionConfig config;
+
+    /** The connector open with the remote server */
+    private IoConnector connector;
+
+    /** A mutex used to avoid a double close of the connector */
+    private ReentrantLock connectorMutex = new ReentrantLock();
+
+    /**
+     * The created session, created when we open a connection with
+     * the Ldap server.
+     */
+    private IoSession ldapSession;
+
+    /** a map to hold the ResponseFutures for all operations */
+    private Map<Integer, ResponseFuture<? extends Response>> futureMap = new ConcurrentHashMap<Integer, ResponseFuture<? extends Response>>();
+
+    /** list of controls supported by the server */
+    private List<String> supportedControls;
+
+    /** The ROOT DSE entry */
+    private Entry rootDse;
+
+    /** A flag indicating that the BindRequest has been issued and successfully authenticated the user */
+    private AtomicBoolean authenticated = new AtomicBoolean( false );
+
+    /** A flag indicating that the connection is connected or not */
+    private AtomicBoolean connected = new AtomicBoolean( false );
+
+    /** a list of listeners interested in getting notified when the
+     *  connection's session gets closed cause of network issues
+     */
+    private List<ConnectionClosedEventListener> conCloseListeners;
+
+    /** The Ldap codec protocol filter */
+    private IoFilter ldapProtocolFilter = new ProtocolCodecFilter( codec.getProtocolCodecFactory() );
+
+    /** the SslFilter key */
+    private static final String SSL_FILTER_KEY = "sslFilter";
+
+    /** The exception stored in the session if we've got one */
+    private static final String EXCEPTION_KEY = "sessionException";
+
+    // ~~~~~~~~~~~~~~~~~ common error messages ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    static final String TIME_OUT_ERROR = "TimeOut occurred";
+
+    static final String NO_RESPONSE_ERROR = "The response queue has been emptied, no response was found.";
+
+
+    //--------------------------- Helper methods ---------------------------//
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isConnected()
+    {
+        return ( ldapSession != null ) && connected.get() && !ldapSession.isClosing();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAuthenticated()
+    {
+        return isConnected() && authenticated.get();
+    }
+
+
+    /**
+     * Check that a session is valid, ie we can send requests to the
+     * server
+     *
+     * @throws Exception If the session is not valid
+     */
+    private void checkSession() throws InvalidConnectionException
+    {
+        if ( ldapSession == null )
+        {
+            throw new InvalidConnectionException( "Cannot connect on the server, the connection is null" );
+        }
+
+        if ( !connected.get() )
+        {
+            throw new InvalidConnectionException( "Cannot connect on the server, the connection is invalid" );
+        }
+    }
+
+
+    private void addToFutureMap( int messageId, ResponseFuture<? extends Response> future )
+    {
+        LOG.debug( "Adding <" + messageId + ", " + future.getClass().getName() + ">" );
+        futureMap.put( messageId, future );
+    }
+
+
+    private ResponseFuture<? extends Response> getFromFutureMap( int messageId )
+    {
+        ResponseFuture<? extends Response> future = futureMap.remove( messageId );
+
+        if ( future != null )
+        {
+            LOG.debug( "Removing <" + messageId + ", " + future.getClass().getName() + ">" );
+        }
+
+        return future;
+    }
+
+
+    private ResponseFuture<? extends Response> peekFromFutureMap( int messageId )
+    {
+        ResponseFuture<? extends Response> future = futureMap.get( messageId );
+
+        // future can be null if there was a abandon operation on that messageId
+        if ( future != null )
+        {
+            LOG.debug( "Getting <" + messageId + ", " + future.getClass().getName() + ">" );
+        }
+
+        return future;
+    }
+
+
+    /**
+     * Get the largest timeout from the search time limit and the connection
+     * timeout.
+     */
+    static long getTimeout( long connectionTimoutInMS, int searchTimeLimitInSeconds )
+    {
+        if ( searchTimeLimitInSeconds < 0 )
+        {
+            return connectionTimoutInMS;
+        }
+        else if ( searchTimeLimitInSeconds == 0 )
+        {
+            return Long.MAX_VALUE;
+        }
+        else
+        {
+            long searchTimeLimitInMS = searchTimeLimitInSeconds * 1000L;
+            return Math.max( searchTimeLimitInMS, connectionTimoutInMS );
+        }
+    }
+
+
+    //------------------------- The constructors --------------------------//
+    /**
+     * Create a new instance of a LdapConnection on localhost,
+     * port 389.
+     */
+    public LdapNetworkConnection()
+    {
+        this( null, -1, false );
+    }
+
+
+    /**
+     *
+     * Creates a new instance of LdapConnection with the given connection configuration.
+     *
+     * @param config the configuration of the LdapConnection
+     */
+    public LdapNetworkConnection( LdapConnectionConfig config )
+    {
+        this( config, LdapApiServiceFactory.getSingleton() );
+    }
+
+
+    public LdapNetworkConnection( LdapConnectionConfig config, LdapApiService ldapApiService )
+    {
+        super( ldapApiService );
+        this.config = config;
+
+        if ( config.getBinaryAttributeDetector() == null )
+        {
+            config.setBinaryAttributeDetector( new DefaultConfigurableBinaryAttributeDetector() );
+        }
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on localhost,
+     * port 389 if the SSL flag is off, or 636 otherwise.
+     *
+     * @param useSsl A flag to tell if it's a SSL connection or not.
+     */
+    public LdapNetworkConnection( boolean useSsl )
+    {
+        this( null, -1, useSsl );
+    }
+
+
+    public LdapNetworkConnection( boolean useSsl, LdapApiService ldapApiService )
+    {
+        this( null, -1, useSsl, ldapApiService );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a given
+     * server, using the default port (389).
+     *
+     * @param server The server we want to be connected to. If null or empty,
+     * we will default to LocalHost.
+     */
+    public LdapNetworkConnection( String server )
+    {
+        this( server, -1, false );
+    }
+
+
+    public LdapNetworkConnection( String server, LdapApiService ldapApiService )
+    {
+        this( server, -1, false, ldapApiService );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a given
+     * server, using the default port (389) if the SSL flag
+     * is off, or 636 otherwise.
+     *
+     * @param server The server we want to be connected to. If null or empty,
+     * we will default to LocalHost.
+     * @param useSsl A flag to tell if it's a SSL connection or not.
+     */
+    public LdapNetworkConnection( String server, boolean useSsl )
+    {
+        this( server, -1, useSsl );
+    }
+
+
+    public LdapNetworkConnection( String server, boolean useSsl, LdapApiService ldapApiService )
+    {
+        this( server, -1, useSsl, ldapApiService );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a
+     * given server and a given port. We don't use ssl.
+     *
+     * @param server The server we want to be connected to
+     * @param port The port the server is listening to
+     */
+    public LdapNetworkConnection( String server, int port )
+    {
+        this( server, port, false );
+    }
+
+
+    public LdapNetworkConnection( String server, int port, LdapApiService ldapApiService )
+    {
+        this( server, port, false, ldapApiService );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a given
+     * server, and a give port. We set the SSL flag accordingly
+     * to the last parameter.
+     *
+     * @param server The server we want to be connected to. If null or empty,
+     * we will default to LocalHost.
+     * @param port The port the server is listening to
+     * @param useSsl A flag to tell if it's a SSL connection or not.
+     */
+    public LdapNetworkConnection( String server, int port, boolean useSsl )
+    {
+        this( buildConfig( server, port, useSsl ) );
+    }
+
+
+    public LdapNetworkConnection( String server, int port, boolean useSsl, LdapApiService ldapApiService )
+    {
+        this( buildConfig( server, port, useSsl ), ldapApiService );
+    }
+
+
+    private static LdapConnectionConfig buildConfig( String server, int port, boolean useSsl )
+    {
+        LdapConnectionConfig config = new LdapConnectionConfig();
+        config.setUseSsl( useSsl );
+
+        if ( port != -1 )
+        {
+            config.setLdapPort( port );
+        }
+        else
+        {
+            if ( useSsl )
+            {
+                config.setLdapPort( config.getDefaultLdapsPort() );
+            }
+            else
+            {
+                config.setLdapPort( config.getDefaultLdapPort() );
+            }
+        }
+
+        // Default to localhost if null
+        if ( Strings.isEmpty( server ) )
+        {
+            try
+            {
+                config.setLdapHost( InetAddress.getLocalHost().getHostName() );
+            }
+            catch ( UnknownHostException uhe )
+            {
+                config.setLdapHost( LdapConnectionConfig.DEFAULT_LDAP_HOST );
+            }
+            
+        }
+        else
+        {
+            config.setLdapHost( server );
+        }
+
+        config.setBinaryAttributeDetector( new DefaultConfigurableBinaryAttributeDetector() );
+
+        return config;
+    }
+
+
+    /**
+     * Create the connector
+     */
+    private void createConnector() throws LdapException
+    {
+        // Use only one thread inside the connector
+        connector = new NioSocketConnector( 1 );
+
+        ( ( SocketSessionConfig ) connector.getSessionConfig() ).setReuseAddress( true );
+
+        // Add the codec to the chain
+        connector.getFilterChain().addLast( "ldapCodec", ldapProtocolFilter );
+
+        // If we use SSL, we have to add the SslFilter to the chain
+        if ( config.isUseSsl() )
+        {
+            addSslFilter();
+        }
+
+        // Inject the protocolHandler
+        connector.setHandler( this );
+    }
+
+
+    //-------------------------- The methods ---------------------------//
+    /**
+     * {@inheritDoc}
+     */
+    public boolean connect() throws LdapException
+    {
+        if ( ( ldapSession != null ) && connected.get() )
+        {
+            // No need to connect if we already have a connected session
+            return true;
+        }
+
+        // Create the connector if needed
+        if ( connector == null )
+        {
+            createConnector();
+        }
+
+        // Build the connection address
+        SocketAddress address = new InetSocketAddress( config.getLdapHost(), config.getLdapPort() );
+
+        // And create the connection future
+        timeout = config.getTimeout();
+        long maxRetry = System.currentTimeMillis() + timeout;
+        ConnectFuture connectionFuture = null;
+
+        while ( maxRetry > System.currentTimeMillis() )
+        {
+            connectionFuture = connector.connect( address );
+
+            boolean result = false;
+
+            // Wait until it's established
+            try
+            {
+                result = connectionFuture.await( timeout );
+            }
+            catch ( InterruptedException e )
+            {
+                connector.dispose();
+                connector = null;
+                LOG.debug( "Interrupted while waiting for connection to establish with server {}:{}",
+                    config.getLdapHost(),
+                    config.getLdapPort(), e );
+                throw new LdapOtherException( e.getMessage(), e );
+            }
+            finally
+            {
+                if ( result )
+                {
+                    boolean isConnected = connectionFuture.isConnected();
+
+                    if ( !isConnected )
+                    {
+                        Throwable connectionException = connectionFuture.getException();
+
+                        if ( ( connectionException instanceof ConnectException )
+                            || ( connectionException instanceof UnresolvedAddressException ) )
+                        {
+                            // No need to wait
+                            // We know that there was a permanent error such as "connection refused".
+                            LOG.debug( "------>> Connection error: {}", connectionFuture.getException().getMessage() );
+                            break;
+                        }
+
+                        LOG.debug( "------>>   Cannot get the connection... Retrying" );
+
+                        // Wait 500 ms and retry
+                        try
+                        {
+                            Thread.sleep( 500 );
+                        }
+                        catch ( InterruptedException e )
+                        {
+                            connector = null;
+                            LOG.debug( "Interrupted while waiting for connection to establish with server {}:{}",
+                                config.getLdapHost(),
+                                config.getLdapPort(), e );
+                            throw new LdapOtherException( e.getMessage(), e );
+                        }
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+
+        if ( connectionFuture == null )
+        {
+            connector.dispose();
+            throw new InvalidConnectionException( "Cannot connect" );
+        }
+
+        boolean isConnected = connectionFuture.isConnected();
+
+        if ( !isConnected )
+        {
+            // disposing connector if not connected
+            try
+            {
+                close();
+            }
+            catch ( IOException ioe )
+            {
+                // Nothing to do
+            }
+
+            Throwable e = connectionFuture.getException();
+
+            if ( e != null )
+            {
+                StringBuilder message = new StringBuilder( "Cannot connect to the server: " );
+
+                // Special case for UnresolvedAddressException
+                // (most of the time no message is associated with this exception)
+                if ( ( e instanceof UnresolvedAddressException ) && ( e.getMessage() == null ) )
+                {
+                    message.append( "Hostname '" );
+                    message.append( config.getLdapHost() );
+                    message.append( "' could not be resolved." );
+                    throw new InvalidConnectionException( message.toString(), e );
+                }
+
+                // Default case
+                message.append( e.getMessage() );
+                throw new InvalidConnectionException( message.toString(), e );
+            }
+
+            return false;
+        }
+
+        // Get the close future for this session
+        CloseFuture closeFuture = connectionFuture.getSession().getCloseFuture();
+
+        // Add a listener to close the session in the session.
+        closeFuture.addListener( new IoFutureListener<IoFuture>()
+        {
+            public void operationComplete( IoFuture future )
+            {
+                // Process all the waiting operations and cancel them
+                LOG.debug( "received a NoD, closing everything" );
+
+                for ( int messageId : futureMap.keySet() )
+                {
+                    ResponseFuture<?> responseFuture = futureMap.get( messageId );
+                    LOG.debug( "closing {}", responseFuture );
+
+                    responseFuture.cancel();
+
+                    try
+                    {
+                        if ( responseFuture instanceof AddFuture )
+                        {
+                            ( ( AddFuture ) responseFuture ).set( AddNoDResponse.PROTOCOLERROR );
+                        }
+                        else if ( responseFuture instanceof BindFuture )
+                        {
+                            ( ( BindFuture ) responseFuture ).set( BindNoDResponse.PROTOCOLERROR );
+                        }
+                        else if ( responseFuture instanceof CompareFuture )
+                        {
+                            ( ( CompareFuture ) responseFuture ).set( CompareNoDResponse.PROTOCOLERROR );
+                        }
+                        else if ( responseFuture instanceof DeleteFuture )
+                        {
+                            ( ( DeleteFuture ) responseFuture ).set( DeleteNoDResponse.PROTOCOLERROR );
+                        }
+                        else if ( responseFuture instanceof ExtendedFuture )
+                        {
+                            ( ( ExtendedFuture ) responseFuture ).set( ExtendedNoDResponse.PROTOCOLERROR );
+                        }
+                        else if ( responseFuture instanceof ModifyFuture )
+                        {
+                            ( ( ModifyFuture ) responseFuture ).set( ModifyNoDResponse.PROTOCOLERROR );
+                        }
+                        else if ( responseFuture instanceof ModifyDnFuture )
+                        {
+                            ( ( ModifyDnFuture ) responseFuture ).set( ModifyDnNoDResponse.PROTOCOLERROR );
+                        }
+                        else if ( responseFuture instanceof SearchFuture )
+                        {
+                            ( ( SearchFuture ) responseFuture ).set( SearchNoDResponse.PROTOCOLERROR );
+                        }
+                    }
+                    catch ( ExecutionException e )
+                    {
+                        LOG.error( "Error while processing the NoD for {}", responseFuture );
+                    }
+                    catch ( InterruptedException e )
+                    {
+                        LOG.error( "Error while processing the NoD for {}", responseFuture );
+                    }
+
+                    futureMap.remove( messageId );
+                }
+
+                futureMap.clear();
+            }
+        } );
+
+        // Get back the session
+        ldapSession = connectionFuture.getSession();
+        connected.set( true );
+
+        // Store the container into the session if we don't have one
+        @SuppressWarnings("unchecked")
+        LdapMessageContainer<MessageDecorator<? extends Message>> container =
+            ( LdapMessageContainer<MessageDecorator<? extends Message>> ) ldapSession
+                .getAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR );
+
+        if ( container != null )
+        {
+            if ( ( schemaManager != null ) && !( container.getBinaryAttributeDetector() instanceof SchemaBinaryAttributeDetector ) )
+            {
+                container.setBinaryAttributeDetector( new SchemaBinaryAttributeDetector( schemaManager ) );
+            }
+        }
+        else
+        {
+            BinaryAttributeDetector atDetector = new DefaultConfigurableBinaryAttributeDetector();
+
+            if ( schemaManager != null )
+            {
+                atDetector = new SchemaBinaryAttributeDetector( schemaManager );
+            }
+
+            ldapSession.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR,
+                new LdapMessageContainer<MessageDecorator<? extends Message>>( codec, atDetector ) );
+        }
+
+        // Initialize the MessageId
+        messageId.set( 0 );
+
+        // And return
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException
+    {
+        // Close the session
+        if ( ( ldapSession != null ) && connected.get() )
+        {
+            ldapSession.close( true );
+            connected.set( false );
+        }
+
+        // And close the connector if it has been created locally
+        // Release the connector
+        connectorMutex.lock();
+
+        try
+        {
+            if ( connector != null )
+            {
+                connector.dispose();
+                connector = null;
+            }
+        }
+        finally
+        {
+            connectorMutex.unlock();
+        }
+
+        // Reset the messageId
+        messageId.set( 0 );
+    }
+
+
+    //------------------------ The LDAP operations ------------------------//
+    // Add operations                                                      //
+    //---------------------------------------------------------------------//
+    /**
+     * {@inheritDoc}
+     */
+    public void add( Entry entry ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            String msg = "Cannot add an empty entry";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        AddRequest addRequest = new AddRequestImpl();
+        addRequest.setEntry( entry );
+
+        AddResponse addResponse = add( addRequest );
+
+        processResponse( addResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddFuture addAsync( Entry entry ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            String msg = "Cannot add null entry";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        AddRequest addRequest = new AddRequestImpl();
+        addRequest.setEntry( entry );
+
+        return addAsync( addRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddResponse add( AddRequest addRequest ) throws LdapException
+    {
+        if ( addRequest == null )
+        {
+            String msg = "Cannot process a null addRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( addRequest.getEntry() == null )
+        {
+            String msg = "Cannot add a null entry";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        AddFuture addFuture = addAsync( addRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            AddResponse addResponse = addFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( addResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Add failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( addResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Add successful : {}", addResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Add failed : {}", addResponse );
+            }
+
+            return addResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !addFuture.isCancelled() )
+            {
+                abandon( addRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Add failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            // Send an abandon request
+            if ( !addFuture.isCancelled() )
+            {
+                abandon( addRequest.getMessageId() );
+            }
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddFuture addAsync( AddRequest addRequest ) throws LdapException
+    {
+        if ( addRequest == null )
+        {
+            String msg = "Cannot process a null addRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( addRequest.getEntry() == null )
+        {
+            String msg = "Cannot add a null entry";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        checkSession();
+
+        int newId = messageId.incrementAndGet();
+
+        addRequest.setMessageId( newId );
+        AddFuture addFuture = new AddFuture( this, newId );
+        addToFutureMap( newId, addFuture );
+
+        // Send the request to the server
+        writeRequest( addRequest );
+
+        // Ok, done return the future
+        return addFuture;
+    }
+
+
+    //------------------------ The LDAP operations ------------------------//
+
+    /**
+     * {@inheritDoc}
+     */
+    public void abandon( int messageId )
+    {
+        if ( messageId < 0 )
+        {
+            String msg = "Cannot abandon a negative message ID";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        AbandonRequest abandonRequest = new AbandonRequestImpl();
+        abandonRequest.setAbandoned( messageId );
+
+        abandonInternal( abandonRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void abandon( AbandonRequest abandonRequest )
+    {
+        if ( abandonRequest == null )
+        {
+            String msg = "Cannot process a null abandonRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        abandonInternal( abandonRequest );
+    }
+
+
+    /**
+     * Internal AbandonRequest handling
+     */
+    private void abandonInternal( AbandonRequest abandonRequest )
+    {
+        LOG.debug( "Sending request \n{}", abandonRequest );
+
+        int newId = messageId.incrementAndGet();
+        abandonRequest.setMessageId( newId );
+
+        // Send the request to the server
+        ldapSession.write( abandonRequest );
+
+        // remove the associated listener if any
+        int abandonId = abandonRequest.getAbandoned();
+
+        ResponseFuture<? extends Response> rf = getFromFutureMap( abandonId );
+
+        // if the listener is not null, this is a async operation and no need to
+        // send cancel signal on future, sending so will leave a dangling poision object in the corresponding queue
+        // this is a sync operation send cancel signal to the corresponding ResponseFuture
+        if ( rf != null )
+        {
+            LOG.debug( "sending cancel signal to future" );
+            rf.cancel( true );
+        }
+        else
+        {
+            // this shouldn't happen
+            LOG
+                .warn(
+                    "There is no future associated with operation message ID {}, the operation has been completed.",
+                    abandonId );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind() throws LdapException
+    {
+        LOG.debug( "Bind request" );
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( config.getName(), Strings.getBytesUtf8( config.getCredentials() ) );
+
+        BindResponse bindResponse = bind( bindRequest );
+
+        processResponse( bindResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void anonymousBind() throws LdapException
+    {
+        LOG.debug( "Anonymous Bind request" );
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( StringConstants.EMPTY, StringConstants.EMPTY_BYTES );
+
+        BindResponse bindResponse = bind( bindRequest );
+
+        processResponse( bindResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindFuture bindAsync() throws LdapException
+    {
+        LOG.debug( "Asynchronous Bind request" );
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( config.getName(), Strings.getBytesUtf8( config.getCredentials() ) );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindFuture anonymousBindAsync() throws LdapException
+    {
+        LOG.debug( "Anonymous asynchronous Bind request" );
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( StringConstants.EMPTY, StringConstants.EMPTY_BYTES );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /**
+     * Asynchronous unauthenticated authentication bind
+     *
+     * @param name The name we use to authenticate the user. It must be a
+     * valid Dn
+     * @return The BindResponse LdapResponse
+     * @throws LdapException if some error occurred
+     */
+    public BindFuture bindAsync( String name ) throws LdapException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( name, StringConstants.EMPTY_BYTES );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindFuture bindAsync( String name, String credentials ) throws LdapException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // The password must not be empty or null
+        if ( Strings.isEmpty( credentials ) && Strings.isNotEmpty( name ) )
+        {
+            LOG.debug( "The password is missing" );
+            throw new LdapAuthenticationException( "The password is missing" );
+        }
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( name, Strings.getBytesUtf8( credentials ) );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /**
+     * Asynchronous unauthenticated authentication Bind on a server.
+     *
+     * @param name The name we use to authenticate the user. It must be a
+     * valid Dn
+     * @return The BindResponse LdapResponse
+     * @throws LdapException if some error occurred
+     */
+    public BindFuture bindAsync( Dn name ) throws LdapException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( name, StringConstants.EMPTY_BYTES );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindFuture bindAsync( Dn name, String credentials ) throws LdapException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // The password must not be empty or null
+        if ( Strings.isEmpty( credentials ) && ( !Dn.EMPTY_DN.equals( name ) ) )
+        {
+            LOG.debug( "The password is missing" );
+            throw new LdapAuthenticationException( "The password is missing" );
+        }
+
+        // Create the BindRequest
+        BindRequest bindRequest = createBindRequest( name, Strings.getBytesUtf8( credentials ) );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindResponse bind( BindRequest bindRequest ) throws LdapException
+    {
+        if ( bindRequest == null )
+        {
+            String msg = "Cannot process a null bindRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        BindFuture bindFuture = bindAsync( bindRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( bindResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Bind failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                authenticated.set( true );
+
+                // Everything is fine, return the response
+                LOG.debug( "Bind successful : {}", bindResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Bind failed : {}", bindResponse );
+            }
+
+            return bindResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Bind failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * Create a Simple BindRequest ready to be sent.
+     */
+    private BindRequest createBindRequest( String name, byte[] credentials ) throws LdapException
+    {
+        return createBindRequest( name, credentials, null, ( Control[] ) null );
+    }
+
+
+    /**
+     * Create a Simple BindRequest ready to be sent.
+     */
+    private BindRequest createBindRequest( Dn name, byte[] credentials ) throws LdapException
+    {
+        return createBindRequest( name.getName(), credentials, null, ( Control[] ) null );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindFuture bindAsync( BindRequest bindRequest ) throws LdapException
+    {
+        if ( bindRequest == null )
+        {
+            String msg = "Cannot process a null bindRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        // First switch to anonymous state
+        authenticated.set( false );
+
+        // try to connect, if we aren't already connected.
+        connect();
+
+        // establish TLS layer if TLS is enabled and SSL is NOT
+        if ( config.isUseTls() && !config.isUseSsl() )
+        {
+            startTls();
+        }
+
+        // If the session has not been establish, or is closed, we get out immediately
+        checkSession();
+
+        // Update the messageId
+        int newId = messageId.incrementAndGet();
+        bindRequest.setMessageId( newId );
+
+        LOG.debug( "Sending request \n{}", bindRequest );
+
+        // Create a future for this Bind operation
+        BindFuture bindFuture = new BindFuture( this, newId );
+
+        addToFutureMap( newId, bindFuture );
+
+        writeRequest( bindRequest );
+
+        // Ok, done return the future
+        return bindFuture;
+    }
+
+
+    /**
+     * SASL PLAIN Bind on a server.
+     *
+     * @param authcid The Authentication identity
+     * @param credentials The password. It can't be null
+     * @return The BindResponse LdapResponse
+     * @throws {@link LdapException} if some error occurred
+     */
+    public BindResponse bindSaslPlain( String authcid, String credentials ) throws LdapException
+    {
+        return bindSaslPlain( null, authcid, credentials );
+    }
+
+
+    /**
+     * SASL PLAIN Bind on a server.
+     *
+     * @param authzid The Authorization identity
+     * @param authcid The Authentication identity
+     * @param credentials The password. It can't be null
+     * @return The BindResponse LdapResponse
+     * @throws {@link LdapException} if some error occurred
+     */
+    public BindResponse bindSaslPlain( String authzid, String authcid, String credentials ) throws LdapException
+    {
+        LOG.debug( "SASL PLAIN Bind request" );
+
+        // Create the BindRequest
+        SaslPlainRequest saslRequest = new SaslPlainRequest();
+        saslRequest.setAuthorizationId( authzid );
+        saslRequest.setUsername( authcid );
+        saslRequest.setCredentials( credentials );
+
+        BindFuture bindFuture = bindAsync( saslRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( bindResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Bind failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                authenticated.set( true );
+
+                // Everything is fine, return the response
+                LOG.debug( "Bind successful : {}", bindResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Bind failed : {}", bindResponse );
+            }
+
+            return bindResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Bind failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * Bind to the server using a CramMd5Request object.
+     *
+     * @param request The CramMd5Request POJO containing all the needed parameters
+     * @return A LdapResponse containing the result
+     * @throws LdapException if some error occurred
+     */
+    public BindResponse bind( SaslCramMd5Request request ) throws LdapException
+    {
+        if ( request == null )
+        {
+            String msg = "Cannot process a null request";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        BindFuture bindFuture = bindAsync( request );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( bindResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Bind failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                authenticated.set( true );
+
+                // Everything is fine, return the response
+                LOG.debug( "Bind successful : {}", bindResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Bind failed : {}", bindResponse );
+            }
+
+            return bindResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Bind failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * Do an asynchronous bind, based on a SaslPlainRequest.
+     *
+     * @param request The SaslPlainRequest POJO containing all the needed parameters
+     * @return The bind operation's future
+     * @throws LdapException if some error occurred
+     */
+    public BindFuture bindAsync( SaslRequest request )
+        throws LdapException
+    {
+        return bindSasl( request );
+    }
+
+
+    /**
+     * Bind to the server using a DigestMd5Request object.
+     *
+     * @param request The DigestMd5Request POJO containing all the needed parameters
+     * @return A LdapResponse containing the result
+     * @throws LdapException if some error occurred
+     */
+    public BindResponse bind( SaslDigestMd5Request request ) throws LdapException
+    {
+        if ( request == null )
+        {
+            String msg = "Cannot process a null request";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        BindFuture bindFuture = bindAsync( request );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( bindResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Bind failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                authenticated.set( true );
+
+                // Everything is fine, return the response
+                LOG.debug( "Bind successful : {}", bindResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Bind failed : {}", bindResponse );
+            }
+
+            return bindResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Bind failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * Bind to the server using a GssApiRequest object.
+     *
+     * @param request The GssApiRequest POJO containing all the needed parameters
+     * @return A LdapResponse containing the result
+     * @throws LdapException if some error occurred
+     */
+    public BindResponse bind( SaslGssApiRequest request ) throws LdapException
+    {
+        if ( request == null )
+        {
+            String msg = "Cannot process a null request";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        BindFuture bindFuture = bindAsync( request );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( bindResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Bind failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                authenticated.set( true );
+
+                // Everything is fine, return the response
+                LOG.debug( "Bind successful : {}", bindResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Bind failed : {}", bindResponse );
+            }
+
+            return bindResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Bind failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * Do an asynchronous bind, based on a GssApiRequest.
+     *
+     * @param request The GssApiRequest POJO containing all the needed parameters
+     * @return The bind operation's future
+     * @throws LdapException if some error occurred
+     */
+    public BindFuture bindAsync( SaslGssApiRequest request )
+        throws LdapException
+    {
+        // Krb5.conf file
+        if ( request.getKrb5ConfFilePath() != null )
+        {
+            // Using the krb5.conf file provided by the user
+            System.setProperty( "java.security.krb5.conf", request.getKrb5ConfFilePath() );
+        }
+        else if ( ( request.getRealmName() != null ) && ( request.getKdcHost() != null )
+            && ( request.getKdcPort() != 0 ) )
+        {
+            try
+            {
+                // Using a custom krb5.conf we create from the settings provided by the user
+                String krb5ConfPath = createKrb5ConfFile( request.getRealmName(), request.getKdcHost(),
+                    request.getKdcPort() );
+                System.setProperty( "java.security.krb5.conf", krb5ConfPath );
+            }
+            catch ( IOException ioe )
+            {
+                throw new LdapException( ioe );
+            }
+        }
+        else
+        {
+            // Using the system Kerberos configuration
+            System.clearProperty( "java.security.krb5.conf" );
+        }
+
+        // Login Module configuration
+        if ( request.getLoginModuleConfiguration() != null )
+        {
+            // Using the configuration provided by the user
+            Configuration.setConfiguration( request.getLoginModuleConfiguration() );
+        }
+        else
+        {
+            // Using the default configuration
+            Configuration.setConfiguration( new Krb5LoginConfiguration() );
+        }
+
+        try
+        {
+            System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true" );
+            LoginContext loginContext = new LoginContext( request.getLoginContextName(),
+                new SaslCallbackHandler( request ) );
+            loginContext.login();
+
+            final SaslGssApiRequest requetFinal = request;
+            return ( BindFuture ) Subject.doAs( loginContext.getSubject(), new PrivilegedExceptionAction<Object>()
+            {
+                public Object run() throws Exception
+                {
+                    return bindSasl( requetFinal );
+                }
+            } );
+        }
+        catch ( Exception e )
+        {
+            throw new LdapException( e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryCursor search( Dn baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        if ( baseDn == null )
+        {
+            LOG.debug( "received a null dn for a search" );
+            throw new IllegalArgumentException( "The base Dn cannot be null" );
+        }
+
+        // Create a new SearchRequest object
+        SearchRequest searchRequest = new SearchRequestImpl();
+
+        searchRequest.setBase( baseDn );
+        searchRequest.setFilter( filter );
+        searchRequest.setScope( scope );
+        searchRequest.addAttributes( attributes );
+        searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
+
+        // Process the request in blocking mode
+        return new EntryCursorImpl( search( searchRequest ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryCursor search( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        return search( new Dn( baseDn ), filter, scope, attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchFuture searchAsync( Dn baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        // Create a new SearchRequest object
+        SearchRequest searchRequest = new SearchRequestImpl();
+
+        searchRequest.setBase( baseDn );
+        searchRequest.setFilter( filter );
+        searchRequest.setScope( scope );
+        searchRequest.addAttributes( attributes );
+        searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
+
+        // Process the request in blocking mode
+        return searchAsync( searchRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchFuture searchAsync( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        return searchAsync( new Dn( baseDn ), filter, scope, attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchFuture searchAsync( SearchRequest searchRequest ) throws LdapException
+    {
+        if ( searchRequest == null )
+        {
+            String msg = "Cannot process a null searchRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( searchRequest.getBase() == null )
+        {
+            String msg = "Cannot process a searchRequest which base DN is null";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        // If the session has not been establish, or is closed, we get out immediately
+        checkSession();
+
+        int newId = messageId.incrementAndGet();
+        searchRequest.setMessageId( newId );
+
+        if ( searchRequest.isIgnoreReferrals() )
+        {
+            // We want to ignore the referral, inject the ManageDSAIT control in the request
+            searchRequest.addControl( new ManageDsaITImpl() );
+        }
+
+        LOG.debug( "Sending request \n{}", searchRequest );
+
+        SearchFuture searchFuture = new SearchFuture( this, searchRequest.getMessageId() );
+        addToFutureMap( searchRequest.getMessageId(), searchFuture );
+
+        // Send the request to the server
+        writeRequest( searchRequest );
+
+        // Check that the future hasn't be canceled
+        if ( searchFuture.isCancelled() )
+        {
+            // Throw an exception here
+            throw new LdapException( searchFuture.getCause() );
+        }
+
+        // Ok, done return the future
+        return searchFuture;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchCursor search( SearchRequest searchRequest ) throws LdapException
+    {
+        if ( searchRequest == null )
+        {
+            String msg = "Cannot process a null searchRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        SearchFuture searchFuture = searchAsync( searchRequest );
+
+        long searchTimeout = getTimeout( timeout, searchRequest.getTimeLimit() );
+
+        return new SearchCursorImpl( searchFuture, searchTimeout, TimeUnit.MILLISECONDS );
+    }
+
+
+    //------------------------ The LDAP operations ------------------------//
+    // Unbind operations                                                   //
+    //---------------------------------------------------------------------//
+    /**
+     * {@inheritDoc}
+     */
+    public void unBind() throws LdapException
+    {
+        // If the session has not been establish, or is closed, we get out immediately
+        checkSession();
+
+        // Creates the messageID and stores it into the
+        // initial message and the transmitted message.
+        int newId = messageId.incrementAndGet();
+
+        // Create the UnbindRequest
+        UnbindRequest unbindRequest = new UnbindRequestImpl();
+        unbindRequest.setMessageId( newId );
+
+        LOG.debug( "Sending Unbind request \n{}", unbindRequest );
+
+        // Send the request to the server
+        // Use this for logging instead: WriteFuture unbindFuture = ldapSession.write( unbindRequest );
+        WriteFuture unbindFuture = ldapSession.write( unbindRequest );
+
+        //LOG.debug( "waiting for unbindFuture" );
+        unbindFuture.awaitUninterruptibly( timeout );
+        //LOG.debug( "unbindFuture done" );
+
+        authenticated.set( false );
+
+        // Close all the Future for this session
+        for ( ResponseFuture<? extends Response> responseFuture : futureMap.values() )
+        {
+            responseFuture.cancel();
+        }
+
+        // clear the mappings
+        clearMaps();
+
+        //  We now have to close the session
+        try
+        {
+            close();
+        }
+        catch ( IOException e )
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        connected.set( false );
+
+        // Last, not least, reset the MessageId value
+        messageId.set( 0 );
+
+        // And get out
+        LOG.debug( "Unbind successful" );
+    }
+
+
+    /**
+     * Set the connector to use.
+     *
+     * @param connector The connector to use
+     */
+    public void setConnector( IoConnector connector )
+    {
+        this.connector = connector;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTimeOut( long timeout )
+    {
+        if ( timeout <= 0 )
+        {
+            // Set a date in the far future : 100 years
+            this.timeout = 1000L * 60L * 60L * 24L * 365L * 100L;
+        }
+        else
+        {
+            this.timeout = timeout;
+        }
+    }
+
+
+    /**
+     * Handle the exception we got.
+     *
+     * @param session The session we got the exception on
+     * @param cause The exception cause
+     * @throws Exception The t
+     */
+    @Override
+    public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
+    {
+        LOG.warn( cause.getMessage(), cause );
+        session.setAttribute( EXCEPTION_KEY, cause );
+
+        if ( cause instanceof ProtocolEncoderException )
+        {
+            Throwable realCause = ( ( ProtocolEncoderException ) cause ).getCause();
+
+            if ( realCause instanceof MessageEncoderException )
+            {
+                int messageId = ( ( MessageEncoderException ) realCause ).getMessageId();
+
+                ResponseFuture<?> response = futureMap.get( messageId );
+                response.cancel( true );
+                response.setCause( realCause );
+            }
+        }
+
+        session.close( true );
+    }
+
+
+    /**
+     * Check if the message is a NoticeOfDisconnect message
+     */
+    private boolean isNoticeOfDisconnect( Message message )
+    {
+        if ( message instanceof ExtendedResponse )
+        {
+            ExtendedResponse response = ( ExtendedResponse ) message;
+
+            if ( response.getResponseName().equals( NoticeOfDisconnect.EXTENSION_OID ) )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Handle the incoming LDAP messages. This is where we feed the cursor for search
+     * requests, or call the listener.
+     *
+     * @param session The session that received a message
+     * @param message The received message
+     * @throws Exception If there is some error while processing the message
+     */
+    @Override
+    public void messageReceived( IoSession session, Object message ) throws Exception
+    {
+        // Feed the response and store it into the session
+        Message response = ( Message ) message;
+        LOG.debug( "-------> {} Message received <-------", response );
+        int messageId = response.getMessageId();
+
+        // this check is necessary to prevent adding an abandoned operation's
+        // result(s) to corresponding queue
+        ResponseFuture<? extends Response> responseFuture = peekFromFutureMap( messageId );
+
+        boolean isNoD = isNoticeOfDisconnect( response );
+
+        if ( ( responseFuture == null ) && !isNoD )
+        {
+            LOG.info( "There is no future associated with the messageId {}, ignoring the message", messageId );
+            return;
+        }
+
+        if ( isNoD )
+        {
+            // close the session
+            session.close( true );
+
+            return;
+        }
+
+        switch ( response.getType() )
+        {
+            case ADD_RESPONSE:
+                // Transform the response
+                AddResponse addResponse = ( AddResponse ) response;
+
+                AddFuture addFuture = ( AddFuture ) responseFuture;
+
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
+                {
+                    if ( addResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Add successful : {}", addResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Add failed : {}", addResponse );
+                    }
+                }
+
+                // Store the response into the future
+                addFuture.set( addResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case BIND_RESPONSE:
+                // Transform the response
+                BindResponse bindResponse = ( BindResponse ) response;
+
+                BindFuture bindFuture = ( BindFuture ) responseFuture;
+
+                // remove the listener from the listener map
+                if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                {
+                    authenticated.set( true );
+
+                    // Everything is fine, return the response
+                    LOG.debug( "Bind successful : {}", bindResponse );
+                }
+                else
+                {
+                    // We have had an error
+                    LOG.debug( "Bind failed : {}", bindResponse );
+                }
+
+                // Store the response into the future
+                bindFuture.set( bindResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case COMPARE_RESPONSE:
+                // Transform the response
+                CompareResponse compareResponse = ( CompareResponse ) response;
+
+                CompareFuture compareFuture = ( CompareFuture ) responseFuture;
+
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
+                {
+                    if ( compareResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Compare successful : {}", compareResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Compare failed : {}", compareResponse );
+                    }
+                }
+
+                // Store the response into the future
+                compareFuture.set( compareResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case DEL_RESPONSE:
+                // Transform the response
+                DeleteResponse deleteResponse = ( DeleteResponse ) response;
+
+                DeleteFuture deleteFuture = ( DeleteFuture ) responseFuture;
+
+                if ( LOG.isDebugEnabled() )
+                {
+                    if ( deleteResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Delete successful : {}", deleteResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Delete failed : {}", deleteResponse );
+                    }
+                }
+
+                // Store the response into the future
+                deleteFuture.set( deleteResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case EXTENDED_RESPONSE:
+                // Transform the response
+                ExtendedResponse extendedResponse = ( ExtendedResponse ) response;
+
+                ExtendedFuture extendedFuture = ( ExtendedFuture ) responseFuture;
+
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
+                {
+                    if ( extendedResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Extended successful : {}", extendedResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Extended failed : {}", extendedResponse );
+                    }
+                }
+
+                // Store the response into the future
+                extendedFuture.set( extendedResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case INTERMEDIATE_RESPONSE:
+                IntermediateResponse intermediateResponse = null;
+
+                if ( responseFuture instanceof SearchFuture )
+                {
+                    intermediateResponse = new IntermediateResponseImpl( messageId );
+                    addControls( intermediateResponse, response );
+                    ( ( SearchFuture ) responseFuture ).set( intermediateResponse );
+                }
+                else if ( responseFuture instanceof ExtendedFuture )
+                {
+                    intermediateResponse = new IntermediateResponseImpl( messageId );
+                    addControls( intermediateResponse, response );
+                    ( ( ExtendedFuture ) responseFuture ).set( intermediateResponse );
+                }
+                else
+                {
+                    // currently we only support IR for search and extended operations
+                    throw new UnsupportedOperationException( "Unknown ResponseFuture type "
+                        + responseFuture.getClass().getName() );
+                }
+
+                intermediateResponse.setResponseName( ( ( IntermediateResponse ) response ).getResponseName() );
+                intermediateResponse.setResponseValue( ( ( IntermediateResponse ) response ).getResponseValue() );
+
+                break;
+
+            case MODIFY_RESPONSE:
+                // Transform the response
+                ModifyResponse modifyResponse = ( ModifyResponse ) response;
+
+                ModifyFuture modifyFuture = ( ModifyFuture ) responseFuture;
+
+                if ( LOG.isDebugEnabled() )
+                {
+                    if ( modifyResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "ModifyFuture successful : {}", modifyResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "ModifyFuture failed : {}", modifyResponse );
+                    }
+                }
+
+                // Store the response into the future
+                modifyFuture.set( modifyResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case MODIFYDN_RESPONSE:
+                // Transform the response
+                ModifyDnResponse modifyDnResponse = ( ModifyDnResponse ) response;
+
+                ModifyDnFuture modifyDnFuture = ( ModifyDnFuture ) responseFuture;
+
+                if ( LOG.isDebugEnabled() )
+                {
+                    if ( modifyDnResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "ModifyDN successful : {}", modifyDnResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "ModifyDN failed : {}", modifyDnResponse );
+                    }
+                }
+
+                // Store the response into the future
+                modifyDnFuture.set( modifyDnResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case SEARCH_RESULT_DONE:
+                // Store the response into the responseQueue
+                SearchResultDone searchResultDone = ( SearchResultDone ) response;
+
+                SearchFuture searchFuture = ( SearchFuture ) responseFuture;
+
+                if ( LOG.isDebugEnabled() )
+                {
+                    if ( searchResultDone.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Search successful : {}", searchResultDone );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Search failed : {}", searchResultDone );
+                    }
+                }
+
+                // Store the response into the future
+                searchFuture.set( searchResultDone );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case SEARCH_RESULT_ENTRY:
+                // Store the response into the responseQueue
+                SearchResultEntry searchResultEntry = ( SearchResultEntry ) response;
+
+                if ( schemaManager != null )
+                {
+                    searchResultEntry.setEntry( new DefaultEntry( schemaManager, searchResultEntry.getEntry() ) );
+                }
+
+                searchFuture = ( SearchFuture ) responseFuture;
+
+                if ( LOG.isDebugEnabled() )
+                {
+                    LOG.debug( "Search entry found : {}", searchResultEntry );
+                }
+
+                // Store the response into the future
+                searchFuture.set( searchResultEntry );
+
+                break;
+
+            case SEARCH_RESULT_REFERENCE:
+                // Store the response into the responseQueue
+                SearchResultReference searchResultReference = ( SearchResultReference ) response;
+
+                searchFuture = ( SearchFuture ) responseFuture;
+
+                if ( LOG.isDebugEnabled() )
+                {
+                    LOG.debug( "Search reference found : {}", searchResultReference );
+                }
+
+                // Store the response into the future
+                searchFuture.set( searchResultReference );
+
+                break;
+
+            default:
+                throw new IllegalStateException( "Unexpected response type " + response.getType() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( Entry entry, ModificationOperation modOp ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            LOG.debug( "received a null entry for modification" );
+            throw new IllegalArgumentException( "Entry to be modified cannot be null" );
+        }
+
+        ModifyRequest modReq = new ModifyRequestImpl();
+        modReq.setName( entry.getDn() );
+
+        Iterator<Attribute> itr = entry.iterator();
+
+        while ( itr.hasNext() )
+        {
+            modReq.addModification( itr.next(), modOp );
+        }
+
+        ModifyResponse modifyResponse = modify( modReq );
+
+        processResponse( modifyResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( Dn dn, Modification... modifications ) throws LdapException
+    {
+        if ( dn == null )
+        {
+            LOG.debug( "received a null dn for modification" );
+            throw new IllegalArgumentException( "The Dn to be modified cannot be null" );
+        }
+
+        if ( ( modifications == null ) || ( modifications.length == 0 ) )
+        {
+            String msg = "Cannot process a ModifyRequest without any modification";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        ModifyRequest modReq = new ModifyRequestImpl();
+        modReq.setName( dn );
+
+        for ( Modification modification : modifications )
+        {
+            modReq.addModification( modification );
+        }
+
+        ModifyResponse modifyResponse = modify( modReq );
+
+        processResponse( modifyResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( String dn, Modification... modifications ) throws LdapException
+    {
+        modify( new Dn( dn ), modifications );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyResponse modify( ModifyRequest modRequest ) throws LdapException
+    {
+        if ( modRequest == null )
+        {
+            String msg = "Cannot process a null modifyRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        ModifyFuture modifyFuture = modifyAsync( modRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            ModifyResponse modifyResponse = modifyFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( modifyResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Modify failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( modifyResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Modify successful : {}", modifyResponse );
+            }
+            else
+            {
+                if ( modifyResponse instanceof ModifyNoDResponse )
+                {
+                    // A NoticeOfDisconnect : deserves a special treatment
+                    throw new LdapException( modifyResponse.getLdapResult().getDiagnosticMessage() );
+                }
+
+                // We have had an error
+                LOG.debug( "Modify failed : {}", modifyResponse );
+            }
+
+            return modifyResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !modifyFuture.isCancelled() )
+            {
+                abandon( modRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            // Send an abandon request
+            if ( !modifyFuture.isCancelled() )
+            {
+                abandon( modRequest.getMessageId() );
+            }
+
+            throw new LdapException( ie.getMessage(), ie );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyFuture modifyAsync( ModifyRequest modRequest ) throws LdapException
+    {
+        if ( modRequest == null )
+        {
+            String msg = "Cannot process a null modifyRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( modRequest.getName() == null )
+        {
+            String msg = "Cannot process a modifyRequest which DN is null";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        checkSession();
+
+        int newId = messageId.incrementAndGet();
+        modRequest.setMessageId( newId );
+
+        ModifyFuture modifyFuture = new ModifyFuture( this, newId );
+        addToFutureMap( newId, modifyFuture );
+
+        // Send the request to the server
+        writeRequest( modRequest );
+
+        // Ok, done return the future
+        return modifyFuture;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( String entryDn, String newRdn ) throws LdapException
+    {
+        rename( entryDn, newRdn, true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( Dn entryDn, Rdn newRdn ) throws LdapException
+    {
+        rename( entryDn, newRdn, true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( String entryDn, String newRdn, boolean deleteOldRdn ) throws LdapException
+    {
+        if ( entryDn == null )
+        {
+            String msg = "Cannot process a rename of a null Dn";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( newRdn == null )
+        {
+            String msg = "Cannot process a rename with a null Rdn";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        try
+        {
+            rename( new Dn( entryDn ), new Rdn( newRdn ), deleteOldRdn );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+            throw new LdapException( e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( Dn entryDn, Rdn newRdn, boolean deleteOldRdn ) throws LdapException
+    {
+        if ( entryDn == null )
+        {
+            String msg = "Cannot process a rename of a null Dn";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( newRdn == null )
+        {
+            String msg = "Cannot process a rename with a null Rdn";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        ModifyDnRequest modDnRequest = new ModifyDnRequestImpl();
+        modDnRequest.setName( entryDn );
+        modDnRequest.setNewRdn( newRdn );
+        modDnRequest.setDeleteOldRdn( deleteOldRdn );
+
+        ModifyDnResponse modifyDnResponse = modifyDn( modDnRequest );
+
+        processResponse( modifyDnResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void move( String entryDn, String newSuperiorDn ) throws LdapException
+    {
+        if ( entryDn == null )
+        {
+            String msg = "Cannot process a move of a null Dn";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( newSuperiorDn == null )
+        {
+            String msg = "Cannot process a move to a null newSuperior";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        try
+        {
+            move( new Dn( entryDn ), new Dn( newSuperiorDn ) );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+            throw new LdapException( e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void move( Dn entryDn, Dn newSuperiorDn ) throws LdapException
+    {
+        if ( entryDn == null )
+        {
+            String msg = "Cannot process a move of a null Dn";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( newSuperiorDn == null )
+        {
+            String msg = "Cannot process a move to a null newSuperior";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        ModifyDnRequest modDnRequest = new ModifyDnRequestImpl();
+        modDnRequest.setName( entryDn );
+        modDnRequest.setNewSuperior( newSuperiorDn );
+
+        //TODO not setting the below value is resulting in error
+        modDnRequest.setNewRdn( entryDn.getRdn() );
+
+        ModifyDnResponse modifyDnResponse = modifyDn( modDnRequest );
+
+        processResponse( modifyDnResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( Dn entryDn, Dn newDn ) throws LdapException
+    {
+        moveAndRename( entryDn, newDn, true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( String entryDn, String newDn ) throws LdapException
+    {
+        moveAndRename( new Dn( entryDn ), new Dn( newDn ), true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( Dn entryDn, Dn newDn, boolean deleteOldRdn ) throws LdapException
+    {
+        // Check the parameters first
+        if ( entryDn == null )
+        {
+            throw new IllegalArgumentException( "The entry Dn must not be null" );
+        }
+
+        if ( entryDn.isRootDse() )
+        {
+            throw new IllegalArgumentException( "The RootDSE cannot be moved" );
+        }
+
+        if ( newDn == null )
+        {
+            throw new IllegalArgumentException( "The new Dn must not be null" );
+        }
+
+        if ( newDn.isRootDse() )
+        {
+            throw new IllegalArgumentException( "The RootDSE cannot be the target" );
+        }
+
+        // Create the request
+        ModifyDnRequest modDnRequest = new ModifyDnRequestImpl();
+        modDnRequest.setName( entryDn );
+        modDnRequest.setNewRdn( newDn.getRdn() );
+        
+        // Check if we really need to specify newSuperior.
+        // newSuperior is optional [RFC4511, section 4.9]
+        // Some servers (e.g. OpenDJ 2.6) require a special privilege if
+        // newSuperior is specified even if it is the same as the old one. Therefore let's not
+        // specify it if we do not need it. This is better interoperability. 
+        Dn newDnParent = newDn.getParent();
+        if ( newDnParent != null && !newDnParent.equals( entryDn.getParent() ) )
+        {
+            modDnRequest.setNewSuperior( newDnParent );
+        }
+        
+        modDnRequest.setDeleteOldRdn( deleteOldRdn );
+
+        ModifyDnResponse modifyDnResponse = modifyDn( modDnRequest );
+
+        processResponse( modifyDnResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( String entryDn, String newDn, boolean deleteOldRdn ) throws LdapException
+    {
+        moveAndRename( new Dn( entryDn ), new Dn( newDn ), true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest ) throws LdapException
+    {
+        if ( modDnRequest == null )
+        {
+            String msg = "Cannot process a null modDnRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        ModifyDnFuture modifyDnFuture = modifyDnAsync( modDnRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            ModifyDnResponse modifyDnResponse = modifyDnFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( modifyDnResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "ModifyDN failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( modifyDnResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "ModifyDN successful : {}", modifyDnResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Modify failed : {}", modifyDnResponse );
+            }
+
+            return modifyDnResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !modifyDnFuture.isCancelled() )
+            {
+                abandon( modDnRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            // Send an abandon request
+            if ( !modifyDnFuture.isCancelled() )
+            {
+                abandon( modDnRequest.getMessageId() );
+            }
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnFuture modifyDnAsync( ModifyDnRequest modDnRequest ) throws LdapException
+    {
+        if ( modDnRequest == null )
+        {
+            String msg = "Cannot process a null modDnRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( modDnRequest.getName() == null )
+        {
+            String msg = "Cannot process a modifyRequest which DN is null";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( ( modDnRequest.getNewSuperior() == null ) && ( modDnRequest.getNewRdn() == null ) )
+        {
+            String msg = "Cannot process a modifyRequest which new superior and new Rdn are null";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        checkSession();
+
+        int newId = messageId.incrementAndGet();
+        modDnRequest.setMessageId( newId );
+
+        ModifyDnFuture modifyDnFuture = new ModifyDnFuture( this, newId );
+        addToFutureMap( newId, modifyDnFuture );
+
+        // Send the request to the server
+        writeRequest( modDnRequest );
+
+        // Ok, done return the future
+        return modifyDnFuture;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete( String dn ) throws LdapException
+    {
+        delete( new Dn( dn ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete( Dn dn ) throws LdapException
+    {
+        DeleteRequest deleteRequest = new DeleteRequestImpl();
+        deleteRequest.setName( dn );
+
+        DeleteResponse deleteResponse = delete( deleteRequest );
+
+        processResponse( deleteResponse );
+    }
+
+
+    /**
+     * deletes the entry with the given Dn, and all its children
+     *
+     * @param dn the target entry's Dn
+     * @return operation's response
+     * @throws LdapException If the Dn is not valid or if the deletion failed
+     */
+    public void deleteTree( Dn dn ) throws LdapException
+    {
+        String treeDeleteOid = "1.2.840.113556.1.4.805";
+
+        if ( isControlSupported( treeDeleteOid ) )
+        {
+            DeleteRequest deleteRequest = new DeleteRequestImpl();
+            deleteRequest.setName( dn );
+            deleteRequest.addControl( new OpaqueControl( treeDeleteOid ) );
+            DeleteResponse deleteResponse = delete( deleteRequest );
+
+            processResponse( deleteResponse );
+        }
+        else
+        {
+            String msg = "The subtreeDelete control (1.2.840.113556.1.4.805) is not supported by the server\n"
+                + " The deletion has been aborted";
+            LOG.error( msg );
+            throw new LdapException( msg );
+        }
+    }
+
+
+    /**
+     * deletes the entry with the given Dn, and all its children
+     *
+     * @param dn the target entry's Dn as a String
+     * @return operation's response
+     * @throws LdapException If the Dn is not valid or if the deletion failed
+     */
+    public void deleteTree( String dn ) throws LdapException
+    {
+        try
+        {
+            String treeDeleteOid = "1.2.840.113556.1.4.805";
+            Dn newDn = new Dn( dn );
+
+            if ( isControlSupported( treeDeleteOid ) )
+            {
+                DeleteRequest deleteRequest = new DeleteRequestImpl();
+                deleteRequest.setName( newDn );
+                deleteRequest.addControl( new OpaqueControl( treeDeleteOid ) );
+                DeleteResponse deleteResponse = delete( deleteRequest );
+
+                processResponse( deleteResponse );
+            }
+            else
+            {
+                String msg = "The subtreeDelete control (1.2.840.113556.1.4.805) is not supported by the server\n"
+                    + " The deletion has been aborted";
+                LOG.error( msg );
+                throw new LdapException( msg );
+            }
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+            throw new LdapException( e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteResponse delete( DeleteRequest deleteRequest ) throws LdapException
+    {
+        if ( deleteRequest == null )
+        {
+            String msg = "Cannot process a null deleteRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        DeleteFuture deleteFuture = deleteAsync( deleteRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            DeleteResponse delResponse = deleteFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( delResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Delete failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( delResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Delete successful : {}", delResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Delete failed : {}", delResponse );
+            }
+
+            return delResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !deleteFuture.isCancelled() )
+            {
+                abandon( deleteRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Del failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            // Send an abandon request
+            if ( !deleteFuture.isCancelled() )
+            {
+                abandon( deleteRequest.getMessageId() );
+            }
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteFuture deleteAsync( DeleteRequest deleteRequest ) throws LdapException
+    {
+        if ( deleteRequest == null )
+        {
+            String msg = "Cannot process a null deleteRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( deleteRequest.getName() == null )
+        {
+            String msg = "Cannot process a deleteRequest which DN is null";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        checkSession();
+
+        int newId = messageId.incrementAndGet();
+
+        deleteRequest.setMessageId( newId );
+
+        DeleteFuture deleteFuture = new DeleteFuture( this, newId );
+        addToFutureMap( newId, deleteFuture );
+
+        // Send the request to the server
+        writeRequest( deleteRequest );
+
+        // Ok, done return the future
+        return deleteFuture;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( String dn, String attributeName, String value ) throws LdapException
+    {
+        return compare( new Dn( dn ), attributeName, value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( String dn, String attributeName, byte[] value ) throws LdapException
+    {
+        return compare( new Dn( dn ), attributeName, value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( String dn, String attributeName, Value<?> value ) throws LdapException
+    {
+        return compare( new Dn( dn ), attributeName, value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( Dn dn, String attributeName, String value ) throws LdapException
+    {
+        CompareRequest compareRequest = new CompareRequestImpl();
+        compareRequest.setName( dn );
+        compareRequest.setAttributeId( attributeName );
+        compareRequest.setAssertionValue( value );
+
+        CompareResponse compareResponse = compare( compareRequest );
+
+        return processResponse( compareResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( Dn dn, String attributeName, byte[] value ) throws LdapException
+    {
+        CompareRequest compareRequest = new CompareRequestImpl();
+        compareRequest.setName( dn );
+        compareRequest.setAttributeId( attributeName );
+        compareRequest.setAssertionValue( value );
+
+        CompareResponse compareResponse = compare( compareRequest );
+
+        return processResponse( compareResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( Dn dn, String attributeName, Value<?> value ) throws LdapException
+    {
+        CompareRequest compareRequest = new CompareRequestImpl();
+        compareRequest.setName( dn );
+        compareRequest.setAttributeId( attributeName );
+
+        if ( value.isHumanReadable() )
+        {
+            compareRequest.setAssertionValue( value.getString() );
+        }
+        else
+        {
+            compareRequest.setAssertionValue( value.getBytes() );
+        }
+
+        CompareResponse compareResponse = compare( compareRequest );
+
+        return processResponse( compareResponse );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareResponse compare( CompareRequest compareRequest ) throws LdapException
+    {
+        if ( compareRequest == null )
+        {
+            String msg = "Cannot process a null compareRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        CompareFuture compareFuture = compareAsync( compareRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            CompareResponse compareResponse = compareFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( compareResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Compare failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( compareResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Compare successful : {}", compareResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Compare failed : {}", compareResponse );
+            }
+
+            return compareResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !compareFuture.isCancelled() )
+            {
+                abandon( compareRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Compare failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            // Send an abandon request
+            if ( !compareFuture.isCancelled() )
+            {
+                abandon( compareRequest.getMessageId() );
+            }
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareFuture compareAsync( CompareRequest compareRequest ) throws LdapException
+    {
+        if ( compareRequest == null )
+        {
+            String msg = "Cannot process a null compareRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( compareRequest.getName() == null )
+        {
+            String msg = "Cannot process a compareRequest which DN is null";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        checkSession();
+
+        int newId = messageId.incrementAndGet();
+
+        compareRequest.setMessageId( newId );
+
+        CompareFuture compareFuture = new CompareFuture( this, newId );
+        addToFutureMap( newId, compareFuture );
+
+        // Send the request to the server
+        writeRequest( compareRequest );
+
+        // Ok, done return the future
+        return compareFuture;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse extended( String oid ) throws LdapException
+    {
+        return extended( oid, null );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse extended( String oid, byte[] value ) throws LdapException
+    {
+        try
+        {
+            return extended( Oid.fromString( oid ), value );
+        }
+        catch ( DecoderException e )
+        {
+            String msg = "Failed to decode the OID " + oid;
+            LOG.error( msg );
+            throw new LdapException( msg, e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse extended( Oid oid ) throws LdapException
+    {
+        return extended( oid, null );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse extended( Oid oid, byte[] value ) throws LdapException
+    {
+        ExtendedRequest extendedRequest =
+            LdapApiServiceFactory.getSingleton().newExtendedRequest( oid.toString(), value );
+        return extended( extendedRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse extended( ExtendedRequest extendedRequest ) throws LdapException
+    {
+        if ( extendedRequest == null )
+        {
+            String msg = "Cannot process a null extendedRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        ExtendedFuture extendedFuture = extendedAsync( extendedRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            // Get the response, blocking
+            ExtendedResponse response = ( ExtendedResponse ) extendedFuture
+                .get( timeout, TimeUnit.MILLISECONDS );
+
+            if ( response == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Extended failed : timeout occurred" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+
+            if ( response.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Extended successful : {}", response );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Extended failed : {}", response );
+            }
+
+            // Get back the response. It's still an opaque response
+            if ( Strings.isEmpty( response.getResponseName() ) )
+            {
+                response.setResponseName( extendedRequest.getRequestName() );
+            }
+
+            // Decode the payload now
+            ExtendedResponseDecorator<?> decoratedResponse = codec.decorate( response );
+
+            return decoratedResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !extendedFuture.isCancelled() )
+            {
+                abandon( extendedRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Extended failed : timeout occurred" );
+            throw new LdapException( TIME_OUT_ERROR, te );
+        }
+        catch ( Exception ie )
+        {
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+
+            // Send an abandon request
+            if ( !extendedFuture.isCancelled() )
+            {
+                abandon( extendedRequest.getMessageId() );
+            }
+
+            throw new LdapException( NO_RESPONSE_ERROR, ie );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedFuture extendedAsync( ExtendedRequest extendedRequest ) throws LdapException
+    {
+        if ( extendedRequest == null )
+        {
+            String msg = "Cannot process a null extendedRequest";
+            LOG.debug( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        checkSession();
+
+        int newId = messageId.incrementAndGet();
+
+        extendedRequest.setMessageId( newId );
+        ExtendedFuture extendedFuture = new ExtendedFuture( this, newId );
+        addToFutureMap( newId, extendedFuture );
+
+        // Send the request to the server
+        writeRequest( extendedRequest );
+
+        // Ok, done return the future
+        return extendedFuture;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean exists( String dn ) throws LdapException
+    {
+        return exists( new Dn( dn ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean exists( Dn dn ) throws LdapException
+    {
+        try
+        {
+            Entry entry = lookup( dn, SchemaConstants.NO_ATTRIBUTE_ARRAY );
+
+            return entry != null;
+        }
+        catch ( LdapNoPermissionException lnpe )
+        {
+            // Special case to deal with insufficient permissions
+            return false;
+        }
+        catch ( LdapException le )
+        {
+            throw le;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry getRootDse() throws LdapException
+    {
+        return lookup( Dn.ROOT_DSE, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry getRootDse( String... attributes ) throws LdapException
+    {
+        return lookup( Dn.ROOT_DSE, attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( Dn dn ) throws LdapException
+    {
+        return lookup( dn, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( String dn ) throws LdapException
+    {
+        return lookup( dn, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( Dn dn, String... attributes ) throws LdapException
+    {
+        return lookup( dn, null, attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( Dn dn, Control[] controls, String... attributes ) throws LdapException
+    {
+        Entry entry = null;
+
+        try
+        {
+            SearchRequest searchRequest = new SearchRequestImpl();
+
+            searchRequest.setBase( dn );
+            searchRequest.setFilter( LdapConstants.OBJECT_CLASS_STAR );
+            searchRequest.setScope( SearchScope.OBJECT );
+            searchRequest.addAttributes( attributes );
+            searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
+
+            if ( ( controls != null ) && ( controls.length > 0 ) )
+            {
+                searchRequest.addAllControls( controls );
+            }
+
+            Cursor<Response> cursor = search( searchRequest );
+
+            // Read the response
+            if ( cursor.next() )
+            {
+                // cursor will always hold SearchResultEntry objects cause there is no ManageDsaITControl passed with search request
+                entry = ( ( SearchResultEntry ) cursor.get() ).getEntry();
+            }
+
+            // Pass through the SaerchResultDone, or stop
+            // if we have other responses
+            cursor.next();
+
+            // And close the cursor
+            cursor.close();
+        }
+        catch ( CursorException e )
+        {
+            throw new LdapException( e );
+        }
+
+        return entry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( String dn, String... attributes ) throws LdapException
+    {
+        return lookup( new Dn( dn ), null, attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( String dn, Control[] controls, String... attributes ) throws LdapException
+    {
+        return lookup( new Dn( dn ), controls, attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isControlSupported( String controlOID ) throws LdapException
+    {
+        return getSupportedControls().contains( controlOID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getSupportedControls() throws LdapException
+    {
+        if ( supportedControls != null )
+        {
+            return supportedControls;
+        }
+
+        if ( rootDse == null )
+        {
+            fetchRootDSE();
+        }
+
+        supportedControls = new ArrayList<String>();
+
+        Attribute attr = rootDse.get( SchemaConstants.SUPPORTED_CONTROL_AT );
+
+        if ( attr == null )
+        {
+            // Unlikely. Perhaps the server does not respond properly to "+" attribute query
+            // (such as 389ds server). So let's try again and let's be more explicit.
+            fetchRootDSE( SchemaConstants.ALL_USER_ATTRIBUTES, 
+                SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.SUPPORTED_CONTROL_AT );
+            attr = rootDse.get( SchemaConstants.SUPPORTED_CONTROL_AT );
+            if ( attr == null )
+            {
+                return supportedControls;
+            }
+        }
+        
+        for ( Value<?> value : attr )
+        {
+            supportedControls.add( value.getString() );
+        }
+
+        return supportedControls;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void loadSchema() throws LdapException
+    {
+        loadSchema( new DefaultSchemaLoader( this ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void loadSchemaRelaxed() throws LdapException
+    {
+        loadSchema( new DefaultSchemaLoader( this, true ) );
+    }
+
+
+    /**
+     * loads schema using the specified schema loader
+     *
+     * @param loader the {@link SchemaLoader} to be used to load schema
+     * @throws LdapException
+     */
+    public void loadSchema( SchemaLoader loader ) throws LdapException
+    {
+        try
+        {
+            SchemaManager tmp = new DefaultSchemaManager( loader );
+
+            tmp.loadAllEnabled();
+
+            if ( !tmp.getErrors().isEmpty() && loader.isStrict() )
+            {
+                String msg = "there are errors while loading the schema";
+                LOG.error( msg + " {}", tmp.getErrors() );
+                throw new LdapException( msg );
+            }
+
+            schemaManager = tmp;
+
+            // Change the container's BinaryDetector
+            ldapSession.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR,
+                new LdapMessageContainer<MessageDecorator<? extends Message>>( codec,
+                    new SchemaBinaryAttributeDetector( schemaManager ) ) );
+
+        }
+        catch ( LdapException le )
+        {
+            throw le;
+        }
+        catch ( Exception e )
+        {
+            LOG.error( "failed to load the schema", e );
+            throw new LdapException( e );
+        }
+    }
+
+
+    /**
+     * parses the given schema file present in OpenLDAP schema format
+     * and adds all the SchemaObjects present in it to the SchemaManager
+     *
+     * @param schemaFile the schema file in OpenLDAP schema format
+     * @throws LdapException in case of any errors while parsing
+     */
+    public void addSchema( File schemaFile ) throws LdapException
+    {
+        try
+        {
+            if ( schemaManager == null )
+            {
+                loadSchema();
+            }
+
+            OpenLdapSchemaParser olsp = new OpenLdapSchemaParser();
+            olsp.setQuirksMode( true );
+            olsp.parse( schemaFile );
+
+            Registries registries = schemaManager.getRegistries();
+            List<Throwable> errors = new ArrayList<Throwable>();
+
+            for ( AttributeType atType : olsp.getAttributeTypes() )
+            {
+                registries.buildReference( errors, atType );
+                registries.getAttributeTypeRegistry().register( atType );
+            }
+
+            for ( ObjectClass oc : olsp.getObjectClassTypes() )
+            {
+                registries.buildReference( errors, oc );
+                registries.getObjectClassRegistry().register( oc );
+            }
+
+            LOG.info( "successfully loaded the schema from file {}", schemaFile.getAbsolutePath() );
+        }
+        catch ( Exception e )
+        {
+            LOG.error( "failed to load the schema from file {}", schemaFile.getAbsolutePath() );
+            throw new LdapException( e );
+        }
+    }
+
+
+    /**
+     * @see #addSchema(File)
+     */
+    public void addSchema( String schemaFileName ) throws LdapException
+    {
+        addSchema( new File( schemaFileName ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaManager getSchemaManager()
+    {
+        return schemaManager;
+    }
+
+
+    /**
+     * fetches the rootDSE from the server
+     * @throws LdapException
+     */
+    private void fetchRootDSE( String... explicitAttributes ) throws LdapException
+    {
+        EntryCursor cursor = null;
+
+        String[] attributes = explicitAttributes;
+        if ( attributes.length == 0 )
+        {
+            attributes = new String[]
+                { SchemaConstants.ALL_USER_ATTRIBUTES, SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES };
+        }
+        
+        try
+        {
+            cursor = search( "", LdapConstants.OBJECT_CLASS_STAR, SearchScope.OBJECT, attributes );
+            if ( cursor.next() )
+            {
+                rootDse = cursor.get();
+            }
+            else
+            {
+                throw new LdapException( "Search for root DSE returned no entry" );
+            }
+        }
+        catch ( Exception e )
+        {
+            String msg = "Failed to fetch the RootDSE";
+            LOG.error( msg );
+            throw new LdapException( msg, e );
+        }
+        finally
+        {
+            if ( cursor != null )
+            {
+                try
+                {
+                    cursor.close();
+                }
+                catch ( Exception e )
+                {
+                    LOG.error( "Failed to close open cursor", e );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * gives the configuration information of the connection
+     *
+     * @return the configuration of the connection
+     */
+    public LdapConnectionConfig getConfig()
+    {
+        return config;
+    }
+
+
+    private void addControls( Message codec, Message message )
+    {
+        Map<String, Control> controls = codec.getControls();
+
+        if ( controls != null )
+        {
+            for ( Control cc : controls.values() )
+            {
+                if ( cc == null )
+                {
+                    continue;
+                }
+
+                message.addControl( cc );
+            }
+        }
+    }
+
+
+    /**
+     * removes the Objects associated with the given message ID
+     * from future and response queue maps
+     *
+     * @param msgId id of the message
+     */
+    private void removeFromFutureMaps( int msgId )
+    {
+        getFromFutureMap( msgId );
+    }
+
+
+    /**
+     * clears the async listener, responseQueue and future mapppings to the corresponding request IDs
+     */
+    private void clearMaps()
+    {
+        futureMap.clear();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean doesFutureExistFor( int messageId )
+    {
+        ResponseFuture<?> responseFuture = futureMap.get( messageId );
+        return responseFuture != null;
+    }
+
+
+    /**
+     * Adds the connection closed event listener.
+     *
+     * @param ccListener the connection closed listener
+     */
+    public void addConnectionClosedEventListener( ConnectionClosedEventListener ccListener )
+    {
+        if ( conCloseListeners == null )
+        {
+            conCloseListeners = new ArrayList<ConnectionClosedEventListener>();
+        }
+
+        conCloseListeners.add( ccListener );
+    }
+
+
+    /**
+     * This method is called when a new session is created. We will store some
+     * informations that the session will need to process incoming requests.
+     * 
+     * @param session the newly created session
+     */
+    public void sessionCreated( IoSession session ) throws Exception
+    {
+        // Last, store the message container
+        LdapMessageContainer<? extends MessageDecorator<Message>> ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<Message>>(
+                codec, config.getBinaryAttributeDetector() );
+
+        session.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR, ldapMessageContainer );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void sessionClosed( IoSession session ) throws Exception
+    {
+        // no need to handle if this session was closed by the user
+        if ( !connected.get() )
+        {
+            return;
+        }
+
+        ldapSession.close( true );
+        connected.set( false );
+        // Reset the messageId
+        messageId.set( 0 );
+
+        connectorMutex.lock();
+
+        try
+        {
+            if ( connector != null )
+            {
+                connector.dispose();
+                connector = null;
+            }
+        }
+        finally
+        {
+            connectorMutex.unlock();
+        }
+
+        clearMaps();
+
+        if ( conCloseListeners != null )
+        {
+            LOG.debug( "notifying the registered ConnectionClosedEventListeners.." );
+
+            for ( ConnectionClosedEventListener listener : conCloseListeners )
+            {
+                listener.connectionClosed();
+            }
+        }
+    }
+
+
+    /**
+     * Sends the StartTLS extended request to server and adds a security layer
+     * upon receiving a response with successful result. Note that we will use
+     * the default LDAP connection.
+     *
+     * @throws LdapException
+     */
+    public void startTls() throws LdapException
+    {
+        try
+        {
+            if ( config.isUseSsl() )
+            {
+                throw new LdapException( "Cannot use TLS when the useSsl flag is set true in the configuration" );
+            }
+
+            checkSession();
+
+            IoFilter sslFilter = ldapSession.getFilterChain().get( SSL_FILTER_KEY );
+            if ( sslFilter != null )
+            {
+                LOG.debug( "LDAP session already using startTLS" );
+                return;
+            }
+
+            ExtendedResponse resp = extended( new StartTlsRequestImpl() );
+            LdapResult result = resp.getLdapResult();
+
+            if ( result.getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                addSslFilter();
+            }
+            else
+            {
+                throw new LdapOperationException( result.getResultCode(), result.getDiagnosticMessage() );
+            }
+        }
+        catch ( LdapException e )
+        {
+            throw e;
+        }
+        catch ( Exception e )
+        {
+            throw new LdapException( e );
+        }
+    }
+
+
+    /**
+     * adds {@link SslFilter} to the IOConnector or IOSession's filter chain
+     */
+    private void addSslFilter() throws LdapException
+    {
+        try
+        {
+            SSLContext sslContext = SSLContext.getInstance( config.getSslProtocol() );
+            sslContext.init( config.getKeyManagers(), config.getTrustManagers(), config.getSecureRandom() );
+
+            SslFilter sslFilter = new SslFilter( sslContext, true );
+            sslFilter.setUseClientMode( true );
+
+            // Configure the enabled cipher lists
+            String[] enabledCipherSuite = config.getEnabledCipherSuites();
+
+            if ( ( enabledCipherSuite != null ) && ( enabledCipherSuite.length != 0 ) )
+            {
+                sslFilter.setEnabledCipherSuites( enabledCipherSuite );
+            }
+
+            // Be sure we disable SSLV3
+            String[] enabledProtocols = config.getEnabledProtocols();
+
+            if ( ( enabledProtocols != null ) && ( enabledProtocols.length != 0 ) )
+            {
+                sslFilter.setEnabledProtocols( enabledProtocols );
+            }
+            else
+            {
+                // Default to TLS
+                sslFilter.setEnabledProtocols( new String[]
+                    { "TLSv1", "TLSv1.1", "TLSv1.2" } );
+            }
+
+            // for LDAPS
+            if ( ldapSession == null )
+            {
+                connector.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
+            }
+            else
+            // for StartTLS
+            {
+                ldapSession.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
+            }
+        }
+        catch ( Exception e )
+        {
+            String msg = "Failed to initialize the SSL context";
+            LOG.error( msg, e );
+            throw new LdapException( msg, e );
+        }
+    }
+
+
+    /**
+     * Process the SASL Bind. It's a dialog with the server, we will send a first BindRequest, receive
+     * a response and the, if this response is a challenge, continue by sending a new BindRequest with
+     * the requested informations.
+     */
+    private BindFuture bindSasl( SaslRequest saslRequest ) throws LdapException
+    {
+        // First switch to anonymous state
+        authenticated.set( false );
+
+        // try to connect, if we aren't already connected.
+        connect();
+
+        // If the session has not been establish, or is closed, we get out immediately
+        checkSession();
+
+        BindRequest bindRequest = createBindRequest( ( String ) null, null,
+            saslRequest.getSaslMechanism(), saslRequest
+                .getControls() );
+
+        // Update the messageId
+        int newId = messageId.incrementAndGet();
+        bindRequest.setMessageId( newId );
+
+        LOG.debug( "Sending request \n{}", bindRequest );
+
+        // Create a future for this Bind operation
+        BindFuture bindFuture = new BindFuture( this, newId );
+
+        // Store it in the future Map
+        addToFutureMap( newId, bindFuture );
+
+        try
+        {
+            BindResponse bindResponse = null;
+            byte[] response = null;
+            ResultCodeEnum result = null;
+
+            // Creating a map for SASL properties
+            Map<String, Object> properties = new HashMap<String, Object>();
+
+            // Quality of Protection SASL property
+            if ( saslRequest.getQualityOfProtection() != null )
+            {
+                properties.put( Sasl.QOP, saslRequest.getQualityOfProtection().getValue() );
+            }
+
+            // Security Strength SASL property
+            if ( saslRequest.getSecurityStrength() != null )
+            {
+                properties.put( Sasl.STRENGTH, saslRequest.getSecurityStrength().getValue() );
+            }
+
+            // Mutual Authentication SASL property
+            if ( saslRequest.isMutualAuthentication() )
+            {
+                properties.put( Sasl.SERVER_AUTH, "true" );
+            }
+
+            // Creating a SASL Client
+            SaslClient sc = Sasl.createSaslClient(
+                new String[]
+                    { bindRequest.getSaslMechanism() },
+                saslRequest.getAuthorizationId(),
+                "ldap",
+                config.getLdapHost(),
+                properties,
+                new SaslCallbackHandler( saslRequest ) );
+
+            // If the SaslClient wasn't created, that means we can't create the SASL client
+            // for the requested mechanism. We then produce an Exception
+            if ( sc == null )
+            {
+                String message = "Cannot find a SASL factory for the " + bindRequest.getSaslMechanism() + " mechanism";
+                LOG.error( message );
+                throw new LdapException( message );
+            }
+
+            // Corner case : the SASL mech might send an initial challenge, and we have to
+            // deal with it immediately.
+            if ( sc.hasInitialResponse() )
+            {
+                byte[] challengeResponse = sc.evaluateChallenge( new byte[0] );
+
+                // Stores the challenge's response, and send it to the server
+                bindRequest.setCredentials( challengeResponse );
+                writeRequest( bindRequest );
+
+                // Get the server's response, blocking
+                bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+                if ( bindResponse == null )
+                {
+                    // We didn't received anything : this is an error
+                    LOG.error( "bind failed : timeout occurred" );
+                    throw new LdapException( TIME_OUT_ERROR );
+                }
+
+                result = bindResponse.getLdapResult().getResultCode();
+            }
+            else
+            {
+                // Copy the bindRequest without setting the credentials
+                BindRequest bindRequestCopy = new BindRequestImpl();
+                bindRequestCopy.setMessageId( newId );
+
+                bindRequestCopy.setName( bindRequest.getName() );
+                bindRequestCopy.setSaslMechanism( bindRequest.getSaslMechanism() );
+                bindRequestCopy.setSimple( bindRequest.isSimple() );
+                bindRequestCopy.setVersion3( bindRequest.getVersion3() );
+                bindRequestCopy.addAllControls( bindRequest.getControls().values().toArray( new Control[0] ) );
+
+                writeRequest( bindRequestCopy );
+
+                bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+                if ( bindResponse == null )
+                {
+                    // We didn't received anything : this is an error
+                    LOG.error( "bind failed : timeout occurred" );
+                    throw new LdapException( TIME_OUT_ERROR );
+                }
+
+                result = bindResponse.getLdapResult().getResultCode();
+            }
+
+            while ( !sc.isComplete()
+                && ( ( result == ResultCodeEnum.SASL_BIND_IN_PROGRESS ) || ( result == ResultCodeEnum.SUCCESS ) ) )
+            {
+                response = sc.evaluateChallenge( bindResponse.getServerSaslCreds() );
+
+                if ( result == ResultCodeEnum.SUCCESS )
+                {
+                    if ( response != null )
+                    {
+                        throw new LdapException( "protocol error" );
+                    }
+                }
+                else
+                {
+                    newId = messageId.incrementAndGet();
+                    bindRequest.setMessageId( newId );
+                    bindRequest.setCredentials( response );
+
+                    addToFutureMap( newId, bindFuture );
+
+                    writeRequest( bindRequest );
+
+                    bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+                    if ( bindResponse == null )
+                    {
+                        // We didn't received anything : this is an error
+                        LOG.error( "bind failed : timeout occurred" );
+                        throw new LdapException( TIME_OUT_ERROR );
+                    }
+
+                    result = bindResponse.getLdapResult().getResultCode();
+                }
+            }
+
+            bindFuture.set( bindResponse );
+
+            return bindFuture;
+        }
+        catch ( LdapException e )
+        {
+            throw e;
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+            throw new LdapException( e );
+        }
+    }
+
+
+    /**
+     * a reusable code block to be used in various bind methods
+     */
+    private void writeRequest( Request request ) throws LdapException
+    {
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( request );
+
+        long localTimeout = timeout;
+
+        while ( localTimeout > 0 )
+        {
+            // Wait only 100 ms
+            boolean done = writeFuture.awaitUninterruptibly( 100 );
+
+            if ( done )
+            {
+                return;
+            }
+
+            // Wait for the message to be sent to the server
+            if ( !ldapSession.isConnected() )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Message failed : something wrong has occurred" );
+
+                Exception exception = ( Exception ) ldapSession.removeAttribute( EXCEPTION_KEY );
+
+                if ( exception != null )
+                {
+                    if ( exception instanceof LdapException )
+                    {
+                        throw ( LdapException ) exception;
+                    }
+                    else
+                    {
+                        throw new InvalidConnectionException( exception.getMessage() );
+                    }
+                }
+
+                throw new InvalidConnectionException( "Error while sending some message : the session has been closed" );
+            }
+
+            localTimeout -= 100;
+        }
+
+        LOG.error( "TimeOut has occurred" );
+        throw new LdapException( TIME_OUT_ERROR );
+    }
+
+
+    /**
+     * method to write the kerberos config in the standard MIT kerberos format
+     *
+     * This is required cause the JGSS api is not able to recognize the port value set
+     * in the system property java.security.krb5.kdc this issue makes it impossible
+     * to set a kdc running non standard ports (other than 88)
+     *
+     * e.g localhost:6088
+     *
+     * <pre>
+     * [libdefaults]
+     *     default_realm = EXAMPLE.COM
+     *
+     * [realms]
+     *     EXAMPLE.COM = {
+     *         kdc = localhost:6088
+     *     }
+     * </pre>
+     *
+     * @return the full path of the config file
+     */
+    private String createKrb5ConfFile( String realmName, String kdcHost, int kdcPort ) throws IOException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "[libdefaults]" )
+            .append( "\n\t" );
+        sb.append( "default_realm = " )
+            .append( realmName )
+            .append( "\n" );
+
+        sb.append( "[realms]" )
+            .append( "\n\t" );
+
+        sb.append( realmName )
+            .append( " = {" )
+            .append( "\n\t\t" );
+        sb.append( "kdc = " )
+            .append( kdcHost )
+            .append( ":" )
+            .append( kdcPort )
+            .append( "\n\t}\n" );
+
+        File krb5Conf = File.createTempFile( "client-api-krb5", ".conf" );
+        krb5Conf.deleteOnExit();
+        FileWriter fw = new FileWriter( krb5Conf );
+
+        try
+        {
+            fw.write( sb.toString() );
+        }
+        finally
+        {
+            fw.close();
+        }
+
+        String krb5ConfPath = krb5Conf.getAbsolutePath();
+
+        LOG.debug( "krb 5 config file created at {}", krb5ConfPath );
+
+        return krb5ConfPath;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BinaryAttributeDetector getBinaryAttributeDetector()
+    {
+        if ( config != null )
+        {
+            return config.getBinaryAttributeDetector();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector )
+    {
+        if ( config != null )
+        {
+            config.setBinaryAttributeDetector( binaryAttributeDetector );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdifAnonymizer.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdifAnonymizer.java
new file mode 100644
index 0000000..70ff999
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdifAnonymizer.java
@@ -0,0 +1,593 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.ldap.model.ldif.anonymizer.Anonymizer;
+import org.apache.directory.api.ldap.model.ldif.anonymizer.BinaryAnonymizer;
+import org.apache.directory.api.ldap.model.ldif.anonymizer.IntegerAnonymizer;
+import org.apache.directory.api.ldap.model.ldif.anonymizer.StringAnonymizer;
+import org.apache.directory.api.ldap.model.name.Ava;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DnSyntaxChecker;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+
+
+/**
+ * Anonymize the content of a LDIF file.
+ * 
+ * We will replace the values of the defined attributes with random chars. There are a default
+ * list of attributes that are going to be anonymized :
+ * <ul>
+ * <li>userPassword</li>
+ * <li>displayName</li>
+ * <li>givenName</li>
+ * <li>surName</li>
+ * <li>homePhone</li>
+ * <li>homePostalAddress</li>
+ * <li>jpegPhoto</li>
+ * <li>labeledURI</li>
+ * <li>mail</li>
+ * <li>manager</li>
+ * <li>mobile</li>
+ * <li>organizationName</li>
+ * <li>pager</li>
+ * <li>photo</li>
+ * <li>secretary</li>
+ * <li>uid</li>
+ * <li>userCertificate</li>
+ * <li>userPKCS12</li>
+ * <li>userSMIMECertificate</li>
+ * <li>x500UniqueIdentifier</li>
+ * <li>carLicense</li>
+ * <li>host</li>
+ * <li>locality</li>
+ * <li>organizationName</li>
+ * <li>organizationalUnitName</li>
+ * <li>seelAlso</li>
+ * <li>homeDirectory</li>
+ * <li>uidNumber</li>
+ * <li>gidNumber</li>
+ * <li>commonName</li>
+ * <li>gecos</li>
+ * <li>description</li>
+ * <li>memberUid</li>
+ * </ul>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifAnonymizer
+{
+    /** The map that stores the anonymized values associated to the original value */
+    Map<Value<?>, Value<?>> valueMap = new HashMap<Value<?>, Value<?>>();
+    
+    /** The map of AttributeType'sOID we want to anonymize. They are all associated with anonymizers */
+    Map<String, Anonymizer> attributeAnonymizers = new HashMap<String, Anonymizer>();
+    
+    /** The list of existing NamingContexts */
+    Set<Dn> namingContexts = new HashSet<Dn>();
+
+    /** The schemaManager */
+    SchemaManager schemaManager;
+
+    /**
+     * Creates a default instance of LdifAnonymizer. The list of anonymized attribute
+     * is set to a default value.
+     *
+     */
+    public LdifAnonymizer()
+    {
+        try
+        {
+            schemaManager = new DefaultSchemaManager();
+        }
+        catch ( Exception e )
+        {
+            // Todo : we need a schemaManager
+            System.out.println( "Missing a SchemaManager !" );
+            System.exit( -1 );
+        }
+
+        init();
+    }
+    
+
+    /**
+     * Creates a default instance of LdifAnonymizer. The list of anonymized attribute
+     * is set to a default value.
+     * 
+     * @param schemaManager The SchemaManager instance we will use
+     */
+    public LdifAnonymizer( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+
+        init();
+    }
+    
+    
+    /**
+     * Initialize the anonymizer, filling the maps we use.
+     */
+    private void init()
+    {
+        // Load the anonymizers
+        attributeAnonymizers.put( SchemaConstants.CAR_LICENSE_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.CN_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.DESCRIPTION_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.DISPLAY_NAME_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.GECOS_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.GID_NUMBER_AT_OID,
+            new IntegerAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.GIVENNAME_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.HOME_DIRECTORY_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.HOME_PHONE_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.HOME_POSTAL_ADDRESS_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.HOST_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.HOUSE_IDENTIFIER_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.JPEG_PHOTO_AT_OID,
+            new BinaryAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.LABELED_URI_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.LOCALITY_NAME_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.MAIL_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.MANAGER_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.MEMBER_UID_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.MOBILE_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.ORGANIZATION_NAME_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.ORGANIZATIONAL_UNIT_NAME_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.PAGER_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.POSTAL_ADDRESS_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.PHOTO_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.SECRETARY_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers
+            .put( SchemaConstants.SEE_ALSO_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.SN_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.TELEPHONE_NUMBER_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.UID_AT_OID, new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.UID_NUMBER_AT_OID,
+            new IntegerAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.USER_CERTIFICATE_AT_OID,
+            new StringAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.USER_PASSWORD_AT_OID,
+            new BinaryAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.USER_PKCS12_AT_OID,
+            new BinaryAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.USER_SMIME_CERTIFICATE_AT_OID,
+            new BinaryAnonymizer() );
+        attributeAnonymizers.put( SchemaConstants.X500_UNIQUE_IDENTIFIER_AT_OID,
+            new BinaryAnonymizer() );
+    }
+    
+    
+    /**
+     * Add an attributeType that has to be anonymized
+     *
+     * @param attributeType the AttributeType that has to be anonymized
+     * @throws LdapException If the attributeType cannot be added
+     */
+    public void addAnonAttributeType( AttributeType attributeType ) throws LdapException
+    {
+        schemaManager.add( attributeType );
+        LdapSyntax syntax = attributeType.getSyntax();
+        
+        if ( syntax.isHumanReadable() )
+        {
+            if ( syntax.getOid().equals( SchemaConstants.INTEGER_SYNTAX ) )
+            {
+                attributeAnonymizers.put( attributeType.getOid(), new IntegerAnonymizer() );
+            }
+            else
+            {
+                attributeAnonymizers.put( attributeType.getOid(), new StringAnonymizer() );
+            }
+        }
+        else
+        {
+            attributeAnonymizers.put( attributeType.getOid(), new BinaryAnonymizer() );
+        }
+    }
+    
+    
+    /**
+     * Remove an attributeType that has to be anonymized
+     *
+     * @param attributeType the AttributeType that we don't want to be anonymized
+     * @throws LdapException If the attributeType cannot be removed
+     */
+    public void removeAnonAttributeType( AttributeType attributeType ) throws LdapException
+    {
+        attributeAnonymizers.remove( attributeType );
+    }
+    
+    
+    /**
+     * Add a new NamingContext
+     *
+     * @param dn The naming context to add
+     * @throws LdapInvalidDnException if it's an invalid naming context
+     */
+    public void addNamingContext( String dn ) throws LdapInvalidDnException
+    {
+        Dn namingContext = new Dn( schemaManager, dn );
+        namingContexts.add( namingContext );
+    }
+
+    
+    /**
+     * Anonymize an AVA
+     */
+    private Ava anonymizeAva( Ava ava ) throws LdapInvalidDnException, LdapInvalidAttributeValueException
+    {
+        Value<?> value = ava.getValue();
+        AttributeType attributeType = ava.getAttributeType();
+        Value<?> anonymizedValue = valueMap.get( value );
+        Ava anonymizedAva = null;
+        
+        if ( anonymizedValue == null )
+        {
+            Attribute attribute = new DefaultAttribute( attributeType );
+            attribute.add( value );
+            Anonymizer anonymizer = attributeAnonymizers.get( attribute.getAttributeType() );
+
+            if ( value.isHumanReadable() )
+            {
+                if ( anonymizer == null )
+                {
+                    anonymizedAva = new Ava( schemaManager, attributeType.getName(), value.getString() );
+                }
+                else
+                {
+                    Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, attribute );
+
+                    anonymizedAva = new Ava( schemaManager, attributeType.getName(), anonymizedAttribute.getString() );
+                }
+            }
+            else
+            {
+                if ( anonymizer == null )
+                {
+                    anonymizedAva = new Ava( schemaManager, attributeType.getName(), value.getBytes() );
+                }
+                else
+                {
+                    Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, attribute );
+
+                    anonymizedAva = new Ava( schemaManager, attributeType.getName(), anonymizedAttribute.getBytes() );
+                }
+            }
+        }
+        else
+        {
+            if ( value.isHumanReadable() )
+            {
+                anonymizedAva = new Ava( schemaManager, attributeType.getName(), anonymizedValue.getString() );
+            }
+            else
+            {
+                anonymizedAva = new Ava( schemaManager, attributeType.getName(), anonymizedValue.getBytes() );
+            }
+        }
+
+        return anonymizedAva;
+    }
+    
+    
+    /**
+     * Anonymize the entry's DN
+     */
+    private Dn anonymizeDn( Dn entryDn ) throws LdapException
+    {
+        // Search for the naming context
+        Dn descendant = entryDn;
+        Dn namingContext = null;
+        
+        for ( Dn nc : namingContexts )
+        {
+            if ( entryDn.isDescendantOf( nc ) )
+            { 
+                descendant = entryDn.getDescendantOf( nc );
+                namingContext = nc;
+                break;
+            }
+        }
+
+        Rdn[] anonymizedRdns = new Rdn[entryDn.size()];
+        int rdnPos = entryDn.size() - 1;
+
+        // Copy the naming contex
+        for ( Rdn ncRdn : namingContext )
+        {
+            anonymizedRdns[rdnPos] = ncRdn;
+            rdnPos--;
+        }
+        
+        // Iterate on all the RDN
+        for ( Rdn rdn : descendant )
+        {
+            Ava[] anonymizedAvas = new Ava[rdn.size()];
+            int pos = 0;
+            
+            // Iterate on the AVAs
+            for ( Ava ava : rdn )
+            {
+                Ava anonymizedAva = anonymizeAva( ava );
+                anonymizedAvas[pos] = anonymizedAva;
+                pos++;
+            }
+
+            Rdn anonymizedRdn = new Rdn( schemaManager, anonymizedAvas );
+            anonymizedRdns[rdnPos] = anonymizedRdn;
+            rdnPos--;
+        }
+        
+        Dn anonymizedDn = new Dn( schemaManager, anonymizedRdns );
+        
+        return anonymizedDn;
+    }
+
+
+    /**
+     * Anonymize a LDIF 
+     * 
+     * @param ldif The ldif content to anonymize
+     * @return an anonymized version of the given ldif
+     * @throws LdapException If we got some LDAP related exception
+     * @throws IOException If we had some issue during some IO operations
+     */
+    public String anonymizeFile( String ldifFile ) throws LdapException, IOException
+    {
+        LdifReader ldifReader = new LdifReader( schemaManager );
+
+        try
+        {
+            List<LdifEntry> entries = ldifReader.parseLdifFile( ldifFile );
+            StringBuilder result = new StringBuilder();
+
+            for ( LdifEntry ldifEntry : entries )
+            {
+                Entry entry = ldifEntry.getEntry();
+                Entry newEntry = new DefaultEntry( schemaManager );
+
+                // Process the DN first
+                Dn entryDn = entry.getDn();
+                
+                Dn anonymizedDn = anonymizeDn( entryDn );
+
+                // Now, process the entry
+                for ( Attribute attribute : entry )
+                {
+                    AttributeType attributeType = attribute.getAttributeType();
+                    
+                    if ( attributeType.getSyntax().getSyntaxChecker() instanceof DnSyntaxChecker )
+                    {
+                        for ( Value<?> dnValue : attribute )
+                        {
+                            Dn dn = new Dn( schemaManager, dnValue.getString() );
+                            Dn newdDn = anonymizeDn( dn );
+                            newEntry.add( attributeType, newdDn.toString() );
+                        }
+                    }
+                    else
+                    {
+                        int h = attribute.getAttributeType().hashCode();
+                        Anonymizer anonymizer = attributeAnonymizers.get( attribute.getAttributeType().getOid() );
+    
+                        if ( anonymizer == null )
+                        {
+                            newEntry.add( attribute );
+                        }
+                        else
+                        {
+                            Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, attribute );
+    
+                            newEntry.add( anonymizedAttribute );
+                        }
+                    }
+                }
+
+                newEntry.setDn( anonymizedDn );
+                result.append( LdifUtils.convertToLdif( newEntry ) );
+                result.append( "\n" );
+            }
+
+            return result.toString();
+        }
+        finally
+        {
+            ldifReader.close();
+        }
+    }
+
+
+    /**
+     * Anonymize a LDIF 
+     * 
+     * @param ldif The ldif content to anonymize
+     * @return an anonymized version of the given ldif
+     * @throws LdapException If we got some LDAP related exception
+     * @throws IOException If we had some issue during some IO operations
+     */
+    public String anonymize( String ldif ) throws LdapException, IOException
+    {
+        LdifReader ldifReader = new LdifReader( schemaManager );
+
+        try
+        {
+            List<LdifEntry> entries = ldifReader.parseLdif( ldif );
+            StringBuilder result = new StringBuilder();
+
+            for ( LdifEntry ldifEntry : entries )
+            {
+                Entry entry = ldifEntry.getEntry();
+                Entry newEntry = new DefaultEntry( schemaManager );
+
+                // Process the DN first
+                Dn entryDn = entry.getDn();
+                
+                Dn anonymizedDn = anonymizeDn( entryDn );
+
+                // Now, process the entry
+                for ( Attribute attribute : entry )
+                {
+                    AttributeType attributeType = attribute.getAttributeType();
+                    
+                    if ( attributeType.getSyntax().getSyntaxChecker() instanceof DnSyntaxChecker )
+                    {
+                        for ( Value<?> dnValue : attribute )
+                        {
+                            Dn dn = new Dn( schemaManager, dnValue.getString() );
+                            Dn newdDn = anonymizeDn( dn );
+                            newEntry.add( attributeType, newdDn.toString() );
+                        }
+                    }
+                    else
+                    {
+                        Anonymizer anonymizer = attributeAnonymizers.get( attribute.getAttributeType() );
+    
+                        if ( anonymizer == null )
+                        {
+                            newEntry.add( attribute );
+                        }
+                        else
+                        {
+                            Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, attribute );
+    
+                            newEntry.add( anonymizedAttribute );
+                        }
+                    }
+                }
+
+                newEntry.setDn( anonymizedDn );
+                result.append( LdifUtils.convertToLdif( newEntry ) );
+                result.append( "\n" );
+            }
+
+            return result.toString();
+        }
+        finally
+        {
+            ldifReader.close();
+        }
+    }
+
+
+    /**
+     * @return the valueMap
+     */
+    public Map<Value<?>, Value<?>> getValueMap()
+    {
+        return valueMap;
+    }
+
+
+    /**
+     * @param valueMap the valueMap to set
+     */
+    public void setValueMap( Map<Value<?>, Value<?>> valueMap )
+    {
+        this.valueMap = valueMap;
+    }
+
+
+    /**
+     * The entry point, when used as a standalone application.
+     *
+     * @param args Contains the arguments : the file to convert. The anonymized 
+     * LDIF will be printed on stdout
+     */
+    public static void main( String[] args ) throws IOException, LdapException
+    {
+        if ( ( args == null ) || ( args.length < 1 ) )
+        {
+            System.out.println( "No file to anonymize" );
+            return;
+        }
+
+        LdifAnonymizer anonymizer = new LdifAnonymizer();
+
+        BufferedReader br = new BufferedReader( new FileReader( args[0] ) );
+        String ldifString = null;
+
+        try
+        {
+            StringBuilder sb = new StringBuilder();
+            String line = br.readLine();
+
+            while ( line != null )
+            {
+                sb.append( line );
+                sb.append( System.lineSeparator() );
+                line = br.readLine();
+            }
+
+            ldifString = sb.toString();
+        }
+        finally
+        {
+            br.close();
+        }
+
+        String result = anonymizer.anonymize( ldifString );
+
+        System.out.println( result );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LookupLdapConnectionValidator.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LookupLdapConnectionValidator.java
new file mode 100755
index 0000000..8e85d0e
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LookupLdapConnectionValidator.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * An implementation of {@link LdapConnectionValidator} that attempts a simple
+ * lookup on the rootDSE.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LookupLdapConnectionValidator implements LdapConnectionValidator
+{
+    /**
+     * Returns true if <code>connection</code> is connected, authenticated, and
+     * a lookup on the rootDSE returns a non-null response.
+     * 
+     * @param connection The connection to validate
+     * @return True, if the connection is still valid
+     */
+    public boolean validate( LdapConnection connection )
+    {
+        try
+        {
+            return connection.isConnected()
+                && connection.isAuthenticated()
+                && ( connection.lookup( Dn.ROOT_DSE, SchemaConstants.NO_ATTRIBUTE ) != null );
+        }
+        catch ( LdapException e )
+        {
+            return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/MonitoringLdapConnection.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/MonitoringLdapConnection.java
new file mode 100755
index 0000000..857c302
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/MonitoringLdapConnection.java
@@ -0,0 +1,195 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * 
+ * TODO MonitoringLdapConnection.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class MonitoringLdapConnection extends LdapConnectionWrapper
+{
+    private static final Oid START_TLS_OID;
+
+    static
+    {
+        try
+        {
+            START_TLS_OID = Oid.fromString( StartTlsRequest.EXTENSION_OID );
+        }
+        catch ( DecoderException de )
+        {
+            throw new IllegalStateException( "StartTlsRequest.EXTENSION_OID is not a valid oid... This cant happen", de );
+        }
+    }
+
+    private boolean bindCalled = false;
+    private boolean startTlsCalled = false;
+
+
+    MonitoringLdapConnection( LdapConnection connection )
+    {
+        super( connection );
+    }
+
+
+    public boolean bindCalled()
+    {
+        return bindCalled;
+    }
+
+
+    public void resetMonitors()
+    {
+        bindCalled = false;
+        startTlsCalled = false;
+    }
+
+
+    public boolean startTlsCalled()
+    {
+        return startTlsCalled;
+    }
+
+
+    @Override
+    public void bind() throws LdapException
+    {
+        connection.bind();
+        bindCalled = true;
+    }
+
+
+    @Override
+    public void anonymousBind() throws LdapException
+    {
+        connection.anonymousBind();
+        bindCalled = true;
+    }
+
+
+    @Override
+    public void bind( String name ) throws LdapException
+    {
+        connection.bind( name );
+        bindCalled = true;
+    }
+
+
+    @Override
+    public void bind( String name, String credentials ) throws LdapException
+    {
+        connection.bind( name, credentials );
+        bindCalled = true;
+    }
+
+
+    @Override
+    public void bind( Dn name ) throws LdapException
+    {
+        connection.bind( name );
+        bindCalled = true;
+    }
+
+
+    @Override
+    public void bind( Dn name, String credentials ) throws LdapException
+    {
+        connection.bind( name, credentials );
+        bindCalled = true;
+    }
+
+
+    @Override
+    public BindResponse bind( BindRequest bindRequest ) throws LdapException
+    {
+        BindResponse response = connection.bind( bindRequest );
+        bindCalled = true;
+        return response;
+    }
+
+
+    @Override
+    public ExtendedResponse extended( String oid ) throws LdapException
+    {
+        if ( StartTlsRequest.EXTENSION_OID.equals( oid ) )
+        {
+            startTlsCalled = true;
+        }
+        return connection.extended( oid );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( String oid, byte[] value ) throws LdapException
+    {
+        if ( StartTlsRequest.EXTENSION_OID.equals( oid ) )
+        {
+            startTlsCalled = true;
+        }
+        return connection.extended( oid, value );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( Oid oid ) throws LdapException
+    {
+        if ( START_TLS_OID.equals( oid ) )
+        {
+            startTlsCalled = true;
+        }
+        return connection.extended( oid );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( Oid oid, byte[] value ) throws LdapException
+    {
+        if ( START_TLS_OID.equals( oid ) )
+        {
+            startTlsCalled = true;
+        }
+        return connection.extended( oid, value );
+    }
+
+
+    @Override
+    public ExtendedResponse extended( ExtendedRequest extendedRequest ) throws LdapException
+    {
+        if ( extendedRequest.hasControl( StartTlsRequest.EXTENSION_OID ) )
+        {
+            startTlsCalled = true;
+        }
+        return connection.extended( extendedRequest );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/NoVerificationTrustManager.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/NoVerificationTrustManager.java
new file mode 100644
index 0000000..0678088
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/NoVerificationTrustManager.java
@@ -0,0 +1,71 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.X509TrustManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An implementation of {@link X509TrustManager} which trusts the given certificates without verifying them.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NoVerificationTrustManager implements X509TrustManager
+{
+
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( NoVerificationTrustManager.class );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkClientTrusted( X509Certificate[] x509Certificates, String s ) throws CertificateException
+    {
+        LOG.debug( "checkClientTrusted {}", x509Certificates[0] );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkServerTrusted( X509Certificate[] x509Certificates, String s ) throws CertificateException
+    {
+        LOG.debug( "checkServerTrusted {}", x509Certificates[0] );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public X509Certificate[] getAcceptedIssuers()
+    {
+        return new X509Certificate[0];
+    }
+
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslCramMd5Request.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslCramMd5Request.java
new file mode 100644
index 0000000..635d220
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslCramMd5Request.java
@@ -0,0 +1,41 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
+
+
+/**
+ * Holds the data required to complete the CRAM-MD5 SASL operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SaslCramMd5Request extends SaslRequest
+{
+    /**
+     * Creates a new instance of SaslCramMd5Request.
+     */
+    public SaslCramMd5Request()
+    {
+        super( SupportedSaslMechanisms.CRAM_MD5 );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslDigestMd5Request.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslDigestMd5Request.java
new file mode 100644
index 0000000..c64f4c8
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslDigestMd5Request.java
@@ -0,0 +1,51 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
+
+
+/**
+ * Holds the data required to complete the DIGEST-MD5 SASL operation
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SaslDigestMd5Request extends SaslRequest
+{
+    /**
+     * Creates a new instance of SaslDigestMd5Request.
+     */
+    public SaslDigestMd5Request()
+    {
+        super( SupportedSaslMechanisms.DIGEST_MD5 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    // Overriding the visibility of the method to public
+    public void setRealmName( String realmName )
+    {
+        super.setRealmName( realmName );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslGssApiRequest.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslGssApiRequest.java
new file mode 100644
index 0000000..1f23be0
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslGssApiRequest.java
@@ -0,0 +1,179 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import javax.security.auth.login.Configuration;
+
+import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
+
+
+/**
+ * Holds the data required to complete the GSS-API SASL operation
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SaslGssApiRequest extends SaslRequest
+{
+    /** The KDC host*/
+    protected String kdcHost;
+
+    /** The KDC port */
+    protected int kdcPort = 0;
+
+    /** The krb5.conf file absolute path */
+    protected String krb5ConfFilePath;
+
+    /** The name for the {@link javax.security.auth.login.LoginContext} object */
+    protected String loginContextName = "ldapnetworkconnection";
+
+    /** The {@link javax.security.auth.login.Configuration} object for LoginModule */
+    protected Configuration loginModuleConfiguration;
+
+
+    /**
+     * Creates a new instance of SaslGssApiRequest.
+     */
+    public SaslGssApiRequest()
+    {
+        super( SupportedSaslMechanisms.GSSAPI );
+    }
+
+
+    /**
+     * Gets the KDC host.
+     *
+     * @return the KDC host
+     */
+    public String getKdcHost()
+    {
+        return kdcHost;
+    }
+
+
+    /**
+     * Gets the KDC port.
+     *
+     * @return the KDC port
+     */
+    public int getKdcPort()
+    {
+        return kdcPort;
+    }
+
+
+    /**
+     * Gets the (absolute) path to the 'krb5.conf' file.
+     *
+     * @return the (absolute) path to the 'krb5.conf' file
+     */
+    public String getKrb5ConfFilePath()
+    {
+        return krb5ConfFilePath;
+    }
+
+
+    /**
+     * Gets the name for the {@link javax.security.auth.login.LoginContext} object. 
+     * 
+     * @return the name for the {@link javax.security.auth.login.LoginContext} object
+     */
+    public String getLoginContextName()
+    {
+        return loginContextName;
+    }
+
+
+    /**
+     * Gets the {@link javax.security.auth.login.Configuration} object for Login Module.
+     *
+     * @return the {@link javax.security.auth.login.Configuration} object for Login Module
+     */
+    public Configuration getLoginModuleConfiguration()
+    {
+        return loginModuleConfiguration;
+    }
+
+
+    /**
+     * Sets the KDC host.
+     *
+     * @param kdcHost the KDC host
+     */
+    public void setKdcHost( String kdcHost )
+    {
+        this.kdcHost = kdcHost;
+    }
+
+
+    /**
+     * Sets the KDC port.
+     *
+     * @param kdcPort the KDC port
+     */
+    public void setKdcPort( int kdcPort )
+    {
+        this.kdcPort = kdcPort;
+    }
+
+
+    /**
+     * Sets the (absolute) path to the 'krb5.conf' file.
+     *
+     * @param krb5ConfFilePath the (absolute) path to the 'krb5.conf' file
+     */
+    public void setKrb5ConfFilePath( String krb5ConfFilePath )
+    {
+        this.krb5ConfFilePath = krb5ConfFilePath;
+    }
+
+
+    /**
+     * Sets the name for the {@link javax.security.auth.login.LoginContext} object.
+     * 
+     * @param loginContextName the name for the {@link javax.security.auth.login.LoginContext} object
+     */
+    public void setLoginContextName( String loginContextName )
+    {
+        this.loginContextName = loginContextName;
+    }
+
+
+    /**
+     * Sets the {@link javax.security.auth.login.Configuration} object for Login Module.
+     *
+     * @param loginModuleConfiguration the {@link javax.security.auth.login.Configuration} object for Login Module
+     */
+    public void setLoginModuleConfiguration( Configuration loginModuleConfiguration )
+    {
+        this.loginModuleConfiguration = loginModuleConfiguration;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    // Overriding the visibility of the method to public
+    public void setRealmName( String realmName )
+    {
+        super.setRealmName( realmName );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslPlainRequest.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslPlainRequest.java
new file mode 100644
index 0000000..9823346
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslPlainRequest.java
@@ -0,0 +1,41 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
+
+
+/**
+ * Holds the data required to complete the SASL PLAIN  operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SaslPlainRequest extends SaslRequest
+{
+    /**
+     * Creates a new instance of SaslPlainRequest.
+     */
+    public SaslPlainRequest()
+    {
+        super( SupportedSaslMechanisms.PLAIN );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslRequest.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslRequest.java
new file mode 100644
index 0000000..1b6e16e
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SaslRequest.java
@@ -0,0 +1,307 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.constants.SaslQoP;
+import org.apache.directory.api.ldap.model.constants.SaslSecurityStrength;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Holds the data required to complete the SASL operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class SaslRequest
+{
+    /** The mechanism used to decode user identity */
+    protected String saslMechanism;
+
+    /** The list of controls */
+    protected List<Control> controls = new ArrayList<Control>();
+
+    /** The username */
+    protected String username;
+
+    /** The credentials */
+    protected byte[] credentials;
+
+    /** The realm name on the server */
+    protected String realmName;
+
+    /** The authorization ID of the entity */
+    protected String authorizationId;
+
+    /** The quality of protection */
+    protected SaslQoP qualityOfProtection;
+
+    /** The security strength */
+    protected SaslSecurityStrength securityStrength;
+
+    /** Require mutual authentication */
+    protected boolean mutualAuthentication = false;
+
+
+    /**
+     * Creates a new instance of SaslRequest.
+     *
+     * @param saslMechanism
+     *      the SASL mechanism
+     */
+    protected SaslRequest( String saslMechanism )
+    {
+        this.saslMechanism = saslMechanism;
+    }
+
+
+    /**
+     * Adds the given controls.
+     *
+     * @param controls the controls
+     */
+    public void addAllControls( Control[] controls )
+    {
+        this.controls.addAll( Arrays.asList( controls ) );
+    }
+
+
+    /**
+     * Adds the given control.
+     *
+     * @param control the control
+     */
+    public void addControl( Control control )
+    {
+        this.controls.add( control );
+    }
+
+
+    /**
+     * Gets the authorization ID.
+     *
+     * @return the authorization ID
+     */
+    public String getAuthorizationId()
+    {
+        return authorizationId;
+    }
+
+
+    /**
+     * Gets the controls.
+     *
+     * @return the controls
+     */
+    public Control[] getControls()
+    {
+        return controls.toArray( new Control[0] );
+    }
+
+
+    /**
+     * Gets the crendentials
+     *
+     * @return the credentials
+     */
+    public byte[] getCredentials()
+    {
+        if ( credentials != null )
+        {
+            return credentials;
+        }
+        else
+        {
+            return StringConstants.EMPTY_BYTES;
+        }
+    }
+
+
+    /**
+     * Gets the quality of protection.
+     *
+     * @return the quality of protection
+     */
+    public SaslQoP getQualityOfProtection()
+    {
+        return qualityOfProtection;
+    }
+
+
+    /**
+     * Gets realm name.
+     *
+     * @return the realm name
+     */
+    public String getRealmName()
+    {
+        return realmName;
+    }
+
+
+    /**
+     * Gets the SASL mechanism.
+     *
+     * @return the SASL mechanism
+     */
+    public String getSaslMechanism()
+    {
+        return saslMechanism;
+    }
+
+
+    /**
+     * Gets the security strength.
+     *
+     * @return the security strength
+     */
+    public SaslSecurityStrength getSecurityStrength()
+    {
+        return securityStrength;
+    }
+
+
+    /**
+     * Gets the username.
+     *
+     * @return the username
+     */
+    public String getUsername()
+    {
+        return username;
+    }
+
+
+    /**
+     * Indicates if mutual authentication is required.
+     *
+     * @return the flag indicating if mutual authentication is required
+     */
+    public boolean isMutualAuthentication()
+    {
+        return mutualAuthentication;
+    }
+
+
+    /**
+     * Sets the Authorization ID
+     *
+     * @param authorizationId The authorization ID
+     */
+    public void setAuthorizationId( String authorizationId )
+    {
+        this.authorizationId = authorizationId;
+    }
+
+
+    /**
+     * Sets the credentials.
+     *
+     * @param credentials the credentials
+     */
+    public void setCredentials( byte[] credentials )
+    {
+        this.credentials = credentials;
+    }
+
+
+    /**
+     * Sets the credentials.
+     *
+     * @param credentials the credentials
+     */
+    public void setCredentials( String credentials )
+    {
+        this.credentials = Strings.getBytesUtf8( credentials );
+    }
+
+
+    /**
+     * Sets the flag indicating if mutual authentication is required.
+     *
+     * @param mutualAuthentication the flag indicating if mutual authentication is required
+     */
+    public void setMutualAuthentication( boolean mutualAuthentication )
+    {
+        this.mutualAuthentication = mutualAuthentication;
+    }
+
+
+    /**
+     * Sets the quality of protection.
+     *
+     * @param qualityOfProtection the quality of protection
+     */
+    public void setQualityOfProtection( SaslQoP qualityOfProtection )
+    {
+        this.qualityOfProtection = qualityOfProtection;
+    }
+
+
+    /**
+     * Sets the realm name.
+     * 
+     * @param realmName The realm name
+     */
+    protected void setRealmName( String realmName )
+    {
+        this.realmName = realmName;
+    }
+
+
+    /**
+     * Sets the SASL mechanism
+     *
+     * @param saslMechanism the SASL mechanism
+     */
+    protected void setSaslMechanism( String saslMechanism )
+    {
+        this.saslMechanism = saslMechanism;
+    }
+
+
+    /**
+     * Sets the security strength.
+     *
+     * @param securityStrength the security strength
+     */
+    public void setSecurityStrength( SaslSecurityStrength securityStrength )
+    {
+        this.securityStrength = securityStrength;
+    }
+
+
+    /**
+     * Sets the username.
+     *
+     * @param username the username
+     */
+    public void setUsername( String username )
+    {
+        this.username = username;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SearchCursorImpl.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SearchCursorImpl.java
new file mode 100644
index 0000000..a5cde7a
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/SearchCursorImpl.java
@@ -0,0 +1,401 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapReferralException;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.ldap.client.api.future.SearchFuture;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An implementation of Cursor based on the underlying SearchFuture instance.
+ * 
+ * Note: This is a forward only cursor hence the only valid operations are next(), get() and close() 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchCursorImpl extends AbstractCursor<Response> implements SearchCursor
+{
+    /** A dedicated log for cursors */
+    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
+
+    /** the search future */
+    private SearchFuture future;
+
+    /** wait time while polling for a SearchResponse */
+    private long timeout;
+
+    /** time units of timeout value */
+    private TimeUnit timeUnit;
+
+    /** a reference to hold the retrieved SearchResponse object from SearchFuture */
+    private Response response;
+
+    /** the done flag */
+    private boolean done;
+
+    /** a reference to hold the SearchResultDone response */
+    private SearchResultDone searchDoneResp;
+
+
+    /**
+     * Instantiates a new search cursor.
+     *
+     * @param future the future
+     * @param timeout the timeout
+     * @param timeUnit the time unit
+     */
+    public SearchCursorImpl( SearchFuture future, long timeout, TimeUnit timeUnit )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Creating SearchCursorImpl {}", this );
+        }
+
+        this.future = future;
+        this.timeout = timeout;
+        this.timeUnit = timeUnit;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean next() throws LdapException, CursorException
+    {
+        if ( done )
+        {
+            return false;
+        }
+
+        try
+        {
+            if ( future.isCancelled() )
+            {
+                response = null;
+                done = true;
+                return false;
+            }
+
+            response = future.get( timeout, timeUnit );
+        }
+        catch ( Exception e )
+        {
+            LdapException ldapException = new LdapException( LdapNetworkConnection.NO_RESPONSE_ERROR, e );
+
+            // Send an abandon request
+            if ( !future.isCancelled() )
+            {
+                future.cancel( true );
+            }
+
+            // close the cursor
+            close( ldapException );
+
+            throw ldapException;
+        }
+
+        if ( response == null )
+        {
+            future.cancel( true );
+
+            throw new LdapException( LdapNetworkConnection.TIME_OUT_ERROR );
+        }
+
+        done = ( response instanceof SearchResultDone );
+
+        if ( done )
+        {
+            searchDoneResp = ( SearchResultDone ) response;
+
+            // Process the response and throw an exception if needed
+            //ResultCodeEnum.processResponse( searchDoneResp );
+
+            response = null;
+        }
+
+        return !done;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Response get() throws InvalidCursorPositionException
+    {
+        if ( !available() )
+        {
+            throw new InvalidCursorPositionException();
+        }
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchResultDone getSearchResultDone()
+    {
+        return searchDoneResp;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean available()
+    {
+        return response != null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close()
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing SearchCursorImpl {}", this );
+        }
+
+        close( null );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close( Exception cause )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing SearchCursorImpl {}", this );
+        }
+
+        if ( done )
+        {
+            super.close();
+            return;
+        }
+
+        if ( !future.isCancelled() )
+        {
+            future.cancel( true );
+        }
+
+        if ( cause != null )
+        {
+            super.close( cause );
+        }
+        else
+        {
+            super.close();
+        }
+    }
+
+
+    // rest of all operations will throw UnsupportedOperationException
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void after( Response element ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "after( Response element )" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void afterLast() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "afterLast()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void before( Response element ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "before( Response element )" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public void beforeFirst() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "beforeFirst()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public boolean first() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "first()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public boolean last() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "last()" ) ) );
+    }
+
+
+    /**
+     * This operation is not supported in SearchCursor.
+     * {@inheritDoc}
+     */
+    public boolean previous() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "previous()" ) ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDone()
+    {
+        return done;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isReferral()
+    {
+        return response instanceof SearchResultReference;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Referral getReferral() throws LdapException
+    {
+        if ( isReferral() )
+        {
+            return ( ( SearchResultReference ) response ).getReferral();
+        }
+
+        throw new LdapException();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEntry()
+    {
+        return response instanceof SearchResultEntry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry getEntry() throws LdapException
+    {
+        if ( isEntry() )
+        {
+            return ( ( SearchResultEntry ) response ).getEntry();
+        }
+        
+        if ( isReferral() )
+        {
+            Referral referral = ( ( SearchResultReference ) response ).getReferral();
+            throw new LdapReferralException( referral.getLdapUrls() );
+        }
+
+        throw new LdapException();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isIntermediate()
+    {
+        return response instanceof IntermediateResponse;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public IntermediateResponse getIntermediate() throws LdapException
+    {
+        if ( isEntry() )
+        {
+            return ( IntermediateResponse ) response;
+        }
+
+        throw new LdapException();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactory.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactory.java
new file mode 100644
index 0000000..85d799d
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactory.java
@@ -0,0 +1,162 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A factory for creating LdapConnection objects managed by LdapConnectionPool. 
+ * A bind operation is executed upon return if any of the following operations 
+ * were performed on the connection while it was checked out:
+ * 
+ * <ul>
+ * <li>{@link LdapConnection#bind() bind()}</li>
+ * <li>{@link LdapConnection#anonymousBind() anonymousBind()}</li>
+ * <li>{@link LdapConnection#bind(String) bind(String)}</li>
+ * <li>{@link LdapConnection#bind(String, String) bind(String, String)}</li>
+ * <li>{@link LdapConnection#bind(Dn) bind(Dn)}</li>
+ * <li>{@link LdapConnection#bind(Dn, String) bind(Dn, String)}</li>
+ * <li>{@link LdapConnection#bind(BindRequest) bind(BindRequest)}</li>
+ * <li>{@link LdapConnection#extended(String) extended(String)} <i>where oid is StartTLS</i></li>
+ * <li>{@link LdapConnection#extended(String, byte[]) extended(String, byte[])} <i>where oid is StartTLS</i></li>
+ * <li>{@link LdapConnection#extended(Oid) extended(String)} <i>where oid is StartTLS</i></li>
+ * <li>{@link LdapConnection#extended(Oid, byte[]) extended(String, byte[])} <i>where oid is StartTLS</i></li>
+ * <li>{@link LdapConnection#extended(ExtendedRequest) extended(ExtendedRequest)} <i>where ExtendedRequest is StartTLS</i></li>
+ * </ul>
+ * 
+ * This is a <i>MOSTLY</i> safe way to handle connections in a pool. If one 
+ * would like to use a slightly less expensive pool factory, the 
+ * {@link DefaultPoolableLdapConnectionFactory} may be the right choice.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ValidatingPoolableLdapConnectionFactory extends AbstractPoolableLdapConnectionFactory
+{
+    /** This class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( ValidatingPoolableLdapConnectionFactory.class );
+
+
+    /**
+     * Creates a new instance of ValidatingPoolableLdapConnectionFactory.
+     *
+     * @param config the configuration for creating LdapConnections
+     */
+    public ValidatingPoolableLdapConnectionFactory( LdapConnectionConfig config )
+    {
+        this( new DefaultLdapConnectionFactory( config ) );
+    }
+
+
+    /**
+     * Creates a new instance of ValidatingPoolableLdapConnectionFactory.  The
+     * <code>connectionFactoryClass</code> must have a public constructor accepting
+     * an <code>LdapConnectionConfig</code> object or an 
+     * <code>IllegalArgumentException</code> will be thrown.
+     *
+     * @param config the configuration for creating LdapConnections
+     * @param connectionFactoryClass An implementation class of for the 
+     * LDAP connection factory.
+     * @throws IllegalArgumentException If the instantiation of an instance of 
+     * the <code>connectionFactoryClass</code> fails.
+     */
+    public ValidatingPoolableLdapConnectionFactory( LdapConnectionConfig config,
+        Class<? extends LdapConnectionFactory> connectionFactoryClass )
+    {
+        this( newLdapConnectionFactory( config, connectionFactoryClass ) );
+    }
+
+
+    /**
+     * Creates a new instance of ValidatingPoolableLdapConnectionFactory.
+     *
+     * @param connectionFactory the connection factory for creating LdapConnections
+     */
+    public ValidatingPoolableLdapConnectionFactory( LdapConnectionFactory connectionFactory )
+    {
+        this.connectionFactory = connectionFactory;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * There is nothing to do to activate a connection.
+     */
+    @Override
+    public void activateObject( LdapConnection connection ) throws LdapException
+    {
+        LOG.debug( "Activating {}", connection );
+        super.activateObject( connection );
+
+        // clear the monitors
+        ( ( MonitoringLdapConnection ) connection ).resetMonitors();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * Specifically, we are creating a new connection based on the LdapConnection Factory
+     * we used to create this pool of connections. The default is to create bound connections.
+     * 
+     * @throws LdapException If unable to connect.
+     */
+    public MonitoringLdapConnection makeObject() throws LdapException
+    {
+        LOG.debug( "Creating a LDAP connection" );
+        return new MonitoringLdapConnection( connectionFactory.newLdapConnection() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * Here, passivating a connection means we re-bind it, so that the existing LDAPSession
+     * is reset.
+     * 
+     * @throws LdapException If unable to reconfigure and rebind.
+     */
+    public void passivateObject( LdapConnection connection ) throws LdapException
+    {
+        LOG.debug( "Passivating {}", connection );
+
+        if ( !connection.isConnected() || !connection.isAuthenticated()
+            || ( ( MonitoringLdapConnection ) connection ).bindCalled() )
+        {
+            LOG.debug( "rebind due to bind on connection {}", connection );
+            connectionFactory.bindConnection( connection );
+        }
+        if ( ( ( MonitoringLdapConnection ) connection ).startTlsCalled() )
+        {
+            LOG.debug( "unbind/rebind due to startTls on {}", connection );
+            // unbind to clear the tls
+            connection.unBind();
+            connectionFactory.bindConnection( connection );
+        }
+
+        // in case connection had configuration changed
+        connectionFactory.configureConnection( connection );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/Wrapper.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/Wrapper.java
new file mode 100755
index 0000000..d6923cd
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/Wrapper.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+/**
+ * An interface for defining wrapper objects.  An implementation of this class
+ * <b>MUST</b> implement <code>T</code> as well
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Wrapper<T>
+{
+    /**
+     * Returns the wrapped object.
+     *
+     * @return The wrapped object
+     */
+    T wrapped();
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/callback/SaslCallbackHandler.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/callback/SaslCallbackHandler.java
new file mode 100644
index 0000000..73d666d
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/callback/SaslCallbackHandler.java
@@ -0,0 +1,160 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api.callback;
+
+
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.RealmCallback;
+import javax.security.sasl.RealmChoiceCallback;
+
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.ldap.client.api.SaslRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The CallbackHandler implementation used by the LdapConnection during SASL mechanism based bind operations.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SaslCallbackHandler implements CallbackHandler
+{
+    /** The sasl request. */
+    private SaslRequest saslReq;
+
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( SaslCallbackHandler.class );
+
+
+    /**
+     * Instantiates a new SASL callback handler.
+     *
+     * @param saslReq the SASL request
+     */
+    public SaslCallbackHandler( SaslRequest saslReq )
+    {
+        this.saslReq = saslReq;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException
+    {
+        for ( Callback cb : callbacks )
+        {
+            if ( cb instanceof NameCallback )
+            {
+                NameCallback ncb = ( NameCallback ) cb;
+
+                String name = saslReq.getUsername();
+                LOG.debug( "sending name {} in the NameCallback", name );
+                ncb.setName( name );
+            }
+            else if ( cb instanceof PasswordCallback )
+            {
+                PasswordCallback pcb = ( PasswordCallback ) cb;
+
+                LOG.debug( "sending credentials in the PasswordCallback" );
+                pcb.setPassword( Strings.utf8ToString( saslReq.getCredentials() ).toCharArray() );
+            }
+            else if ( cb instanceof RealmCallback )
+            {
+                RealmCallback rcb = ( RealmCallback ) cb;
+
+                if ( saslReq.getRealmName() != null )
+                {
+                    LOG.debug( "sending the user specified realm value {} in the RealmCallback", saslReq.getRealmName() );
+                    rcb.setText( saslReq.getRealmName() );
+                }
+                else
+                {
+                    LOG.debug(
+                        "No user specified relam value, sending the default realm value {} in the RealmCallback",
+                        rcb.getDefaultText() );
+                    rcb.setText( rcb.getDefaultText() );
+                }
+            }
+            else if ( cb instanceof RealmChoiceCallback )
+            {
+                RealmChoiceCallback rccb = ( RealmChoiceCallback ) cb;
+
+                boolean foundRealmName = false;
+
+                String[] realmNames = rccb.getChoices();
+                for ( int i = 0; i < realmNames.length; i++ )
+                {
+                    String realmName = realmNames[i];
+                    if ( realmName.equals( saslReq.getRealmName() ) )
+                    {
+                        foundRealmName = true;
+
+                        LOG.debug( "sending the user specified realm value {} in the RealmChoiceCallback", realmName );
+                        rccb.setSelectedIndex( i );
+                        break;
+                    }
+                }
+
+                if ( !foundRealmName )
+                {
+                    throw new IOException(
+                        MessageFormat
+                            .format(
+                                "Cannot match ''java.naming.security.sasl.realm'' property value ''{0}'' with choices ''{1}'' in RealmChoiceCallback.",
+                                saslReq.getRealmName(), getRealmNamesAsString( realmNames ) ) );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Gets the realm names as a string.
+     *
+     * @param realmNames the array of realm names
+     * @return  the realm names as a string
+     */
+    private String getRealmNamesAsString( String[] realmNames )
+    {
+        StringBuilder sb = new StringBuilder();
+
+        if ( ( realmNames != null ) && ( realmNames.length > 0 ) )
+        {
+            for ( String realmName : realmNames )
+            {
+                sb.append( realmName );
+                sb.append( ',' );
+            }
+            sb.deleteCharAt( sb.length() - 1 );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/exception/InvalidConnectionException.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/exception/InvalidConnectionException.java
new file mode 100644
index 0000000..9765d1c
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/exception/InvalidConnectionException.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api.exception;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * A InvalidConnectionException is thrown if one tries to apply an operation
+ * on a closed connection
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InvalidConnectionException extends LdapException
+{
+    /** The serialVersionUID. */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Instantiates a new invalid connection exception.
+     */
+    public InvalidConnectionException()
+    {
+        super();
+    }
+
+
+    /**
+     * Instantiates a new invalid connection exception.
+     *
+     * @param explanation the explanation
+     */
+    public InvalidConnectionException( String explanation )
+    {
+        super( explanation );
+    }
+
+
+    /**
+     * Instantiates a new invalid connection exception.
+     *
+     * @param explanation the explanation
+     * @param cause The root cause for this exception
+     */
+    public InvalidConnectionException( String explanation, Throwable cause )
+    {
+        super( explanation, cause );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/AddFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/AddFuture.java
new file mode 100644
index 0000000..597a4d0
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/AddFuture.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage AddRequests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddFuture extends ResponseFuture<AddResponse>
+{
+    /**
+     * Creates a new instance of AddFuture.
+     * 
+     * @param connection the LDAP connection
+     * @param messageId The associated messageId
+     */
+    public AddFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the AddResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     * 
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the add response
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public AddResponse get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "AddFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/BindFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/BindFuture.java
new file mode 100644
index 0000000..c2e83ad
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/BindFuture.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage BindRequests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BindFuture extends ResponseFuture<BindResponse>
+{
+    /**
+     * Creates a new instance of BindFuture.
+     *
+     * @param connection the LDAP connection
+     * @param messageId the associated messageId
+     */
+    public BindFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the BindResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     * 
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the bind response
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public BindResponse get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "BindFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/CompareFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/CompareFuture.java
new file mode 100644
index 0000000..c3024fb
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/CompareFuture.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage CompareRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CompareFuture extends ResponseFuture<CompareResponse>
+{
+    /**
+     * Creates a new instance of CompareFuture.
+     *
+     * @param connection the LDAP connection
+     * @param messageId the associated messageId
+     */
+    public CompareFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the CompareResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     * 
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the compare response
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public CompareResponse get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "CompareFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/DeleteFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/DeleteFuture.java
new file mode 100644
index 0000000..2bf43b6
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/DeleteFuture.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage DeleteRequests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DeleteFuture extends ResponseFuture<DeleteResponse>
+{
+    /**
+     * Creates a new instance of DeleteFuture.
+     *
+     * @param connection the LDAP connection
+     * @param messageId The associated messageId
+     */
+    public DeleteFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the DeleteResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     * 
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the delete response
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public DeleteResponse get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "DeleteFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ExtendedFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ExtendedFuture.java
new file mode 100644
index 0000000..43ee198
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ExtendedFuture.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage ExtendedRequests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtendedFuture extends ResponseFuture<Response>
+{
+    /**
+     * Creates a new instance of ExtendedFuture.
+     *
+     * @param connection the LDAP connection
+     * @param messageId The associated messageId
+     */
+    public ExtendedFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the ExtendedResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     *
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the extended response
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public Response get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "ExtendedFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ModifyDnFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ModifyDnFuture.java
new file mode 100644
index 0000000..320f8fd
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ModifyDnFuture.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage ModifyDnRequest
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyDnFuture extends ResponseFuture<ModifyDnResponse>
+{
+    /**
+     * Creates a new instance of ModifyDnFuture.
+     *
+     * @param connection the LDAP connection
+     * @param messageId The associated messageId
+     */
+    public ModifyDnFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the ModifyDnResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     * 
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the modify Dn response
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public ModifyDnResponse get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "ModifyDnFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ModifyFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ModifyFuture.java
new file mode 100644
index 0000000..675d37f
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ModifyFuture.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage ModifyRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyFuture extends ResponseFuture<ModifyResponse>
+{
+    /**
+     * Creates a new instance of ModifyFuture.
+     *
+     * @param connection the LDAP connection
+     * @param messageId The associated messageId
+     */
+    public ModifyFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the ModifyResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     *
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the modify response
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public ModifyResponse get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "ModifyFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ResponseFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ResponseFuture.java
new file mode 100644
index 0000000..3dc60e8
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/ResponseFuture.java
@@ -0,0 +1,199 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future implementation used in LdapConnection operations.
+ *
+ * @param <R> The result type returned by this Future's <tt>get</tt> method
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ResponseFuture<R extends Response> implements Future<Response>
+{
+    /** the blocking queue holding LDAP responses */
+    protected BlockingQueue<R> queue;
+
+    /** flag to determine if this future is cancelled */
+    protected boolean cancelled = false;
+
+    /** If the request has been cancelled because of an exception  it will be stored here */
+    protected Throwable cause;
+
+    /** The messageID for this future */
+    protected int messageId;
+
+    /** The connection used by the request */
+    protected LdapConnection connection;
+
+
+    /**
+     * Creates a new instance of ResponseFuture.
+     *
+     * @param connection The LdapConnection used by the request
+     * @param messageId The associated message ID
+     */
+    public ResponseFuture( LdapConnection connection, int messageId )
+    {
+        queue = new LinkedBlockingQueue<R>();
+        this.messageId = messageId;
+        this.connection = connection;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean cancel( boolean mayInterruptIfRunning )
+    {
+        if ( cancelled )
+        {
+            return cancelled;
+        }
+
+        // set the cancel flag first
+        cancelled = true;
+
+        // Send an abandonRequest only if this future exists
+        if ( connection.doesFutureExistFor( messageId ) )
+        {
+            connection.abandon( messageId );
+        }
+
+        // then clear the queue, cause the might be some incoming messages before this abandon request
+        // hits the server
+        queue.clear();
+
+        return cancelled;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws InterruptedException if the operation has been cancelled by client
+     */
+    public R get() throws InterruptedException, ExecutionException
+    {
+        R response = null;
+
+        response = queue.take();
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws InterruptedException if the operation has been cancelled by client
+     */
+    public void set( R response ) throws InterruptedException, ExecutionException
+    {
+        queue.add( response );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws InterruptedException if the operation has been cancelled by client
+     */
+    public R get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException, TimeoutException
+    {
+        R response = queue.poll( timeout, unit );
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isCancelled()
+    {
+        return cancelled;
+    }
+
+
+    /**
+     * This operation is not supported in this implementation of Future.
+     * 
+     * {@inheritDoc}
+     */
+    public boolean isDone()
+    {
+        throw new UnsupportedOperationException( "Operation not supported" );
+    }
+
+
+    /**
+     * @return the cause
+     */
+    public Throwable getCause()
+    {
+        return cause;
+    }
+
+
+    /**
+     * Associate a cause to the ResponseFuture
+     * @param cause the cause to set
+     */
+    public void setCause( Throwable cause )
+    {
+        this.cause = cause;
+    }
+
+
+    /**
+     * Cancel the Future
+     *
+     */
+    public void cancel()
+    {
+        // set the cancel flag first
+        cancelled = true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "[msgId : " ).append( messageId ).append( ", " );
+        sb.append( "size : " ).append( queue.size() ).append( ", " );
+        sb.append( "Canceled :" ).append( cancelled ).append( "]" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/SearchFuture.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/SearchFuture.java
new file mode 100644
index 0000000..dfe7a8e
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/future/SearchFuture.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api.future;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A Future to manage SerachRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchFuture extends ResponseFuture<Response>
+{
+    /**
+     * Creates a new instance of SearchFuture.
+     *
+     * @param connection the LDAP connection
+     * @param messageId The associated messageId
+     */
+    public SearchFuture( LdapConnection connection, int messageId )
+    {
+        super( connection, messageId );
+    }
+
+
+    /**
+     * Get the SearchResponse, blocking until one is received, or until the
+     * given timeout is reached. It can be either a SearchResultEntry, 
+     * a SearchResultReference or a SearchResultDone, the last of all 
+     * the search responses.
+     * 
+     * Get the ModifyResponse, blocking until one is received, or until the
+     * given timeout is reached.
+     *
+     * @param timeout {@inheritDoc}
+     * @param unit {@inheritDoc}
+     * @return the response, either a SearchResultEntry, a SearchResultReference, or a SearchResultDone
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ExecutionException {@inheritDoc}
+     * @throws TimeoutException {@inheritDoc}
+     */
+    public Response get( long timeout, TimeUnit unit ) throws InterruptedException, ExecutionException,
+        TimeoutException
+    {
+        return super.get( timeout, unit );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "SearchFuture" ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AbstractFilter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AbstractFilter.java
new file mode 100755
index 0000000..0eac8f6
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AbstractFilter.java
@@ -0,0 +1,38 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+/**
+ * An abstract class used as a base for all the Filter implementations
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No qualifier*/abstract class AbstractFilter implements Filter
+{
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StringBuilder build()
+    {
+        return build( new StringBuilder() );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AttributeDescriptionFilter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AttributeDescriptionFilter.java
new file mode 100755
index 0000000..c45052c
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AttributeDescriptionFilter.java
@@ -0,0 +1,63 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+/**
+ * This class is used to handle the Present filter (ie, attr =* )
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No qualifier*/final class AttributeDescriptionFilter extends AbstractFilter
+{
+    /** The attribute that must be prersent */
+    private String attribute;
+
+
+    /**
+     * Creates a new instance of AttributeDescription filter.
+     */
+    private AttributeDescriptionFilter( String attribute )
+    {
+        this.attribute = attribute;
+    }
+
+
+    /**
+     * Creates a new AttributeDescription 
+     *
+     * @param attribute The attribute that must be present
+     * @return The created PresenceFilter instance
+     */
+    public static AttributeDescriptionFilter present( String attribute )
+    {
+        return new AttributeDescriptionFilter( attribute );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StringBuilder build( StringBuilder builder )
+    {
+        return builder.append( "(" ).append( attribute ).append( FilterOperator.PRESENT.operator() ).append( ")" );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AttributeValueAssertionFilter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AttributeValueAssertionFilter.java
new file mode 100755
index 0000000..c9985eb
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/AttributeValueAssertionFilter.java
@@ -0,0 +1,116 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import org.apache.directory.api.ldap.model.filter.FilterEncoder;
+
+
+/**
+ * A class to represent the various filters that take a value, like =, <=, >= or ~=.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No qualifier*/final class AttributeValueAssertionFilter extends AbstractFilter
+{
+    /** The associated attribute */
+    private String attribute;
+
+    /** The filter value */
+    private String value;
+
+    /** The Filter operator */
+    private FilterOperator operator;
+
+
+    /**
+     * Creates a new instance of AttributeValueAssertionFilter.
+     */
+    private AttributeValueAssertionFilter( String attribute, String value, FilterOperator operator )
+    {
+        this.attribute = attribute;
+        this.value = value;
+        this.operator = operator;
+    }
+
+
+    /**
+     * Creates an Approximate Filter : ( <attribute> ~= <value> )
+     *
+     * @param attribute The AttributeType
+     * @param value The Value
+     * @return An instance of the Approximate Filter
+     */
+    public static AttributeValueAssertionFilter approximatelyEqual( String attribute, String value )
+    {
+        return new AttributeValueAssertionFilter( attribute, value, FilterOperator.APPROXIMATELY_EQUAL );
+    }
+
+
+    /**
+     * Creates an equal Filter : ( <attribute> = <value> )
+     *
+     * @param attribute The AttributeType
+     * @param value The Value
+     * @return An instance of the Equal Filter
+     */
+    public static AttributeValueAssertionFilter equal( String attribute, String value )
+    {
+        return new AttributeValueAssertionFilter( attribute, value, FilterOperator.EQUAL );
+    }
+
+
+    /**
+     * Creates a Greater Than Or Equal Filter : ( <attribute> >= <value> )
+     *
+     * @param attribute The AttributeType
+     * @param value The Value
+     * @return An instance of the Greater Than Or Equal Filter
+     */
+    public static AttributeValueAssertionFilter greaterThanOrEqual( String attribute, String value )
+    {
+        return new AttributeValueAssertionFilter( attribute, value, FilterOperator.GREATER_THAN_OR_EQUAL );
+    }
+
+
+    /**
+     * Creates a Less Than Or Equal Filter : ( <attribute> <= <value> )
+     *
+     * @param attribute The AttributeType
+     * @param value The Value
+     * @return An instance of the Less Than Or Equal Filter
+     */
+    public static AttributeValueAssertionFilter lessThanOrEqual( String attribute, String value )
+    {
+        return new AttributeValueAssertionFilter( attribute, value, FilterOperator.LESS_THAN_OR_EQUAL );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StringBuilder build( StringBuilder builder )
+    {
+        return builder.append( "(" ).append( attribute )
+            .append( operator.operator() )
+            .append( FilterEncoder.encodeFilterValue( value ) ).append( ")" );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/Filter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/Filter.java
new file mode 100755
index 0000000..9260fd0
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/Filter.java
@@ -0,0 +1,46 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+/**
+ * 
+ * TODO Filter.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No qualifier*/interface Filter
+{
+    /**
+     * Constructs a String representation of a Filter
+     *
+     * @return The constructed String
+     */
+    StringBuilder build();
+
+
+    /**
+     * Constructs a String representation of a Filter
+     *
+     * @param builder The current buffer containing the on going representation of the filter
+     * @return The constructed String
+     */
+    StringBuilder build( StringBuilder builder );
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/FilterBuilder.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/FilterBuilder.java
new file mode 100755
index 0000000..847c37c
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/FilterBuilder.java
@@ -0,0 +1,475 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+/**
+ * A builder for constructing well formed search filters according to
+ * <a href="https://tools.ietf.org/html/rfc4515.html">RFC 4515</a>.  This 
+ * builder is most convenient when you use static imports.  For example:
+ * <pre>
+ * import static org.apache.directory.ldap.client.api.search.FilterBuilder.and;
+ * import static org.apache.directory.ldap.client.api.search.FilterBuilder.equal;
+ * import static org.apache.directory.ldap.client.api.search.FilterBuilder.or;
+ * 
+ * ...
+ * 
+ *         String filter = 
+ *                 or(
+ *                     and( 
+ *                         equal( "givenName", "kermit" ), 
+ *                         equal( "sn", "the frog" ) ),
+ *                     and( 
+ *                         equal( "givenName", "miss" ), 
+ *                         equal( "sn", "piggy" ) ) )
+ *                 .toString()
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class FilterBuilder
+{
+    /** The built filter */
+    /* No qualifier */ Filter filter;
+
+
+    /**
+     * A private constructor that creates a new instance of a FilterBuilder
+     * containing a given filter.
+     */
+    /* No qualifier*/ FilterBuilder( Filter filter )
+    {
+        this.filter = filter;
+    }
+
+
+    /**
+     * Returns a new FilterBuilder that will <code>&</code> together all of the 
+     * supplied filters.  For example:
+     * 
+     * <pre>
+     * and( equal( "givenName", "kermit" ), equal( "sn", "the frog" ) ).toString()
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (&(givenName=kermit)(sn=the frog))
+     * </pre>
+     * 
+     * Which would match all entries with a given name of <code>kermit</code>
+     * and a surname <code>the frog</code>.
+     *
+     * @param filters The filters to and together
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder and( FilterBuilder... filters )
+    {
+        SetOfFiltersFilter filter = SetOfFiltersFilter.and();
+
+        for ( FilterBuilder builder : filters )
+        {
+            filter.add( builder.filter );
+        }
+
+        return new FilterBuilder( filter );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder for testing the approximate equality of an 
+     * attribute. For example:
+     * 
+     * <pre>
+     * approximatelyEqual( "l", "san fransico" ).toString();
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (l~=san fransico)
+     * </pre>
+     * 
+     * Which <i>MIGHT</i> match results whose locality is 
+     * <code>San Francisco</code>.  The matching rule used to apply this filter
+     * is dependent on the server implementation.
+     *
+     * @param attribute The attribute 
+     * @param value The value
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder approximatelyEqual( String attribute, String value )
+    {
+        return new FilterBuilder( AttributeValueAssertionFilter.approximatelyEqual( attribute, value ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder for testing equality of an attribute. For 
+     * example:
+     * 
+     * <pre>
+     * equal( "cn", "Kermit The Frog" ).toString();
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (cn>=Kermit The Frog)
+     * </pre>
+     * 
+     * Which would match entries with the common name 
+     * <code>Kermit The Frog</code>.
+     *
+     * @param attribute The attribute 
+     * @param value The value
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder equal( String attribute, String value )
+    {
+        return new FilterBuilder( AttributeValueAssertionFilter.equal( attribute, value ) );
+    }
+
+
+    /**
+     * Creates an extensible match filter by calling 
+     * {@link #extensible(String, String) extensible(null, value)}.
+     *
+     * @param value The value to test for
+     * @return A new MatchingRuleAssertionFilterBuilder
+     */
+    public static MatchingRuleAssertionFilterBuilder extensible( String value )
+    {
+        return new MatchingRuleAssertionFilterBuilder( null, value );
+    }
+
+
+    /**
+     * Creates an extensible match filter.  This filter can be used to specify
+     * that dn attributes should be included in the match, which matcher to 
+     * use, or that all attributes that support a specific matcher will be
+     * checked.  For example:
+     * 
+     * <pre>
+     * extensible( "sn", "Barney Rubble" )
+     *     .useDnAttributes()
+     *     .setMatchingRule( "2.4.6.8.10" )
+     *     .toString();
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn:dn:2.4.6.8.10:=Barney Rubble)
+     * </pre>
+     * 
+     * Not that the specialized filter builder that is returned <b>IS</b> a 
+     * FilterBuilder so it can be chained with other filters.  For example:
+     * 
+     * <pre>
+     * and(
+     *     extensible( "sn", "Rubble" )
+     *         .useDnAttributes()
+     *         .setMatchingRule( "2.4.6.8.10" ),
+     *     equal( "givenName", "Barney" ) )
+     *     .toString();
+     * </pre>
+     *
+     * @param attribute The attribute to test
+     * @param value The value to test for
+     * @return A new MatchingRuleAssertionFilterBuilder
+     */
+    public static MatchingRuleAssertionFilterBuilder extensible( String attribute, String value )
+    {
+        return new MatchingRuleAssertionFilterBuilder( attribute, value );
+    }
+    
+    
+    /**
+     * Returns a new FilterBuilder for testing lexicographical greater than.  
+     * For example:
+     * 
+     * <pre>
+     * greaterThanOrEqual( "sn", "n" ).toString();
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn>=n)
+     * </pre>
+     * 
+     * which would match results whose surname starts with the second half of
+     * the alphabet.  
+     *
+     * @param attribute The attribute 
+     * @param value The value
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder greaterThanOrEqual( String attribute, String value )
+    {
+        return new FilterBuilder( AttributeValueAssertionFilter.greaterThanOrEqual( attribute, value ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder for testing lexicographical less than.  For
+     * example:
+     * 
+     * <pre>
+     * lessThanOrEqual( "sn", "mzzzzzz" ).toString();
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn<=mzzzzzz)
+     * </pre>
+     * 
+     * which would match results whose surname starts with the first half of
+     * the alphabet.  <i>Note, this is not perfect, but if you know anybody with
+     * a last name that starts with an <code>m</code> followed by six
+     * <code>z</code>'s...</i>
+     *
+     * @param attribute The attribute 
+     * @param value The value
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder lessThanOrEqual( String attribute, String value )
+    {
+        return new FilterBuilder( AttributeValueAssertionFilter.lessThanOrEqual( attribute, value ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder for negating another filter.  For example:
+     * 
+     * <pre>
+     * not( present( "givenName" ) ).toString();
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (!(givenName=*))
+     * </pre>
+     *
+     * @param builder The filter to negate
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder not( FilterBuilder builder )
+    {
+        return new FilterBuilder( UnaryFilter.not( builder.filter ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder that will <code>|</code> together all of the 
+     * supplied filters.  For example:
+     * 
+     * <pre>
+     * or( equal( "givenName", "kermit" ), equal( "givenName", "walter" ) ).toString()
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (|(givenName=kermit)(givenName=walter))
+     * </pre>
+     * 
+     * Which would match any entry with the <code>givenName</code> of either
+     * <code>kermit</code> or <code>walter</code>.
+     *
+     * @param builders The filters to or together
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder or( FilterBuilder... builders )
+    {
+        SetOfFiltersFilter filter = SetOfFiltersFilter.or();
+
+        for ( FilterBuilder builder : builders )
+        {
+            filter.add( builder.filter );
+        }
+
+        return new FilterBuilder( filter );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder for testing the presence of an attributes.  
+     * For example:
+     * 
+     * <pre>
+     * present( "givenName" ).toString();
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (givenName=*)
+     * </pre>
+     * 
+     * Which would match any entry that has a <code>givenName</code> attribute.
+     *
+     * @param attribute The attribute to test the presence of
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder present( String attribute )
+    {
+        return new FilterBuilder( AttributeDescriptionFilter.present( attribute ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder that will construct a SubString filter, with an <em>initial</em part, 
+     * and zero to N <em>any</em> part, but no <em>final</em> part.  
+     * 
+     * For instance:
+     * 
+     * <pre>
+     * startswith( "sn", "Th", "Soft", "Foun" )).toString()
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn=Th*Soft*Foun*)
+     * </pre>
+     * 
+     * Which would match any entry with the <code>sn</code> starting with <code>'Th'</code>, and 
+     * having a <code>Soft</code> and <code>Foun</code> strings in the middle, like 
+     * 'The Apache Software Foundation'.
+     *
+     * @param builders The filters to or together
+     * @param parts The sub elements to use in the filter
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder startsWith( String attribute, String... parts )
+    {
+        if ( ( parts == null ) || ( parts.length == 0 ) )
+        {
+            throw new IllegalArgumentException( "An 'initial' part is needed" );
+        }
+
+        return new FilterBuilder( SubstringFilter.startsWith( attribute, parts ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder that will construct a SubString filter, with an <em>initial</em part, 
+     * and zero to N <em>any</em> parts, but no <em>final</em> part.  
+     * 
+     * For instance:
+     * 
+     * <pre>
+     * startswith( "sn", "Th", "Soft", "Foun" )).toString()
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn=Th*Soft*Foun*)
+     * </pre>
+     * 
+     * Which would match any entry with the <code>sn</code> starting with <code>'Th'</code>, and 
+     * having a <code>Soft</code> and <code>Foun</code> strings in the middle, like 
+     * 'The Apache Software Foundation'.
+     *
+     * @param builders The filters to or together
+     * @param parts The sub elements to use in the filter
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder endsWith( String attribute, String... parts )
+    {
+        if ( ( parts == null ) || ( parts.length == 0 ) )
+        {
+            throw new IllegalArgumentException( "At a 'final' part is needed" );
+        }
+
+        return new FilterBuilder( SubstringFilter.endsWith( attribute, parts ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder that will construct a SubString filter, with zero to N <em>any</em> parts, 
+     * but no <em>initial</em> or <em>final</em> parts.  
+     * 
+     * For instance:
+     * 
+     * <pre>
+     * contains( "sn", "Soft", "Foun" )).toString()
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn=*Soft*Foun*)
+     * </pre>
+     * 
+     * Which would match any entry with the <code>sn</code> having a <code>Soft</code> 
+     * and <code>Foun</code> strings in the middle, like 
+     * 'The Apache Software Foundation'.
+     *
+     * @param builders The filters to or together
+     * @param parts The sub elements to use in the filter
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder contains( String attribute, String... parts )
+    {
+        if ( ( parts == null ) || ( parts.length == 0 ) )
+        {
+            throw new IllegalArgumentException( "At least one 'any' part is needed" );
+        }
+
+        return new FilterBuilder( SubstringFilter.contains( attribute, parts ) );
+    }
+
+
+    /**
+     * Returns a new FilterBuilder that will construct a SubString filter, with a <em>initial</em> part, 
+     * zero to N <em>any</em> parts, and a <em>final</em> part.
+     * 
+     * For instance:
+     * 
+     * <pre>
+     * substring( "sn", "The", "Soft", "Foun", "ion" )).toString()
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn=The*Soft*Foun*ion)
+     * </pre>
+     * 
+     * Which would match any entry with the <code>sn</code> having a <code>Soft</code> 
+     * and <code>Foun</code> strings in the middle, starts with <code>The</code> and ends with <code>ion</code> like 
+     * 'The Apache Software Foundation'.
+     * <p>
+     * Note that if we have only two strings in the parts, they will be the <em>initial</em> and <em>final</em> ones :
+     * 
+     * <pre>
+     * substring( "sn", "The", "ion" )).toString()
+     * </pre>
+     * would result in the string:
+     * <pre>
+     * (sn=The*ion)
+     * </pre>
+     * 
+     * @param builders The filters to or together
+     * @param parts The sub elements to use in the filter
+     * @return A new FilterBuilder
+     */
+    public static FilterBuilder substring( String attribute, String... parts )
+    {
+        if ( ( parts == null ) || ( parts.length == 0 ) )
+        {
+            throw new IllegalArgumentException( "At least one if 'initial', 'any' or 'final' part is needed" );
+        }
+
+        return new FilterBuilder( SubstringFilter.substring( attribute, parts ) );
+    }
+
+
+    /**
+     * Returns the string version of the filter represented by this FilterBuilder.
+     * 
+     * @return The string representation of the filter
+     */
+    @Override
+    public String toString()
+    {
+        return filter.build().toString();
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/FilterOperator.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/FilterOperator.java
new file mode 100644
index 0000000..b272316
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/FilterOperator.java
@@ -0,0 +1,71 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api.search;
+
+
+/**
+ * The operators that can be used in a Filter :
+ * <ul>
+ * <li>AND: the '&' operator</li>
+ * <li>OR: the '|' operator</li>
+ * <li>NOT: the '!' operator</li>
+ * <li>EQUAL: the '=' operator</li>
+ * <li>LESS_THAN_OR_EQUAL: the '<=' operator</li>
+ * <li>GREATER_THAN_OR_EQUAL: the '>=' operator</li>
+ * <li>PRESENT: the '=*' operator</li>
+ * <li>APPROXIMATELY_EQUAL: the '~=' operator</li>
+ * </ul>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No Qualifier */enum FilterOperator
+{
+    AND("&"),
+    OR("|"),
+    NOT("!"),
+    APPROXIMATELY_EQUAL("~="),
+    EQUAL("="),
+    PRESENT("=*"),
+    GREATER_THAN_OR_EQUAL(">="),
+    LESS_THAN_OR_EQUAL("<="),
+    EXTENSIBLE_EQUAL(":=");
+
+    /** The String representing the operator in a FIlter */
+    private String operator;
+
+
+    /**
+     * Creates a new instance of FilterOperator.
+     */
+    private FilterOperator( String operator )
+    {
+        this.operator = operator;
+    }
+
+
+    /**
+     * @return The String representation of the operator
+     */
+    public String operator()
+    {
+        return operator;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilter.java
new file mode 100755
index 0000000..8ff1dfa
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilter.java
@@ -0,0 +1,139 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import org.apache.directory.api.ldap.model.filter.FilterEncoder;
+
+
+/**
+ * A class to represent the extensible matching filter.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No qualifier*/class MatchingRuleAssertionFilter extends AbstractFilter
+{
+    /** The associated attribute */
+    private String attribute;
+    
+    /** The rule to use */
+    private String matchingRule;
+
+    /** The Filter operator */
+    private FilterOperator operator;
+    
+    /** Whether or not to include dn attributes in the matching */
+    private boolean useDnAttributes = false;
+
+    /** The filter value */
+    private String value;
+
+
+    /**
+     * Creates a new instance of MatchingRuleAssertionFilter.
+     * 
+     * @param attribute The attribute to test
+     * @param value The value to test for
+     * @param operator The FilterOperator
+     */
+    MatchingRuleAssertionFilter( String attribute, String value, 
+        FilterOperator operator )
+    {
+        this.attribute = attribute;
+        this.value = value;
+        this.operator = operator;
+    }
+
+
+    /**
+     * Creates a new instance of MatchingRuleAssertionFilter without an attribute.
+     * 
+     * @param value The value to test for
+     * @return A new MatchingRuleAssertionFilter
+     */
+    public static MatchingRuleAssertionFilter extensible( String value )
+    {
+        return new MatchingRuleAssertionFilter( null, value, 
+            FilterOperator.EXTENSIBLE_EQUAL );
+    }
+
+
+    /**
+     * Creates an extensible filter
+     *
+     * @param attribute The attribute to test
+     * @param value The value to test for
+     * @return A new MatchingRuleAssertionFilter
+     */
+    public static MatchingRuleAssertionFilter extensible( String attribute, String value )
+    {
+        return new MatchingRuleAssertionFilter( attribute, value, 
+            FilterOperator.EXTENSIBLE_EQUAL );
+    }
+
+
+    /**
+     * Sets the matching rule to use.  Can be either a name or an OID string.
+     *
+     * @param matchingRule The matching rule to use
+     * @return This filter
+     */
+    public MatchingRuleAssertionFilter setMatchingRule( String matchingRule )
+    {
+        this.matchingRule = matchingRule;
+        return this;
+    }
+
+    
+    /**
+     * If set, the dn attributes will be included in the matching.
+     *
+     * @return This filter
+     */
+    public MatchingRuleAssertionFilter useDnAttributes()
+    {
+        this.useDnAttributes = true;
+        return this;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StringBuilder build( StringBuilder builder )
+    {
+        builder.append( "(" );
+        if ( attribute != null )
+        {
+            builder.append( attribute );
+        }
+        if ( useDnAttributes )
+        {
+            builder.append( ":dn" );
+        }
+        if ( matchingRule != null && !matchingRule.isEmpty() )
+        {
+            builder.append( ":" ).append( matchingRule );
+        }
+        return builder.append( operator.operator() )
+            .append( FilterEncoder.encodeFilterValue( value ) ).append( ")" );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilterBuilder.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilterBuilder.java
new file mode 100755
index 0000000..d97c579
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilterBuilder.java
@@ -0,0 +1,64 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+/**
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MatchingRuleAssertionFilterBuilder extends FilterBuilder
+{
+    /**
+     * Creates a new instance of MatchingRuleAssertionFilterBuilder.
+     *
+     * @param attribute The attribute to test
+     * @param value The value to test for
+     */
+    /* No qualifier*/ MatchingRuleAssertionFilterBuilder( String attribute, String value )
+    {
+        super( MatchingRuleAssertionFilter.extensible( attribute, value ) );
+    }
+    
+    
+    /**
+     * Sets the matching rule to use.  Can be either a name or an OID string.
+     *
+     * @param matchingRule The matching rule to use
+     * @return This filter
+     */
+    public MatchingRuleAssertionFilterBuilder setMatchingRule( String matchingRule )
+    {
+        ( ( MatchingRuleAssertionFilter ) filter ).setMatchingRule( matchingRule );
+        return this;
+    }
+    
+    
+    /**
+     * If set, the dn attributes will be included in the matching.
+     *
+     * @return This filter
+     */
+    public MatchingRuleAssertionFilterBuilder useDnAttributes()
+    {
+        ( ( MatchingRuleAssertionFilter ) filter ).useDnAttributes();
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/SetOfFiltersFilter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/SetOfFiltersFilter.java
new file mode 100755
index 0000000..1561a8d
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/SetOfFiltersFilter.java
@@ -0,0 +1,139 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * An implementation of the Filter interface for the AND and OR Filters
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No qualifier*/final class SetOfFiltersFilter extends AbstractFilter
+{
+    /** The operator to use with this set (AND or OR) */
+    private FilterOperator operator;
+
+    /** The list of inner filters */
+    private List<Filter> filters;
+
+
+    /**
+     * Creates a new instance of SetOfFiltersFilter.
+     */
+    private SetOfFiltersFilter( FilterOperator operator )
+    {
+        this.operator = operator;
+        this.filters = new ArrayList<Filter>();
+    }
+
+
+    /**
+     * Adds a Filter into the set of Filters 
+     *
+     * @param filter The filter to add
+     * @return The Set of Filters with the added filter
+     */
+    public SetOfFiltersFilter add( Filter filter )
+    {
+        filters.add( filter );
+        return this;
+    }
+
+
+    /**
+     * Injects a list of Filters into the set of Filters 
+     *
+     * @param filters The filters to inject
+     * @return The Set of Filters with the injected filters
+     */
+    public SetOfFiltersFilter addAll( Filter... filters )
+    {
+        for ( Filter filter : filters )
+        {
+            this.filters.add( filter );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * Injects a list of Filters into the set of Filters 
+     *
+     * @param filters The filters to inject
+     * @return The Set of Filters with the injected filters
+     */
+    public SetOfFiltersFilter addAll( List<Filter> filters )
+    {
+        this.filters.addAll( filters );
+
+        return this;
+    }
+
+
+    /**
+     * Creates an AND set of filters
+     *
+     * @param filters The inner filters
+     * @return An AND filter
+     */
+    public static SetOfFiltersFilter and( Filter... filters )
+    {
+        return new SetOfFiltersFilter( FilterOperator.AND ).addAll( filters );
+    }
+
+
+    /**
+     * Creates an OR set of filters
+     *
+     * @param filters The inner filters
+     * @return An OR filter
+     */
+    public static SetOfFiltersFilter or( Filter... filters )
+    {
+        return new SetOfFiltersFilter( FilterOperator.OR ).addAll( filters );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StringBuilder build( StringBuilder builder )
+    {
+        if ( filters.isEmpty() )
+        {
+            throw new IllegalStateException( "at least one filter required" );
+        }
+
+        builder.append( "(" ).append( operator.operator() );
+
+        for ( Filter filter : filters )
+        {
+            filter.build( builder );
+        }
+
+        return builder.append( ")" );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/SubstringFilter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/SubstringFilter.java
new file mode 100644
index 0000000..03fd2c1
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/SubstringFilter.java
@@ -0,0 +1,253 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.filter.FilterEncoder;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A class used to manage Substring Filters.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+final class SubstringFilter extends AbstractFilter
+{
+    /** The AttributeType for this filter */
+    private String attribute;
+
+    /** The initial substring string. It may be null */
+    private String initial;
+
+    /** The array of any substring strings. It may be null */
+    private String[] any;
+
+    /** The final substring string. It may be null */
+    private String end;
+
+
+    /**
+     * A private constructor that builds a SubstringFilter 
+     */
+    private SubstringFilter( String attribute, String initial, String[] any, String end )
+    {
+        this.attribute = attribute;
+        this.initial = initial;
+
+        // We have to filter the 'any' and remove every empty strings
+        if ( ( any != null ) && ( any.length != 0 ) )
+        {
+            List<String> anyList = new ArrayList<String>();
+
+            for ( String string : any )
+            {
+                if ( !Strings.isEmpty( string ) )
+                {
+                    anyList.add( string );
+                }
+            }
+
+            if ( anyList.size() > 0 )
+            {
+                this.any = anyList.toArray( new String[]
+                    {} );
+            }
+        }
+
+        this.end = end;
+    }
+
+
+    /**
+     * Create a SubstringFilter based on the filter elements. Such a filter
+     * has a form like <b>Attribute=initial*([any]*)*</b>. We don't expect any
+     * <em>final</em> String.
+     *
+     * @param attribute The AttributeType for this filter
+     * @param parts The parts that are the initial string and zero to N any strings
+     * @return An instance of a SubstringFilter
+     */
+    public static SubstringFilter startsWith( String attribute, String... parts )
+    {
+        if ( ( parts != null ) && ( parts.length > 0 ) )
+        {
+            if ( parts.length > 1 )
+            {
+                String[] any = new String[parts.length - 1];
+                System.arraycopy( parts, 1, any, 0, any.length );
+
+                return new SubstringFilter( attribute, parts[0], any, null );
+            }
+            else
+            {
+                return new SubstringFilter( attribute, parts[0], null, null );
+            }
+        }
+        else
+        {
+            // This is a presence filter, kind of
+            return new SubstringFilter( attribute, null, null, null );
+        }
+    }
+
+
+    /**
+     * Create a SubstringFilter based on the filter elements. Such a filter
+     * has a form like <b>Attribute=*([any]*)*final</b>. We don't expect any
+     * <em>initial</em> String.
+     *
+     * @param attribute The AttributeType for this filter
+     * @param parts The parts that are zero to N any strings followed by a final string
+     * @return An instance of a SubstringFilter
+     */
+    public static SubstringFilter endsWith( String attribute, String... parts )
+    {
+        if ( ( parts != null ) && ( parts.length > 0 ) )
+        {
+            if ( parts.length > 1 )
+            {
+                String[] any = new String[parts.length - 1];
+                System.arraycopy( parts, 0, any, 0, any.length );
+
+                return new SubstringFilter( attribute, null, any, parts[parts.length - 1] );
+            }
+            else
+            {
+                return new SubstringFilter( attribute, null, null, parts[0] );
+            }
+        }
+        else
+        {
+            // This is a presence filter, kind of
+            return new SubstringFilter( attribute, null, null, null );
+        }
+    }
+
+
+    /**
+     * Create a SubstringFilter based on the filter elements. Such a filter
+     * has a form like <b>Attribute=*([any]*)*</b>. We don't expect any
+     * <em>initial</em>or <em>final</em> Strings.
+     *
+     * @param attribute The AttributeType for this filter
+     * @param parts The parts that are zero to N any strings with no initial nor final Strings
+     * @return An instance of a SubstringFilter
+     */
+    public static SubstringFilter contains( String attribute, String... parts )
+    {
+        if ( ( parts != null ) && ( parts.length > 0 ) )
+        {
+            if ( parts.length > 1 )
+            {
+                String[] any = new String[parts.length];
+                System.arraycopy( parts, 0, any, 0, any.length );
+
+                return new SubstringFilter( attribute, null, any, null );
+            }
+            else
+            {
+                return new SubstringFilter( attribute, null, parts, null );
+            }
+        }
+        else
+        {
+            // This is a presence filter, kind of
+            return new SubstringFilter( attribute, null, null, null );
+        }
+    }
+
+
+    /**
+     * Create a SubstringFilter based on the filter elements. Such a filter
+     * has a form like <b>Attribute=initial*([any]*)*final</b>.
+     *
+     * @param attribute The AttributeType for this filter
+     * @param parts The parts that are zero to N any strings starting with an initial String and 
+     * followed by a final string
+     * @return An instance of a SubstringFilter
+     */
+    public static SubstringFilter substring( String attribute, String... parts )
+    {
+        if ( ( parts != null ) && ( parts.length > 0 ) )
+        {
+            if ( parts.length > 2 )
+            {
+                // We have initial, any and final
+                String[] any = new String[parts.length - 2];
+                System.arraycopy( parts, 1, any, 0, any.length );
+
+                return new SubstringFilter( attribute, parts[0], any, parts[parts.length - 1] );
+            }
+            else if ( parts.length > 1 )
+            {
+                // we only have initial and final
+                return new SubstringFilter( attribute, parts[0], null, parts[1] );
+            }
+            else
+            {
+                // We don't have any or final
+                return new SubstringFilter( attribute, parts[0], null, null );
+            }
+        }
+        else
+        {
+            // This is a presence filter, kind of
+            return new SubstringFilter( attribute, null, null, null );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StringBuilder build( StringBuilder builder )
+    {
+        builder.append( "(" ).append( attribute ).append( '=' );
+
+        if ( !Strings.isEmpty( initial ) )
+        {
+            builder.append( FilterEncoder.encodeFilterValue( initial ) );
+        }
+
+        if ( any != null )
+        {
+            for ( String string : any )
+            {
+                builder.append( '*' ).append( FilterEncoder.encodeFilterValue( string ) );
+            }
+        }
+
+        builder.append( '*' );
+
+        if ( !Strings.isEmpty( end ) )
+        {
+            builder.append( FilterEncoder.encodeFilterValue( end ) );
+        }
+
+        builder.append( ")" );
+
+        return builder;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/UnaryFilter.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/UnaryFilter.java
new file mode 100755
index 0000000..c3a72f9
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/search/UnaryFilter.java
@@ -0,0 +1,84 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+/**
+ * Creates a NOT filter
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No qualifier*/final class UnaryFilter extends AbstractFilter
+{
+    /** The NOT filter */
+    private Filter filter;
+
+
+    /**
+     * Creates a new instance of UnaryFilter.
+     */
+    private UnaryFilter()
+    {
+    }
+
+
+    /**
+     * Constructs a NOT filter 
+     *
+     * @return The constructed NOT Filter
+     */
+    public static UnaryFilter not()
+    {
+        return new UnaryFilter();
+    }
+
+
+    /**
+     * Constructs a NOT filter with the associated inner Filter
+     *
+     * @param Filter The inner Filter
+     * @return The constructed NOT Filter
+     */
+    public static UnaryFilter not( Filter filter )
+    {
+        UnaryFilter notFilter = not();
+        notFilter.filter = filter;
+
+        return notFilter;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StringBuilder build( StringBuilder builder )
+    {
+        if ( filter == null )
+        {
+            throw new IllegalStateException( "filter not set" );
+        }
+
+        builder.append( "(" ).append( FilterOperator.NOT.operator() );
+        filter.build( builder );
+
+        return builder.append( ")" );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/AbstractPasswordPolicyResponder.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/AbstractPasswordPolicyResponder.java
new file mode 100755
index 0000000..2fbb4f8
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/AbstractPasswordPolicyResponder.java
@@ -0,0 +1,139 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.ldap.client.template.exception.PasswordException;
+
+
+/**
+ * A base, abstract, implementation of <code>PasswordPolicyResponder</code>.  
+ * Extend this class and override {@link #success(PasswordPolicy)}, 
+ * {@link #fail(ResultResponse, PasswordPolicy, ResultCodeEnum)}, or
+ * {@link #exception(LdapException)}.  If that does not offer enough
+ * flexibility, you must implement PasswordPolicyResponder yourself.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractPasswordPolicyResponder implements PasswordPolicyResponder
+{
+    private final PasswordPolicyDecorator passwordPolicyRequestControl;
+
+
+    protected AbstractPasswordPolicyResponder( LdapApiService ldapApiService )
+    {
+        this.passwordPolicyRequestControl = new PasswordPolicyDecorator(
+            ldapApiService );
+    }
+    
+    
+    /**
+     * Translates an <code>LdapException</code> to a 
+     * <code>PasswordException</code> to be thrown when 
+     * {@link #process(PasswordPolicyOperation)} fails.
+     * 
+     * @param e
+     * @return
+     */
+    protected PasswordException exception( LdapException e )
+    {
+        return new PasswordException().setLdapException( e );
+    }
+    
+    
+    /**
+     * Returns an exception to be thrown in the case of a non SUCCESS 
+     * <code>resultCode</code>.
+     * 
+     * @param resultResponse
+     * @param passwordPolicy
+     * @param resultCode
+     * @return
+     */
+    protected PasswordException fail( ResultResponse resultResponse, 
+            PasswordPolicy passwordPolicy, ResultCodeEnum resultCode )
+    {
+        PasswordException exception = new PasswordException();
+        exception.setResultCode( resultCode );
+        if ( passwordPolicy != null
+            && passwordPolicy.getResponse() != null
+            && passwordPolicy.getResponse().getPasswordPolicyError() != null )
+        {
+            exception.setPasswordPolicyError( passwordPolicy.getResponse().getPasswordPolicyError() );
+        }
+        return exception;
+    }
+
+
+    private PasswordPolicy getPasswordPolicy( Response response )
+    {
+        Control control = response.getControls().get( passwordPolicyRequestControl.getOid() );
+        return control == null
+            ? null
+            : ( ( PasswordPolicyDecorator ) control ).getDecorated();
+    }
+
+
+    @Override
+    public final PasswordWarning process( PasswordPolicyOperation operation )
+        throws PasswordException
+    {
+        try
+        {
+            ResultResponse response = operation.process();
+            PasswordPolicy passwordPolicy = getPasswordPolicy( response );
+            ResultCodeEnum resultCode = response.getLdapResult().getResultCode();
+            if ( resultCode == ResultCodeEnum.SUCCESS )
+            {
+                return success( passwordPolicy );
+            }
+            else
+            {
+                throw fail( response, passwordPolicy, resultCode );
+            }
+        }
+        catch ( LdapException e )
+        {
+            throw new PasswordException().setLdapException( e );
+        }
+    }
+    
+    /**
+     * Returns a <code>PasswordWarning</code>, or <code>null</code> if no 
+     * warnings were present in the supplied <code>passwordPolicy</code>.
+     * 
+     * @param passwordPolicy
+     * @return
+     */
+    protected PasswordWarning success( PasswordPolicy passwordPolicy ) 
+    {
+        return passwordPolicy == null
+                ? null
+                : PasswordWarningImpl.newWarning( passwordPolicy );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ConnectionCallback.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ConnectionCallback.java
new file mode 100755
index 0000000..5c34066
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ConnectionCallback.java
@@ -0,0 +1,43 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.ldap.client.api.LdapConnection;
+
+
+/**
+ * A callback for running code against a managed {@link LdapConnection}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ConnectionCallback<T>
+{
+    /**
+     * Provides a managed connection to the implementation of this method.
+     * The implementation is not responsible for open/close or borrow/return.
+     *
+     * @param connection The connection supplied to the implementation.
+     * @return Anything you want
+     * @throws LdapException If you want to
+     */
+    T doWithConnection( LdapConnection connection ) throws LdapException;
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/EntryMapper.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/EntryMapper.java
new file mode 100755
index 0000000..ef26ead
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/EntryMapper.java
@@ -0,0 +1,42 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * A callback for processing entries from a search result.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface EntryMapper<T>
+{
+    /**
+     * Will be called once for each entry in the search result.
+     *
+     * @param entry An entry from the search result
+     * @return A object modeling the entry
+     * @throws LdapException If something goes wrong
+     */
+    T map( Entry entry ) throws LdapException;
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/LdapConnectionOperations.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/LdapConnectionOperations.java
new file mode 100755
index 0000000..e59cf4e
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/LdapConnectionOperations.java
@@ -0,0 +1,583 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.ldap.client.api.search.FilterBuilder;
+import org.apache.directory.ldap.client.template.exception.PasswordException;
+
+
+/**
+ * Specifies the set of operations available on
+ * {@link org.apache.directory.ldap.client.template.LdapConnectionTemplate
+ * LdapConnectionTemplate}.  This interface can be useful for unit testing
+ * in order to stub out methods.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface LdapConnectionOperations
+{
+
+    /**
+     * Adds an entry specified by an AddRequest to the LDAP server.
+     *
+     * @param addRequest The request
+     * @return An AddResponse
+     */
+    AddResponse add( AddRequest addRequest );
+
+
+    /**
+     * Adds an entry specified by a Dn and an array of Attribute's to the LDAP
+     * server.
+     *
+     * @param dn The distinguished name of the new entry
+     * @param attributes The attributes of the new entry
+     * @return An AddResponse
+     */
+    AddResponse add( Dn dn, Attribute... attributes );
+
+
+    /**
+     * Adds an entry specified by a Dn, to be filled out by a RequestBuilder,
+     * to the LDAP server.
+     *
+     * @param dn The distinguished name of the new entry
+     * @param requestBuilder The request builder
+     * @return An AddResponse
+     */
+    AddResponse add( Dn dn, RequestBuilder<AddRequest> requestBuilder );
+
+
+    /**
+     * Attempts to authenticate the supplied credentials against the first 
+     * entry found matching the search criteria.  If authentication fails, 
+     * a PasswordException is thrown.  If successful, the response is 
+     * checked for warnings, and if present, a PasswordWarning is returned.
+     * Otherwise, null is returned.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param password
+     * @return
+     * @throws PasswordException
+     * @see {@link #authenticate(Dn, char[])}
+     * @see {@link #searchFirst(String, String, SearchScope, EntryMapper)}
+     */
+    PasswordWarning authenticate( String baseDn, String filter, SearchScope scope, char[] password )
+        throws PasswordException;
+
+
+    /**
+     * Attempts to authenticate the supplied credentials against the first 
+     * entry found matching the search criteria.  If authentication fails, 
+     * a PasswordException is thrown.  If successful, the response is 
+     * checked for warnings, and if present, a PasswordWarning is returned.
+     * Otherwise, null is returned.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param password
+     * @return
+     * @throws PasswordException
+     * @see {@link #authenticate(Dn, char[])}
+     * @see {@link #searchFirst(Dn, String, SearchScope, EntryMapper)}
+     */
+    PasswordWarning authenticate( Dn baseDn, String filter, SearchScope scope, char[] password )
+        throws PasswordException;
+
+
+    /**
+     * Attempts to authenticate the supplied credentials against the first 
+     * entry found matching the search criteria.  If authentication fails, 
+     * a PasswordException is thrown.  If successful, the response is 
+     * checked for warnings, and if present, a PasswordWarning is returned.
+     * Otherwise, null is returned.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param password
+     * @return
+     * @throws PasswordException
+     * @see {@link #authenticate(Dn, char[])}
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    PasswordWarning authenticate( SearchRequest searchRequest, char[] password ) throws PasswordException;
+
+
+    /**
+     * Attempts to authenticate the supplied credentials.  If authentication
+     * fails, a PasswordException is thrown.  If successful, the response is 
+     * checked for warnings, and if present, a PasswordWarning is returned.
+     * Otherwise, null is returned.
+     *
+     * @param userDn The distinguished name of the user
+     * @param password The password
+     * @return A PasswordWarning or null
+     * @throws PasswordException If authentication fails
+     */
+    PasswordWarning authenticate( Dn userDn, char[] password ) throws PasswordException;
+
+
+    /**
+     * Deletes an entry specified by a DeleteRequest from the LDAP server.
+     *
+     * @param deleteRequest The request
+     * @return A DeleteResponse
+     */
+    DeleteResponse delete( DeleteRequest deleteRequest );
+
+
+    /**
+     * Deletes an entry specified by Dn from the LDAP server.
+     *
+     * @param dn The distinguished name of the entry
+     * @return A DeleteResponse
+     */
+    DeleteResponse delete( Dn dn );
+
+
+    /**
+     * Deletes an entry specified by Dn, and whose request is configured
+     * by a RequestBuilder, from the LDAP server.
+     *
+     * @param dn The distinguished name of the entry
+     * @param requestBuilder The RequestBuilder
+     * @return A DeleteResponse
+     */
+    DeleteResponse delete( Dn dn, RequestBuilder<DeleteRequest> requestBuilder );
+
+
+    /**
+     * Executes the <code>connectionCallback</code>, supplying it a managed
+     * connection.
+     *
+     * @param connectionCallback The callback
+     * @return Whatever the callback returns
+     */
+    <T> T execute( ConnectionCallback<T> connectionCallback );
+
+
+    /**
+     * Performs a lookup, and supplies the matching entry to the 
+     * <code>entryMapper</code>.
+     *
+     * @param dn The distinguished name of the entry
+     * @param entryMapper The mapper from entry to model object
+     * @return Whatever the <code>entryMapper</code> returns
+     */
+    <T> T lookup( Dn dn, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Performs a lookup, requesting <code>attributes</code>, and supplies 
+     * the matching entry to the <code>entryMapper</code>.
+     *
+     * @param dn The distinguished name of the entry
+     * @param attributes The attributes to be fetched
+     * @param entryMapper The mapper from entry to model object
+     * @return Whatever the <code>entryMapper</code> returns
+     */
+    <T> T lookup( Dn dn, String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Modifies the password for <code>userDn</code> to
+     * <code>newPassword</code> using the admin account.
+     *
+     * @param userDn
+     * @param newPassword
+     * @throws PasswordException
+     * @see {@link #modifyPassword(Dn, char[], char[], boolean)}
+     */
+    void modifyPassword( Dn userDn, char[] newPassword )
+        throws PasswordException;
+
+
+    /**
+     * Modifies the password for <code>userDn</code> from 
+     * <code>oldPassword</code> to <code>newPassword</code>.
+     *
+     * @param userDn
+     * @param oldPassword
+     * @param newPassword
+     * @throws PasswordException
+     * @see {@link #modifyPassword(Dn, char[], char[], boolean)}
+     */
+    void modifyPassword( Dn userDn, char[] oldPassword,
+        char[] newPassword ) throws PasswordException;
+
+
+    /**
+     * Modifies the password for <code>userDn</code> from 
+     * <code>oldPassword</code> to <code>newPassword</code>, optionally using
+     * an admin account.  If <code>asAdmin</code> is true, then the operation
+     * is performed in admin context which means <code>oldPassword</code> is
+     * may be <code>null</code>.
+     *
+     * @param userDn The distinguished name of the user
+     * @param oldPassword The users old password (optional if asAdmin is true)
+     * @param newPassword The users new password
+     * @param asAdmin If true, execute in admin context
+     * @throws PasswordException If the password modification fails
+     */
+    void modifyPassword( Dn userDn, char[] oldPassword, char[] newPassword,
+        boolean asAdmin ) throws PasswordException;
+
+
+    /**
+     * Modifies an entry specified by a ModifyRequest on the LDAP server.
+     *
+     * @param modifyRequest The request
+     * @return A ModifyResponse
+     */
+    ModifyResponse modify( ModifyRequest modifyRequest );
+
+
+    /**
+     * Modifies an entry specified by Dn, and whose request is configured
+     * by a RequestBuilder, on the LDAP server.
+     *
+     * @param dn The distinguished name of the entry
+     * @param requestBuilder The RequestBuilder
+     * @return A ModifyResponse
+     */
+    ModifyResponse modify( Dn dn, RequestBuilder<ModifyRequest> requestBuilder );
+
+
+    /**
+     * Checks the supplied response for its result code, and if not 
+     * {@link ResultCodeEnum#SUCCESS}, an exception is thrown. This method is 
+     * intened to be used inline:
+     * 
+     * <pre>
+     * template.responseOrException( template.delete( dn ) );
+     * </pre>
+     *
+     * @param response The response to check for success
+     * @return The supplied <code>response</code>
+     * @throws LdapRequestUnsuccessfulException If the response is not
+     * {@link ResultCodeEnum#SUCCESS}
+     */
+    <T extends ResultResponse> T responseOrException( T response );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( String baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( String baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #search(SearchRequest, EntryMapper)}
+     */
+    <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the entries matching the supplied 
+     * <code>searchRequest</code>, feeding the result into the 
+     * <code>entryMapper</code>.
+     *
+     * @param searchRequest The search request
+     * @param entryMapper The mapper
+     * @return The mapped entries
+     */
+    <T> List<T> search( SearchRequest searchRequest,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( String baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( String baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied criteria, feeding the 
+     * result into the <code>entryMapper</code>, querying only the requested 
+     * attributes.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @param entryMapper
+     * @return The mapped entries
+     * @see {@link #searchFirst(SearchRequest, EntryMapper)}
+     */
+    <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper );
+
+
+    /**
+     * Searches for the first entry matching the supplied 
+     * <code>searchRequest</code>, feeding the result into the 
+     * <code>entryMapper</code>. This is basically the same as 
+     * {@link #search(SearchRequest, EntryMapper)}, but is optimized by
+     * modifying the <code>searchRequest</code> to set its size limit to 1.
+     * The <code>searchRequest</code> is returned to its original size limit
+     * before this method returns (or throws an exception).
+     *
+     * @param searchRequest The search request
+     * @param entryMapper The mapper
+     * @return The mapped entry
+     */
+    <T> T searchFirst( SearchRequest searchRequest,
+        EntryMapper<T> entryMapper );
+
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/LdapConnectionTemplate.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/LdapConnectionTemplate.java
new file mode 100755
index 0000000..9e5bf9d
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/LdapConnectionTemplate.java
@@ -0,0 +1,824 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.ldap.client.api.EntryCursorImpl;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapConnectionPool;
+import org.apache.directory.ldap.client.api.search.FilterBuilder;
+import org.apache.directory.ldap.client.template.exception.LdapRequestUnsuccessfulException;
+import org.apache.directory.ldap.client.template.exception.LdapRuntimeException;
+import org.apache.directory.ldap.client.template.exception.PasswordException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A facade for LDAP operations that handles all of the boiler plate code for 
+ * you allowing more concise operations through the use of callbacks.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * 
+ * @see <a href="http://en.wikipedia.org/wiki/Template_method_pattern">Template method pattern</a>
+ */
+public class LdapConnectionTemplate implements LdapConnectionOperations, ModelFactory
+{
+    private static final Logger LOG = LoggerFactory.getLogger( LdapConnectionTemplate.class );
+    private static final EntryMapper<Dn> DN_ENTRY_MAPPER = new EntryMapper<Dn>()
+    {
+        @Override
+        public Dn map( Entry entry ) throws LdapException
+        {
+            return entry.getDn();
+        }
+    };
+
+    private LdapConnectionPool connectionPool;
+    private final PasswordPolicyDecorator passwordPolicyRequestControl;
+    private PasswordPolicyResponder passwordPolicyResponder;
+    private ModelFactory modelFactory;
+
+
+    /**
+     * Creates a new instance of LdapConnectionTemplate.
+     *
+     * @param connectionPool The pool to obtain connections from.
+     */
+    public LdapConnectionTemplate( LdapConnectionPool connectionPool )
+    {
+        LOG.debug( "creating new connection template from connectionPool" );
+        this.connectionPool = connectionPool;
+        this.passwordPolicyRequestControl = new PasswordPolicyDecorator(
+            connectionPool.getLdapApiService() );
+        this.passwordPolicyResponder = new PasswordPolicyResponderImpl(
+            connectionPool.getLdapApiService() );
+        this.modelFactory = new ModelFactoryImpl();
+    }
+
+
+    @Override
+    public AddResponse add( Dn dn, final Attribute... attributes )
+    {
+        return add( dn,
+            new RequestBuilder<AddRequest>()
+            {
+                @Override
+                public void buildRequest( AddRequest request ) throws LdapException
+                {
+                    request.getEntry().add( attributes );
+                }
+            } );
+    }
+
+
+    @Override
+    public AddResponse add( Dn dn, RequestBuilder<AddRequest> requestBuilder )
+    {
+        AddRequest addRequest = newAddRequest( newEntry( dn ) );
+        try
+        {
+            requestBuilder.buildRequest( addRequest );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        return add( addRequest );
+    }
+
+
+    @Override
+    public AddResponse add( AddRequest addRequest )
+    {
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+            return connection.add( addRequest );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+    }
+
+
+    @Override
+    public PasswordWarning authenticate( String baseDn, String filter, SearchScope scope, char[] password )
+        throws PasswordException
+    {
+        return authenticate( newSearchRequest( baseDn, filter, scope ), password );
+    }
+
+
+    @Override
+    public PasswordWarning authenticate( Dn baseDn, String filter, SearchScope scope, char[] password )
+        throws PasswordException
+    {
+        return authenticate( newSearchRequest( baseDn, filter, scope ), password );
+    }
+
+
+    @Override
+    public PasswordWarning authenticate( SearchRequest searchRequest, char[] password ) throws PasswordException
+    {
+        Dn userDn = searchFirst( searchRequest, DN_ENTRY_MAPPER );
+        if ( userDn == null )
+        {
+            throw new PasswordException().setResultCode( ResultCodeEnum.INVALID_CREDENTIALS );
+        }
+
+        return authenticate( userDn, password );
+    }
+
+
+    @Override
+    public PasswordWarning authenticate( Dn userDn, char[] password ) throws PasswordException
+    {
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+            return authenticateConnection( connection, userDn, password );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+    }
+
+
+    private PasswordWarning authenticateConnection( final LdapConnection connection,
+        final Dn userDn, final char[] password ) throws PasswordException
+    {
+        return passwordPolicyResponder.process(
+            new PasswordPolicyOperation()
+            {
+                @Override
+                public ResultResponse process() throws LdapException
+                {
+                    MemoryClearingBuffer passwordBuffer = MemoryClearingBuffer.newInstance( password );
+                    try
+                    {
+                        BindRequest bindRequest = new BindRequestImpl()
+                            .setDn( userDn )
+                            .setCredentials( passwordBuffer.getBytes() )
+                            .addControl( passwordPolicyRequestControl );
+
+                        return connection.bind( bindRequest );
+                    }
+                    finally
+                    {
+                        passwordBuffer.clear();
+                    }
+                }
+            } );
+    }
+
+
+    @Override
+    public DeleteResponse delete( Dn dn )
+    {
+        return delete( dn, null );
+    }
+
+
+    @Override
+    public DeleteResponse delete( Dn dn, RequestBuilder<DeleteRequest> requestBuilder )
+    {
+        DeleteRequest deleteRequest = newDeleteRequest( dn );
+        if ( requestBuilder != null )
+        {
+            try
+            {
+                requestBuilder.buildRequest( deleteRequest );
+            }
+            catch ( LdapException e )
+            {
+                throw new LdapRuntimeException( e );
+            }
+        }
+        return delete( deleteRequest );
+    }
+
+
+    @Override
+    public DeleteResponse delete( DeleteRequest deleteRequest )
+    {
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+            return connection.delete( deleteRequest );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+    }
+
+
+    @Override
+    public <T> T execute( ConnectionCallback<T> connectionCallback )
+    {
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+            return connectionCallback.doWithConnection( connection );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+    }
+
+
+    @Override
+    public <T> T lookup( Dn dn, EntryMapper<T> entryMapper )
+    {
+        return lookup( dn, null, entryMapper );
+    }
+
+
+    @Override
+    public <T> T lookup( Dn dn, String[] attributes, EntryMapper<T> entryMapper )
+    {
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+            Entry entry = attributes == null
+                ? connection.lookup( dn )
+                : connection.lookup( dn, attributes );
+            return entry == null ? null : entryMapper.map( entry );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+    }
+
+
+    private void modifyPassword( final LdapConnection connection, final Dn userDn,
+        final char[] newPassword ) throws PasswordException
+    {
+        passwordPolicyResponder.process(
+            new PasswordPolicyOperation()
+            {
+                @Override
+                public ResultResponse process() throws PasswordException, LdapException
+                {
+                    // Can't use Password Modify:
+                    // https://issues.apache.org/jira/browse/DIRSERVER-1935
+                    // So revert to regular Modify
+                    MemoryClearingBuffer newPasswordBuffer = MemoryClearingBuffer.newInstance( newPassword );
+                    try
+                    {
+                        ModifyRequest modifyRequest = new ModifyRequestImpl()
+                            .setName( userDn )
+                            .replace( "userPassword", newPasswordBuffer.getComputedBytes() )
+                            .addControl( passwordPolicyRequestControl );
+
+                        return connection.modify( modifyRequest );
+                    }
+                    finally
+                    {
+                        newPasswordBuffer.clear();
+                    }
+                }
+            } );
+
+    }
+
+
+    @Override
+    public void modifyPassword( Dn userDn, char[] newPassword )
+        throws PasswordException
+    {
+        modifyPassword( userDn, null, newPassword, true );
+    }
+
+
+    @Override
+    public void modifyPassword( Dn userDn, char[] oldPassword,
+        char[] newPassword ) throws PasswordException
+    {
+        modifyPassword( userDn, oldPassword, newPassword, false );
+    }
+
+
+    @Override
+    public void modifyPassword( Dn userDn, char[] oldPassword,
+        char[] newPassword, boolean asAdmin ) throws PasswordException
+    {
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+            if ( !asAdmin )
+            {
+                authenticateConnection( connection, userDn, oldPassword );
+            }
+
+            modifyPassword( connection, userDn, newPassword );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+    }
+
+
+    @Override
+    public ModifyResponse modify( Dn dn, RequestBuilder<ModifyRequest> requestBuilder )
+    {
+        ModifyRequest modifyRequest = newModifyRequest( dn );
+        try
+        {
+            requestBuilder.buildRequest( modifyRequest );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        return modify( modifyRequest );
+    }
+
+
+    @Override
+    public ModifyResponse modify( ModifyRequest modifyRequest )
+    {
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+            return connection.modify( modifyRequest );
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+    }
+
+
+    @Override
+    public AddRequest newAddRequest( Entry entry )
+    {
+        return modelFactory.newAddRequest( entry );
+    }
+
+
+    @Override
+    public Attribute newAttribute( String name )
+    {
+        return modelFactory.newAttribute( name );
+    }
+
+
+    @Override
+    public Attribute newAttribute( String name, byte[]... values )
+    {
+        return modelFactory.newAttribute( name, values );
+    }
+
+
+    @Override
+    public Attribute newAttribute( String name, String... values )
+    {
+        return modelFactory.newAttribute( name, values );
+    }
+
+
+    @Override
+    public Attribute newAttribute( String name, Value<?>... values )
+    {
+        return modelFactory.newAttribute( name, values );
+    }
+
+
+    @Override
+    public DeleteRequest newDeleteRequest( Dn dn )
+    {
+        return modelFactory.newDeleteRequest( dn );
+    }
+
+
+    @Override
+    public Dn newDn( String dn )
+    {
+        return modelFactory.newDn( dn );
+    }
+
+
+    @Override
+    public Entry newEntry( String dn )
+    {
+        return modelFactory.newEntry( dn );
+    }
+
+
+    @Override
+    public Entry newEntry( Dn dn )
+    {
+        return modelFactory.newEntry( dn );
+    }
+
+
+    @Override
+    public ModifyRequest newModifyRequest( String dn )
+    {
+        return modelFactory.newModifyRequest( dn );
+    }
+
+
+    @Override
+    public ModifyRequest newModifyRequest( Dn dn )
+    {
+        return modelFactory.newModifyRequest( dn );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter, SearchScope scope )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, String filter, SearchScope scope )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter, SearchScope scope )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, String filter, SearchScope scope )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter, SearchScope scope, String... attributes )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, String filter, SearchScope scope, String... attributes )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter, SearchScope scope, String... attributes )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, String filter, SearchScope scope, String... attributes )
+    {
+        return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
+    }
+
+
+    @Override
+    public <T extends ResultResponse> T responseOrException( T response )
+    {
+        if ( ResultCodeEnum.SUCCESS != response.getLdapResult().getResultCode() )
+        {
+            throw new LdapRequestUnsuccessfulException( response );
+        }
+        return response;
+    }
+
+
+    private void returnLdapConnection( LdapConnection connection )
+    {
+        if ( connection != null )
+        {
+            try
+            {
+                connectionPool.releaseConnection( connection );
+            }
+            catch ( LdapException e )
+            {
+                throw new LdapRuntimeException( e );
+            }
+        }
+    }
+
+
+    @Override
+    public <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( String baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( String baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return search(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> List<T> search( SearchRequest searchRequest,
+        EntryMapper<T> entryMapper )
+    {
+        List<T> entries = new ArrayList<T>();
+
+        LdapConnection connection = null;
+        try
+        {
+            connection = connectionPool.getConnection();
+
+            for ( Entry entry : new EntryCursorImpl( connection.search( searchRequest ) ) )
+            {
+                entries.add( entryMapper.map( entry ) );
+            }
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        finally
+        {
+            returnLdapConnection( connection );
+        }
+
+        return entries;
+    }
+
+
+    @Override
+    public <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( String baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
+        EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( String baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
+        String[] attributes, EntryMapper<T> entryMapper )
+    {
+        return searchFirst(
+            modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
+            entryMapper );
+    }
+
+
+    @Override
+    public <T> T searchFirst( SearchRequest searchRequest,
+        EntryMapper<T> entryMapper )
+    {
+        // in case the caller did not set size limit, we cache original value,
+        // set to 1, then set back to original value before returning...
+        long originalSizeLimit = searchRequest.getSizeLimit();
+        try
+        {
+            searchRequest.setSizeLimit( 1 );
+            List<T> entries = search( searchRequest, entryMapper );
+            return entries.isEmpty() ? null : entries.get( 0 );
+        }
+        finally
+        {
+            searchRequest.setSizeLimit( originalSizeLimit );
+        }
+    }
+
+
+    /**
+     * Sets the <code>modelFactory</code> implementation for this facade.
+     *
+     * @param modelFactory The model factory implementation
+     */
+    public void setModelFactory( ModelFactory modelFactory )
+    {
+        this.modelFactory = modelFactory;
+    }
+
+
+    /**
+     * Sets the <code>passwordPolicyResponder</code> implementation for this
+     * facade.
+     *
+     * @param passwordPolicyResponder The password policy responder 
+     * implementation
+     */
+    public void setPasswordPolicyResponder( PasswordPolicyResponder passwordPolicyResponder )
+    {
+        this.passwordPolicyResponder = passwordPolicyResponder;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/MemoryClearingBuffer.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/MemoryClearingBuffer.java
new file mode 100755
index 0000000..1734e0a
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/MemoryClearingBuffer.java
@@ -0,0 +1,250 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+
+/**
+ * A buffer for storing sensitive information like passwords.  It provides 
+ * useful operations for characters such as character encoding/decoding, 
+ * whitespace trimming, and lowercasing.  It can be cleared out when operations
+ * are complete.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class MemoryClearingBuffer
+{
+    private static final Charset UTF8 = Charset.forName( "UTF-8" );
+    private byte[] computedBytes;
+    private char[] computedChars;
+    private byte[] originalBytes;
+    private char[] originalChars;
+    private char[] precomputedChars;
+
+
+    private MemoryClearingBuffer( byte[] originalBytes, char[] originalChars, boolean trim, boolean lowerCase )
+    {
+        this.originalBytes = originalBytes;
+        this.originalChars = originalChars;
+
+        if ( trim || lowerCase )
+        {
+            if ( this.originalChars == null )
+            {
+                throw new UnsupportedOperationException( "trim and lowerCase only applicable to char[]" );
+            }
+
+            char[] working = Arrays.copyOf( originalChars, originalChars.length );
+            int startIndex = 0;
+            int endIndex = working.length;
+
+            if ( trim )
+            {
+                // ltrim
+                for ( ; startIndex < working.length; startIndex++ )
+                {
+                    if ( !Character.isWhitespace( working[startIndex] ) )
+                    {
+                        break;
+                    }
+                }
+
+                // rtrim
+                for ( endIndex--; endIndex > startIndex; endIndex-- )
+                {
+                    if ( !Character.isWhitespace( working[endIndex] ) )
+                    {
+                        break;
+                    }
+                }
+                endIndex++;
+            }
+
+            if ( lowerCase )
+            {
+                // lower case
+                for ( int i = startIndex; i < endIndex; i++ )
+                {
+                    working[i] = Character.toLowerCase( working[i] );
+                }
+            }
+
+            this.precomputedChars = new char[endIndex - startIndex];
+            System.arraycopy( working, startIndex, this.precomputedChars, 0, endIndex - startIndex );
+        }
+        else
+        {
+            this.precomputedChars = this.originalChars;
+        }
+    }
+
+
+    /**
+     * Creates a new instance of MemoryClearingBuffer from a 
+     * <code>byte[]</code>.
+     *
+     * @param bytes A byte[]
+     * @return A buffer
+     */
+    public static MemoryClearingBuffer newInstance( byte[] bytes )
+    {
+        return new MemoryClearingBuffer( bytes, null, false, false );
+    }
+
+
+    /**
+     * Creates a new instance of MemoryClearingBuffer from a 
+     * <code>char[]</code>.
+     *
+     * @param chars A char[]
+     * @return A buffer
+     */
+    public static MemoryClearingBuffer newInstance( char[] chars )
+    {
+        return new MemoryClearingBuffer( null, chars, false, false );
+    }
+
+
+    /**
+     * Creates a new instance of MemoryClearingBuffer from a 
+     * <code>char[]</code>, optionally performing whitespace trimming and
+     * conversion to lower case.
+     *
+     * @param chars A char[]
+     * @param trim If true, whitespace will be trimmed off of both ends of the
+     * <code>char[]</code>
+     * @param lowerCase If true, the characters will be converted to lower case
+     * @return A buffer
+     */
+    public static MemoryClearingBuffer newInstance( char[] chars, boolean trim, boolean lowerCase )
+    {
+        return new MemoryClearingBuffer( null, chars, trim, lowerCase );
+    }
+
+
+    /**
+     *  Clears the buffer out, filling its cells with null.
+     */
+    public void clear()
+    {
+        // clear out computed memory
+        if ( computedBytes != null )
+        {
+            Arrays.fill( computedBytes, ( byte ) 0 );
+        }
+        if ( computedChars != null )
+        {
+            Arrays.fill( computedChars, '0' );
+        }
+        if ( precomputedChars != null && precomputedChars != this.originalChars )
+        {
+            // only nullify if NOT originalChars
+            Arrays.fill( precomputedChars, '0' );
+        }
+
+        computedBytes = null;
+        computedChars = null;
+        originalBytes = null;
+        originalChars = null;
+        precomputedChars = null;
+    }
+
+
+    /**
+     * Returns a UTF8 encoded <code>byte[]</code> representation of the 
+     * <code>char[]</code> used to create this buffer.
+     * 
+     * @return A byte[]
+     */
+    byte[] getComputedBytes()
+    {
+        if ( computedBytes == null )
+        {
+            ByteBuffer byteBuffer = UTF8.encode(
+                CharBuffer.wrap( precomputedChars, 0, precomputedChars.length ) );
+            computedBytes = new byte[byteBuffer.remaining()];
+            byteBuffer.get( computedBytes );
+
+            // clear out the temporary bytebuffer
+            byteBuffer.flip();
+            byte[] nullifier = new byte[byteBuffer.limit()];
+            Arrays.fill( nullifier, ( byte ) 0 );
+            byteBuffer.put( nullifier );
+        }
+        return computedBytes;
+    }
+
+
+    /**
+     * Returns a UTF8 decoded <code>char[]</code> representation of the 
+     * <code>byte[]</code> used to create this buffer.
+     *
+     * @return A char[]
+     */
+    private char[] getComputedChars()
+    {
+        if ( computedChars == null )
+        {
+            CharBuffer charBuffer = UTF8.decode(
+                ByteBuffer.wrap( originalBytes, 0, originalBytes.length ) );
+            computedChars = new char[charBuffer.remaining()];
+            charBuffer.get( computedChars );
+
+            // clear out the temporary bytebuffer
+            charBuffer.flip();
+            char[] nullifier = new char[charBuffer.limit()];
+            Arrays.fill( nullifier, ( char ) 0 );
+            charBuffer.put( nullifier );
+        }
+        return computedChars;
+    }
+
+
+    /**
+     * Returns the <code>byte[]</code> used to create this buffer, or 
+     * {@link #getComputedBytes()} if created with a <code>char[]</code>.
+     *
+     * @return A byte[]
+     */
+    public byte[] getBytes()
+    {
+        return originalBytes == null
+            ? getComputedBytes()
+            : originalBytes;
+    }
+
+    /**
+     * Returns the <code>char[]</code> used to create this buffer, or 
+     * {@link #getComputedChars()} if created with a <code>byte[]</code>.
+     *
+     * @return A byte[]
+     */
+    public char[] getChars()
+    {
+        return precomputedChars == null
+            ? getComputedChars()
+            : precomputedChars;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ModelFactory.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ModelFactory.java
new file mode 100755
index 0000000..1dcfdc3
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ModelFactory.java
@@ -0,0 +1,263 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.ldap.client.api.search.FilterBuilder;
+
+
+/**
+ * A factory for creating {@link org.apache.directory.api.ldap.model} objects.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ModelFactory
+{
+    /**
+     * Returns a new <code>AddRequest</code> for the <code>entry</code>.
+     *
+     * @param entry
+     * @return
+     */
+    AddRequest newAddRequest( Entry entry );
+
+
+    /**
+     * Returns a new Attribute for with the provided <code>name</code> and
+     * a null value.  This is useful for clearing out an Attribute with a
+     * ModifyRequest, replace function.
+     *
+     * @param name
+     * @return
+     */
+    Attribute newAttribute( String name );
+
+
+    /**
+     * Returns a new Attribute for with the provided <code>name</code> and
+     * <code>value(s)</code>.
+     *
+     * @param name
+     * @param values
+     * @return
+     */
+    Attribute newAttribute( String name, byte[]... values );
+
+
+    /**
+     * Returns a new Attribute for with the provided <code>name</code> and
+     * <code>value(s)</code>.
+     *
+     * @param name
+     * @param values
+     * @return
+     */
+    Attribute newAttribute( String name, String... values );
+
+
+    /**
+     * Returns a new Attribute for with the provided <code>name</code> and
+     * <code>value(s)</code>.
+     *
+     * @param name
+     * @param values
+     * @return
+     */
+    Attribute newAttribute( String name, Value<?>... values );
+
+
+    /**
+     * Returns a new <code>DeleteRequest</code> for the <code>dn</code>.
+     *
+     * @param dn
+     * @return
+     */
+    DeleteRequest newDeleteRequest( Dn dn );
+
+
+    /**
+     * Returns a <code>Dn</code> that represents <code>dn</code>.
+     *
+     * @param dn
+     * @return
+     */
+    Dn newDn( String dn );
+
+
+    /**
+     * Returns a <code>Entry</code> with the specified <code>dn</code>.
+     *
+     * @param dn
+     * @return
+     */
+    Entry newEntry( String dn );
+
+
+    /**
+     * Returns a <code>Entry</code> with the specified <code>dn</code>.
+     *
+     * @param dn
+     * @return
+     */
+    Entry newEntry( Dn dn );
+
+
+    /**
+     * Returns a new <code>ModifyRequest</code> for the <code>dn</code>.
+     *
+     * @param dn 
+     * @return
+     */
+    ModifyRequest newModifyRequest( String dn );
+
+
+    /**
+     * Returns a new <code>ModifyRequest</code> for the <code>dn</code>.
+     *
+     * @param dn
+     * @return
+     */
+    ModifyRequest newModifyRequest( Dn dn );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * all normal attributes for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @return
+     */
+    SearchRequest newSearchRequest( String baseDn, FilterBuilder filter,
+        SearchScope scope );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * all normal attributes for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @return
+     */
+    SearchRequest newSearchRequest( String baseDn, String filter,
+        SearchScope scope );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * all normal attributes for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @return
+     */
+    SearchRequest newSearchRequest( Dn baseDn, String filter,
+        SearchScope scope );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * all normal attributes for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @return
+     */
+    SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter,
+        SearchScope scope );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * <code>attributes</code> for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @return
+     */
+    SearchRequest newSearchRequest( String baseDn, String filter,
+        SearchScope scope, String... attributes );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * <code>attributes</code> for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @return
+     */
+    SearchRequest newSearchRequest( String baseDn, FilterBuilder filter,
+        SearchScope scope, String... attributes );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * <code>attributes</code> for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @return
+     */
+    SearchRequest newSearchRequest( Dn baseDn, String filter,
+        SearchScope scope, String... attributes );
+
+
+    /**
+     * Returns a new <code>SearchRequest</code> over <code>baseDn</code> in
+     * <code>scope</code> matching <code>filter</code> returning 
+     * <code>attributes</code> for each matching entry.
+     *
+     * @param baseDn
+     * @param filter
+     * @param scope
+     * @param attributes
+     * @return
+     */
+    SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter,
+        SearchScope scope, String... attributes );
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ModelFactoryImpl.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ModelFactoryImpl.java
new file mode 100755
index 0000000..2e63d8e
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/ModelFactoryImpl.java
@@ -0,0 +1,213 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddRequestImpl;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.ldap.client.api.search.FilterBuilder;
+import org.apache.directory.ldap.client.template.exception.LdapRuntimeException;
+
+
+/**
+ * The default implementation of {@link ModelFactory}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ModelFactoryImpl implements ModelFactory
+{
+    @Override
+    public AddRequest newAddRequest( Entry entry )
+    {
+        return new AddRequestImpl().setEntry( entry );
+    }
+
+
+    @Override
+    public Attribute newAttribute( String name )
+    {
+        return new DefaultAttribute( name );
+    }
+
+
+    @Override
+    public Attribute newAttribute( String name, byte[]... values )
+    {
+        return new DefaultAttribute( name, values );
+    }
+
+    
+    @Override
+    public Attribute newAttribute( String name, String... values )
+    {
+        return new DefaultAttribute( name, values );
+    }
+    
+
+    @Override
+    public Attribute newAttribute( String name, Value<?>... values )
+    {
+        return new DefaultAttribute( name, values );
+    }
+
+
+    @Override
+    public DeleteRequest newDeleteRequest( Dn dn )
+    {
+        return new DeleteRequestImpl()
+            .setName( dn );
+    }
+
+
+    @Override
+    public Dn newDn( String dn )
+    {
+        try
+        {
+            return new Dn( dn );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+    }
+
+
+    @Override
+    public Entry newEntry( String dn )
+    {
+        return newEntry( newDn( dn ) );
+    }
+
+
+    @Override
+    public Entry newEntry( Dn dn )
+    {
+        return new DefaultEntry( dn );
+    }
+
+
+    @Override
+    public ModifyRequest newModifyRequest( String dn )
+    {
+        return newModifyRequest( newDn( dn ) );
+    }
+
+
+    @Override
+    public ModifyRequest newModifyRequest( Dn dn )
+    {
+        return new ModifyRequestImpl().setName( dn );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter,
+        SearchScope scope )
+    {
+        return newSearchRequest( newDn( baseDn ), filter.toString(), scope );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, String filter,
+        SearchScope scope )
+    {
+        return newSearchRequest( newDn( baseDn ), filter, scope );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter,
+        SearchScope scope )
+    {
+        return newSearchRequest( baseDn, filter.toString(), scope, ( String[] ) null );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, String filter,
+        SearchScope scope )
+    {
+        return newSearchRequest( baseDn, filter, scope, ( String[] ) null );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter,
+        SearchScope scope, String... attributes )
+    {
+        return newSearchRequest( newDn( baseDn ), filter.toString(), scope, attributes );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( String baseDn, String filter,
+        SearchScope scope, String... attributes )
+    {
+        return newSearchRequest( newDn( baseDn ), filter, scope, attributes );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter,
+        SearchScope scope, String... attributes )
+    {
+        return newSearchRequest( baseDn, filter.toString(), scope, attributes );
+    }
+
+
+    @Override
+    public SearchRequest newSearchRequest( Dn baseDn, String filter,
+        SearchScope scope, String... attributes )
+    {
+        SearchRequest searchRequest = null;
+        try
+        {
+            searchRequest = new SearchRequestImpl()
+                .setBase( baseDn )
+                .setFilter( filter )
+                .setScope( scope == null ? SearchScope.OBJECT : scope );
+            if ( attributes != null && attributes.length > 0 )
+            {
+                searchRequest.addAttributes( attributes );
+            }
+        }
+        catch ( LdapException e )
+        {
+            throw new LdapRuntimeException( e );
+        }
+        return searchRequest;
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyOperation.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyOperation.java
new file mode 100755
index 0000000..9740ea6
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyOperation.java
@@ -0,0 +1,46 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.ldap.client.template.exception.PasswordException;
+
+
+/**
+ * An callback for processing requests whose success/failure imply some sort
+ * of password policy information.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PasswordPolicyOperation
+{
+    /**
+     * Execute operations whose results imply somme sort of password policy
+     * information.
+     *
+     * @return The final response of the operation
+     * @throws PasswordException If there was a failure for a password policy
+     * reason
+     * @throws LdapException If there was an general ldap failure
+     */
+    ResultResponse process() throws PasswordException, LdapException;
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyResponder.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyResponder.java
new file mode 100755
index 0000000..ce17c4f
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyResponder.java
@@ -0,0 +1,49 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.ldap.client.template.exception.PasswordException;
+
+
+/**
+ * A class for translating the outcome of a {@link PasswordPolicyOperation}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PasswordPolicyResponder
+{
+    /**
+     * Execute the <code>operation</code> and translate the outcome as follows:
+     * 
+     * <ul>
+     * <li>SUCCESS: return null</li>
+     * <li>WARNING: return {@link PasswordWarning}</li>
+     * <li>FAILURE: throw {@link PasswordException}</li>
+     * </ul>
+     * 
+     * @param operation An operation whose outcome implies password policy 
+     * information
+     * @return A <code>PasswordWarning</code> if warnings are present, or null 
+     * if completely successful.
+     * @throws PasswordException If the <code>operation</code> was a failure.
+     */
+    PasswordWarning process( PasswordPolicyOperation operation ) throws PasswordException;
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyResponderImpl.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyResponderImpl.java
new file mode 100755
index 0000000..f1cde1b
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordPolicyResponderImpl.java
@@ -0,0 +1,38 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+
+
+/**
+ * The default implementation of {@link PasswordPolicyResponder}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+final class PasswordPolicyResponderImpl extends AbstractPasswordPolicyResponder 
+    implements PasswordPolicyResponder
+{
+    PasswordPolicyResponderImpl( LdapApiService ldapApiService )
+    {
+        super( ldapApiService );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordWarning.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordWarning.java
new file mode 100755
index 0000000..314ac4b
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordWarning.java
@@ -0,0 +1,56 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import java.io.Serializable;
+
+
+/**
+ * A container for password warning information.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PasswordWarning extends Serializable
+{
+    /**
+     * Returns the number of seconds before the password will expire.
+     *
+     * @return The number of seconds before the password will expire
+     */
+    int getTimeBeforeExpiration();
+
+
+    /**
+     * Returns the number of remaining authentications before the account will 
+     * be locked.
+     *
+     * @return The number of authentications before lockout
+     */
+    int getGraceAuthNsRemaining();
+
+
+    /**
+     * Returns true, if a password reset is required.
+     *
+     * @return True, if a password reset is required
+     */
+    boolean isChangeAfterReset();
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordWarningImpl.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordWarningImpl.java
new file mode 100755
index 0000000..bac1b5f
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/PasswordWarningImpl.java
@@ -0,0 +1,88 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyResponse;
+
+
+/**
+ * The default implementation of {@link PasswordWarning}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+final class PasswordWarningImpl implements PasswordWarning
+{
+    private static final long serialVersionUID = -8952246313604352357L;
+
+    private int timeBeforeExpiration = -1;
+    private int graceAuthNsRemaining = -1;
+    private boolean changeAfterReset = false;
+
+
+    private PasswordWarningImpl()
+    {
+    }
+
+
+    static PasswordWarning newWarning( PasswordPolicy policy )
+    {
+        PasswordPolicyResponse response = policy.getResponse();
+        if ( response != null )
+        {
+            PasswordWarningImpl policyWarning = new PasswordWarningImpl();
+            policyWarning.timeBeforeExpiration = response.getTimeBeforeExpiration();
+            policyWarning.graceAuthNsRemaining = response.getGraceAuthNRemaining();
+            policyWarning.changeAfterReset = response.getPasswordPolicyError() == PasswordPolicyErrorEnum.CHANGE_AFTER_RESET;
+
+            if ( policyWarning.timeBeforeExpiration >= 0 || policyWarning.graceAuthNsRemaining >= 0
+                || policyWarning.changeAfterReset )
+            {
+                // it actually is a warning!
+                return policyWarning;
+            }
+        }
+        return null;
+    }
+
+
+    @Override
+    public int getTimeBeforeExpiration()
+    {
+        return timeBeforeExpiration;
+    }
+
+
+    @Override
+    public int getGraceAuthNsRemaining()
+    {
+        return graceAuthNsRemaining;
+    }
+
+
+    @Override
+    public boolean isChangeAfterReset()
+    {
+        return changeAfterReset;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/RequestBuilder.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/RequestBuilder.java
new file mode 100755
index 0000000..9950bd8
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/RequestBuilder.java
@@ -0,0 +1,44 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * Edits a supplied request adding specifics.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface RequestBuilder<T>
+{
+    /**
+     * Modifies the provided request adding specific information to it.
+     * The supplied request is typically a factory built request with just
+     * its Dn set.  It is the responsibility of this method to fill in all
+     * of the details.  The request will be sent to the LDAP server upon
+     * upon returning from this method.
+     *
+     * @param request The request to be modified
+     * @throws LdapException If something goes wrong
+     */
+    void buildRequest( T request ) throws LdapException;
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/LdapRequestUnsuccessfulException.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/LdapRequestUnsuccessfulException.java
new file mode 100755
index 0000000..becc4da
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/LdapRequestUnsuccessfulException.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.template.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+
+
+/**
+ * An RuntimeException wrapper class that allows the user to choose to have
+ * unsuccessful responses thrown as exceptions rather than checking the 
+ * response itself for process flow.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapRequestUnsuccessfulException extends RuntimeException
+{
+    private static final long serialVersionUID = 1982294624076306127L;
+
+    private ResultResponse response;
+
+
+    public LdapRequestUnsuccessfulException( ResultResponse response )
+    {
+        super();
+        this.response = response;
+    }
+
+
+    public ResultResponse getResponse()
+    {
+        return response;
+    }
+
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/LdapRuntimeException.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/LdapRuntimeException.java
new file mode 100755
index 0000000..95041e0
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/LdapRuntimeException.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.template.exception;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * An RuntimeException wrapper class for exceptions which add LDAP specific 
+ * information to Exceptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapRuntimeException extends RuntimeException
+{
+    private static final long serialVersionUID = 3618077059423567243L;
+
+
+    public LdapRuntimeException( LdapException exception )
+    {
+        super( exception );
+    }
+}
diff --git a/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/PasswordException.java b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/PasswordException.java
new file mode 100644
index 0000000..eb90426
--- /dev/null
+++ b/trunk/ldap/client/api/src/main/java/org/apache/directory/ldap/client/template/exception/PasswordException.java
@@ -0,0 +1,103 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.template.exception;
+
+
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * Thrown when an attempt to bind or modify a userPassword fails when using
+ * {@link LdapConnectionTemplate}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordException extends Exception
+{
+    private static final long serialVersionUID = -1185823188085178776L;
+
+    private LdapException ldapException;
+    private ResultCodeEnum resultCode;
+    private PasswordPolicyErrorEnum passwordPolicyError;
+
+
+    public PasswordException()
+    {
+        super();
+    }
+
+
+    /**
+     * If an LdapException was thrown causing this exception, that 
+     * LdapException is returned.  Otherwise null is returned.
+     *
+     * @return The LdapException that was thrown, or null.
+     */
+    public LdapException getLdapException()
+    {
+        return ldapException;
+    }
+
+
+    /**
+     * Returns the result code from the attempt to bind or modify the 
+     * userPassword.
+     *
+     * @return The result code.
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return resultCode;
+    }
+
+
+    /**
+     * Returns the password policy error code if present, otherwise null.
+     *
+     * @return The password policy error code or null.
+     */
+    public PasswordPolicyErrorEnum getPasswordPolicyError()
+    {
+        return passwordPolicyError;
+    }
+
+
+    public PasswordException setLdapException( LdapException ldapException )
+    {
+        this.ldapException = ldapException;
+        return this;
+    }
+
+
+    public PasswordException setPasswordPolicyError( PasswordPolicyErrorEnum passwordPolicyError )
+    {
+        this.passwordPolicyError = passwordPolicyError;
+        return this;
+    }
+
+
+    public PasswordException setResultCode( ResultCodeEnum resultCode )
+    {
+        this.resultCode = resultCode;
+        return this;
+    }
+}
diff --git a/trunk/ldap/client/api/src/site/site.xml b/trunk/ldap/client/api/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/client/api/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdapNetworkConnectionTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdapNetworkConnectionTest.java
new file mode 100644
index 0000000..e1b6990
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdapNetworkConnectionTest.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+
+/**
+ * Tests LdapNetworkConnection.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(Parameterized.class)
+public class LdapNetworkConnectionTest
+{
+
+    private long connectionTimeoutInMS;
+    private int searchTimeLimitInSeconds;
+    private long expectedTimeoutInMS;
+
+
+    @Parameters(name = "{index}: {0},{1}->{2}")
+    public static Collection<Object[]> data()
+    {
+        return Arrays.asList( new Object[][]
+            {
+                    // index 0: connection timout in ms
+                    // index 1: search time limit in seconds
+                    // index 2: expected timeout in ms
+                    { 2000, -1, 2000, "Invalid search time limit, use connection timeout" },
+                    { 2000, 0, Long.MAX_VALUE, "Search time limit is 0, use max value" },
+                    { 2000, 1, 2000, "search time limit < connection timeout, use connection timeout" },
+                    { 2000, 5, 5000, "search time limit > connection timeout, use search time limit" },
+                    { 2000, Integer.MAX_VALUE, 2147483647000L, "Integer overflow" },
+                    { 30000, -1, 30000, "Invalid search time limit, use connection timeout" },
+                    { 30000, 0, Long.MAX_VALUE, "Search time limit is 0, use max value" },
+                    { 30000, 1, 30000, "search time limit < connection timeout, use connection timeout" },
+                    { 30000, 29, 30000, "search time limit < connection timeout, use connection timeout" },
+                    { 30000, 31, 31000, "search time limit > connection timeout, use search time limit" },
+                    { 30000, 60, 60000, "search time limit > connection timeout, use search time limit" },
+                    { Long.MAX_VALUE, -1, Long.MAX_VALUE, "Invalid search time limit, use connection timeout" },
+                    { Long.MAX_VALUE, 0, Long.MAX_VALUE, "Search time limit is 0, use max value" },
+                    { Long.MAX_VALUE, 1, Long.MAX_VALUE,
+                        "search time limit < connection timeout, use connection timeout" }, } );
+    }
+
+
+    public LdapNetworkConnectionTest( long connectionTimeoutInMS, int searchTimeLimitInSeconds,
+        long expectedTimeoutInMS, String testDescription )
+    {
+        this.connectionTimeoutInMS = connectionTimeoutInMS;
+        this.searchTimeLimitInSeconds = searchTimeLimitInSeconds;
+        this.expectedTimeoutInMS = expectedTimeoutInMS;
+    }
+
+
+    @Test
+    public void testGetClientTimeout()
+    {
+        long timeout = LdapNetworkConnection.getTimeout( connectionTimeoutInMS, searchTimeLimitInSeconds );
+        assertEquals( expectedTimeoutInMS, timeout );
+    }
+
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdifAnonymizerTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdifAnonymizerTest.java
new file mode 100644
index 0000000..f400f75
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdifAnonymizerTest.java
@@ -0,0 +1,139 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api;
+
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+/**
+ * A class used to test the LDIFAnonymizer
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifAnonymizerTest
+{
+    private static SchemaManager schemaManager;
+    
+    @BeforeClass
+    public static void setup()
+    {
+        schemaManager = null;
+        
+        try
+        {
+            schemaManager = new DefaultSchemaManager();
+        }
+        catch ( Exception e )
+        {
+            // Todo : we need a schemaManager
+            System.out.println( "Missing a SchemaManager !" );
+            System.exit( -1 );
+        }
+    }
+    
+    
+    @Test
+    public void testLdifAnonymizer() throws Exception, Exception
+    {
+        String ldif =
+            "dn: cn=test,dc=example,dc=com\n" +
+            "ObjectClass: top\n" +
+            "objectClass: person\n" +
+            "cn: test\n" +
+            "sn: Test\n" +
+            "\n" +
+            "dn: cn=emmanuel,dc=acme,dc=com\n" +
+            "ObjectClass: top\n" +
+            "objectClass: person\n" +
+            "cn: emmanuel\n" +
+            "sn: elecharny\n"+
+            "\n" +
+            "dn: cn=emmanuel,dc=test,dc=example,dc=com\n" +
+            "ObjectClass: top\n" +
+            "objectClass: person\n" +
+            "cn: emmanuel\n" +
+            "seeAlso: cn=emmanuel,dc=acme,dc=com\n" +
+            "sn: elecharny\n";
+
+        SchemaManager schemaManager = null;
+        
+        try
+        {
+            schemaManager = new DefaultSchemaManager();
+        }
+        catch ( Exception e )
+        {
+            // Todo : we need a schemaManager
+            System.out.println( "Missing a SchemaManager !" );
+            System.exit( -1 );
+        }
+
+        LdifAnonymizer anonymizer = new LdifAnonymizer( schemaManager );
+        anonymizer.addNamingContext( "dc=example,dc=com" );
+        anonymizer.addNamingContext( "dc=acme,dc=com" );
+        anonymizer.removeAnonAttributeType( schemaManager.getAttributeType( "sn" ) );
+        
+        anonymizer.anonymize( ldif );
+    }
+
+
+    @Test
+    public void testLdifAnonymizer2() throws Exception, Exception
+    {
+        String ldif =
+            "dn: cn=cn2 + sn=elecharny, dc=example, dc=com\n" +
+                "ObjectClass: top\n" +
+                "objectClass: person\n" +
+                "cn: cn1\n" +
+                "cn: cn2\n" +
+                "cn: cn3\n" +
+                "sn: elecharny\n" +
+                "givenname: test\n";
+
+        LdifAnonymizer anonymizer = new LdifAnonymizer( schemaManager );
+        anonymizer.addNamingContext( "dc=example,dc=com" );
+        anonymizer.anonymize( ldif );
+    }
+
+
+    @Test
+    public void testLdifAnonymizer3() throws Exception, Exception
+    {
+        String ldif =
+            "dn: cn=cn2 + sn=elecharny, dc=example, dc=com\n" +
+                "ObjectClass: top\n" +
+                "objectClass: person\n" +
+                "cn: cn1\n" +
+                "cn: cn2\n" +
+                "cn: cn3\n" +
+                "userPassword: test\n" +
+                "sn: elecharny\n" +
+                "givenname: test\n";
+
+        LdifAnonymizer anonymizer = new LdifAnonymizer( schemaManager );
+        anonymizer.addNamingContext( "dc=example,dc=com" );
+        anonymizer.anonymize( ldif );
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/MockLdapConnectionFactory.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/MockLdapConnectionFactory.java
new file mode 100755
index 0000000..4bb9d82
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/MockLdapConnectionFactory.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+public class MockLdapConnectionFactory extends DefaultLdapConnectionFactory
+{
+    Queue<LdapConnection> connections = new LinkedList<LdapConnection>();
+
+
+    public MockLdapConnectionFactory( LdapConnectionConfig config )
+    {
+        super( config );
+    }
+
+
+    public MockLdapConnectionFactory addConnection( LdapConnection connection )
+    {
+        this.connections.add( connection );
+        return this;
+    }
+
+
+    @Override
+    public LdapConnection newLdapConnection() throws LdapException
+    {
+        return bindConnection( this.connections.remove() );
+    }
+
+
+    @Override
+    public LdapConnection newUnboundLdapConnection()
+    {
+        return this.connections.remove();
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactoryTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactoryTest.java
new file mode 100755
index 0000000..3b2ab17
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/ValidatingPoolableLdapConnectionFactoryTest.java
@@ -0,0 +1,568 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequestImpl;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.mockito.exceptions.misusing.NotAMockException;
+import org.mockito.internal.util.MockUtil;
+import org.mockito.verification.VerificationMode;
+
+
+public class ValidatingPoolableLdapConnectionFactoryTest
+{
+    private static final String ADMIN_CREDENTIALS = "secret";
+    private static final String ADMIN_DN = "uid=admin, ou=system";
+    private static final MockUtil MOCK_UTIL = new MockUtil();
+
+
+    @Test
+    public void testPoolWithBind()
+    {
+        PoolTester tester = new PoolTester();
+
+        // no bind
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // bind()
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.bind();
+                    verify( connection, times( 1 ) ).bind();
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // anonymousBind()
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.anonymousBind();
+                    verify( connection, times( 1 ) ).anonymousBind();
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // bind( String )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.bind( "" );
+                    verify( connection, times( 1 ) ).bind( "" );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // admin bind( String, String )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.bind( ADMIN_DN, ADMIN_CREDENTIALS );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // bind( String, String )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.bind( "", "" );
+                    verify( connection, times( 1 ) ).bind( "", "" );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // bind( Dn )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    Dn dn = new Dn();
+                    connection.bind( dn );
+                    verify( connection, times( 1 ) ).bind( dn );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // bind( Dn, String )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    Dn dn = new Dn();
+                    connection.bind( dn, "" );
+                    verify( connection, times( 1 ) ).bind( dn, "" );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // bind( BindRequest );
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    BindRequest bindRequest = new BindRequestImpl();
+                    connection.bind( bindRequest );
+                    verify( connection, times( 1 ) ).bind( bindRequest );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+    }
+
+
+    @Test
+    public void testPoolWithStartTls()
+    {
+        PoolTester tester = new PoolTester();
+
+        // extended( String )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.extended( StartTlsRequest.EXTENSION_OID );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // extended( String, byte[] )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.extended( StartTlsRequest.EXTENSION_OID, new byte[]
+                        {} );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // extended( Oid )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    try
+                    {
+                        connection.extended( Oid.fromString( StartTlsRequest.EXTENSION_OID ) );
+                    }
+                    catch ( DecoderException e )
+                    {
+                        throw new IllegalArgumentException( "invalid oid: " + StartTlsRequest.EXTENSION_OID );
+                    }
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // extended( Oid, byte[] )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    try
+                    {
+                        connection.extended( Oid.fromString( StartTlsRequest.EXTENSION_OID ), new byte[]
+                            {} );
+                    }
+                    catch ( DecoderException e )
+                    {
+                        throw new IllegalArgumentException( "invalid oid: " + StartTlsRequest.EXTENSION_OID );
+                    }
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+
+        // extended( ExtendedRequest )
+        tester.execute(
+            new WithConnection()
+            {
+                @Override
+                public void execute( LdapConnection connection, Counts counts ) throws LdapException
+                {
+                    connection.extended( new StartTlsRequestImpl() );
+                    verifyAdminBind( connection, times( counts.adminBindCount ) );
+                }
+            } );
+    }
+
+
+    private static final void verifyAdminBind( LdapConnection connection, VerificationMode mode ) throws LdapException
+    {
+        verify( connection, mode ).bind( ADMIN_DN, ADMIN_CREDENTIALS );
+    }
+
+
+    private static final LdapConnection verify( LdapConnection connection, VerificationMode mode )
+    {
+        if ( MOCK_UTIL.isMock( connection ) )
+        {
+            return org.mockito.Mockito.verify( connection, mode );
+        }
+        else
+        {
+            if ( connection instanceof Wrapper )
+            {
+                @SuppressWarnings("unchecked")
+                LdapConnection unwrapped = ( ( Wrapper<LdapConnection> ) connection ).wrapped();
+                return verify( unwrapped, mode );
+            }
+        }
+        throw new NotAMockException( "connection is not a mock, nor a wrapper for a connection that is one" );
+    }
+
+    private static final class Counts
+    {
+        private int adminBindCount = 0;
+        private int unBindCount = 0;
+    }
+
+    public static final class InternalMonitoringLdapConnection extends LdapConnectionWrapper
+    {
+        private static final Oid START_TLS_OID;
+
+        static
+        {
+            try
+            {
+                START_TLS_OID = Oid.fromString( StartTlsRequest.EXTENSION_OID );
+            }
+            catch ( DecoderException e )
+            {
+                throw new IllegalStateException( "StartTlsRequest.EXTENSION_OID is not a valid oid...  IMPOSSIBLE" );
+            }
+        }
+
+        private int borrowedCount = 0;
+        private boolean bindCalled = false;
+        private Counts counts = new Counts();
+        private boolean startTlsCalled = false;
+        private boolean unBindCalled = false;
+
+
+        InternalMonitoringLdapConnection( LdapConnection connection )
+        {
+            super( connection );
+        }
+
+
+        private int incrementBorrowedCount()
+        {
+            return ++borrowedCount;
+        }
+
+
+        public boolean bindCalled()
+        {
+            return bindCalled;
+        }
+
+
+        public void resetMonitors()
+        {
+            bindCalled = false;
+            startTlsCalled = false;
+            unBindCalled = false;
+        }
+
+
+        public boolean startTlsCalled()
+        {
+            return startTlsCalled;
+        }
+
+
+        public boolean unBindCalled()
+        {
+            return unBindCalled;
+        }
+
+
+        @Override
+        public void bind() throws LdapException
+        {
+            connection.bind();
+            bindCalled = true;
+        }
+
+
+        @Override
+        public void anonymousBind() throws LdapException
+        {
+            connection.anonymousBind();
+            bindCalled = true;
+        }
+
+
+        @Override
+        public void bind( String name ) throws LdapException
+        {
+            connection.bind( name );
+            bindCalled = true;
+        }
+
+
+        @Override
+        public void bind( String name, String credentials ) throws LdapException
+        {
+            connection.bind( name, credentials );
+            if ( ADMIN_DN.equals( name )
+                && ADMIN_CREDENTIALS.equals( credentials ) )
+            {
+                counts.adminBindCount++;
+            }
+            bindCalled = true;
+        }
+
+
+        @Override
+        public void bind( Dn name ) throws LdapException
+        {
+            connection.bind( name );
+            bindCalled = true;
+        }
+
+
+        @Override
+        public void bind( Dn name, String credentials ) throws LdapException
+        {
+            connection.bind( name, credentials );
+            bindCalled = true;
+        }
+
+
+        @Override
+        public BindResponse bind( BindRequest bindRequest ) throws LdapException
+        {
+            BindResponse response = connection.bind( bindRequest );
+            bindCalled = true;
+            return response;
+        }
+
+
+        @Override
+        public ExtendedResponse extended( String oid ) throws LdapException
+        {
+            if ( StartTlsRequest.EXTENSION_OID.equals( oid ) )
+            {
+                startTlsCalled = true;
+            }
+            return connection.extended( oid );
+        }
+
+
+        @Override
+        public ExtendedResponse extended( String oid, byte[] value ) throws LdapException
+        {
+            if ( StartTlsRequest.EXTENSION_OID.equals( oid ) )
+            {
+                startTlsCalled = true;
+            }
+            return connection.extended( oid, value );
+        }
+
+
+        @Override
+        public ExtendedResponse extended( Oid oid ) throws LdapException
+        {
+            if ( START_TLS_OID.equals( oid ) )
+            {
+                startTlsCalled = true;
+            }
+            return connection.extended( oid );
+        }
+
+
+        @Override
+        public ExtendedResponse extended( Oid oid, byte[] value ) throws LdapException
+        {
+            if ( START_TLS_OID.equals( oid ) )
+            {
+                startTlsCalled = true;
+            }
+            return connection.extended( oid, value );
+        }
+
+
+        @Override
+        public ExtendedResponse extended( ExtendedRequest extendedRequest ) throws LdapException
+        {
+            if ( extendedRequest.hasControl( StartTlsRequest.EXTENSION_OID ) )
+            {
+                startTlsCalled = true;
+            }
+            return connection.extended( extendedRequest );
+        }
+
+
+        @Override
+        public void unBind() throws LdapException
+        {
+            counts.unBindCount++;
+            unBindCalled = true;
+            connection.unBind();
+        }
+    }
+
+    private static class PoolTester
+    {
+        private LdapConnectionConfig config;
+        private LdapConnectionPool pool;
+        private LdapConnectionValidator validator;
+
+
+        public PoolTester()
+        {
+            LdapConnection mockConnection = mock( LdapConnection.class );
+            when( mockConnection.isAuthenticated() ).thenReturn( true );
+            when( mockConnection.isConnected() ).thenReturn( true );
+
+            config = new LdapConnectionConfig();
+            config.setName( ADMIN_DN );
+            config.setCredentials( ADMIN_CREDENTIALS );
+
+            MockLdapConnectionFactory mockConnectionFactory = new MockLdapConnectionFactory( config );
+            mockConnectionFactory.addConnection(
+                new InternalMonitoringLdapConnection( mockConnection ) );
+
+            validator = mock( LdapConnectionValidator.class );
+            when( validator.validate( any( LdapConnection.class ) ) ).thenReturn( true );
+            ValidatingPoolableLdapConnectionFactory poolableFactory =
+                new ValidatingPoolableLdapConnectionFactory( mockConnectionFactory );
+            poolableFactory.setValidator( validator );
+
+            pool = new LdapConnectionPool( poolableFactory );
+            pool.setMaxActive( 1 );
+            pool.setTestOnBorrow( true );
+            pool.setTestOnReturn( true );
+        }
+
+
+        public void execute( WithConnection withConnection )
+        {
+            LdapConnection connection = null;
+            InternalMonitoringLdapConnection internal = null;
+            int borrowedCount = 0;
+            try
+            {
+                connection = pool.getConnection();
+                assertNotNull( connection );
+                internal = ( InternalMonitoringLdapConnection ) ( ( LdapConnectionWrapper ) connection ).wrapped();
+                borrowedCount = internal.incrementBorrowedCount();
+                org.mockito.Mockito.verify( validator, times( 2 * borrowedCount - 1 ) ).validate( connection );
+                internal.resetMonitors();
+
+                withConnection.execute( connection, internal.counts );
+            }
+            catch ( LdapException e )
+            {
+                fail( "unable to getConnection(): " + e.getMessage() );
+            }
+            finally
+            {
+                try
+                {
+                    int adminBindCount = internal.counts.adminBindCount;
+                    pool.releaseConnection( connection );
+                    org.mockito.Mockito.verify( validator, times( 2 * borrowedCount ) ).validate( connection );
+
+                    if ( internal.startTlsCalled() )
+                    {
+                        verify( connection, times( internal.counts.unBindCount ) ).unBind();
+                    }
+
+                    int expectedCount = internal.bindCalled() || internal.startTlsCalled() || internal.unBindCalled()
+                        ? adminBindCount + 1
+                        : adminBindCount;
+                    verifyAdminBind( connection, times( expectedCount ) );
+                }
+                catch ( LdapException e )
+                {
+                    fail( "unable to releaseConnection(): " + e.getMessage() );
+                }
+            }
+        }
+    }
+
+    private static interface WithConnection
+    {
+        /** 
+         * Executes code using the supplied connection.
+         * 
+         * @param connection The ldap connection
+         * @param counts The counters for specific calls
+         */
+        public void execute( LdapConnection connection, Counts counts ) throws LdapException;
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/AttributeDescriptionFilterTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/AttributeDescriptionFilterTest.java
new file mode 100755
index 0000000..509f7cf
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/AttributeDescriptionFilterTest.java
@@ -0,0 +1,45 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api.search;
+
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+
+/**
+ * 
+ * TODO AttributeFilterTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeDescriptionFilterTest
+{
+    @Test
+    public void testPresent()
+    {
+        assertEquals( "(objectClass=*)", AttributeDescriptionFilter.present( "objectClass" ).build().toString() );
+        assertEquals( "(uid=*)", AttributeDescriptionFilter.present( "uid" ).build().toString() );
+        assertEquals( "(userPassword=*)", AttributeDescriptionFilter.present( "userPassword" ).build().toString() );
+        assertEquals( "(cn=*)", AttributeDescriptionFilter.present( "cn" ).build().toString() );
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/AttributeValueAssertionTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/AttributeValueAssertionTest.java
new file mode 100755
index 0000000..7fa43b9
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/AttributeValueAssertionTest.java
@@ -0,0 +1,85 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+
+/**
+ * 
+ * TODO AttributeValueAssertionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeValueAssertionTest
+{
+    @Test
+    public void testApproximatelyEqual()
+    {
+        assertEquals( "(objectClass~=person)",
+            AttributeValueAssertionFilter.approximatelyEqual( "objectClass", "person" )
+                .build().toString() );
+        assertEquals( "(uid~=admin)",
+            AttributeValueAssertionFilter.approximatelyEqual( "uid", "admin" )
+                .build().toString() );
+    }
+
+
+    @Test
+    public void testEqual()
+    {
+        assertEquals( "(objectClass=person)",
+            AttributeValueAssertionFilter.equal( "objectClass", "person" )
+                .build().toString() );
+        assertEquals( "(uid=admin)",
+            AttributeValueAssertionFilter.equal( "uid", "admin" )
+                .build().toString() );
+        assertEquals( "(cn=lu\\2A)",
+            AttributeValueAssertionFilter.equal( "cn", "lu*" )
+                .build().toString() );
+    }
+
+
+    @Test
+    public void testGreaterThanOrEqual()
+    {
+        assertEquals( "(objectClass>=person)",
+            AttributeValueAssertionFilter.greaterThanOrEqual( "objectClass", "person" )
+                .build().toString() );
+        assertEquals( "(uid>=admin)",
+            AttributeValueAssertionFilter.greaterThanOrEqual( "uid", "admin" )
+                .build().toString() );
+    }
+
+
+    @Test
+    public void testLessThanOrEqual()
+    {
+        assertEquals( "(objectClass<=person)",
+            AttributeValueAssertionFilter.lessThanOrEqual( "objectClass", "person" )
+                .build().toString() );
+        assertEquals( "(uid<=admin)",
+            AttributeValueAssertionFilter.lessThanOrEqual( "uid", "admin" )
+                .build().toString() );
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/FilterBuilderTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/FilterBuilderTest.java
new file mode 100755
index 0000000..5fd55d7
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/FilterBuilderTest.java
@@ -0,0 +1,147 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.and;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.contains;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.endsWith;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.equal;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.extensible;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.not;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.or;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.startsWith;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.substring;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+
+/**
+ * Unit tests for {@link FilterBuilder}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class FilterBuilderTest
+{
+    @Test
+    public void testExtensible()
+    {
+        assertEquals( "(cn:caseExactMatch:=Fred Flintstone)", 
+            extensible( "cn", "Fred Flintstone" )
+                .setMatchingRule( "caseExactMatch" ).toString() );
+    }
+
+    @Test
+    public void testFilterBuilder()
+    {
+        assertEquals( "(cn=Babs Jensen)", equal( "cn", "Babs Jensen" ).toString() );
+        assertEquals( "(!(cn=Tim Howes))", not( equal( "cn", "Tim Howes" ) ).toString() );
+        assertEquals( "(&(objectClass=Person)(|(sn=Jensen)(cn=Babs J\\2A)))",
+            and( equal( "objectClass", "Person" ),
+                or( equal( "sn", "Jensen" ),
+                    equal( "cn", "Babs J*" ) ) ).toString() );
+        assertEquals( "(o=univ\\2Aof\\2Amich\\2A)", equal( "o", "univ*of*mich*" ).toString() );
+    }
+
+
+    /**
+     * Test the substring builder startsWith method
+     */
+    @Test
+    public void testSubstringFilterBuilderStartsWith()
+    {
+        try
+        {
+            assertEquals( "(o=*)", startsWith( "o" ).toString() );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+        assertEquals( "(o=univ*)", startsWith( "o", "univ" ).toString() );
+        assertEquals( "(o=univ*of*mich*)", startsWith( "o", "univ", "of", "mich" ).toString() );
+    }
+
+
+    /**
+     * Test the substring builder endsWith method
+     */
+    @Test
+    public void testSubstringFilterBuilderEndsWith()
+    {
+        try
+        {
+            assertEquals( "(o=*)", endsWith( "o" ).toString() );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+        assertEquals( "(o=*igan)", endsWith( "o", "igan" ).toString() );
+        assertEquals( "(o=*sit*of*igan)", endsWith( "o", "sit", "of", "igan" ).toString() );
+    }
+
+
+    /**
+     * Test the substring builder contains method
+     */
+    @Test
+    public void testSubstringFilterBuilderContains()
+    {
+        try
+        {
+            assertEquals( "(o=*)", contains( "o" ).toString() );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+        assertEquals( "(o=*of*)", contains( "o", "of" ).toString() );
+        assertEquals( "(o=*sit*of*chi*)", contains( "o", "sit", "of", "chi" ).toString() );
+        assertEquals( "(cn=*\u00e9*)", contains( "cn", "\u00e9" ).toString() );
+        assertEquals( "(cn=*\\C3\\E9*)", contains( "cn", "\\C3\\E9" ).toString() );
+    }
+
+
+    /**
+     * Test the substring builder substring method
+     */
+    @Test
+    public void testSubstringFilterBuilderSubstring()
+    {
+        try
+        {
+            assertEquals( "(o=*)", substring( "o" ).toString() );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected
+        }
+        assertEquals( "(o=of*)", substring( "o", "of" ).toString() );
+        assertEquals( "(o=the*igan)", substring( "o", "the", "igan" ).toString() );
+        assertEquals( "(o=the*sit*of*igan)", substring( "o", "the", "sit", "of", "igan" ).toString() );
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilterTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilterTest.java
new file mode 100755
index 0000000..da65776
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/MatchingRuleAssertionFilterTest.java
@@ -0,0 +1,59 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.ldap.client.api.search;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.apache.directory.ldap.client.api.search.FilterBuilder.extensible;
+
+import org.junit.Test;
+
+
+/**
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MatchingRuleAssertionFilterTest
+{
+    @Test
+    public void testExtensible()
+    {
+        assertEquals( "(cn:caseExactMatch:=Fred Flintstone)", 
+            extensible( "cn", "Fred Flintstone" )
+                .setMatchingRule( "caseExactMatch" ).toString() );
+        assertEquals( "(cn:=Betty Rubble)",
+            extensible( "cn", "Betty Rubble" ).toString() );
+        assertEquals( "(sn:dn:2.4.6.8.10:=Barney Rubble)", 
+            extensible( "sn", "Barney Rubble" )
+                .useDnAttributes()
+                .setMatchingRule( "2.4.6.8.10" ).toString() );
+        assertEquals( "(o:dn:=Ace Industry)", 
+            extensible( "o", "Ace Industry" ) 
+                .useDnAttributes().toString() );
+        assertEquals( "(:1.2.3:=Wilma Flintstone)", 
+            extensible( "Wilma Flintstone" )
+                .setMatchingRule( "1.2.3" ).toString() );
+        assertEquals( "(:dn:2.4.6.8.10:=Dino)", 
+            extensible( "Dino" )
+                .useDnAttributes()
+                .setMatchingRule( "2.4.6.8.10" ).toString() );
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/SetOfFiltersFilterTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/SetOfFiltersFilterTest.java
new file mode 100755
index 0000000..73d4fc2
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/SetOfFiltersFilterTest.java
@@ -0,0 +1,110 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+
+/**
+ * 
+ * TODO SetOfFiltersFilterTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SetOfFiltersFilterTest
+{
+    private String expected( FilterOperator operator, Filter... filters )
+    {
+        StringBuilder builder = new StringBuilder( "(" )
+            .append( operator.operator() );
+
+        for ( Filter filter : filters )
+        {
+            filter.build( builder );
+        }
+
+        return builder.append( ")" ).toString();
+    }
+
+
+    @Test
+    public void testAnd()
+    {
+        AttributeDescriptionFilter attributeFilter = AttributeDescriptionFilter.present( "objectClass" );
+        AttributeValueAssertionFilter attributeValueAssertionFilter =
+            AttributeValueAssertionFilter.equal( "objectClass", "person" );
+        String expected = expected( FilterOperator.AND, attributeFilter, attributeValueAssertionFilter );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.and( attributeFilter, attributeValueAssertionFilter )
+                .build().toString() );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.and()
+                .add( attributeFilter )
+                .add( attributeValueAssertionFilter )
+                .build().toString() );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.and()
+                .addAll( attributeFilter, attributeValueAssertionFilter )
+                .build().toString() );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.and()
+                .addAll( Arrays.asList( ( Filter ) attributeFilter, ( Filter ) attributeValueAssertionFilter ) )
+                .build().toString() );
+    }
+
+
+    @Test
+    public void testOr()
+    {
+        AttributeDescriptionFilter attributeFilter = AttributeDescriptionFilter.present( "objectClass" );
+        AttributeValueAssertionFilter attributeValueAssertionFilter =
+            AttributeValueAssertionFilter.equal( "objectClass", "person" );
+        String expected = expected( FilterOperator.OR, attributeFilter, attributeValueAssertionFilter );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.or( attributeFilter, attributeValueAssertionFilter )
+                .build().toString() );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.or()
+                .add( attributeFilter )
+                .add( attributeValueAssertionFilter )
+                .build().toString() );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.or()
+                .addAll( attributeFilter, attributeValueAssertionFilter )
+                .build().toString() );
+
+        assertEquals( expected,
+            SetOfFiltersFilter.or()
+                .addAll( Arrays.asList( ( Filter ) attributeFilter, ( Filter ) attributeValueAssertionFilter ) )
+                .build().toString() );
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/UnaryFilterTest.java b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/UnaryFilterTest.java
new file mode 100755
index 0000000..ad5c9f1
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/search/UnaryFilterTest.java
@@ -0,0 +1,48 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api.search;
+
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+
+/**
+ * 
+ * TODO UnaryFilterTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UnaryFilterTest
+{
+    @Test
+    public void testNot()
+    {
+        AttributeDescriptionFilter attributeFilter = AttributeDescriptionFilter.present( "objectClass" );
+        assertEquals( "(!" + attributeFilter.build().toString() + ")",
+            UnaryFilter.not( attributeFilter ).build().toString() );
+
+        AttributeValueAssertionFilter attributeValueAssertionFilter =
+            AttributeValueAssertionFilter.equal( "objectClass", "person" );
+        assertEquals( "(!" + attributeValueAssertionFilter.build().toString() + ")",
+            UnaryFilter.not( attributeValueAssertionFilter ).build().toString() );
+    }
+}
diff --git a/trunk/ldap/client/api/src/test/resources/log4j.properties b/trunk/ldap/client/api/src/test/resources/log4j.properties
new file mode 100644
index 0000000..8fcd92e
--- /dev/null
+++ b/trunk/ldap/client/api/src/test/resources/log4j.properties
@@ -0,0 +1,24 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+
+#log4j.logger.org.apache.directory.api.client.api=DEBUG
+log4j.logger.org.apache.directory.api.asn1.ber=FATAL
diff --git a/trunk/ldap/client/pom.xml b/trunk/ldap/client/pom.xml
new file mode 100644
index 0000000..9d18b7e
--- /dev/null
+++ b/trunk/ldap/client/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-client-parent</artifactId>
+  <name>Apache Directory LDAP API Client Parent</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>all</module>
+    <module>api</module>
+  </modules>
+
+</project>
diff --git a/trunk/ldap/client/src/site/site.xml b/trunk/ldap/client/src/site/site.xml
new file mode 100644
index 0000000..b6ec180
--- /dev/null
+++ b/trunk/ldap/client/src/site/site.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="modules" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/codec/core/pom.xml b/trunk/ldap/codec/core/pom.xml
new file mode 100644
index 0000000..c04ed2f
--- /dev/null
+++ b/trunk/ldap/codec/core/pom.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-codec-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-codec-core</artifactId>
+  <name>Apache Directory LDAP API Codec Core</name>
+  <packaging>bundle</packaging>
+  <description>LDAP Codec used by clients and servers</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-api</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-ber</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>org.apache.mina</groupId>
+      <artifactId>mina-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>generate-sources</phase>
+            <configuration />
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-ActivationPolicy>lazy</Bundle-ActivationPolicy>
+            <Bundle-SymbolicName>${project.groupId}.ldap.codec.core</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.codec;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.actions;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.actions.*;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.api;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.controls;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.controls.*;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.decorators;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.osgi;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.codec.search;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.asn1.actions;version=${project.version},
+              org.apache.directory.api.asn1.ber;version=${project.version},
+              org.apache.directory.api.asn1.ber.grammar;version=${project.version},
+              org.apache.directory.api.asn1.ber.tlv;version=${project.version},
+              org.apache.directory.api.asn1.util;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.model.entry;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.filter;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.message.controls;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.schema;version=${project.version},
+              org.apache.directory.api.ldap.model.url;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.apache.directory.api.util.exception;version=${project.version},
+              org.apache.mina.filter.codec;version=${mina.core.version},
+              org.apache.mina.util;version=${mina.core.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              org.osgi.framework;version="[1.0.0,2.0.0)",
+              javax.naming,
+              javax.naming.directory,
+              javax.naming.ldap
+            </Import-Package>
+            <Bundle-Activator>
+              org.apache.directory.api.ldap.codec.osgi.DefaultActivator
+            </Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/codec/core/src/checkstyle/suppressions.xml b/trunk/ldap/codec/core/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..ce9ade9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/checkstyle/suppressions.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+
+  <suppress files="org.apache.directory.api.ldap.codec.LdapMessageGrammar" checks="FileLength"/>
+
+</suppressions>
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/AttributeValueAssertion.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/AttributeValueAssertion.java
new file mode 100644
index 0000000..5026ffe
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/AttributeValueAssertion.java
@@ -0,0 +1,211 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A class to store an attribute value assertion. 
+ * The grammar is :
+ * 
+ * AttributeValueAssertion ::= SEQUENCE {
+ *           attributeDesc   AttributeDescription,
+ *           assertionValue  AssertionValue }
+ *
+ * AttributeDescription ::= LDAPString
+ * 
+ * AssertionValue ::= OCTET STRING
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeValueAssertion
+{
+    // ~ Instance fields
+    // ----------------------------------------------------------------------------
+
+    /** The attribute description */
+    private String attributeDesc;
+
+    /** The assertion value */
+    private Value<?> assertionValue;
+
+
+    /**
+     *
+     * Helper method to render an object which can be a String or a byte[]
+     *
+     * @return A string representing the object
+     */
+    public static String dumpObject( Object object )
+    {
+        if ( object != null )
+        {
+            if ( object instanceof String )
+            {
+                return ( String ) object;
+            }
+            else if ( object instanceof byte[] )
+            {
+                return Strings.dumpBytes( ( byte[] ) object );
+            }
+            else if ( object instanceof StringValue )
+            {
+                return ( ( StringValue ) object ).getValue();
+            }
+            else if ( object instanceof BinaryValue )
+            {
+                return Strings.dumpBytes( ( ( BinaryValue ) object ).getValue() );
+            }
+            else
+            {
+                return "<unknown type>";
+            }
+        }
+        else
+        {
+            return "";
+        }
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * Get the assertion value
+     * 
+     * @return Returns the assertionValue.
+     */
+    public Value<?> getAssertionValue()
+    {
+        return assertionValue;
+    }
+
+
+    /**
+     * Set the assertion value
+     * 
+     * @param assertionValue The assertionValue to set.
+     */
+    public void setAssertionValue( Value<?> assertionValue )
+    {
+        this.assertionValue = assertionValue;
+    }
+
+
+    /**
+     * Get the attribute description
+     * 
+     * @return Returns the attributeDesc.
+     */
+    public String getAttributeDesc()
+    {
+        return attributeDesc;
+    }
+
+
+    /**
+     * Set the attribute description
+     * 
+     * @param attributeDesc The attributeDesc to set.
+     */
+    public void setAttributeDesc( String attributeDesc )
+    {
+        this.attributeDesc = attributeDesc;
+    }
+
+
+    /**
+     * Get a String representation of an AttributeValueAssertion
+     * 
+     * @param tabs The spacing to be put before the string
+     * @return An AttributeValueAssertion String
+     */
+    public String toString( String tabs )
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( tabs ).append( "AttributeValueAssertion\n" );
+        sb.append( tabs ).append( "    Assertion description : '" );
+        sb.append( attributeDesc != null ? attributeDesc : "null" );
+        sb.append( "'\n" );
+        sb.append( tabs ).append( "    Assertion value : '" ).append( dumpObject( assertionValue ) ).append( "'\n" );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Get a String representation of an AttributeValueAssertion, as of RFC
+     * 2254.
+     * 
+     * @param filterType The filter type
+     * @return An AttributeValueAssertion String
+     */
+    public String toStringRFC2254( int filterType )
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( attributeDesc );
+
+        switch ( filterType )
+        {
+            case LdapCodecConstants.EQUALITY_MATCH_FILTER:
+                sb.append( '=' );
+                break;
+
+            case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
+                sb.append( "<=" );
+                break;
+
+            case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
+                sb.append( ">=" );
+                break;
+
+            case LdapCodecConstants.APPROX_MATCH_FILTER:
+                sb.append( "~=" );
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected filter type: " + filterType );
+        }
+
+        sb.append( dumpObject( assertionValue ) );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Get a String representation of an AttributeValueAssertion
+     * 
+     * @return An AttributeValueAssertion String
+     */
+    public String toString()
+    {
+        return toString( "" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/BasicControlDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/BasicControlDecorator.java
new file mode 100644
index 0000000..b5d6577
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/BasicControlDecorator.java
@@ -0,0 +1,103 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A decorator for handling opaque Control objects where we know nothing about 
+ * their encoded value. These Controls are generated by default when an 
+ * {@link ControlFactory} for them has not been registered with the 
+ * {@link LdapApiService}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class BasicControlDecorator<E> extends ControlDecorator<Control>
+{
+    /**
+     * Creates a new instance of BasicControlDecorator, decorating a 
+     * {@link Control}.
+     *
+     * @param codec The LDAP codec service.
+     * @param control The {@link Control} to decorate.
+     */
+    public BasicControlDecorator( LdapApiService codec, Control control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int computeLength()
+    {
+        // Call the super class to compute the global control length
+        if ( getValue() == null )
+        {
+            valueLength = 0;
+        }
+        else
+        {
+            valueLength = getValue().length;
+        }
+
+        return valueLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        if ( valueLength != 0 )
+        {
+            buffer.put( getValue() );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/LdapMessageGrammar.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/LdapMessageGrammar.java
new file mode 100644
index 0000000..c3713b9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/LdapMessageGrammar.java
@@ -0,0 +1,5474 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.BOOLEAN;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.ENUMERATED;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.INTEGER;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.OCTET_STRING;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SEQUENCE;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SET;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.actions.CheckNotNullLength;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.actions.AllowGrammarEnd;
+import org.apache.directory.api.ldap.codec.actions.CheckLengthNotNull;
+import org.apache.directory.api.ldap.codec.actions.abandonRequest.InitAbandonRequest;
+import org.apache.directory.api.ldap.codec.actions.addRequest.AddAddRequestAttributeType;
+import org.apache.directory.api.ldap.codec.actions.addRequest.AddAttributeValue;
+import org.apache.directory.api.ldap.codec.actions.addRequest.InitAddRequest;
+import org.apache.directory.api.ldap.codec.actions.addRequest.StoreAddRequestEntryName;
+import org.apache.directory.api.ldap.codec.actions.addResponse.InitAddResponse;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.InitBindRequest;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.InitSaslBind;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.StoreName;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.StoreSaslCredentials;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.StoreSaslMechanism;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.StoreSimpleAuth;
+import org.apache.directory.api.ldap.codec.actions.bindRequest.StoreVersion;
+import org.apache.directory.api.ldap.codec.actions.bindResponse.InitBindResponse;
+import org.apache.directory.api.ldap.codec.actions.bindResponse.StoreServerSASLCreds;
+import org.apache.directory.api.ldap.codec.actions.compareRequest.InitCompareRequest;
+import org.apache.directory.api.ldap.codec.actions.compareRequest.StoreCompareRequestAssertionValue;
+import org.apache.directory.api.ldap.codec.actions.compareRequest.StoreCompareRequestAttributeDesc;
+import org.apache.directory.api.ldap.codec.actions.compareRequest.StoreCompareRequestEntryName;
+import org.apache.directory.api.ldap.codec.actions.compareResponse.InitCompareResponse;
+import org.apache.directory.api.ldap.codec.actions.controls.AddControl;
+import org.apache.directory.api.ldap.codec.actions.controls.InitControls;
+import org.apache.directory.api.ldap.codec.actions.controls.StoreControlCriticality;
+import org.apache.directory.api.ldap.codec.actions.controls.StoreControlValue;
+import org.apache.directory.api.ldap.codec.actions.delRequest.InitDelRequest;
+import org.apache.directory.api.ldap.codec.actions.delResponse.InitDelResponse;
+import org.apache.directory.api.ldap.codec.actions.extendedRequest.InitExtendedRequest;
+import org.apache.directory.api.ldap.codec.actions.extendedRequest.StoreExtendedRequestName;
+import org.apache.directory.api.ldap.codec.actions.extendedRequest.StoreExtendedRequestValue;
+import org.apache.directory.api.ldap.codec.actions.extendedResponse.InitExtendedResponse;
+import org.apache.directory.api.ldap.codec.actions.extendedResponse.StoreExtendedResponseName;
+import org.apache.directory.api.ldap.codec.actions.extendedResponse.StoreExtendedResponseValue;
+import org.apache.directory.api.ldap.codec.actions.intermediateResponse.InitIntermediateResponse;
+import org.apache.directory.api.ldap.codec.actions.intermediateResponse.StoreIntermediateResponseName;
+import org.apache.directory.api.ldap.codec.actions.intermediateResponse.StoreIntermediateResponseValue;
+import org.apache.directory.api.ldap.codec.actions.ldapMessage.InitLdapMessage;
+import org.apache.directory.api.ldap.codec.actions.ldapMessage.StoreMessageId;
+import org.apache.directory.api.ldap.codec.actions.ldapResult.AddReferral;
+import org.apache.directory.api.ldap.codec.actions.ldapResult.InitReferrals;
+import org.apache.directory.api.ldap.codec.actions.ldapResult.StoreErrorMessage;
+import org.apache.directory.api.ldap.codec.actions.ldapResult.StoreMatchedDN;
+import org.apache.directory.api.ldap.codec.actions.ldapResult.StoreResultCode;
+import org.apache.directory.api.ldap.codec.actions.modifyDnRequest.InitModifyDnRequest;
+import org.apache.directory.api.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestDeleteOldRdn;
+import org.apache.directory.api.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestEntryName;
+import org.apache.directory.api.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestNewRdn;
+import org.apache.directory.api.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestNewSuperior;
+import org.apache.directory.api.ldap.codec.actions.modifyDnResponse.InitModifyDnResponse;
+import org.apache.directory.api.ldap.codec.actions.modifyRequest.AddModifyRequestAttribute;
+import org.apache.directory.api.ldap.codec.actions.modifyRequest.InitAttributeVals;
+import org.apache.directory.api.ldap.codec.actions.modifyRequest.InitModifyRequest;
+import org.apache.directory.api.ldap.codec.actions.modifyRequest.StoreModifyRequestAttributeValue;
+import org.apache.directory.api.ldap.codec.actions.modifyRequest.StoreModifyRequestObjectName;
+import org.apache.directory.api.ldap.codec.actions.modifyRequest.StoreOperationType;
+import org.apache.directory.api.ldap.codec.actions.modifyResponse.InitModifyResponse;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.InitSearchRequest;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.InitSearchRequestAttributeDescList;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreSearchRequestAttributeDesc;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreSearchRequestBaseObject;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreSearchRequestDerefAlias;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreSearchRequestScope;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreSearchRequestSizeLimit;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreSearchRequestTimeLimit;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreSearchRequestTypesOnly;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.StoreTypeMatchingRule;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitAndFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitApproxMatchFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitAssertionValueFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitAttributeDescFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitEqualityMatchFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitExtensibleMatchFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitGreaterOrEqualFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitLessOrEqualFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitNotFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitOrFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitPresentFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.InitSubstringsFilter;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.StoreAny;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.StoreFinal;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.StoreInitial;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.StoreMatchValue;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.StoreMatchingRuleDnAttributes;
+import org.apache.directory.api.ldap.codec.actions.searchRequest.filter.StoreSubstringFilterType;
+import org.apache.directory.api.ldap.codec.actions.searchResultDone.InitSearchResultDone;
+import org.apache.directory.api.ldap.codec.actions.searchResultEntry.AddAttributeType;
+import org.apache.directory.api.ldap.codec.actions.searchResultEntry.InitSearchResultEntry;
+import org.apache.directory.api.ldap.codec.actions.searchResultEntry.StoreSearchResultAttributeValue;
+import org.apache.directory.api.ldap.codec.actions.searchResultEntry.StoreSearchResultEntryObjectName;
+import org.apache.directory.api.ldap.codec.actions.searchResultReference.InitSearchResultReference;
+import org.apache.directory.api.ldap.codec.actions.searchResultReference.StoreReference;
+import org.apache.directory.api.ldap.codec.actions.unbindRequest.InitUnbindRequest;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the LdapMessage message. All the actions are declared
+ * in this class. As it is a singleton, these declaration are only done once. If
+ * an action is to be added or modified, this is where the work is to be done !
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LdapMessageGrammar<E> extends
+    AbstractGrammar<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( LdapMessageGrammar.class );
+
+    /** A speedup for logger */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. LdapMessageGrammar is a singleton */
+    private static Grammar<LdapMessageContainer<MessageDecorator<? extends Message>>> instance =
+        new LdapMessageGrammar<LdapMessageContainer<MessageDecorator<? extends Message>>>();
+
+
+    /**
+     * Creates a new LdapMessageGrammar object.
+     */
+    @SuppressWarnings(
+        { "unchecked", "rawtypes" })
+    private LdapMessageGrammar()
+    {
+
+        setName( LdapMessageGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[LdapStatesEnum.LAST_LDAP_STATE.ordinal()][256];
+
+        // ============================================================================================
+        // Transition from START to LdapMessage
+        // ============================================================================================
+        // This is the starting state :
+        // LDAPMessage --> SEQUENCE { ...
+        //
+        // We have a LDAPMessage, and the tag must be 0x30.
+        //
+        // The next state will be LDAP_MESSAGE_STATE
+        //
+        // We will just check that the length is not null
+        super.transitions[LdapStatesEnum.START_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<LdapMessageContainer<MessageDecorator<? extends Message>>>(
+                LdapStatesEnum.START_STATE,
+                LdapStatesEnum.LDAP_MESSAGE_STATE,
+                SEQUENCE,
+                new InitLdapMessage() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from LdapMessage to Message ID
+        // --------------------------------------------------------------------------------------------
+        // LDAPMessage --> ... MessageId ...
+        //
+        // Checks that MessageId is in [0 .. 2147483647] and store the value in
+        // the LdapMessage Object
+        //
+        // (2147483647 = Integer.MAX_VALUE)
+        // The next state will be MESSAGE_ID_STATE
+        //
+        // The message ID will be temporarily stored in the container, because we can't store it
+        // into an object.
+        super.transitions[LdapStatesEnum.LDAP_MESSAGE_STATE.ordinal()][INTEGER.getValue()] =
+            new GrammarTransition<LdapMessageContainer<MessageDecorator<? extends Message>>>(
+                LdapStatesEnum.LDAP_MESSAGE_STATE,
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                INTEGER,
+                new StoreMessageId() );
+
+        // ********************************************************************************************
+        // We have a ProtocolOp :
+        // If the Tag is 0x42, then it's an UnBindRequest.
+        // If the Tag is 0x4A, then it's a DelRequest.
+        // If the Tag is 0x50, then it's an AbandonRequest.
+        // If the Tag is 0x60, then it's a BindRequest.
+        // If the Tag is 0x61, then it's a BindResponse.
+        // If the Tag is 0x63, then it's a SearchRequest.
+        // If the Tag is 0x64, then it's a SearchResultEntry.
+        // If the Tag is 0x65, then it's a SearchResultDone
+        // If the Tag is 0x66, then it's a ModifyRequest
+        // If the Tag is 0x67, then it's a ModifyResponse.
+        // If the Tag is 0x68, then it's an AddRequest.
+        // If the Tag is 0x69, then it's an AddResponse.
+        // If the Tag is 0x6B, then it's a DelResponse.
+        // If the Tag is 0x6C, then it's a ModifyDNRequest.
+        // If the Tag is 0x6D, then it's a ModifyDNResponse.
+        // If the Tag is 0x6E, then it's a CompareRequest
+        // If the Tag is 0x6F, then it's a CompareResponse.
+        // If the Tag is 0x73, then it's a SearchResultReference.
+        // If the Tag is 0x77, then it's an ExtendedRequest.
+        // If the Tag is 0x78, then it's an ExtendedResponse.
+        //
+        // We create the associated object in this transition, and store it into the container.
+        // ********************************************************************************************
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message ID to UnBindRequest Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... UnBindRequest ...
+        // unbindRequest ::= [APPLICATION 2] NULL
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.UNBIND_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.UNBIND_REQUEST_STATE,
+                LdapCodecConstants.UNBIND_REQUEST_TAG,
+                new InitUnbindRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // transition from UnBindRequest Message to Controls.
+        // --------------------------------------------------------------------------------------------
+        //         unbindRequest   UnbindRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.UNBIND_REQUEST_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.UNBIND_REQUEST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message ID to DelRequest Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... DelRequest ...
+        // delRequest ::= [APPLICATION 10] LDAPDN
+        //
+        // We store the Dn to bve deleted into the DelRequest object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.DEL_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.DEL_REQUEST_STATE,
+                LdapCodecConstants.DEL_REQUEST_TAG,
+                new InitDelRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // transition from DelRequest Message to Controls.
+        // --------------------------------------------------------------------------------------------
+        //         delRequest   DelRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.DEL_REQUEST_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DEL_REQUEST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message ID to AbandonRequest Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... AbandonRequest ...
+        // AbandonRequest ::= [APPLICATION 16] MessageID
+        //
+        // Create the AbandonRequest object, and store the ID in it
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.ABANDON_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.ABANDON_REQUEST_STATE,
+                LdapCodecConstants.ABANDON_REQUEST_TAG,
+                new InitAbandonRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // transition from AbandonRequest Message to Controls.
+        // --------------------------------------------------------------------------------------------
+        //         abandonRequest   AbandonRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.ABANDON_REQUEST_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ABANDON_REQUEST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message ID to BindRequest Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... BindRequest ...
+        // BindRequest ::= [APPLICATION 0] SEQUENCE { ...
+        //
+        // We have to allocate a BindRequest
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.BIND_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.BIND_REQUEST_STATE,
+                LdapCodecConstants.BIND_REQUEST_TAG,
+                new InitBindRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from BindRequest to version
+        // --------------------------------------------------------------------------------------------
+        // BindRequest ::= [APPLICATION 0] SEQUENCE {
+        //     version                 INTEGER (1 ..  127),
+        //     ....
+        //
+        // The Ldap version is parsed and stored into the BindRequest object
+        super.transitions[LdapStatesEnum.BIND_REQUEST_STATE.ordinal()][INTEGER.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.BIND_REQUEST_STATE,
+                LdapStatesEnum.VERSION_STATE,
+                INTEGER,
+                new StoreVersion() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from version to name
+        // --------------------------------------------------------------------------------------------
+        // BindRequest ::= [APPLICATION 0] SEQUENCE {
+        //     ....
+        //     name                    LDAPDN,
+        //     ....
+        //
+        // The Ldap name is stored into the BindRequest object
+        super.transitions[LdapStatesEnum.VERSION_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VERSION_STATE,
+                LdapStatesEnum.NAME_STATE,
+                OCTET_STRING,
+                new StoreName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from name to Simple Authentication
+        // --------------------------------------------------------------------------------------------
+        // BindRequest ::= [APPLICATION 0] SEQUENCE {
+        //     ....
+        //     authentication          AuthenticationChoice }
+        //
+        // AuthenticationChoice ::= CHOICE {
+        //     simple                  [0] OCTET STRING,
+        //     ...
+        //
+        // We have to create an Authentication Object to store the credentials.
+        super.transitions[LdapStatesEnum.NAME_STATE.ordinal()][LdapCodecConstants.BIND_REQUEST_SIMPLE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NAME_STATE,
+                LdapStatesEnum.SIMPLE_STATE,
+                LdapCodecConstants.BIND_REQUEST_SIMPLE_TAG,
+                new StoreSimpleAuth() );
+
+        // --------------------------------------------------------------------------------------------
+        // transition from Simple Authentication to Controls.
+        // --------------------------------------------------------------------------------------------
+        //         bindRequest   BindRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.SIMPLE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SIMPLE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from name to SASL Authentication
+        // --------------------------------------------------------------------------------------------
+        // BindRequest ::= [APPLICATION 0] SEQUENCE {
+        //     ....
+        //     authentication          AuthenticationChoice }
+        //
+        // AuthenticationChoice ::= CHOICE {
+        //     ...
+        //     sasl                  [3] SaslCredentials }
+        //     ...
+        //
+        // We have to create an Authentication Object to store the credentials.
+        super.transitions[LdapStatesEnum.NAME_STATE.ordinal()][LdapCodecConstants.BIND_REQUEST_SASL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NAME_STATE,
+                LdapStatesEnum.SASL_STATE,
+                LdapCodecConstants.BIND_REQUEST_SASL_TAG,
+                new InitSaslBind() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from SASL Authentication to Mechanism
+        // --------------------------------------------------------------------------------------------
+        // SaslCredentials ::= SEQUENCE {
+        //     mechanism   LDAPSTRING,
+        //     ...
+        //
+        // We have to store the mechanism.
+        super.transitions[LdapStatesEnum.SASL_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SASL_STATE,
+                LdapStatesEnum.MECHANISM_STATE,
+                OCTET_STRING,
+                new StoreSaslMechanism() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Mechanism to Credentials
+        // --------------------------------------------------------------------------------------------
+        // SaslCredentials ::= SEQUENCE {
+        //     ...
+        //     credentials OCTET STRING OPTIONAL }
+        //
+        // We have to store the mechanism.
+        super.transitions[LdapStatesEnum.MECHANISM_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MECHANISM_STATE,
+                LdapStatesEnum.CREDENTIALS_STATE,
+                OCTET_STRING,
+                new StoreSaslCredentials() );
+
+        // --------------------------------------------------------------------------------------------
+        // transition from from Mechanism to Controls.
+        // --------------------------------------------------------------------------------------------
+        //         bindRequest   BindRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.MECHANISM_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MECHANISM_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // transition from credentials to Controls.
+        // --------------------------------------------------------------------------------------------
+        //         bindRequest   BindRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.CREDENTIALS_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.CREDENTIALS_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from MessageId to BindResponse message
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... BindResponse ...
+        // BindResponse ::= [APPLICATION 1] SEQUENCE { ...
+        // We have to switch to the BindResponse grammar
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.BIND_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.BIND_RESPONSE_STATE,
+                LdapCodecConstants.BIND_RESPONSE_TAG,
+                new InitBindResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from BindResponse message to Result Code BR
+        // --------------------------------------------------------------------------------------------
+        // BindResponse ::= [APPLICATION 1] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     ...
+        //
+        // LDAPResult ::= SEQUENCE {
+        //     resultCode ENUMERATED {
+        //         ...
+        //
+        // Stores the result code into the Bind Response object
+        super.transitions[LdapStatesEnum.BIND_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.BIND_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_BR_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Result Code BR to Matched Dn BR
+        // --------------------------------------------------------------------------------------------
+        // LDAPResult ::= SEQUENCE {
+        //     ...
+        //     matchedDN LDAPDN,
+        //     ...
+        //
+        // Stores the matched Dn
+        super.transitions[LdapStatesEnum.RESULT_CODE_BR_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.RESULT_CODE_BR_STATE,
+                LdapStatesEnum.MATCHED_DN_BR_STATE,
+                OCTET_STRING,
+                new StoreMatchedDN() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Matched Dn BR to Error Message BR
+        // --------------------------------------------------------------------------------------------
+        // LDAPResult ::= SEQUENCE {
+        //     ...
+        //     errorMessage LDAPString,
+        //     ...
+        //
+        // Stores the error message
+        super.transitions[LdapStatesEnum.MATCHED_DN_BR_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCHED_DN_BR_STATE,
+                LdapStatesEnum.ERROR_MESSAGE_BR_STATE,
+                OCTET_STRING,
+                new StoreErrorMessage() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message BR to Server SASL credentials
+        // --------------------------------------------------------------------------------------------
+        // BindResponse ::= APPLICATION 1] SEQUENCE {
+        //     ...
+        //     serverSaslCreds [7] OCTET STRING OPTIONAL }
+        //
+        // Stores the sasl credentials
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_BR_STATE.ordinal()][LdapCodecConstants.SERVER_SASL_CREDENTIAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_BR_STATE,
+                LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
+                LdapCodecConstants.SERVER_SASL_CREDENTIAL_TAG,
+                new StoreServerSASLCreds() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message BR to Referrals BR
+        // --------------------------------------------------------------------------------------------
+        // LDAPResult ::= SEQUENCE {
+        //     ...
+        //     referral   [3] Referral OPTIONNAL }
+        //
+        // Initialiaze the referrals list
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_BR_STATE.ordinal()][LdapCodecConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_BR_STATE,
+                LdapStatesEnum.REFERRALS_BR_STATE,
+                LdapCodecConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG,
+                new InitReferrals() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referrals BR to Referral BR
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Add a first Referral
+        super.transitions[LdapStatesEnum.REFERRALS_BR_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRALS_BR_STATE,
+                LdapStatesEnum.REFERRAL_BR_STATE,
+                OCTET_STRING,
+                new AddReferral() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral BR to Referral BR
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_BR_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_BR_STATE,
+                LdapStatesEnum.REFERRAL_BR_STATE,
+                OCTET_STRING,
+                new AddReferral() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral BR to Server SASL Credentials
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_BR_STATE.ordinal()][LdapCodecConstants.SERVER_SASL_CREDENTIAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_BR_STATE,
+                LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
+                LdapCodecConstants.SERVER_SASL_CREDENTIAL_TAG,
+                new StoreServerSASLCreds() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral BR to Controls
+        // --------------------------------------------------------------------------------------------
+        //         bindResponse   BindResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_BR_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_BR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message BR to controls
+        // --------------------------------------------------------------------------------------------
+        //         bindResponse   BindResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_BR_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_BR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Server SASL credentials to Controls
+        // --------------------------------------------------------------------------------------------
+        //         bindResponse   BindResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Result Code to Matched Dn
+        // --------------------------------------------------------------------------------------------
+        // LDAPResult ::= SEQUENCE {
+        //     ...
+        //     matchedDN LDAPDN,
+        //     ...
+        //
+        // Stores the matched Dn
+        super.transitions[LdapStatesEnum.RESULT_CODE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.RESULT_CODE_STATE,
+                LdapStatesEnum.MATCHED_DN_STATE,
+                OCTET_STRING,
+                new StoreMatchedDN() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Matched Dn to Error Message
+        // --------------------------------------------------------------------------------------------
+        // LDAPResult ::= SEQUENCE {
+        //     ...
+        //     errorMessage LDAPString,
+        //     ...
+        //
+        // Stores the error message
+        super.transitions[LdapStatesEnum.MATCHED_DN_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCHED_DN_STATE,
+                LdapStatesEnum.ERROR_MESSAGE_STATE,
+                OCTET_STRING,
+                new StoreErrorMessage() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message to Referrals
+        // --------------------------------------------------------------------------------------------
+        // LDAPResult ::= SEQUENCE {
+        //     ...
+        //     referral   [3] Referral OPTIONNAL }
+        //
+        // Initialize the referrals list
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_STATE.ordinal()][LdapCodecConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_STATE,
+                LdapStatesEnum.REFERRALS_STATE,
+                LdapCodecConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG,
+                new InitReferrals() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referrals to Referral
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Add a first Referral
+        super.transitions[LdapStatesEnum.REFERRALS_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRALS_STATE,
+                LdapStatesEnum.REFERRAL_STATE,
+                OCTET_STRING,
+                new AddReferral() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral to Referral
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_STATE,
+                LdapStatesEnum.REFERRAL_STATE,
+                OCTET_STRING,
+                new AddReferral() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral to Controls
+        // --------------------------------------------------------------------------------------------
+        //         xxxResponse   xxxResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message to controls
+        // --------------------------------------------------------------------------------------------
+        //         xxxResponse   xxxResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from MessageId to SearchResultEntry Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... SearchResultEntry ...
+        // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+        //
+        // Initialize the searchResultEntry object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.SEARCH_RESULT_ENTRY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_RESULT_ENTRY_STATE,
+                LdapCodecConstants.SEARCH_RESULT_ENTRY_TAG,
+                new InitSearchResultEntry() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from SearchResultEntry Message to ObjectName
+        // --------------------------------------------------------------------------------------------
+        // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+        // objectName LDAPDN,
+        // ...
+        //
+        // Store the object name.
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_ENTRY_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_ENTRY_STATE,
+                LdapStatesEnum.OBJECT_NAME_STATE,
+                OCTET_STRING,
+                new StoreSearchResultEntryObjectName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ObjectName to AttributesSR
+        // --------------------------------------------------------------------------------------------
+        // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+        // ...
+        // attributes PartialAttributeList }
+        //
+        // PartialAttributeList ::= *SEQUENCE* OF SEQUENCE {
+        // ...
+        //
+        // We may have no attributes. Just allows the grammar to end
+        super.transitions[LdapStatesEnum.OBJECT_NAME_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.OBJECT_NAME_STATE,
+                LdapStatesEnum.ATTRIBUTES_SR_STATE,
+                SEQUENCE,
+                new AllowGrammarEnd() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AttributesSR to PartialAttributesList
+        // --------------------------------------------------------------------------------------------
+        // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+        // ...
+        // attributes PartialAttributeList }
+        //
+        // PartialAttributeList ::= SEQUENCE OF *SEQUENCE* {
+        // ...
+        //
+        // nothing to do
+        super.transitions[LdapStatesEnum.ATTRIBUTES_SR_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTES_SR_STATE,
+                LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE,
+                SEQUENCE,
+                null );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AttributesSR to Controls
+        // --------------------------------------------------------------------------------------------
+        //     searchResultEntry SearchResultEntry,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Initialize the controls
+        super.transitions[LdapStatesEnum.ATTRIBUTES_SR_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTES_SR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from PartialAttributesList to typeSR
+        // --------------------------------------------------------------------------------------------
+        // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+        // ...
+        // attributes PartialAttributeList }
+        //
+        // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+        //     type  AttributeDescription,
+        //     ...
+        //
+        // Store the attribute's name.
+        super.transitions[LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE,
+                LdapStatesEnum.TYPE_SR_STATE,
+                OCTET_STRING,
+                new AddAttributeType() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from typeSR to ValsSR
+        // --------------------------------------------------------------------------------------------
+        // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+        // ...
+        // attributes PartialAttributeList }
+        //
+        // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // We may have no value. Just allows the grammar to end
+        super.transitions[LdapStatesEnum.TYPE_SR_STATE.ordinal()][SET.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPE_SR_STATE,
+                LdapStatesEnum.VALS_SR_STATE,
+                SET,
+                new AllowGrammarEnd() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ValsSR to AttributeValueSR
+        // --------------------------------------------------------------------------------------------
+        // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue ::= OCTET STRING
+        //
+        // Store the attribute value
+        super.transitions[LdapStatesEnum.VALS_SR_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_SR_STATE,
+                LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE,
+                OCTET_STRING,
+                new StoreSearchResultAttributeValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ValsSR to PartialAttributesList
+        // --------------------------------------------------------------------------------------------
+        // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // Loop when we don't have any attribute value. Nothing to do
+        super.transitions[LdapStatesEnum.VALS_SR_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_SR_STATE,
+                LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ValsSR to Controls
+        // --------------------------------------------------------------------------------------------
+        //     searchResultEntry SearchResultEntry,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Initialize the controls
+        super.transitions[LdapStatesEnum.VALS_SR_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_SR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AttributeValueSR to AttributeValueSR
+        // --------------------------------------------------------------------------------------------
+        // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue ::= OCTET STRING
+        //
+        // Store the attribute value
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE,
+                LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE,
+                OCTET_STRING,
+                new StoreSearchResultAttributeValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AttributeValueSR to PartialAttributesList
+        // --------------------------------------------------------------------------------------------
+        // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // Loop when we don't have any attribute value. Nothing to do
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE,
+                LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AttributeValueSR to Controls
+        // --------------------------------------------------------------------------------------------
+        //     searchResultEntry SearchResultEntry,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Initialize the controls
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // SearchResultDone Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... SearchResultDone ...
+        // SearchResultDone ::= [APPLICATION 5] SEQUENCE { ...
+        //
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.SEARCH_RESULT_DONE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_RESULT_DONE_STATE,
+                LdapCodecConstants.SEARCH_RESULT_DONE_TAG,
+                new InitSearchResultDone() );
+
+        // --------------------------------------------------------------------------------------------
+        // SearchResultDone Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... SearchResultDone ...
+        // SearchResultDone ::= [APPLICATION 5] LDAPResult
+        //
+        // LDAPResult ::= SEQUENCE {
+        //     resultCode    ENUMERATED {
+        //         ...
+        //
+        // Stores the result code
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_DONE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_DONE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message ID to ModifyRequest Message
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ModifyRequest ...
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE { ...
+        //
+        // Creates the Modify Request object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.MODIFY_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_REQUEST_STATE,
+                LdapCodecConstants.MODIFY_REQUEST_TAG,
+                new InitModifyRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ModifyRequest Message to Object
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     object    LDAPDN,
+        //     ...
+        //
+        // Stores the object Dn
+        super.transitions[LdapStatesEnum.MODIFY_REQUEST_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFY_REQUEST_STATE,
+                LdapStatesEnum.OBJECT_STATE,
+                OCTET_STRING,
+                new StoreModifyRequestObjectName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Object to modifications
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification *SEQUENCE OF* SEQUENCE {
+        //     ...
+        //
+        // Initialize the modifications list
+        super.transitions[LdapStatesEnum.OBJECT_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.OBJECT_STATE,
+                LdapStatesEnum.MODIFICATIONS_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from modifications to modification sequence
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF *SEQUENCE* {
+        //     ...
+        //
+        // Nothing to do
+        super.transitions[LdapStatesEnum.MODIFICATIONS_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFICATIONS_STATE,
+                LdapStatesEnum.MODIFICATIONS_SEQ_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from modification sequence to operation
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF SEQUENCE {
+        //         operation  ENUMERATED {
+        //             ...
+        //
+        // Store operation type
+        super.transitions[LdapStatesEnum.MODIFICATIONS_SEQ_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFICATIONS_SEQ_STATE,
+                LdapStatesEnum.OPERATION_STATE,
+                ENUMERATED,
+                new StoreOperationType() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from operation to modification
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF SEQUENCE {
+        //             ...
+        //         modification   AttributeTypeAndValues }
+        //
+        // AttributeTypeAndValues ::= SEQUENCE {
+        //     ...
+        //
+        // Nothing to do
+        super.transitions[LdapStatesEnum.OPERATION_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.OPERATION_STATE,
+                LdapStatesEnum.MODIFICATION_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from modification to TypeMod
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF SEQUENCE {
+        //             ...
+        //         modification   AttributeTypeAndValues }
+        //
+        // AttributeTypeAndValues ::= SEQUENCE {
+        //     type AttributeDescription,
+        //     ...
+        //
+        // Stores the type
+        super.transitions[LdapStatesEnum.MODIFICATION_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFICATION_STATE,
+                LdapStatesEnum.TYPE_MOD_STATE,
+                OCTET_STRING,
+                new AddModifyRequestAttribute() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypeMod to vals
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF SEQUENCE {
+        //             ...
+        //         modification   AttributeTypeAndValues }
+        //
+        // AttributeTypeAndValues ::= SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // Initialize the list of values
+        super.transitions[LdapStatesEnum.TYPE_MOD_STATE.ordinal()][SET.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPE_MOD_STATE,
+                LdapStatesEnum.VALS_STATE,
+                SET,
+                new InitAttributeVals() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from vals to Attribute Value
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF SEQUENCE {
+        //             ...
+        //         modification   AttributeTypeAndValues }
+        //
+        // AttributeTypeAndValues ::= SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue ::= OCTET STRING
+        //
+        // Stores a value
+        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_STATE,
+                LdapStatesEnum.ATTRIBUTE_VALUE_STATE,
+                OCTET_STRING,
+                new StoreModifyRequestAttributeValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from vals to ModificationsSeq
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF *SEQUENCE* {
+        //             ...
+        //         modification   AttributeTypeAndValues }
+        //
+        // AttributeTypeAndValues ::= SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue ::= OCTET STRING
+        //
+        // Nothing to do
+        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_STATE,
+                LdapStatesEnum.MODIFICATIONS_SEQ_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from vals to Controls
+        // --------------------------------------------------------------------------------------------
+        //     modifyRequest ModifyRequest,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Nothing to do
+        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute Value to Attribute Value
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF SEQUENCE {
+        //             ...
+        //         modification   AttributeTypeAndValues }
+        //
+        // AttributeTypeAndValues ::= SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue ::= OCTET STRING
+        //
+        // Stores a value
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_STATE,
+                LdapStatesEnum.ATTRIBUTE_VALUE_STATE,
+                OCTET_STRING,
+                new StoreModifyRequestAttributeValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute Value to ModificationsSeq
+        // --------------------------------------------------------------------------------------------
+        // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+        //     ...
+        //     modification SEQUENCE OF *SEQUENCE* {
+        //             ...
+        //         modification   AttributeTypeAndValues }
+        //
+        // AttributeTypeAndValues ::= SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue ::= OCTET STRING
+        //
+        // Nothing to do
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_STATE,
+                LdapStatesEnum.MODIFICATIONS_SEQ_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute Value to Controls
+        // --------------------------------------------------------------------------------------------
+        //     modifyRequest ModifyRequest,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Nothing to do
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // ModifyResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ModifyResponse ...
+        // ModifyResponse ::= [APPLICATION 7] SEQUENCE { ...
+        // We have to switch to the ModifyResponse grammar
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.MODIFY_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_RESPONSE_STATE,
+                LdapCodecConstants.MODIFY_RESPONSE_TAG,
+                new InitModifyResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // ModifyResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ModifyResponse ...
+        // ModifyResponse ::= [APPLICATION 7] LDAPResult
+        //
+        // LDAPResult ::= SEQUENCE {
+        //     resultCode    ENUMERATED {
+        //         ...
+        //
+        // Stores the result code
+        super.transitions[LdapStatesEnum.MODIFY_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFY_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // AddRequest Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... AddRequest ...
+        // AddRequest ::= [APPLICATION 8] SEQUENCE { ...
+        //
+        // Initialize the AddRequest object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.ADD_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.ADD_REQUEST_STATE,
+                LdapCodecConstants.ADD_REQUEST_TAG,
+                new InitAddRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Add Request to Entry
+        // --------------------------------------------------------------------------------------------
+        // AddRequest ::= [APPLICATION 8] SEQUENCE {
+        //     entry           LDAPDN,
+        //     ...
+        //
+        // Stores the Dn
+        super.transitions[LdapStatesEnum.ADD_REQUEST_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ADD_REQUEST_STATE,
+                LdapStatesEnum.ENTRY_STATE,
+                OCTET_STRING,
+                new StoreAddRequestEntryName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Entry to Attributes
+        // --------------------------------------------------------------------------------------------
+        // AddRequest ::= [APPLICATION 8] SEQUENCE {
+        //     ...
+        //    attributes AttributeList }
+        //
+        // AttributeList ::= SEQUENCE OF ...
+        //
+        // Initialize the attribute list
+        super.transitions[LdapStatesEnum.ENTRY_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ENTRY_STATE,
+                LdapStatesEnum.ATTRIBUTES_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attributes to Attribute
+        // --------------------------------------------------------------------------------------------
+        // AttributeList ::= SEQUENCE OF SEQUENCE {
+        //
+        // We don't do anything in this transition. The attribute will be created when we met the type
+        super.transitions[LdapStatesEnum.ATTRIBUTES_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTES_STATE,
+                LdapStatesEnum.ATTRIBUTE_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute to type
+        // --------------------------------------------------------------------------------------------
+        // AttributeList ::= SEQUENCE OF SEQUENCE {
+        //     type    AttributeDescription,
+        //     ...
+        //
+        // AttributeDescription LDAPString
+        //
+        // We store the type in the current attribute
+        super.transitions[LdapStatesEnum.ATTRIBUTE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_STATE,
+                LdapStatesEnum.TYPE_STATE,
+                OCTET_STRING,
+                new AddAddRequestAttributeType() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from type to vals
+        // --------------------------------------------------------------------------------------------
+        // AttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // Nothing to do here.
+        super.transitions[LdapStatesEnum.TYPE_STATE.ordinal()][SET.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPE_STATE,
+                LdapStatesEnum.VALUES_STATE,
+                SET );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from vals to Value
+        // --------------------------------------------------------------------------------------------
+        // AttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue OCTET STRING
+        //
+        // Store the value into the current attribute
+        super.transitions[LdapStatesEnum.VALUES_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALUES_STATE,
+                LdapStatesEnum.VALUE_STATE,
+                OCTET_STRING,
+                new AddAttributeValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Value to Value
+        // --------------------------------------------------------------------------------------------
+        // AttributeList ::= SEQUENCE OF SEQUENCE {
+        //     ...
+        //     vals SET OF AttributeValue }
+        //
+        // AttributeValue OCTET STRING
+        //
+        // Store the value into the current attribute
+        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALUE_STATE,
+                LdapStatesEnum.VALUE_STATE,
+                OCTET_STRING,
+                new AddAttributeValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Value to Attribute
+        // --------------------------------------------------------------------------------------------
+        // AttributeList ::= SEQUENCE OF SEQUENCE {
+        //
+        // Nothing to do here.
+        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALUE_STATE,
+                LdapStatesEnum.ATTRIBUTE_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Value to Controls
+        // --------------------------------------------------------------------------------------------
+        // AttributeList ::= SEQUENCE OF SEQUENCE {
+        //
+        // Initialize the controls
+        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // AddResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... AddResponse ...
+        // AddResponse ::= [APPLICATION 9] LDAPResult
+        //
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.ADD_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.ADD_RESPONSE_STATE,
+                LdapCodecConstants.ADD_RESPONSE_TAG,
+                new InitAddResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // AddResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... AddResponse ...
+        // AddResponse ::= [APPLICATION 9] LDAPResult
+        //
+        // LDAPResult ::= SEQUENCE {
+        //     resultCode    ENUMERATED {
+        //         ...
+        //
+        // Stores the result code
+        super.transitions[LdapStatesEnum.ADD_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ADD_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // DelResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... DelResponse ...
+        // DelResponse ::= [APPLICATION 11] LDAPResult
+        // We have to switch to the DelResponse grammar
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.DEL_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.DEL_RESPONSE_STATE,
+                LdapCodecConstants.DEL_RESPONSE_TAG,
+                new InitDelResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // DelResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... DelResponse ...
+        // DelResponse ::= [APPLICATION 11] LDAPResult
+        //
+        // LDAPResult ::= SEQUENCE {
+        //     resultCode    ENUMERATED {
+        //         ...
+        //
+        // Stores the result code
+        super.transitions[LdapStatesEnum.DEL_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.DEL_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from MessageID to ModifydDNRequest Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ModifyDNRequest ...
+        // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+        //
+        // Create the ModifyDNRequest Object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.MODIFY_DN_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_DN_REQUEST_STATE,
+                LdapCodecConstants.MODIFY_DN_REQUEST_TAG,
+                new InitModifyDnRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ModifydDNRequest Message to EntryModDN
+        // --------------------------------------------------------------------------------------------
+        // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+        //     entry LDAPDN,
+        //     ...
+        //
+        // Stores the entry Dn
+        super.transitions[LdapStatesEnum.MODIFY_DN_REQUEST_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFY_DN_REQUEST_STATE,
+                LdapStatesEnum.ENTRY_MOD_DN_STATE,
+                OCTET_STRING,
+                new StoreModifyDnRequestEntryName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from EntryModDN to NewRDN
+        // --------------------------------------------------------------------------------------------
+        // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+        //     ...
+        //     newrdn  RelativeRDN,
+        //     ...
+        //
+        // RelativeRDN :: LDAPString
+        //
+        // Stores the new Rdn
+        super.transitions[LdapStatesEnum.ENTRY_MOD_DN_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ENTRY_MOD_DN_STATE,
+                LdapStatesEnum.NEW_RDN_STATE,
+                OCTET_STRING,
+                new StoreModifyDnRequestNewRdn() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NewRDN to DeleteOldRDN
+        // --------------------------------------------------------------------------------------------
+        // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+        //     ...
+        //     deleteoldrdn BOOLEAN,
+        //     ...
+        //
+        // Stores the deleteOldRDN flag
+        super.transitions[LdapStatesEnum.NEW_RDN_STATE.ordinal()][BOOLEAN.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.NEW_RDN_STATE,
+                LdapStatesEnum.DELETE_OLD_RDN_STATE,
+                BOOLEAN,
+                new StoreModifyDnRequestDeleteOldRdn() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from DeleteOldRDN to NewSuperior
+        // --------------------------------------------------------------------------------------------
+        // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+        //     ...
+        //     newSuperior [0] LDAPDN OPTIONAL }
+        //
+        // Stores the new superior
+        super.transitions[LdapStatesEnum.DELETE_OLD_RDN_STATE.ordinal()][LdapCodecConstants.MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DELETE_OLD_RDN_STATE,
+                LdapStatesEnum.NEW_SUPERIOR_STATE,
+                LdapCodecConstants.MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG,
+                new StoreModifyDnRequestNewSuperior() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from DeleteOldRDN to Controls
+        // --------------------------------------------------------------------------------------------
+        //     modifyDNRequest ModifyDNRequest,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Stores the new superior
+        super.transitions[LdapStatesEnum.DELETE_OLD_RDN_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DELETE_OLD_RDN_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from DeleteOldRDN to Controls
+        // --------------------------------------------------------------------------------------------
+        //     modifyDNRequest ModifyDNRequest,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Stores the new superior
+        super.transitions[LdapStatesEnum.NEW_SUPERIOR_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NEW_SUPERIOR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from MessageID to ModifyDNResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // ModifyDNResponse ::= [APPLICATION 13] SEQUENCE {
+        //     ...
+        //
+        // Creates the ModifyDNResponse
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.MODIFY_DN_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_DN_RESPONSE_STATE,
+                LdapCodecConstants.MODIFY_DN_RESPONSE_TAG,
+                new InitModifyDnResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ModifyDNResponse Message to Result Code
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ModifyDNResponse ...
+        // ModifyDNResponse ::= [APPLICATION 13] LDAPResult
+        //
+        // LDAPResult ::= SEQUENCE {
+        //     resultCode    ENUMERATED {
+        //         ...
+        //
+        // Stores the result co        //     modifyDNRequest ModifyDNRequest,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        super.transitions[LdapStatesEnum.MODIFY_DN_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFY_DN_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message ID to CompareResquest
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... CompareRequest ...
+        //
+        // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+        // ...
+        //
+        // Initialize the Compare Request object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.COMPARE_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.COMPARE_REQUEST_STATE,
+                LdapCodecConstants.COMPARE_REQUEST_TAG,
+                new InitCompareRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from CompareResquest to entryComp
+        // --------------------------------------------------------------------------------------------
+        // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+        //     entry    LDAPDN,
+        //     ...
+        //
+        // Stores the compared Dn
+        super.transitions[LdapStatesEnum.COMPARE_REQUEST_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.COMPARE_REQUEST_STATE,
+                LdapStatesEnum.ENTRY_COMP_STATE,
+                OCTET_STRING,
+                new StoreCompareRequestEntryName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from entryComp to ava
+        // --------------------------------------------------------------------------------------------
+        // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+        //     ...
+        //     ava AttributeValueAssertion }
+        //
+        // AttributeValueAssertion ::= SEQUENCE {
+        //
+        // Nothing to do
+        super.transitions[LdapStatesEnum.ENTRY_COMP_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ENTRY_COMP_STATE,
+                LdapStatesEnum.AVA_STATE,
+                SEQUENCE );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ava to AttributeDesc
+        // --------------------------------------------------------------------------------------------
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     attributeDesc AttributeDescription,
+        //     ...
+        //
+        // AttributeDescription LDAPString
+        //
+        // Stores the attribute description
+        super.transitions[LdapStatesEnum.AVA_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.AVA_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESC_STATE,
+                OCTET_STRING,
+                new StoreCompareRequestAttributeDesc() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AttributeDesc to Assertion Value
+        // --------------------------------------------------------------------------------------------
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     ...
+        //     assertionValue AssertionValue }
+        //
+        // AssertionValue OCTET STRING
+        //
+        // Stores the attribute value
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESC_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESC_STATE,
+                LdapStatesEnum.ASSERTION_VALUE_STATE,
+                OCTET_STRING,
+                new StoreCompareRequestAssertionValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value to Controls
+        // --------------------------------------------------------------------------------------------
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     ...
+        //     assertionValue AssertionValue }
+        //
+        // AssertionValue OCTET STRING
+        //
+        // Stores the attribute value
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // CompareResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... CompareResponse ...
+        // CompareResponse ::= [APPLICATION 15] LDAPResult
+        // We have to switch to the CompareResponse grammar
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.COMPARE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.COMPARE_RESPONSE_STATE,
+                LdapCodecConstants.COMPARE_RESPONSE_TAG,
+                new InitCompareResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // CompareResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... CompareResponse ...
+        // CompareResponse ::= [APPLICATION 15] LDAPResult
+        //
+        // LDAPResult ::= SEQUENCE {
+        //     resultCode    ENUMERATED {
+        //         ...
+        //
+        // Stores the result code
+        super.transitions[LdapStatesEnum.COMPARE_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.COMPARE_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from MessageID to SearchResultReference Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... SearchResultReference ...
+        // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+        //
+        // Initialization of SearchResultReference object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.SEARCH_RESULT_REFERENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_STATE,
+                LdapCodecConstants.SEARCH_RESULT_REFERENCE_TAG,
+                new InitSearchResultReference() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from SearchResultReference Message to Reference
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... SearchResultReference ...
+        // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+        //
+        // Initialization of SearchResultReference object
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_REFERENCE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_STATE,
+                LdapStatesEnum.REFERENCE_STATE,
+                OCTET_STRING,
+                new StoreReference() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Reference to Reference
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... SearchResultReference ...
+        // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+        //
+        // Initialization of SearchResultReference object
+        super.transitions[LdapStatesEnum.REFERENCE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERENCE_STATE,
+                LdapStatesEnum.REFERENCE_STATE,
+                OCTET_STRING,
+                new StoreReference() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Reference to Controls
+        // --------------------------------------------------------------------------------------------
+        //     searchResultReference SearchResultReference,
+        //     ... },
+        // controls   [0] Controls OPTIONAL }
+        //
+        // Initialization the controls
+        super.transitions[LdapStatesEnum.REFERENCE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERENCE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message Id to ExtendedRequest Message
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedRequest ...
+        // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+        //
+        // Creates the ExtendedRequest object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.EXTENDED_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.EXTENDED_REQUEST_STATE,
+                LdapCodecConstants.EXTENDED_REQUEST_TAG,
+                new InitExtendedRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ExtendedRequest Message to RequestName
+        // --------------------------------------------------------------------------------------------
+        // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+        //     requestName [0] LDAPOID,
+        //     ...
+        //
+        // Stores the name
+        super.transitions[LdapStatesEnum.EXTENDED_REQUEST_STATE.ordinal()][LdapCodecConstants.EXTENDED_REQUEST_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.EXTENDED_REQUEST_STATE,
+                LdapStatesEnum.REQUEST_NAME_STATE,
+                LdapCodecConstants.EXTENDED_REQUEST_NAME_TAG,
+                new StoreExtendedRequestName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from RequestName to RequestValue
+        // --------------------------------------------------------------------------------------------
+        // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+        //     ...
+        //     requestValue  [1] OCTET STRING OPTIONAL }
+        //
+        // Stores the value
+        super.transitions[LdapStatesEnum.REQUEST_NAME_STATE.ordinal()][LdapCodecConstants.EXTENDED_REQUEST_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REQUEST_NAME_STATE,
+                LdapStatesEnum.REQUEST_VALUE_STATE,
+                LdapCodecConstants.EXTENDED_REQUEST_VALUE_TAG,
+                new StoreExtendedRequestValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from RequestName to Controls
+        // --------------------------------------------------------------------------------------------
+        //         extendedRequest   EtendedRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Stores the value
+        super.transitions[LdapStatesEnum.REQUEST_NAME_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REQUEST_NAME_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from RequestValue to Controls
+        // --------------------------------------------------------------------------------------------
+        //         extendedRequest   EtendedRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Stores the value
+        super.transitions[LdapStatesEnum.REQUEST_VALUE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REQUEST_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from MessageId to ExtendedResponse Message.
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //
+        // Creates the ExtendeResponse object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.EXTENDED_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.EXTENDED_RESPONSE_STATE,
+                LdapCodecConstants.EXTENDED_RESPONSE_TAG,
+                new InitExtendedResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ExtendedResponse Message to Result Code ER
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     ...
+        //
+        // Stores the result code
+        super.transitions[LdapStatesEnum.EXTENDED_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.EXTENDED_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_ER_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Result Code ER to Matched Dn ER
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     ...
+        //
+        //
+        super.transitions[LdapStatesEnum.RESULT_CODE_ER_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.RESULT_CODE_ER_STATE,
+                LdapStatesEnum.MATCHED_DN_ER_STATE,
+                OCTET_STRING,
+                new StoreMatchedDN() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Matched Dn ER to Error Message ER
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     ...
+        //
+        //
+        super.transitions[LdapStatesEnum.MATCHED_DN_ER_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCHED_DN_ER_STATE,
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                OCTET_STRING,
+                new StoreErrorMessage() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message ER to Referrals ER
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     ...
+        //
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapCodecConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.REFERRALS_ER_STATE,
+                LdapCodecConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG,
+                new InitReferrals() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referrals ER to Referral ER
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Add a first Referral
+        super.transitions[LdapStatesEnum.REFERRALS_ER_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRALS_ER_STATE,
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                OCTET_STRING,
+                new AddReferral() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral ER to Referral ER
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                OCTET_STRING,
+                new AddReferral() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral ER to ResponseName
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG,
+                new StoreExtendedResponseName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral ER to Response
+        // --------------------------------------------------------------------------------------------
+        // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+        // URI ::= LDAPString
+        //
+        // Add a new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_TAG,
+                new StoreExtendedResponseValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Referral ER to Controls
+        // --------------------------------------------------------------------------------------------
+        //         extendedResponse   ExtendedResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Adda new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message ER to Controls
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     ...
+        //
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message ER to ResponseName
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     responseName   [10] LDAPOID OPTIONAL,
+        //     ...
+        //
+        // Stores the response name
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG,
+                new StoreExtendedResponseName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Response Name to Response
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     ...
+        //     responseName   [10] LDAPOID OPTIONAL,
+        //     response       [11] OCTET STRING OPTIONAL}
+        //
+        // Stores the response
+        super.transitions[LdapStatesEnum.RESPONSE_NAME_STATE.ordinal()][LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_TAG,
+                new StoreExtendedResponseValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ResponseName to Controls
+        // --------------------------------------------------------------------------------------------
+        //         extendedRequest   EtendedRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Init the controls
+        super.transitions[LdapStatesEnum.RESPONSE_NAME_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Error Message ER to Response
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... ExtendedResponse ...
+        // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        //     COMPONENTS OF LDAPResult,
+        //     ...
+        //     response       [11] OCTET STRING OPTIONAL}
+        //
+        // Stores the response
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_TAG,
+                new StoreExtendedResponseValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Response to Controls
+        // --------------------------------------------------------------------------------------------
+        //         extendedRequest   EtendedRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Init the controls
+        super.transitions[LdapStatesEnum.RESPONSE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Message Id to IntermediateResponse Message
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... IntermediateResponse ...
+        // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+        //
+        // Creates the IntermediateResponse object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.INTERMEDIATE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE,
+                LdapCodecConstants.INTERMEDIATE_RESPONSE_TAG,
+                new InitIntermediateResponse() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from IntermediateResponse Message to ResponseName
+        // --------------------------------------------------------------------------------------------
+        // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+        //     responseName [0] LDAPOID OPTIONAL,
+        //     ...
+        //
+        // Stores the name
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE.ordinal()][LdapCodecConstants.INTERMEDIATE_RESPONSE_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE,
+                LdapCodecConstants.INTERMEDIATE_RESPONSE_NAME_TAG,
+                new StoreIntermediateResponseName() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from IntermediateResponse Message to ResponseValue (ResponseName is null)
+        // --------------------------------------------------------------------------------------------
+        // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+        //     ...
+        //     responseValue [1] OCTET STRING OPTIONAL
+        //     }
+        //
+        // Stores the value
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE.ordinal()][LdapCodecConstants.INTERMEDIATE_RESPONSE_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
+                LdapCodecConstants.INTERMEDIATE_RESPONSE_VALUE_TAG,
+                new StoreIntermediateResponseValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ResponseName to ResponseValue
+        // --------------------------------------------------------------------------------------------
+        // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+        //     ...
+        //     responseValue  [1] OCTET STRING OPTIONAL }
+        //
+        // Stores the value
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE.ordinal()][LdapCodecConstants.INTERMEDIATE_RESPONSE_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
+                LdapCodecConstants.INTERMEDIATE_RESPONSE_VALUE_TAG,
+                new StoreIntermediateResponseValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ResponseName to Controls
+        // --------------------------------------------------------------------------------------------
+        //         intermediateResponse   IntermediateResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Stores the value
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from ResponseValue to Controls
+        // --------------------------------------------------------------------------------------------
+        //         intermediateResponse   IntermediateResponse,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Stores the value
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // ============================================================================================
+        // Transition from Controls to Control
+        // ============================================================================================
+        // ...
+        // Controls ::= SEQUENCE OF Control
+        //  ...
+        //
+        // Initialize the controls
+        super.transitions[LdapStatesEnum.CONTROLS_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapStatesEnum.CONTROL_STATE,
+                SEQUENCE,
+                new CheckLengthNotNull() );
+
+        // ============================================================================================
+        // Transition from Control to ControlType
+        // ============================================================================================
+        // Control ::= SEQUENCE {
+        //     ...
+        //
+        // Create a new Control object, and store it in the message Container
+        super.transitions[LdapStatesEnum.CONTROL_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CONTROL_STATE,
+                LdapStatesEnum.CONTROL_TYPE_STATE,
+                OCTET_STRING,
+                new AddControl() );
+
+        // ============================================================================================
+        // Transition from ControlType to Control Criticality
+        // ============================================================================================
+        // Control ::= SEQUENCE {
+        //     ...
+        //     criticality BOOLEAN DEFAULT FALSE,
+        //     ...
+        //
+        // Store the value in the control object created before
+        super.transitions[LdapStatesEnum.CONTROL_TYPE_STATE.ordinal()][BOOLEAN.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CONTROL_TYPE_STATE,
+                LdapStatesEnum.CRITICALITY_STATE,
+                OCTET_STRING,
+                new StoreControlCriticality() );
+
+        // ============================================================================================
+        // Transition from Control Criticality to Control Value
+        // ============================================================================================
+        // Control ::= SEQUENCE {
+        //     ...
+        //     controlValue OCTET STRING OPTIONAL }
+        //
+        // Store the value in the control object created before
+        super.transitions[LdapStatesEnum.CRITICALITY_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CRITICALITY_STATE,
+                LdapStatesEnum.CONTROL_VALUE_STATE,
+                OCTET_STRING,
+                new StoreControlValue() );
+
+        // ============================================================================================
+        // Transition from Control Type to Control Value
+        // ============================================================================================
+        // Control ::= SEQUENCE {
+        //     ...
+        //     controlValue OCTET STRING OPTIONAL }
+        //
+        // Store the value in the control object created before
+        super.transitions[LdapStatesEnum.CONTROL_TYPE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CONTROL_TYPE_STATE,
+                LdapStatesEnum.CONTROL_VALUE_STATE,
+                OCTET_STRING,
+                new StoreControlValue() );
+
+        // ============================================================================================
+        // Transition from Control Type to Control
+        // ============================================================================================
+        // Control ::= SEQUENCE {
+        //     ...
+        //     controlValue OCTET STRING OPTIONAL }
+        //
+        // Store the value in the control object created before
+        super.transitions[LdapStatesEnum.CONTROL_TYPE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CONTROL_TYPE_STATE,
+                LdapStatesEnum.CONTROL_STATE,
+                SEQUENCE,
+                new CheckLengthNotNull() );
+
+        // ============================================================================================
+        // Transition from Control Criticality to Control
+        // ============================================================================================
+        // Control ::= SEQUENCE {
+        //     ...
+        //     controlValue OCTET STRING OPTIONAL }
+        //
+        // Store the value in the control object created before
+        super.transitions[LdapStatesEnum.CRITICALITY_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CRITICALITY_STATE,
+                LdapStatesEnum.CONTROL_STATE,
+                SEQUENCE,
+                new CheckLengthNotNull() );
+
+        // ============================================================================================
+        // Transition from Control Value to Control
+        // ============================================================================================
+        // Control ::= SEQUENCE {
+        //     ...
+        //     controlValue OCTET STRING OPTIONAL }
+        //
+        // Store the value in the control object created before
+        super.transitions[LdapStatesEnum.CONTROL_VALUE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.CONTROL_VALUE_STATE,
+                LdapStatesEnum.CONTROL_STATE,
+                SEQUENCE,
+                new CheckLengthNotNull() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from message ID to SearchRequest Message
+        // --------------------------------------------------------------------------------------------
+        // LdapMessage ::= ... SearchRequest ...
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE { ...
+        //
+        // Initialize the searchRequest object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapCodecConstants.SEARCH_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_REQUEST_STATE,
+                LdapCodecConstants.SEARCH_REQUEST_TAG,
+                new InitSearchRequest() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from SearchRequest Message to BaseObject
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     baseObject LDAPDN,
+        //     ...
+        //
+        // We have a value for the base object, we will store it in the message
+        super.transitions[LdapStatesEnum.SEARCH_REQUEST_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SEARCH_REQUEST_STATE,
+                LdapStatesEnum.BASE_OBJECT_STATE,
+                OCTET_STRING,
+                new StoreSearchRequestBaseObject() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from BaseObject to Scope
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     scope ENUMERATED {
+        //         baseObject   (0),
+        //         singleLevel  (1),
+        //         wholeSubtree (2) },
+        //     ...
+        //
+        // We have a value for the scope, we will store it in the message
+        super.transitions[LdapStatesEnum.BASE_OBJECT_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.BASE_OBJECT_STATE,
+                LdapStatesEnum.SCOPE_STATE,
+                ENUMERATED,
+                new StoreSearchRequestScope() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Scope to DerefAlias
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     derefAliases ENUMERATED {
+        //         neverDerefAliases   (0),
+        //         derefInSearching    (1),
+        //         derefFindingBaseObj (2),
+        //         derefAlways         (3) },
+        //     ...
+        //
+        // We have a value for the derefAliases, we will store it in the message
+        super.transitions[LdapStatesEnum.SCOPE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SCOPE_STATE,
+                LdapStatesEnum.DEREF_ALIAS_STATE,
+                ENUMERATED,
+                new StoreSearchRequestDerefAlias() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from DerefAlias to SizeLimit
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     sizeLimit INTEGER (0 .. maxInt),
+        //     ...
+        //
+        // We have a value for the sizeLimit, we will store it in the message
+        super.transitions[LdapStatesEnum.DEREF_ALIAS_STATE.ordinal()][INTEGER.getValue()] = new
+            GrammarTransition(
+                LdapStatesEnum.DEREF_ALIAS_STATE,
+                LdapStatesEnum.SIZE_LIMIT_STATE,
+                INTEGER,
+                new StoreSearchRequestSizeLimit() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from SizeLimit to TimeLimit
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     timeLimit INTEGER (0 .. maxInt),
+        //     ...
+        //
+        // We have a value for the timeLimit, we will store it in the message
+        super.transitions[LdapStatesEnum.SIZE_LIMIT_STATE.ordinal()][INTEGER.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SIZE_LIMIT_STATE,
+                LdapStatesEnum.TIME_LIMIT_STATE,
+                INTEGER,
+                new StoreSearchRequestTimeLimit() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TimeLimit to TypesOnly
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     typesOnly BOOLEAN,
+        //     ...
+        //
+        // We have a value for the typesOnly, we will store it in the message.
+        super.transitions[LdapStatesEnum.TIME_LIMIT_STATE.ordinal()][BOOLEAN.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.TIME_LIMIT_STATE,
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                BOOLEAN,
+                new StoreSearchRequestTypesOnly() );
+
+        //============================================================================================
+        // Search Request And Filter
+        // This is quite complicated, because we have a tree structure to build,
+        // and we may have many elements on each node. For instance, considering the
+        // search filter :
+        // (& (| (a = b) (c = d)) (! (e = f)) (attr =* h))
+        // We will have to create an And filter with three children :
+        //  - an Or child,
+        //  - a Not child
+        //  - and a Present child.
+        // The Or child will also have two children.
+        //
+        // We know when we have a children while decoding the PDU, because the length
+        // of its parent has not yet reached its expected length.
+        //
+        // This search filter :
+        // (&(|(objectclass=top)(ou=contacts))(!(objectclass=ttt))(objectclass=*top))
+        // is encoded like this :
+        //                              +----------------+---------------+
+        //                              | ExpectedLength | CurrentLength |
+        //+-----------------------------+----------------+---------------+
+        //|A0 52                        | 82             | 0             | new level 1
+        //|   A1 24                     | 82 36          | 0 0           | new level 2
+        //|      A3 12                  | 82 36 18       | 0 0 0         | new level 3
+        //|         04 0B 'objectclass' | 82 36 18       | 0 0 13        |
+        //|         04 03 'top'         | 82 36 18       | 0 20 18       |
+        //|                             |       ^               ^        |
+        //|                             |       |               |        |
+        //|                             |       +---------------+        |
+        //+-----------------------------* end level 3 -------------------*
+        //|      A3 0E                  | 82 36 14       | 0 0 0         | new level 3
+        //|         04 02 'ou'          | 82 36 14       | 0 0 4         |
+        //|         04 08 'contacts'    | 82 36 14       | 38 36 14      |
+        //|                             |    ^  ^             ^  ^       |
+        //|                             |    |  |             |  |       |
+        //|                             |    |  +-------------|--+       |
+        //|                             |    +----------------+          |
+        //+-----------------------------* end level 3, end level 2 ------*
+        //|   A2 14                     | 82 20          | 38 0          | new level 2
+        //|      A3 12                  | 82 20 18       | 38 0 0        | new level 3
+        //|         04 0B 'objectclass' | 82 20 18       | 38 0 13       |
+        //|         04 03 'ttt'         | 82 20 18       | 60 20 18      |
+        //|                             |    ^  ^             ^  ^       |
+        //|                             |    |  |             |  |       |
+        //|                             |    |  +-------------|--+       |
+        //|                             |    +----------------+          |
+        //+-----------------------------* end level 3, end level 2 ------*
+        //|   A4 14                     | 82 20          | 60 0          | new level 2
+        //|      04 0B 'objectclass'    | 82 20          | 60 13         |
+        //|      30 05                  | 82 20          | 60 13         |
+        //|         82 03 'top'         | 82 20          | 82 20         |
+        //|                             | ^  ^             ^  ^          |
+        //|                             | |  |             |  |          |
+        //|                             | |  +-------------|--+          |
+        //|                             | +----------------+             |
+        //+-----------------------------* end level 2, end level 1 ------*
+        //+-----------------------------+----------------+---------------+
+        //
+        // When the current length equals the expected length of the parent PDU,
+        // then we are able to 'close' the parent : it has all its children. This
+        // is propagated through all the tree, until either there are no more
+        // parents, or the expected length of the parent is different from the
+        // current length.
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Equality filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init Present Match filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from TypesOnly to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Extensible Match filter
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from AND to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from OR to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from NOT to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init extensible match filter
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Equality match to Attribute Desc Filter
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch  [3] AttributeValueAssertion,
+        //     ...
+        //
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     attributeDesc   AttributeDescription,
+        //     ...
+        //
+        // Init Attribute Desc filter
+        super.transitions[LdapStatesEnum.EQUALITY_MATCH_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
+                OCTET_STRING,
+                new InitAttributeDescFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute Desc Filter to Assertion Value Filter
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch  [3] AttributeValueAssertion,
+        //     ...
+        //
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     ...
+        //     assertionValue   AssertionValue }
+        //
+        // Init Assertion Value filter
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                OCTET_STRING,
+                new InitAssertionValueFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Assertion Value Filter filter
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Assertion Value Filter to Attribute Description List
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Init attribute description list
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute Description List to AttributeDescription
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Store attribute description
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE,
+                OCTET_STRING,
+                new StoreSearchRequestAttributeDesc() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute Description List to Controls
+        // --------------------------------------------------------------------------------------------
+        //         searchRequest   SearchRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        // Empty attribute description list, with controls
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Attribute Description to AttributeDescription
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Store attribute description
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE,
+                OCTET_STRING,
+                new StoreSearchRequestAttributeDesc() );
+
+        // --------------------------------------------------------------------------------------------
+        // transition from Attribute Description to Controls.
+        // --------------------------------------------------------------------------------------------
+        //         searchRequest   SearchRequest,
+        //         ... },
+        //     controls       [0] Controls OPTIONAL }
+        //
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE.ordinal()][LdapCodecConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapCodecConstants.CONTROLS_TAG,
+                new InitControls() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Greater Or Equal to Attribute Desc Filter
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     attributeDesc   AttributeDescription,
+        //     ...
+        //
+        // Init Attribute Desc filter
+        super.transitions[LdapStatesEnum.GREATER_OR_EQUAL_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
+                OCTET_STRING,
+                new InitAttributeDescFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Less Or Equal to Attribute Desc Filter
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     lessOrEqual  [6] AttributeValueAssertion,
+        //     ...
+        //
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     attributeDesc   AttributeDescription,
+        //     ...
+        //
+        // Init Attribute Desc filter
+        super.transitions[LdapStatesEnum.LESS_OR_EQUAL_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
+                OCTET_STRING,
+                new InitAttributeDescFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Substrings to typeSubstring
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings  [4] SubstringFilter,
+        //     ...
+        //
+        // SubstringFilter ::= SEQUENCE {
+        //     type   AttributeDescription,
+        //     ...
+        //
+        // Init substring type
+        super.transitions[LdapStatesEnum.SUBSTRING_FILTER_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapStatesEnum.TYPE_SUBSTRING_STATE,
+                OCTET_STRING,
+                new StoreSubstringFilterType() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from typeSubstring to substrings
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings  [4] SubstringFilter,
+        //     ...
+        //
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //     ...
+        //
+        // Init substring type
+        super.transitions[LdapStatesEnum.TYPE_SUBSTRING_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPE_SUBSTRING_STATE,
+                LdapStatesEnum.SUBSTRINGS_STATE,
+                SEQUENCE,
+                new CheckNotNullLength<LdapMessageContainer<SearchRequestDecorator>>() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from substrings to Initial
+        // --------------------------------------------------------------------------------------------
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //         initial  [0] LDAPSTRING,
+        //         ...
+        //
+        // Store initial value
+        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_INITIAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SUBSTRINGS_STATE,
+                LdapStatesEnum.INITIAL_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_INITIAL_TAG,
+                new StoreInitial() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from substrings to any
+        // --------------------------------------------------------------------------------------------
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //         ...
+        //         any  [1] LDAPSTRING,
+        //         ...
+        //
+        // Store substring any type
+        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SUBSTRINGS_STATE,
+                LdapStatesEnum.ANY_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG,
+                new StoreAny() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from substrings to final
+        // --------------------------------------------------------------------------------------------
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //         ...
+        //         final  [2] LDAPSTRING }
+        //
+        // Store substring final type
+        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SUBSTRINGS_STATE,
+                LdapStatesEnum.FINAL_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG,
+                new StoreFinal() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to any
+        // --------------------------------------------------------------------------------------------
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //         ...
+        //         any  [1] LDAPSTRING,
+        //         ...
+        //
+        // Store substring any type
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.ANY_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG,
+                new StoreAny() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to final
+        // --------------------------------------------------------------------------------------------
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //         ...
+        //         final  [2] LDAPSTRING }
+        //
+        // Store substring final type
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.FINAL_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG,
+                new StoreFinal() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to Attribute Description List
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Init attribute description list
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from initial to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Assertion Value Filter filter
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to final
+        // --------------------------------------------------------------------------------------------
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //         ...
+        //         final  [2] LDAPSTRING }
+        //
+        // Store substring final type
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.FINAL_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG,
+                new StoreFinal() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to any
+        // --------------------------------------------------------------------------------------------
+        // SubstringFilter ::= SEQUENCE {
+        //     ...
+        //     substrings SEQUENCE OF CHOICE {
+        //         ...
+        //         any  [1] LDAPSTRING
+        //         ...
+        //
+        // Store substring any type
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.ANY_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG,
+                new StoreAny() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to Attribute Description List
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Init attribute description list
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from any to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Assertion Value Filter filter
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to Attribute Description List
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Init attribute description list
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from final to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Assertion Value Filter filter
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Assertion Value Filter filter
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Present Filter to Attribute Description List
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Init attribute description list
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Approx Match to Attribute Desc Filter
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch  [8] AttributeValueAssertion,
+        //     ...
+        //
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     attributeDesc   AttributeDescription,
+        //     ...
+        //
+        // Init Attribute Desc filter
+        super.transitions[LdapStatesEnum.APPROX_MATCH_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
+                OCTET_STRING,
+                new InitAttributeDescFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Extensible Match to MatchingRule
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion }
+        //
+        // MatchingRuleAssertion ::= SEQUENCE {
+        //     matchingRule [1] MatchingRuleId OPTIONAL,
+        //     ...
+        //
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapCodecConstants.MATCHING_RULE_ID_TAG] = new GrammarTransition(
+            LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapStatesEnum.MATCHING_RULE_STATE,
+            LdapCodecConstants.MATCHING_RULE_ID_TAG, new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>(
+                "Store matching rule Value" )
+            {
+                public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+                {
+                    SearchRequestDecorator searchRequest = container.getMessage();
+
+                    TLV tlv = container.getCurrentTLV();
+
+                    // Store the value.
+                    ExtensibleMatchFilter extensibleMatchFilter = ( ExtensibleMatchFilter )
+                        searchRequest.getTerminalFilter();
+
+                    if ( tlv.getLength() == 0 )
+                    {
+                        String msg = I18n.err( I18n.ERR_04109 );
+                        LOG.error( msg );
+
+                        // It will generate a PROTOCOL_ERROR
+                        throw new DecoderException( I18n.err( I18n.ERR_04109 ) );
+                    }
+                    else
+                    {
+                        extensibleMatchFilter.setMatchingRule( Strings.utf8ToString( tlv.getValue().getData() ) );
+                    }
+                }
+            } );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Extensible Match to type matching rule
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion }
+        //
+        // MatchingRuleAssertion ::= SEQUENCE {
+        //     ...
+        //     type [2] AttributeDescription OPTIONAL,
+        //     ...
+        //
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapCodecConstants.MATCHING_RULE_TYPE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
+                LdapCodecConstants.MATCHING_RULE_TYPE_TAG,
+                new StoreTypeMatchingRule() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from Extensible Match to match value
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion }
+        //
+        // MatchingRuleAssertion ::= SEQUENCE {
+        //     ...
+        //     matchValue [3] AssertionValue,
+        //     ...
+        //
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapCodecConstants.MATCH_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapCodecConstants.MATCH_VALUE_TAG,
+                new StoreMatchValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from matching rule to type matching rule
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion }
+        //
+        // MatchingRuleAssertion ::= SEQUENCE {
+        //     ...
+        //     type [2] AttributeDescription OPTIONAL,
+        //     ...
+        //
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.MATCHING_RULE_STATE.ordinal()][LdapCodecConstants.MATCHING_RULE_TYPE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCHING_RULE_STATE,
+                LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
+                LdapCodecConstants.MATCHING_RULE_TYPE_TAG,
+                new StoreTypeMatchingRule() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from matching rule to match value
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion }
+        //
+        // MatchingRuleAssertion ::= SEQUENCE {
+        //     ...
+        //     matchValue [3] AssertionValue,
+        //     ...
+        //
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.MATCHING_RULE_STATE.ordinal()][LdapCodecConstants.MATCH_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCHING_RULE_STATE,
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapCodecConstants.MATCH_VALUE_TAG,
+                new StoreMatchValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from matching type to match value
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion }
+        //
+        // MatchingRuleAssertion ::= SEQUENCE {
+        //     ...
+        //     matchValue [3] AssertionValue,
+        //     ...
+        //
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.TYPE_MATCHING_RULE_STATE.ordinal()][LdapCodecConstants.MATCH_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapCodecConstants.MATCH_VALUE_TAG,
+                new StoreMatchValue() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to dnAttributes
+        // --------------------------------------------------------------------------------------------
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion }
+        //
+        // MatchingRuleAssertion ::= SEQUENCE {
+        //     ...
+        //     dnAttributes [4] BOOLEAN DEFAULT FALSE }
+        //
+        // Store the dnAttributes flag
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG,
+                new StoreMatchingRuleDnAttributes() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Assertion Value Filter filter
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from match value to Attribute Description List
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Init attribute description list
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to AND filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter,
+        //     ...
+        //
+        // Init AND filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapCodecConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to OR filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter,
+        //     ...
+        //
+        // Init OR filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapCodecConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to NOT filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] SET OF Filter,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapCodecConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to Equality Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion,
+        //     ...
+        //
+        // Init NOT filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to Substrings filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings     [4] SubstringFilter,
+        //     ...
+        //
+        // Init Substrings filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapCodecConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to GreaterOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Greater Or Equal filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to LessOrEqual filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     LessOrEqual    [6] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Less Or Equal filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to Present filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     present        [7] AttributeDescription,
+        //     ...
+        //
+        // Init present filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapCodecConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to Approx Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion,
+        //     ...
+        //
+        // Init Approx Match filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapCodecConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to Extensible Match filter
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter Filter,
+        //     ...
+        //
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch  [9] MatchingRuleAssertion,
+        //     ...
+        //
+        // Init Assertion Value Filter filter
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
+
+        // --------------------------------------------------------------------------------------------
+        // Transition from dnAttributes to Attribute Description List
+        // --------------------------------------------------------------------------------------------
+        // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+        //     ...
+        //     filter      Filter,
+        //     attributes  AttributeDescriptionList }
+        //
+        // AttributeDescriptionList ::= SEQUENCE OF
+        //     AttributeDescription
+        //
+        // Init attribute description list
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
+    }
+
+
+    /**
+     * Get the instance of this grammar
+     *
+     * @return An instance on the LdapMessage Grammar
+     */
+    @SuppressWarnings("rawtypes")
+    public static Grammar getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/LdapStatesEnum.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/LdapStatesEnum.java
new file mode 100644
index 0000000..6d2e7e1
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/LdapStatesEnum.java
@@ -0,0 +1,217 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the Ldap grammar's constants. It is also used for debugging
+ * purpose
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum LdapStatesEnum implements States
+{
+    /** The END_STATE */
+    END_STATE,
+
+    START_STATE,
+    LDAP_MESSAGE_STATE,
+    MESSAGE_ID_STATE,
+    BIND_REQUEST_STATE,
+    BIND_RESPONSE_STATE,
+    UNBIND_REQUEST_STATE,
+    SEARCH_REQUEST_STATE,
+    SEARCH_RESULT_ENTRY_STATE,
+    SEARCH_RESULT_DONE_STATE,
+    SEARCH_RESULT_REFERENCE_STATE,
+    MODIFY_REQUEST_STATE,
+    MODIFY_RESPONSE_STATE,
+    ADD_REQUEST_STATE,
+    ADD_RESPONSE_STATE,
+    DEL_REQUEST_STATE,
+    DEL_RESPONSE_STATE,
+    MODIFY_DN_REQUEST_STATE,
+    MODIFY_DN_RESPONSE_STATE,
+    COMPARE_REQUEST_STATE,
+    COMPARE_RESPONSE_STATE,
+    ABANDON_REQUEST_STATE,
+    EXTENDED_REQUEST_STATE,
+    EXTENDED_RESPONSE_STATE,
+    VERSION_STATE,
+    NAME_STATE,
+    SIMPLE_STATE,
+    SASL_STATE,
+    MECHANISM_STATE,
+    CREDENTIALS_STATE,
+    RESULT_CODE_BR_STATE,
+    MATCHED_DN_BR_STATE,
+    ERROR_MESSAGE_BR_STATE,
+    REFERRALS_BR_STATE,
+    REFERRAL_BR_STATE,
+    SERVER_SASL_CREDENTIALS_STATE,
+    RESULT_CODE_STATE,
+    MATCHED_DN_STATE,
+    ERROR_MESSAGE_STATE,
+    REFERRALS_STATE,
+    REFERRAL_STATE,
+    REQUEST_NAME_STATE,
+    REQUEST_VALUE_STATE,
+    RESPONSE_NAME_STATE,
+    RESPONSE_STATE,
+    RESULT_CODE_ER_STATE,
+    MATCHED_DN_ER_STATE,
+    ERROR_MESSAGE_ER_STATE,
+    REFERRALS_ER_STATE,
+    REFERRAL_ER_STATE,
+    ENTRY_STATE,
+    ATTRIBUTES_STATE,
+    ATTRIBUTE_STATE,
+    TYPE_STATE,
+    VALUES_STATE,
+    VALUE_STATE,
+    OBJECT_STATE,
+    MODIFICATIONS_STATE,
+    MODIFICATIONS_SEQ_STATE,
+    OPERATION_STATE,
+    MODIFICATION_STATE,
+    TYPE_MOD_STATE,
+    VALS_STATE,
+    ATTRIBUTE_VALUE_STATE,
+    ENTRY_MOD_DN_STATE,
+    NEW_RDN_STATE,
+    DELETE_OLD_RDN_STATE,
+    NEW_SUPERIOR_STATE,
+    ENTRY_COMP_STATE,
+    AVA_STATE,
+    ATTRIBUTE_DESC_STATE,
+    ASSERTION_VALUE_STATE,
+    BASE_OBJECT_STATE,
+    SCOPE_STATE,
+    DEREF_ALIAS_STATE,
+    SIZE_LIMIT_STATE,
+    TIME_LIMIT_STATE,
+    TYPES_ONLY_STATE,
+    AND_STATE,
+    OR_STATE,
+    NOT_STATE,
+    EQUALITY_MATCH_STATE,
+    SUBSTRING_FILTER_STATE,
+    GREATER_OR_EQUAL_STATE,
+    LESS_OR_EQUAL_STATE,
+    PRESENT_STATE,
+    APPROX_MATCH_STATE,
+    EXTENSIBLE_MATCH_STATE,
+    ATTRIBUTE_DESC_FILTER_STATE,
+    ASSERTION_VALUE_FILTER_STATE,
+    ATTRIBUTE_DESCRIPTION_LIST_STATE,
+    ATTRIBUTE_DESCRIPTION_STATE,
+    TYPE_SUBSTRING_STATE,
+    SUBSTRINGS_STATE,
+    INITIAL_STATE,
+    ANY_STATE,
+    FINAL_STATE,
+    MATCHING_RULE_STATE,
+    TYPE_MATCHING_RULE_STATE,
+    MATCH_VALUE_STATE,
+    DN_ATTRIBUTES_STATE,
+    OBJECT_NAME_STATE,
+    ATTRIBUTES_SR_STATE,
+    PARTIAL_ATTRIBUTES_LIST_STATE,
+    TYPE_SR_STATE,
+    VALS_SR_STATE,
+    ATTRIBUTE_VALUE_SR_STATE,
+    REFERENCE_STATE,
+    CONTROLS_STATE,
+    CONTROL_STATE,
+    CONTROL_TYPE_STATE,
+    CRITICALITY_STATE,
+    CONTROL_VALUE_STATE,
+    INTERMEDIATE_RESPONSE_STATE,
+    INTERMEDIATE_RESPONSE_NAME_STATE,
+    INTERMEDIATE_RESPONSE_VALUE_STATE,
+    LAST_LDAP_STATE;
+
+    /**
+     * Get the grammar name
+     *
+     * @param grammar
+     *            The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "LDAP_MESSAGE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     *
+     * @param grammar
+     *            The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<Asn1Container> grammar )
+    {
+        if ( grammar instanceof LdapMessageGrammar )
+        {
+            return "LDAP_MESSAGE_GRAMMAR";
+        }
+        else
+        {
+            return "UNKNOWN GRAMMAR";
+        }
+    }
+
+
+    /**
+     * Get the string representing the state
+     *
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "LDAP_MESSAGE_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/AllowGrammarEnd.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/AllowGrammarEnd.java
new file mode 100644
index 0000000..041a0ef
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/AllowGrammarEnd.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Message;
+
+
+/**
+ * The action used to indicate that the grammar can terminate after this action
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AllowGrammarEnd extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /**
+     * Instantiates a new value action.
+     */
+    public AllowGrammarEnd()
+    {
+        super( "Allow a grammar end" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        container.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/CheckLengthNotNull.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/CheckLengthNotNull.java
new file mode 100644
index 0000000..1fdc2f3
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/CheckLengthNotNull.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to check that the TLV length is not null
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CheckLengthNotNull extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( CheckLengthNotNull.class );
+
+
+    /**
+     * Instantiates the action.
+     */
+    public CheckLengthNotNull()
+    {
+        super( "Check that the length is not null" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+        int expectedLength = tlv.getLength();
+
+        // The Length should be null
+        if ( expectedLength == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04096 );
+            LOG.error( msg );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/abandonRequest/InitAbandonRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/abandonRequest/InitAbandonRequest.java
new file mode 100644
index 0000000..669bac6
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/abandonRequest/InitAbandonRequest.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.abandonRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.AbandonRequestDecorator;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the AbandonRequest
+ * <pre>
+ * LdapMessage ::= ... AbandonRequest ...
+ * AbandonRequest ::= [APPLICATION 16] MessageID
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitAbandonRequest extends GrammarAction<LdapMessageContainer<AbandonRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitAbandonRequest.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitAbandonRequest()
+    {
+        super( "Init Abandon Request" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<AbandonRequestDecorator> container ) throws DecoderException
+    {
+        // Create the AbandonRequest LdapMessage instance and store it in the container
+        AbandonRequest internalAbandonRequest = new AbandonRequestImpl();
+        internalAbandonRequest.setMessageId( container.getMessageId() );
+        AbandonRequestDecorator abandonRequest = new AbandonRequestDecorator(
+            container.getLdapCodecService(), internalAbandonRequest );
+        container.setMessage( abandonRequest );
+
+        // The current TLV should be a integer
+        // We get it and store it in MessageId
+        TLV tlv = container.getCurrentTLV();
+
+        BerValue value = tlv.getValue();
+
+        if ( ( value == null ) || ( value.getData() == null ) )
+        {
+            String msg = I18n.err( I18n.ERR_04075 );
+            LOG.error( msg );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+
+        try
+        {
+            int abandonnedMessageId = IntegerDecoder.parse( value, 0, Integer.MAX_VALUE );
+
+            abandonRequest.setAbandoned( abandonnedMessageId );
+
+            if ( IS_DEBUG )
+            {
+                LOG
+                    .debug( "AbandonMessage Id has been decoded : {}", Integer
+                        .valueOf( abandonnedMessageId ) );
+            }
+
+            container.setGrammarEndAllowed( true );
+
+            return;
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            LOG.error( I18n
+                .err( I18n.ERR_04076, Strings.dumpBytes( value.getData() ), ide.getMessage() ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( ide.getMessage(), ide );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/AddAddRequestAttributeType.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/AddAddRequestAttributeType.java
new file mode 100644
index 0000000..201ae51
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/AddAddRequestAttributeType.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.addRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AddResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the AddRequest AttributeDescription
+ * <pre>
+ * AttributeList ::= SEQUENCE OF SEQUENCE {
+ *     type    AttributeDescription,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddAddRequestAttributeType extends GrammarAction<LdapMessageContainer<AddRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AddAddRequestAttributeType.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public AddAddRequestAttributeType()
+    {
+        super( "Store attribute type" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<AddRequestDecorator> container ) throws DecoderException
+    {
+        AddRequestDecorator addRequest = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the type. It can't be null.
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04086 );
+            LOG.error( msg );
+
+            AddResponseImpl response = new AddResponseImpl( addRequest.getMessageId() );
+
+            throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX,
+                addRequest.getEntry().getDn(), null );
+        }
+
+        String type = Strings.utf8ToString( tlv.getValue().getData() );
+
+        try
+        {
+            addRequest.addAttributeType( type );
+        }
+        catch ( LdapException ne )
+        {
+            String msg = I18n.err( I18n.ERR_04087 );
+            LOG.error( msg );
+
+            AddResponseImpl response = new AddResponseImpl( addRequest.getMessageId() );
+            throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX,
+                addRequest.getEntry().getDn(), ne );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Adding type {}", type );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/AddAttributeValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/AddAttributeValue.java
new file mode 100644
index 0000000..c105c3c
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/AddAttributeValue.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.addRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a Value to an AddRequest
+ * <pre>
+ * AttributeList ::= SEQUENCE OF SEQUENCE {
+ *     ...
+ *     vals SET OF AttributeValue }
+ *
+ * AttributeValue OCTET STRING
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddAttributeValue extends GrammarAction<LdapMessageContainer<AddRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AddAttributeValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new value action.
+     */
+    public AddAttributeValue()
+    {
+        super( "Store a value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<AddRequestDecorator> container )
+    {
+        AddRequestDecorator addRequest = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value. It can't be null
+        Object value = null;
+
+        try
+        {
+            if ( tlv.getLength() == 0 )
+            {
+                addRequest.addAttributeValue( "" );
+            }
+            else
+            {
+                if ( container.isBinary( addRequest.getCurrentAttributeType() ) )
+                {
+                    value = tlv.getValue().getData();
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Adding value {}", Strings.dumpBytes( ( byte[] ) value ) );
+                    }
+
+                    addRequest.addAttributeValue( ( byte[] ) value );
+                }
+                else
+                {
+                    value = Strings.utf8ToString( tlv.getValue().getData() );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Adding value {}" + value );
+                    }
+
+                    addRequest.addAttributeValue( ( String ) value );
+                }
+            }
+        }
+        catch ( LdapException le )
+        {
+            // Just swallow the exception, it can't occur here
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/InitAddRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/InitAddRequest.java
new file mode 100644
index 0000000..8aa4012
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/InitAddRequest.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.addRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddRequestImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the AddRequest response
+ * <pre>
+ * LdapMessage ::= ... AddRequest ...
+ * AddRequest ::= [APPLICATION 8] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitAddRequest extends GrammarAction<LdapMessageContainer<AddRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitAddRequest.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitAddRequest()
+    {
+        super( "Init AddRequest" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<AddRequestDecorator> container ) throws DecoderException
+    {
+        // Now, we can allocate the AddRequest Object
+        int messageId = container.getMessageId();
+        AddRequest internalAddRequest = new AddRequestImpl();
+        internalAddRequest.setMessageId( messageId );
+        AddRequestDecorator addRequest = new AddRequestDecorator(
+            container.getLdapCodecService(), internalAddRequest );
+        container.setMessage( addRequest );
+
+        // We will check that the request is not null
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04084 );
+            LOG.error( msg );
+
+            // Will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/StoreAddRequestEntryName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/StoreAddRequestEntryName.java
new file mode 100644
index 0000000..d1942ce
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addRequest/StoreAddRequestEntryName.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.addRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.AddResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the AddReqyuest entry name
+ * <pre>
+ * AddRequest ::= [APPLICATION 8] SEQUENCE {
+ *     entry           LDAPDN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreAddRequestEntryName extends GrammarAction<LdapMessageContainer<AddRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreAddRequestEntryName.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreAddRequestEntryName()
+    {
+        super( "Store Add request entry Name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<AddRequestDecorator> container ) throws DecoderException
+    {
+        AddRequestDecorator addRequest = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the entry. It can't be null
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04085 );
+            LOG.error( msg );
+
+            AddResponseImpl response = new AddResponseImpl( addRequest.getMessageId() );
+
+            // I guess that trying to add an entry which Dn is empty is a naming violation...
+            // Not 100% sure though ...
+            throw new ResponseCarryingException( msg, response, ResultCodeEnum.NAMING_VIOLATION,
+                Dn.EMPTY_DN, null );
+        }
+        else
+        {
+            Dn entryDn = null;
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                entryDn = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Invalid Dn given : " + dnStr + " (" + Strings.dumpBytes( dnBytes )
+                    + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                AddResponseImpl response = new AddResponseImpl( addRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    Dn.EMPTY_DN, ine );
+            }
+
+            addRequest.setEntryDn( entryDn );
+        }
+
+        LOG.debug( "Adding an entry with Dn : {}", addRequest.getEntry() );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addResponse/InitAddResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addResponse/InitAddResponse.java
new file mode 100644
index 0000000..cd98fb9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/addResponse/InitAddResponse.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.addResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.AddResponseDecorator;
+import org.apache.directory.api.ldap.model.message.AddResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the AddResponse response
+ * <pre>
+ * LdapMessage ::= ... AddResponse ...
+ * AddResponse ::= [APPLICATION 9] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitAddResponse extends GrammarAction<LdapMessageContainer<AddResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitAddResponse.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitAddResponse()
+    {
+        super( "Init AddResponse" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<AddResponseDecorator> container ) throws DecoderException
+    {
+        // Now, we can allocate the AddResponse Object
+        AddResponseDecorator addResponse = new AddResponseDecorator(
+            container.getLdapCodecService(), new AddResponseImpl( container.getMessageId() ) );
+        container.setMessage( addResponse );
+
+        // We will check that the request is not null
+        TLV tlv = container.getCurrentTLV();
+
+        int expectedLength = tlv.getLength();
+
+        if ( expectedLength == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04088 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        LOG.debug( "Add Response" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/InitBindRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/InitBindRequest.java
new file mode 100644
index 0000000..5ff3c3f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/InitBindRequest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the BindRequest
+ * <pre>
+ * LdapMessage ::= ... BindRequest ...
+ * BindRequest ::= [APPLICATION 0] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitBindRequest extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitBindRequest.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitBindRequest()
+    {
+        super( "Init BindRequest" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
+    {
+        // Create the BindRequest LdapMessage instance and store it in the container
+        BindRequest internalBindRequest = new BindRequestImpl();
+        internalBindRequest.setMessageId( container.getMessageId() );
+        BindRequestDecorator bindRequest = new BindRequestDecorator(
+            container.getLdapCodecService(), internalBindRequest );
+        container.setMessage( bindRequest );
+
+        // We will check that the request is not null
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04077 );
+            LOG.error( msg );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/InitSaslBind.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/InitSaslBind.java
new file mode 100644
index 0000000..26a2971
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/InitSaslBind.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the BindRequest version MessageID.
+ * <pre>
+ * BindRequest ::= [APPLICATION 0] SEQUENCE {
+ *     ....
+ *     authentication          AuthenticationChoice }
+ *
+ * AuthenticationChoice ::= CHOICE {
+ *     ...
+ *     sasl                  [3] SaslCredentials }
+ *     ...
+ *
+ * We have to create an Authentication Object to store the credentials.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitSaslBind extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitSaslBind.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitSaslBind()
+    {
+        super( "Initialize Bind SASL Authentication" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
+    {
+        BindRequest bindRequestMessage = container.getMessage();
+        TLV tlv = container.getCurrentTLV();
+
+        // We will check that the sasl is not null
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04079 );
+            LOG.error( msg );
+
+            BindResponseImpl response = new BindResponseImpl( bindRequestMessage.getMessageId() );
+
+            throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_CREDENTIALS,
+                bindRequestMessage.getDn(), null );
+        }
+
+        bindRequestMessage.setSimple( false );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The SaslCredential has been created" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreName.java
new file mode 100644
index 0000000..88d9ba2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreName.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the BindRequest name.
+ * <pre>
+ * BindRequest ::= [APPLICATION 0] SEQUENCE {
+ *     ....
+ *     name                    LDAPDN,
+ *     ....
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreName extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreName()
+    {
+        super( "Store BindRequest Name value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
+    {
+        BindRequest bindRequestMessage = container.getMessage();
+
+        // Get the Value and store it in the BindRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length name
+        if ( tlv.getLength() == 0 )
+        {
+            bindRequestMessage.setName( "" );
+        }
+        else
+        {
+            byte[] nameBytes = tlv.getValue().getData();
+            String nameStr = Strings.utf8ToString( nameBytes );
+
+            try
+            {
+                // Testing the name as a DN
+                new Dn( nameStr );
+                bindRequestMessage.setName( nameStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Incorrect DN given : " + nameStr + " (" + Strings.dumpBytes( nameBytes )
+                    + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                BindResponseImpl response = new BindResponseImpl( bindRequestMessage.getMessageId() );
+
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    Dn.EMPTY_DN, ine );
+            }
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( " The Bind name is {}", bindRequestMessage.getName() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSaslCredentials.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSaslCredentials.java
new file mode 100644
index 0000000..9280a05
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSaslCredentials.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the BindRequest credentials.
+ * <pre>
+ * SaslCredentials ::= SEQUENCE {
+ *     ...
+ *     credentials OCTET STRING OPTIONAL }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSaslCredentials extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSaslCredentials.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSaslCredentials()
+    {
+        super( "Store SASL credentials" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
+    {
+        BindRequest bindRequestMessage = container.getMessage();
+
+        // Get the Value and store it in the BindRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length
+        // credentials
+        if ( tlv.getLength() == 0 )
+        {
+            bindRequestMessage.setCredentials( StringConstants.EMPTY_BYTES );
+        }
+        else
+        {
+            bindRequestMessage.setCredentials( tlv.getValue().getData() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The credentials are : {}", Strings.dumpBytes( bindRequestMessage
+                .getCredentials() ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSaslMechanism.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSaslMechanism.java
new file mode 100644
index 0000000..a3b5f89
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSaslMechanism.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the BindRequest version MessageID.
+ * <pre>
+ * SaslCredentials ::= SEQUENCE {
+ *     mechanism   LDAPSTRING,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSaslMechanism extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSaslMechanism.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSaslMechanism()
+    {
+        super( "Store SASL mechanism" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindRequestDecorator> container )
+    {
+        BindRequest bindRequestMessage = container.getMessage();
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length
+        // mechanism
+        if ( tlv.getLength() == 0 )
+        {
+            bindRequestMessage.setSaslMechanism( "" );
+        }
+        else
+        {
+            bindRequestMessage.setSaslMechanism( Strings.utf8ToString( tlv.getValue().getData() ) );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The mechanism is : {}", bindRequestMessage.getSaslMechanism() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSimpleAuth.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSimpleAuth.java
new file mode 100644
index 0000000..a95b023
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreSimpleAuth.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the BindRequest simple authentication
+ * <pre>
+ * BindRequest ::= [APPLICATION 0] SEQUENCE {
+ *     ....
+ *     authentication          AuthenticationChoice }
+ *
+ * AuthenticationChoice ::= CHOICE {
+ *     simple                  [0] OCTET STRING,
+ *     ...
+ *
+ * We have to create an Authentication Object to store the credentials.
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSimpleAuth extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSimpleAuth.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSimpleAuth()
+    {
+        super( "Store BindRequest Simple Authentication" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
+    {
+        BindRequest bindRequestMessage = container.getMessage();
+        TLV tlv = container.getCurrentTLV();
+
+        // Allocate the Authentication Object
+        bindRequestMessage.setSimple( true );
+
+        // We have to handle the special case of a 0 length simple
+        if ( tlv.getLength() == 0 )
+        {
+            bindRequestMessage.setCredentials( StringConstants.EMPTY_BYTES );
+        }
+        else
+        {
+            bindRequestMessage.setCredentials( tlv.getValue().getData() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The simple authentication is : {}", Strings.dumpBytes( bindRequestMessage
+                .getCredentials() ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreVersion.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreVersion.java
new file mode 100644
index 0000000..266d829
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindRequest/StoreVersion.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the BindRequest version.
+ * <pre>
+ * BindRequest ::= [APPLICATION 0] SEQUENCE {
+ *     version                 INTEGER (1 ..  127),
+ *     ....
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreVersion extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreVersion.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreVersion()
+    {
+        super( "Store BindRequest Version" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
+    {
+        BindRequest bindRequestMessage = container.getMessage();
+
+        // The current TLV should be a integer between 1 and 127
+        // We get it and store it in Version
+        TLV tlv = container.getCurrentTLV();
+
+        BerValue value = tlv.getValue();
+
+        try
+        {
+            int version = IntegerDecoder.parse( value, 1, 127 );
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "Ldap version ", Integer.valueOf( version ) );
+            }
+
+            bindRequestMessage.setVersion3( version == 3 );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            LOG.error( I18n
+                .err( I18n.ERR_04078, Strings.dumpBytes( value.getData() ), ide.getMessage() ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( ide.getMessage(), ide );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindResponse/InitBindResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindResponse/InitBindResponse.java
new file mode 100644
index 0000000..b9147a1
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindResponse/InitBindResponse.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindResponse;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindResponseDecorator;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+
+
+/**
+ * The action used to initialize the BindResponse
+ * <pre>
+ * LdapMessage ::= ... BindResponse ...
+ * BindResponse ::= [APPLICATION 1] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitBindResponse extends GrammarAction<LdapMessageContainer<BindResponseDecorator>>
+{
+    /**
+     * Instantiates a new action.
+     */
+    public InitBindResponse()
+    {
+        super( "Init BindResponse" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindResponseDecorator> container )
+    {
+        // Now, we can allocate the BindResponse Object
+        BindResponseDecorator bindResponse = new BindResponseDecorator(
+            container.getLdapCodecService(), new BindResponseImpl( container.getMessageId() ) );
+        container.setMessage( bindResponse );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindResponse/StoreServerSASLCreds.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindResponse/StoreServerSASLCreds.java
new file mode 100644
index 0000000..faba3dc
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/bindResponse/StoreServerSASLCreds.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.bindResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindResponseDecorator;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a SASL credentials :
+ * <pre>
+ * BindResponse ::= APPLICATION 1] SEQUENCE {
+ *     ...
+ *     serverSaslCreds [7] OCTET STRING OPTIONAL }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreServerSASLCreds extends GrammarAction<LdapMessageContainer<BindResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreServerSASLCreds.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new server sasl creds action.
+     */
+    public StoreServerSASLCreds()
+    {
+        super( "Store server sasl credentials value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<BindResponseDecorator> container ) throws DecoderException
+    {
+        // Get the Value and store it in the BindRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length server
+        // sasl credentials
+        byte[] serverSaslCreds = null;
+
+        if ( tlv.getLength() == 0 )
+        {
+            serverSaslCreds = StringConstants.EMPTY_BYTES;
+        }
+        else
+        {
+            serverSaslCreds = tlv.getValue().getData();
+        }
+
+        BindResponse response = container.getMessage();
+        response.setServerSaslCreds( serverSaslCreds );
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The SASL credentials value is : {}", Strings.dumpBytes( serverSaslCreds ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/InitCompareRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/InitCompareRequest.java
new file mode 100644
index 0000000..f2f7284
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/InitCompareRequest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareRequestImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the CompareRequest.
+ * <pre>
+ * LdapMessage ::= ... CompareRequest ...
+ *
+ * CompareRequest ::= [APPLICATION 14] SEQUENCE {
+ * ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitCompareRequest extends GrammarAction<LdapMessageContainer<CompareRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitCompareRequest.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitCompareRequest()
+    {
+        super( "Compare Request initialization" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<CompareRequestDecorator> container )
+    {
+        // Now, we can allocate the CompareRequest Object
+        CompareRequest internalCompareRequest = new CompareRequestImpl();
+        internalCompareRequest.setMessageId( container.getMessageId() );
+        CompareRequestDecorator compareRequest = new CompareRequestDecorator(
+            container.getLdapCodecService(), internalCompareRequest );
+        container.setMessage( compareRequest );
+
+        LOG.debug( "Compare Request" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestAssertionValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestAssertionValue.java
new file mode 100644
index 0000000..3e2ff94
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestAssertionValue.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the AssertionValue in a Compare Request
+ * <pre>
+ * CompareRequest ::= [APPLICATION 14] SEQUENCE {
+ *     ...
+ *     ava AttributeValueAssertion }
+ *
+ * AttributeValueAssertion ::= SEQUENCE {
+ *     ...
+ *     assertionValue AssertionValue }
+ *
+ * AssertionValue OCTET STRING
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreCompareRequestAssertionValue extends GrammarAction<LdapMessageContainer<CompareRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreCompareRequestAssertionValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreCompareRequestAssertionValue()
+    {
+        super( "Store CompareRequest assertion value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<CompareRequestDecorator> container )
+    {
+        // Get the CompareRequest Object
+        CompareRequest compareRequest = container.getMessage();
+
+        // Get the Value and store it in the CompareRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length value
+        if ( tlv.getLength() == 0 )
+        {
+            compareRequest.setAssertionValue( "" );
+        }
+        else
+        {
+            if ( container.isBinary( compareRequest.getAttributeId() ) )
+            {
+                compareRequest.setAssertionValue( tlv.getValue().getData() );
+
+                if ( IS_DEBUG )
+                {
+                    LOG.debug( "Comparing attribute value {}", Strings.dumpBytes( compareRequest
+                        .getAssertionValue().getBytes() ) );
+                }
+            }
+            else
+            {
+                compareRequest.setAssertionValue( Strings.utf8ToString( tlv.getValue().getData() ) );
+
+                if ( LOG.isDebugEnabled() )
+                {
+                    LOG.debug( "Comparing attribute value {}", compareRequest.getAssertionValue() );
+                }
+            }
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestAttributeDesc.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestAttributeDesc.java
new file mode 100644
index 0000000..f9c2b33
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestAttributeDesc.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the AssertionValue attributeDescription in a Compare Request
+ * <pre>
+ * CompareRequest ::= [APPLICATION 14] SEQUENCE {
+ *     ...
+ *     ava AttributeValueAssertion }
+ *
+ * AttributeValueAssertion ::= SEQUENCE {
+ *     attributeDesc   AttributeDescription,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreCompareRequestAttributeDesc extends GrammarAction<LdapMessageContainer<CompareRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreCompareRequestAttributeDesc.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreCompareRequestAttributeDesc()
+    {
+        super( "Store CompareRequest assertion description" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<CompareRequestDecorator> container ) throws DecoderException
+    {
+        // Get the CompareRequest Object
+        CompareRequest compareRequest = container.getMessage();
+
+        // Get the Value and store it in the CompareRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // Dn
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04093 );
+            LOG.error( msg );
+            CompareResponseImpl response = new CompareResponseImpl( compareRequest.getMessageId() );
+
+            throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX,
+                compareRequest.getName(), null );
+        }
+
+        String type = Strings.utf8ToString( tlv.getValue().getData() );
+        compareRequest.setAttributeId( type );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Comparing attribute description {}", compareRequest.getAttributeId() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestEntryName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestEntryName.java
new file mode 100644
index 0000000..9bc7da3
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareRequest/StoreCompareRequestEntryName.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the Compare Request name
+ * <pre>
+ * CompareRequest ::= [APPLICATION 14] SEQUENCE {
+ *     entry    LDAPDN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreCompareRequestEntryName extends GrammarAction<LdapMessageContainer<CompareRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreCompareRequestEntryName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreCompareRequestEntryName()
+    {
+        super( "Store CompareRequest entry Name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<CompareRequestDecorator> container ) throws DecoderException
+    {
+        CompareRequest compareRequest = container.getMessage();
+
+        // Get the Value and store it in the CompareRequest
+        TLV tlv = container.getCurrentTLV();
+        Dn entry = null;
+
+        // We have to handle the special case of a 0 length matched
+        // Dn
+        if ( tlv.getLength() == 0 )
+        {
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04089 ) );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                entry = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Invalid Dn given : " + dnStr + " (" + Strings.dumpBytes( dnBytes )
+                    + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                CompareResponseImpl response = new CompareResponseImpl( compareRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    Dn.EMPTY_DN, ine );
+            }
+
+            compareRequest.setName( entry );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Comparing Dn {}", entry );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareResponse/InitCompareResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareResponse/InitCompareResponse.java
new file mode 100644
index 0000000..8297e97
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/compareResponse/InitCompareResponse.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.compareResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.CompareResponseDecorator;
+import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the CompareResponse
+ * <pre>
+ * LdapMessage ::= ... CompareResponse ...
+ * CompareResponse ::= [APPLICATION 15] LDAPResult
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitCompareResponse extends GrammarAction<LdapMessageContainer<CompareResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitCompareResponse.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitCompareResponse()
+    {
+        super( "Compare Response initialization" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<CompareResponseDecorator> container ) throws DecoderException
+    {
+        // Now, we can allocate the CompareResponse Object
+        CompareResponseDecorator compareResponse = new CompareResponseDecorator(
+            container.getLdapCodecService(), new CompareResponseImpl( container.getMessageId() ) );
+        container.setMessage( compareResponse );
+
+        // We will check that the request is not null
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04094 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        LOG.debug( "Compare response " );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java
new file mode 100644
index 0000000..d9f0a99
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.controls;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used add a new control. We store its OID.
+ * <pre>
+ * Control ::= SEQUENCE {
+ *     controlType             LDAPOID,
+ *     ...
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AddControl.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new AddControl action.
+     */
+    public AddControl()
+    {
+        super( "Add a new control" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the type
+        // We have to handle the special case of a 0 length OID
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04097 );
+            LOG.error( msg );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+
+        byte[] value = tlv.getValue().getData();
+        String oidValue = Strings.asciiBytesToString( value );
+
+        // The OID is encoded as a String, not an Object Id
+        if ( !Oid.isOid( oidValue ) )
+        {
+            LOG.error( I18n.err( I18n.ERR_04098, Strings.dumpBytes( value ) ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04099, oidValue ) );
+        }
+
+        Message message = container.getMessage();
+
+        Control control = container.getLdapCodecService().newControl( oidValue );
+
+        message.addControl( control );
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Control OID : " + oidValue );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/InitControls.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/InitControls.java
new file mode 100644
index 0000000..8d7e759
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/InitControls.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.controls;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize a control.
+ * <pre>
+ *         ... },
+ *     controls       [0] Controls OPTIONAL }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitControls extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitControls.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new controls init action.
+     */
+    public InitControls()
+    {
+        super( "Initialize a control" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+        int expectedLength = tlv.getLength();
+
+        // The Length should be null
+        if ( expectedLength == 0 )
+        {
+            LOG.error( "The length of controls must not be null" );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( "The length of controls must not be null" );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "A new list of controls has been initialized" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java
new file mode 100644
index 0000000..497dbd9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.controls;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to set the control criticality flag
+ * <pre>
+ * Control ::= SEQUENCE {
+ *     ...
+ *     criticality BOOLEAN DEFAULT FALSE,
+ *     ...
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreControlCriticality.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new StoreControlCriticality action.
+     */
+    public StoreControlCriticality()
+    {
+        super( "Store the control criticality" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // Get the current control
+        Control control = null;
+
+        MessageDecorator<? extends Message> message = container.getMessage();
+        control = message.getCurrentControl();
+
+        // Store the criticality
+        // We get the value. If it's a 0, it's a FALSE. If it's
+        // a FF, it's a TRUE. Any other value should be an error,
+        // but we could relax this constraint. So if we have
+        // something
+        // which is not 0, it will be interpreted as TRUE, but we
+        // will generate a warning.
+        BerValue value = tlv.getValue();
+
+        try
+        {
+            control.setCritical( BooleanDecoder.parse( value ) );
+        }
+        catch ( BooleanDecoderException bde )
+        {
+            LOG.error( I18n
+                .err( I18n.ERR_04100, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( bde.getMessage(), bde );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Control criticality : " + control.isCritical() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlValue.java
new file mode 100644
index 0000000..29b9155
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlValue.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.controls;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to set the value of a control. This is an extension point
+ * where different controls can be plugged in (at least eventually). For now we
+ * hard code controls.
+ * <pre>
+ * Control ::= SEQUENCE {
+ *     ...
+ *     controlValue OCTET STRING OPTIONAL }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreControlValue extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreControlValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new StoreControlValue action.
+     */
+    public StoreControlValue()
+    {
+        super( "Store the control value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        MessageDecorator<?> message = container.getMessage();
+        CodecControl<? extends Control> control = message.getCurrentControl();
+
+        // Get the current control
+        BerValue value = tlv.getValue();
+
+        // Store the value - have to handle the special case of a 0 length value
+        if ( tlv.getLength() == 0 )
+        {
+            control.setValue( StringConstants.EMPTY_BYTES );
+        }
+        else
+        {
+            control.setValue( value.getData() );
+            control.decode( value.getData() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Control value : " + Strings.dumpBytes( control.getValue() ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/delRequest/InitDelRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/delRequest/InitDelRequest.java
new file mode 100644
index 0000000..62f6a29
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/delRequest/InitDelRequest.java
@@ -0,0 +1,125 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.delRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.DeleteRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
+import org.apache.directory.api.ldap.model.message.DeleteResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the DelRequest.
+ * <pre>
+ * LdapMessage ::= ... DelRequest ...
+ * delRequest ::= [APPLICATION 10] LDAPDN
+ *
+ * We store the Dn to bve deleted into the DelRequest object
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitDelRequest extends GrammarAction<LdapMessageContainer<DeleteRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitDelRequest.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitDelRequest()
+    {
+        super( "Delete Request initialization" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<DeleteRequestDecorator> container ) throws DecoderException
+    {
+        // Create the DeleteRequest LdapMessage instance and store it in the container
+        DeleteRequest internaldelRequest = new DeleteRequestImpl();
+        internaldelRequest.setMessageId( container.getMessageId() );
+        DeleteRequestDecorator delRequest = new DeleteRequestDecorator(
+            container.getLdapCodecService(), internaldelRequest );
+        container.setMessage( delRequest );
+
+        // And store the Dn into it
+        // Get the Value and store it in the DelRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // Dn
+        Dn entry = null;
+
+        if ( tlv.getLength() == 0 )
+        {
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04073 ) );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                entry = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = I18n.err( I18n.ERR_04074, dnStr, Strings.dumpBytes( dnBytes ), ine
+                    .getLocalizedMessage() );
+                LOG.error( msg );
+
+                DeleteResponseImpl response = new DeleteResponseImpl( delRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    Dn.EMPTY_DN, ine );
+            }
+
+            delRequest.setName( entry );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Deleting Dn {}", entry );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/delResponse/InitDelResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/delResponse/InitDelResponse.java
new file mode 100644
index 0000000..faedc0d
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/delResponse/InitDelResponse.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.delResponse;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.DeleteResponseDecorator;
+import org.apache.directory.api.ldap.model.message.DeleteResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the DelResponse response
+ * <pre>
+ * LdapMessage ::= ... DelResponse ...
+ * DelResponse ::= [APPLICATION 11] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitDelResponse extends GrammarAction<LdapMessageContainer<DeleteResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitDelResponse.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitDelResponse()
+    {
+        super( "Init DelResponse" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<DeleteResponseDecorator> container )
+    {
+        // Now, we can allocate the DelResponse Object
+        DeleteResponseDecorator delResponse = new DeleteResponseDecorator(
+            container.getLdapCodecService(), new DeleteResponseImpl( container.getMessageId() ) );
+        container.setMessage( delResponse );
+
+        LOG.debug( "Del response " );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/InitExtendedRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/InitExtendedRequest.java
new file mode 100644
index 0000000..550cb14
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/InitExtendedRequest.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.extendedRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the ExtendedRequest message
+ * <pre>
+ * LdapMessage ::= ... ExtendedRequest ...
+ * ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitExtendedRequest extends GrammarAction<LdapMessageContainer<ExtendedRequestDecorator<?>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitExtendedRequest.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitExtendedRequest()
+    {
+        super( "Init ExtendedRequest" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ExtendedRequestDecorator<?>> container ) throws DecoderException
+    {
+        /*
+         * It is the responsibility of the LdapCodecService to instantiate new
+         * extended requests and responses. So we must delegate this task over
+         * to it instead of creating the requests and responses manually. This
+         * is because we use a plugin model that allows us to use specific 
+         * types for extended requests and responses rather than using a 
+         * generic type.
+         * 
+         * So we have to wait until we at least get our hands on ExtendedRequest 
+         * OID before we can delegate instantiation to the LdapCodecService.
+         */
+
+        LOG.debug( "Extended request being processed ..." );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/StoreExtendedRequestName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/StoreExtendedRequestName.java
new file mode 100644
index 0000000..f2e7a2f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/StoreExtendedRequestName.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.extendedRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the Extended Request name
+ * <pre>
+ * ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+ *     requestName [0] LDAPOID,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreExtendedRequestName extends GrammarAction<LdapMessageContainer<ExtendedRequestDecorator<?>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreExtendedRequestName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreExtendedRequestName()
+    {
+        super( "Store ExtendedRequest Name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ExtendedRequestDecorator<?>> container ) throws DecoderException
+    {
+        ExtendedRequest req;
+
+        // Get the Value and store it in the ExtendedRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // OID
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04095 );
+            LOG.error( msg );
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+        else
+        {
+            byte[] requestNameBytes = tlv.getValue().getData();
+
+            try
+            {
+                String requestName = Strings.utf8ToString( requestNameBytes );
+
+                if ( !Oid.isOid( requestName ) )
+                {
+
+                    String msg = "The Request name is not a valid OID : "
+                        + Strings.utf8ToString( requestNameBytes ) + " ("
+                        + Strings.dumpBytes( requestNameBytes ) + ") is invalid";
+                    LOG.error( msg );
+
+                    // throw an exception, we will get a PROTOCOL_ERROR
+                    throw new DecoderException( msg );
+                }
+
+                req = LdapApiServiceFactory.getSingleton().newExtendedRequest( requestName, null );
+                req.setMessageId( container.getMessageId() );
+                container.setMessage( LdapApiServiceFactory.getSingleton().decorate( req ) );
+            }
+            catch ( DecoderException de )
+            {
+                String msg = "The Request name is not a valid OID : "
+                    + Strings.utf8ToString( requestNameBytes ) + " ("
+                    + Strings.dumpBytes( requestNameBytes ) + ") is invalid";
+                LOG.error( "{} : {}", msg, de.getMessage() );
+
+                // Rethrow the exception, we will get a PROTOCOL_ERROR
+                throw de;
+            }
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "OID read : {}", req.getRequestName() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/StoreExtendedRequestValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/StoreExtendedRequestValue.java
new file mode 100644
index 0000000..cae2c31
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedRequest/StoreExtendedRequestValue.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.extendedRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.util.StringConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the Extended Request value
+ * <pre>
+ * ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+ *     ...
+ *     requestValue  [1] OCTET STRING OPTIONAL }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreExtendedRequestValue extends GrammarAction<LdapMessageContainer<ExtendedRequestDecorator<?>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreExtendedRequestValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreExtendedRequestValue()
+    {
+        super( "Store ExtendedRequest value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ExtendedRequestDecorator<?>> container ) throws DecoderException
+    {
+        // We can allocate the ExtendedRequest Object
+        ExtendedRequestDecorator<?> extendedRequest = container.getMessage();
+
+        // Get the Value and store it in the ExtendedRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // value
+        if ( tlv.getLength() == 0 )
+        {
+            extendedRequest.setRequestValue( StringConstants.EMPTY_BYTES );
+        }
+        else
+        {
+            extendedRequest.setRequestValue( tlv.getValue().getData() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Extended value : {}", extendedRequest.getRequestValue() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/InitExtendedResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/InitExtendedResponse.java
new file mode 100644
index 0000000..fbb4bf2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/InitExtendedResponse.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.extendedResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the ExtendedResponse message
+ * <pre>
+ * LdapMessage ::= ... ExtendedResponse ...
+ * ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitExtendedResponse extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator<?>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitExtendedResponse.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitExtendedResponse()
+    {
+        super( "Init ExtendedResponse" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ExtendedResponseDecorator<?>> container ) throws DecoderException
+    {
+        // Now, we can allocate the ExtendedResponse Object
+        ExtendedResponseDecorator<?> extendedResponse = new ExtendedResponseDecorator<ExtendedResponseImpl>(
+            container.getLdapCodecService(), new ExtendedResponseImpl( container.getMessageId() ) );
+        container.setMessage( extendedResponse );
+
+        LOG.debug( "Extended Response" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/StoreExtendedResponseName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/StoreExtendedResponseName.java
new file mode 100644
index 0000000..e64e3d7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/StoreExtendedResponseName.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.extendedResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.LdapResultDecorator;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a Response Name to an ExtendedResponse
+ * <pre>
+ * LdapMessage ::= ... ExtendedResponse ...
+ * ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+ *     COMPONENTS OF LDAPResult,
+ *     responseName   [10] LDAPOID OPTIONAL,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreExtendedResponseName extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator<?>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreExtendedResponseName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new response name action.
+     */
+    public StoreExtendedResponseName()
+    {
+        super( "Store response name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ExtendedResponseDecorator<?>> container ) throws DecoderException
+    {
+        // We can allocate the ExtendedResponse Object
+        ExtendedResponse extendedResponse = null;
+
+        // Get the Value and store it in the ExtendedResponse
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // OID
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04017 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+        else
+        {
+            String responseName = Oid.fromString( Strings.asciiBytesToString( tlv.getValue().getData() ) )
+                .toString();
+
+            extendedResponse = LdapApiServiceFactory.getSingleton().newExtendedResponse( responseName,
+                container.getMessageId(), null );
+            
+            ( ( ExtendedResponseDecorator<?> ) extendedResponse ).setLdapResult( ( ( LdapResultDecorator ) ( container
+                .getMessage().getLdapResult() ) ) );
+            container.setMessage( LdapApiServiceFactory.getSingleton().decorate( extendedResponse ) );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "OID read : {}", extendedResponse.getResponseName() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/StoreExtendedResponseValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/StoreExtendedResponseValue.java
new file mode 100644
index 0000000..407fab6
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/extendedResponse/StoreExtendedResponseValue.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.extendedResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.util.StringConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a Response to an ExtendedResponse
+ * <pre>
+ * ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+ *     ...
+ *     response       [11] OCTET STRING OPTIONAL}
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreExtendedResponseValue extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator<?>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreExtendedResponseValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new response action.
+     */
+    public StoreExtendedResponseValue()
+    {
+        super( "Store response value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ExtendedResponseDecorator<?>> container ) throws DecoderException
+    {
+        // We can allocate the ExtendedResponse Object
+        ExtendedResponseDecorator<?> extendedResponse = container.getMessage();
+
+        // Get the Value and store it in the ExtendedResponse
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // OID
+        if ( tlv.getLength() == 0 )
+        {
+            extendedResponse.setResponseValue( StringConstants.EMPTY_BYTES );
+        }
+        else
+        {
+            extendedResponse.setResponseValue( tlv.getValue().getData() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Extended value : {}", extendedResponse.getResponseValue() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/InitIntermediateResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/InitIntermediateResponse.java
new file mode 100644
index 0000000..d552418
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/InitIntermediateResponse.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.intermediateResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.api.ldap.model.message.IntermediateResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the IntermediateResponse message
+ * <pre>
+ * LdapMessage ::= ... IntermediateResponse ...
+ * IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitIntermediateResponse extends GrammarAction<LdapMessageContainer<IntermediateResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitIntermediateResponse.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitIntermediateResponse()
+    {
+        super( "Init Intermediate Response" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<IntermediateResponseDecorator> container ) throws DecoderException
+    {
+        // Now, we can allocate the IntermediateResponse Object
+        IntermediateResponseDecorator intermediateResponse =
+            new IntermediateResponseDecorator( container.getLdapCodecService(),
+                new IntermediateResponseImpl( container.getMessageId() ) );
+        container.setMessage( intermediateResponse );
+
+        LOG.debug( "Intermediate Response" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseName.java
new file mode 100644
index 0000000..0269228
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseName.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.intermediateResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a IntermediateResponse Name
+ * <pre>
+ * IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+ *     responseName [0] LDAPOID OPTIONAL,
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreIntermediateResponseName extends GrammarAction<LdapMessageContainer<IntermediateResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreIntermediateResponseName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new response name action.
+     */
+    public StoreIntermediateResponseName()
+    {
+        super( "Store response name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<IntermediateResponseDecorator> container ) throws DecoderException
+    {
+        // We can get the IntermediateResponse Object
+        IntermediateResponse intermediateResponse = container.getMessage();
+
+        // Get the Value and store it in the IntermediateResponse
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // OID.
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04095 );
+            LOG.error( msg );
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+        else
+        {
+            byte[] responseNameBytes = tlv.getValue().getData();
+
+            String oidStr = Strings.utf8ToString( responseNameBytes );
+
+            if ( Oid.isOid( oidStr ) )
+            {
+                Oid.isOid( oidStr );
+                intermediateResponse.setResponseName( oidStr );
+            }
+            else
+            {
+                String msg = "The Intermediate Response name is not a valid OID : "
+                    + Strings.utf8ToString( responseNameBytes ) + " ("
+                    + Strings.dumpBytes( responseNameBytes ) + ") is invalid";
+                LOG.error( "{} : {}", msg, oidStr );
+
+                // Rethrow the exception, we will get a PROTOCOL_ERROR
+                throw new DecoderException( msg );
+            }
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "OID read : {}", intermediateResponse.getResponseName() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseValue.java
new file mode 100644
index 0000000..b185d0f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseValue.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.intermediateResponse;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a IntermediateResponse value
+ * <pre>
+ * IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+ *     ...
+ *     responseValue [1] OCTET STRING OPTIONAL
+ *     }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreIntermediateResponseValue extends GrammarAction<LdapMessageContainer<IntermediateResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreIntermediateResponseValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new response name action.
+     */
+    public StoreIntermediateResponseValue()
+    {
+        super( "Store response value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<IntermediateResponseDecorator> container ) throws DecoderException
+    {
+        // We can get the IntermediateResponse Object
+        IntermediateResponse intermediateResponse = container.getMessage();
+
+        // Get the Value and store it in the IntermediateResponse
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // value
+        if ( tlv.getLength() == 0 )
+        {
+            intermediateResponse.setResponseValue( StringConstants.EMPTY_BYTES );
+        }
+        else
+        {
+            intermediateResponse.setResponseValue( tlv.getValue().getData() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Value read : {}", Strings.dumpBytes( intermediateResponse.getResponseValue() ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapMessage/InitLdapMessage.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapMessage/InitLdapMessage.java
new file mode 100644
index 0000000..61387fa
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapMessage/InitLdapMessage.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.ldapMessage;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize an LdapMessage
+ * <pre>
+ * LDAPMessage --> SEQUENCE { ...
+ *
+ * We have a LDAPMessage, and the tag must be 0x30.
+ *
+ * The next state will be LDAP_MESSAGE_STATE
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitLdapMessage extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitLdapMessage.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitLdapMessage()
+    {
+        super( "LdapMessage initialization" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // The Length should not be null
+        if ( tlv.getLength() == 0 )
+        {
+            LOG.error( I18n.err( I18n.ERR_04066 ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapMessage/StoreMessageId.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapMessage/StoreMessageId.java
new file mode 100644
index 0000000..278b913
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapMessage/StoreMessageId.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.ldapMessage;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the LdapMessage MessageID.
+ * <pre>
+ * LDAPMessage --> ... MessageId ...
+ *
+ * Checks that MessageId is in [0 .. 2147483647] and store the value in
+ * the LdapMessage Object
+ *
+ * (2147483647 = Integer.MAX_VALUE)
+ * The next state will be MESSAGE_ID_STATE
+ *
+ * The message ID will be temporarily stored in the container, because we can't store it
+ * into an object.
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreMessageId extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreMessageId.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreMessageId()
+    {
+        super( "Store MessageID" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        // The current TLV should be a integer
+        // We get it and store it in MessageId
+        TLV tlv = container.getCurrentTLV();
+
+        // The Length should not be null
+        if ( tlv.getLength() == 0 )
+        {
+            LOG.error( I18n.err( I18n.ERR_04068 ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04069 ) );
+        }
+
+        BerValue value = tlv.getValue();
+
+        try
+        {
+            int messageId = IntegerDecoder.parse( value, 0, Integer.MAX_VALUE );
+
+            container.setMessageId( messageId );
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "Ldap Message Id has been decoded : " + messageId );
+            }
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            LOG.error( I18n.err( I18n.ERR_04070, Strings.dumpBytes( value.getData() ), ide
+                .getLocalizedMessage() ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( ide.getMessage(), ide );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/AddReferral.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/AddReferral.java
new file mode 100644
index 0000000..0eb5784
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/AddReferral.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.ldapResult;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to add a referral to a LdapTresult
+ * <pre>
+ * Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
+ * URI ::= LDAPString
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddReferral extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AddReferral.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new referral action.
+     */
+    public AddReferral()
+    {
+        super( "Add a referral" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        Message response = container.getMessage();
+        LdapResult ldapResult = ( ( ResultResponse ) response ).getLdapResult();
+        Referral referral = ldapResult.getReferral();
+
+        if ( tlv.getLength() == 0 )
+        {
+            referral.addLdapUrl( "" );
+        }
+        else
+        {
+            if ( ldapResult.getResultCode() == ResultCodeEnum.REFERRAL )
+            {
+                try
+                {
+                    String url = Strings.utf8ToString( tlv.getValue().getData() );
+                    referral.addLdapUrl( new LdapUrl( url ).toString() );
+                }
+                catch ( LdapURLEncodingException luee )
+                {
+                    String badUrl = Strings.utf8ToString( tlv.getValue().getData() );
+                    LOG.error( I18n.err( I18n.ERR_04015, badUrl, luee.getMessage() ) );
+                    throw new DecoderException( I18n.err( I18n.ERR_04016, luee.getMessage() ), luee );
+                }
+            }
+            else
+            {
+                LOG.warn( "The Referral error message is not allowed when havind an error code no equals to REFERRAL" );
+                referral.addLdapUrl( LdapUrl.EMPTY_URL.toString() );
+            }
+        }
+
+        if ( IS_DEBUG )
+        {
+            StringBuffer sb = new StringBuffer();
+            boolean isFirst = true;
+
+            for ( String url : ldapResult.getReferral().getLdapUrls() )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( ", " );
+                }
+
+                sb.append( url );
+            }
+
+            LOG.debug( "The referral error message is set to " + sb.toString() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/InitReferrals.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/InitReferrals.java
new file mode 100644
index 0000000..12e411e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/InitReferrals.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.ldapResult;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to init referrals to a LdapResult :
+ * <pre>
+ * LDAPResult ::= SEQUENCE {
+ *     ...
+ *     referral   [3] Referral OPTIONNAL }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitReferrals extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitReferrals.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init referrals action.
+     */
+    public InitReferrals()
+    {
+        super( "Init the referrals list" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // If we hae a Referrals sequence, then it should not be empty
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04011 );
+            LOG.error( msg );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg );
+        }
+
+        ResultResponse response = ( ResultResponse ) container.getMessage();
+        LdapResult ldapResult = response.getLdapResult();
+
+        Referral referral = new ReferralImpl();
+        ldapResult.setReferral( referral );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialising a referrals list" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreErrorMessage.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreErrorMessage.java
new file mode 100644
index 0000000..ecf4ec9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreErrorMessage.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.ldapResult;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to set the LdapResult error message.
+ *
+ * <pre>
+ *  LDAPResult ::= SEQUENCE {
+ *     ...
+ *     errorMessage LDAPString,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreErrorMessage extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreErrorMessage.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new error message action.
+     */
+    public StoreErrorMessage()
+    {
+        super( "Store error message" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        // Get the Value and store it in the BindResponse
+        TLV tlv = container.getCurrentTLV();
+        String errorMessage = null;
+
+        // We have to handle the special case of a 0 length error
+        // message
+        if ( tlv.getLength() == 0 )
+        {
+            errorMessage = "";
+        }
+        else
+        {
+            errorMessage = Strings.utf8ToString( tlv.getValue().getData() );
+        }
+
+        ResultResponse response = ( ResultResponse ) container.getMessage();
+        LdapResult ldapResult = response.getLdapResult();
+        ldapResult.setDiagnosticMessage( errorMessage );
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The error message is : " + errorMessage );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreMatchedDN.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreMatchedDN.java
new file mode 100644
index 0000000..6167c3b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreMatchedDN.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.ldapResult;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to set the LdapResult matched Dn.
+ *
+ * <pre>
+ * LDAPResult ::= SEQUENCE {
+ *     ...
+ *     matchedDN LDAPDN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreMatchedDN extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreMatchedDN.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new matched dn action.
+     */
+    public StoreMatchedDN()
+    {
+        super( "Store matched Dn" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        // Get the Value and store it in the BindResponse
+        TLV tlv = container.getCurrentTLV();
+        Dn matchedDn = null;
+        ResultCodeEnum resultCode = null;
+
+        ResultResponse response = ( ResultResponse ) container.getMessage();
+        LdapResult ldapResult = response.getLdapResult();
+        resultCode = ldapResult.getResultCode();
+
+        // We have to handle the special case of a 0 length matched
+        // Dn
+        if ( tlv.getLength() == 0 )
+        {
+            matchedDn = Dn.EMPTY_DN;
+        }
+        else
+        {
+            // A not null matchedDn is valid for resultCodes
+            // NoSuchObject, AliasProblem, InvalidDNSyntax and
+            // AliasDreferencingProblem.
+
+            switch ( resultCode )
+            {
+                case NO_SUCH_OBJECT:
+                case ALIAS_PROBLEM:
+                case INVALID_DN_SYNTAX:
+                case ALIAS_DEREFERENCING_PROBLEM:
+                    byte[] dnBytes = tlv.getValue().getData();
+                    String dnStr = Strings.utf8ToString( dnBytes );
+
+                    try
+                    {
+                        matchedDn = new Dn( dnStr );
+                    }
+                    catch ( LdapInvalidDnException ine )
+                    {
+                        // This is for the client side. We will never decode LdapResult on the server
+                        String msg = I18n.err( I18n.ERR_04013, dnStr, Strings.dumpBytes( dnBytes ), ine
+                            .getLocalizedMessage() );
+                        LOG.error( msg );
+
+                        throw new DecoderException( I18n.err( I18n.ERR_04014, ine.getLocalizedMessage() ), ine );
+                    }
+
+                    break;
+
+                default:
+                    LOG.warn( "The matched Dn should not be set when the result code is one of NoSuchObject,"
+                        + " AliasProblem, InvalidDNSyntax or AliasDreferencingProblem" );
+
+                    matchedDn = Dn.EMPTY_DN;
+                    break;
+            }
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The matchedDn is " + matchedDn );
+        }
+
+        ldapResult.setMatchedDn( matchedDn );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreResultCode.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreResultCode.java
new file mode 100644
index 0000000..e9242fb
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/ldapResult/StoreResultCode.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.ldapResult;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to set the LdapResult result code.
+ * <pre>
+ * LDAPResult ::= SEQUENCE {
+ *     resultCode ENUMERATED {
+ *         ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreResultCode extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreResultCode.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new result code action.
+     */
+    public StoreResultCode()
+    {
+        super( "Store resultCode" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    {
+        // The current TLV should be a integer
+        // We get it and store it in MessageId
+        TLV tlv = container.getCurrentTLV();
+
+        BerValue value = tlv.getValue();
+        ResultCodeEnum resultCode = ResultCodeEnum.SUCCESS;
+
+        try
+        {
+            resultCode = ResultCodeEnum.getResultCode( IntegerDecoder.parse( value, 0,
+                ResultCodeEnum.E_SYNC_REFRESH_REQUIRED
+                    .getResultCode() ) );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            LOG.error( I18n.err( I18n.ERR_04018, Strings.dumpBytes( value.getData() ), ide.getMessage() ) );
+
+            throw new DecoderException( ide.getMessage(), ide );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The result code is set to " + resultCode );
+        }
+
+        ResultResponse response = ( ResultResponse ) container.getMessage();
+        LdapResult ldapResult = response.getLdapResult();
+        ldapResult.setResultCode( resultCode );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/InitModifyDnRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/InitModifyDnRequest.java
new file mode 100644
index 0000000..8b43ced
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/InitModifyDnRequest.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the ModifyDnRequest message
+ * <pre>
+ * LdapMessage ::= ... ModifyDNRequest ...
+ * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitModifyDnRequest extends GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitModifyDnRequest.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitModifyDnRequest()
+    {
+        super( "Init ModifyDnRequest" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyDnRequestDecorator> container )
+    {
+        // Now, we can allocate the ModifyDNRequest Object
+        ModifyDnRequest internalModifyDnRequest = new ModifyDnRequestImpl();
+        internalModifyDnRequest.setMessageId( container.getMessageId() );
+        ModifyDnRequestDecorator modifyDnRequest = new ModifyDnRequestDecorator(
+            container.getLdapCodecService(), internalModifyDnRequest );
+        container.setMessage( modifyDnRequest );
+
+        LOG.debug( "ModifyDn request" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestDeleteOldRdn.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestDeleteOldRdn.java
new file mode 100644
index 0000000..3ed8903
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestDeleteOldRdn.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the ModifyDnRequest deleteOldRdn flag
+ * <pre>
+ * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+ *     ...
+ *     deleteoldrdn BOOLEAN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreModifyDnRequestDeleteOldRdn extends GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreModifyDnRequestDeleteOldRdn.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreModifyDnRequestDeleteOldRdn()
+    {
+        super( "Store ModifyDN request deleteOldRdn flag" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyDnRequestDecorator> container ) throws DecoderException
+    {
+        ModifyDnRequest modifyDnRequest = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // We get the value. If it's a 0, it's a FALSE. If it's
+        // a FF, it's a TRUE. Any other value should be an error,
+        // but we could relax this constraint. So if we have
+        // something
+        // which is not 0, it will be interpreted as TRUE, but we
+        // will generate a warning.
+        BerValue value = tlv.getValue();
+
+        try
+        {
+            modifyDnRequest.setDeleteOldRdn( BooleanDecoder.parse( value ) );
+        }
+        catch ( BooleanDecoderException bde )
+        {
+            LOG.error( I18n
+                .err( I18n.ERR_04091, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( bde.getMessage(), bde );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            if ( modifyDnRequest.getDeleteOldRdn() )
+            {
+                LOG.debug( " Old Rdn attributes will be deleted" );
+            }
+            else
+            {
+                LOG.debug( " Old Rdn attributes will be retained" );
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestEntryName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestEntryName.java
new file mode 100644
index 0000000..9c05096
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestEntryName.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the ModifyDnRequest entry name
+ * <pre>
+ * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+ *     entry LDAPDN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreModifyDnRequestEntryName extends GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreModifyDnRequestEntryName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreModifyDnRequestEntryName()
+    {
+        super( "Store ModifyDN request entry Name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyDnRequestDecorator> container ) throws DecoderException
+    {
+        ModifyDnRequest modifyDnRequest = container.getMessage();
+
+        // Get the Value and store it in the modifyDNRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // Dn
+        Dn entry = null;
+
+        if ( tlv.getLength() == 0 )
+        {
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04089 ) );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                entry = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Invalid Dn given : " + dnStr + " (" + Strings.dumpBytes( dnBytes )
+                    + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                ModifyDnResponseImpl response = new ModifyDnResponseImpl( modifyDnRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    Dn.EMPTY_DN, ine );
+            }
+
+            modifyDnRequest.setName( entry );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Modifying Dn {}", entry );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewRdn.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewRdn.java
new file mode 100644
index 0000000..32dd41f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewRdn.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the ModifyDnRequest new RDN
+ * <pre>
+ * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+ *     ...
+ *     newrdn  RelativeRDN,
+ *     ...
+ *
+ * RelativeRDN :: LDAPString
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreModifyDnRequestNewRdn extends GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreModifyDnRequestNewRdn.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreModifyDnRequestNewRdn()
+    {
+        super( "Store ModifyDN request new RDN" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyDnRequestDecorator> container ) throws DecoderException
+    {
+        ModifyDnRequest modifyDnRequest = container.getMessage();
+
+        // Get the Value and store it in the modifyDNRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // newDN
+        Rdn newRdn = null;
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04090 );
+            LOG.error( msg );
+
+            ModifyDnResponseImpl response = new ModifyDnResponseImpl( modifyDnRequest.getMessageId() );
+            throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                modifyDnRequest.getName(), null );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                Dn dn = new Dn( dnStr );
+                newRdn = dn.getRdn( dn.size() - 1 );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Invalid new Rdn given : " + dnStr + " (" + Strings.dumpBytes( dnBytes )
+                    + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                ModifyDnResponseImpl response = new ModifyDnResponseImpl( modifyDnRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    modifyDnRequest.getName(), ine );
+            }
+
+            modifyDnRequest.setNewRdn( newRdn );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Modifying with new Rdn {}", newRdn );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewSuperior.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewSuperior.java
new file mode 100644
index 0000000..dae73ac
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewSuperior.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the ModifyDnRequest new Superior
+ * <pre>
+ * ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
+ *     ...
+ *     newSuperior [0] LDAPDN OPTIONAL }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreModifyDnRequestNewSuperior extends GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreModifyDnRequestNewSuperior.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreModifyDnRequestNewSuperior()
+    {
+        super( "Store new superior" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyDnRequestDecorator> container ) throws DecoderException
+    {
+        ModifyDnRequest modifyDnRequest = container.getMessage();
+
+        // Get the Value and store it in the modifyDNRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to handle the special case of a 0 length matched
+        // Dn
+        Dn newSuperior = Dn.EMPTY_DN;
+
+        if ( tlv.getLength() == 0 )
+        {
+
+            if ( modifyDnRequest.getDeleteOldRdn() )
+            {
+                // This will generate a PROTOCOL_ERROR
+                throw new DecoderException( I18n.err( I18n.ERR_04092 ) );
+            }
+            else
+            {
+                LOG.warn( "The new superior is null, so we will change the entry" );
+            }
+
+            modifyDnRequest.setNewSuperior( newSuperior );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                newSuperior = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Invalid new superior Dn given : " + dnStr + " ("
+                    + Strings.dumpBytes( dnBytes ) + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                ModifyDnResponseImpl response = new ModifyDnResponseImpl( modifyDnRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    modifyDnRequest.getName(), ine );
+            }
+
+            modifyDnRequest.setNewSuperior( newSuperior );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "New superior Dn {}", newSuperior );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnResponse/InitModifyDnResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnResponse/InitModifyDnResponse.java
new file mode 100644
index 0000000..1c5d013
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyDnResponse/InitModifyDnResponse.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyDnResponse;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnResponseDecorator;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the ModifyDnResponse message
+ * <pre>
+ * ModifyDNResponse ::= [APPLICATION 13] SEQUENCE {
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitModifyDnResponse extends GrammarAction<LdapMessageContainer<ModifyDnResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitModifyDnResponse.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitModifyDnResponse()
+    {
+        super( "Init ModifyDnResponse" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyDnResponseDecorator> container )
+    {
+        // Now, we can allocate the ModifyDnResponse Object
+        ModifyDnResponseDecorator modifyDnResponse = new ModifyDnResponseDecorator(
+            container.getLdapCodecService(), new ModifyDnResponseImpl( container.getMessageId() ) );
+        container.setMessage( modifyDnResponse );
+
+        LOG.debug( "Modify Dn response " );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/AddModifyRequestAttribute.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/AddModifyRequestAttribute.java
new file mode 100644
index 0000000..ab935fb
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/AddModifyRequestAttribute.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the ModificationRequest's attribute type
+ * <pre>
+ * ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+ *     ...
+ *     modification SEQUENCE OF SEQUENCE {
+ *             ...
+ *         modification   AttributeTypeAndValues }
+ *
+ * AttributeTypeAndValues ::= SEQUENCE {
+ *     type AttributeDescription,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddModifyRequestAttribute extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AddModifyRequestAttribute.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public AddModifyRequestAttribute()
+    {
+        super( "Store Modify request operation type" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyRequestDecorator> container ) throws DecoderException
+    {
+        ModifyRequestDecorator modifyRequestDecorator = container.getMessage();
+        ModifyRequest modifyRequest = modifyRequestDecorator.getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value. It can't be null
+        String type = null;
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04083 );
+            LOG.error( msg );
+
+            ModifyResponseImpl response = new ModifyResponseImpl( modifyRequest.getMessageId() );
+            throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX,
+                modifyRequest.getName(), null );
+        }
+        else
+        {
+            type = Strings.utf8ToString( tlv.getValue().getData() );
+            modifyRequestDecorator.addAttributeTypeAndValues( type );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Modifying type : {}", type );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/InitAttributeVals.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/InitAttributeVals.java
new file mode 100644
index 0000000..4b414d2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/InitAttributeVals.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the set of ModificationRequest AVAs
+ * <pre>
+ * ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+ *     ...
+ *     modification SEQUENCE OF SEQUENCE {
+ *             ...
+ *         modification   AttributeTypeAndValues }
+ *
+ * AttributeTypeAndValues ::= SEQUENCE {
+ *     ...
+ *     vals SET OF AttributeValue }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitAttributeVals extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitAttributeVals.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitAttributeVals()
+    {
+        super( "Init Attribute vals" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyRequestDecorator> container )
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        // If the length is null, we store an empty value
+        if ( tlv.getLength() == 0 )
+        {
+            LOG.debug( "No vals for this attribute" );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        LOG.debug( "Some vals are to be decoded" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/InitModifyRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/InitModifyRequest.java
new file mode 100644
index 0000000..bbe6233
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/InitModifyRequest.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
+
+
+/**
+ * The action used to initialize the ModifyRequest message
+ * <pre>
+ * LdapMessage ::= ... ModifyRequest ...
+ * ModifyRequest ::= [APPLICATION 6] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitModifyRequest extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
+{
+    /**
+     * Instantiates a new action.
+     */
+    public InitModifyRequest()
+    {
+        super( "Init ModifyRequest" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyRequestDecorator> container )
+    {
+        // Now, we can allocate the ModifyRequest Object
+        ModifyRequest internalModifyRequest = new ModifyRequestImpl();
+        internalModifyRequest.setMessageId( container.getMessageId() );
+        ModifyRequestDecorator modifyRequestDecorator = new ModifyRequestDecorator(
+            container.getLdapCodecService(), internalModifyRequest );
+        container.setMessage( modifyRequestDecorator );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreModifyRequestAttributeValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreModifyRequestAttributeValue.java
new file mode 100644
index 0000000..2122f71
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreModifyRequestAttributeValue.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a Value to an modifyRequest
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreModifyRequestAttributeValue extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreModifyRequestAttributeValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new modify attribute value action.
+     */
+    public StoreModifyRequestAttributeValue()
+    {
+        super( "Stores AttributeValue" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyRequestDecorator> container )
+    {
+        ModifyRequestDecorator modifyRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value. It can't be null
+        byte[] value = StringConstants.EMPTY_BYTES;
+
+        try
+        {
+            if ( tlv.getLength() == 0 )
+            {
+                modifyRequestDecorator.addAttributeValue( "" );
+            }
+            else
+            {
+                value = tlv.getValue().getData();
+
+                if ( container.isBinary( modifyRequestDecorator.getCurrentAttributeType() ) )
+                {
+                    modifyRequestDecorator.addAttributeValue( value );
+                }
+                else
+                {
+                    modifyRequestDecorator.addAttributeValue( Strings.utf8ToString( ( byte[] ) value ) );
+                }
+            }
+        }
+        catch ( LdapException le )
+        {
+            // Just swallow the exception, it can't occur here
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Value modified : {}", value );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreModifyRequestObjectName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreModifyRequestObjectName.java
new file mode 100644
index 0000000..3d26ec8
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreModifyRequestObjectName.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the ModificationRequest object name
+ * <pre>
+ * ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+ *     object    LDAPDN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreModifyRequestObjectName extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreModifyRequestObjectName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreModifyRequestObjectName()
+    {
+        super( "Store Modify request object Name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyRequestDecorator> container ) throws DecoderException
+    {
+        ModifyRequestDecorator modifyRequestDecorator = container.getMessage();
+        ModifyRequest modifyRequest = modifyRequestDecorator.getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        Dn object = Dn.EMPTY_DN;
+
+        // Store the value.
+        if ( tlv.getLength() == 0 )
+        {
+            ( modifyRequestDecorator.getDecorated() ).setName( object );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                object = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Invalid Dn given : " + dnStr + " (" + Strings.dumpBytes( dnBytes )
+                    + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                ModifyResponseImpl response = new ModifyResponseImpl( modifyRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    Dn.EMPTY_DN, ine );
+            }
+
+            modifyRequest.setName( object );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Modification of Dn {}", modifyRequest.getName() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreOperationType.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreOperationType.java
new file mode 100644
index 0000000..eb89437
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyRequest/StoreOperationType.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the ModificationRequest operation type
+ * <pre>
+ * ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+ *     ...
+ *     modification SEQUENCE OF SEQUENCE {
+ *         operation  ENUMERATED {
+ *             ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreOperationType extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreOperationType.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreOperationType()
+    {
+        super( "Store Modify request operation type" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyRequestDecorator> container ) throws DecoderException
+    {
+        ModifyRequestDecorator modifyRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Decode the operation type
+        int operation = 0;
+
+        try
+        {
+            operation = IntegerDecoder.parse( tlv.getValue(), 0, 2 );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            String msg = I18n.err( I18n.ERR_04082, Strings.dumpBytes( tlv.getValue().getData() ) );
+            LOG.error( msg );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( msg, ide );
+        }
+
+        // Store the current operation.
+        modifyRequestDecorator.setCurrentOperation( operation );
+
+        if ( IS_DEBUG )
+        {
+            switch ( operation )
+            {
+                case LdapCodecConstants.OPERATION_ADD:
+                    LOG.debug( "Modification operation : ADD" );
+                    break;
+
+                case LdapCodecConstants.OPERATION_DELETE:
+                    LOG.debug( "Modification operation : DELETE" );
+                    break;
+
+                case LdapCodecConstants.OPERATION_REPLACE:
+                    LOG.debug( "Modification operation : REPLACE" );
+                    break;
+
+                default:
+                    LOG.debug( "Modification operation : UNKNOWN" );
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyResponse/InitModifyResponse.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyResponse/InitModifyResponse.java
new file mode 100644
index 0000000..fb3381b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/modifyResponse/InitModifyResponse.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.modifyResponse;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyResponseDecorator;
+import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the ModifyResponse message
+ * <pre>
+ * LdapMessage ::= ... ModifyResponse ...
+ * ModifyResponse ::= [APPLICATION 7] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitModifyResponse extends GrammarAction<LdapMessageContainer<ModifyResponseDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitModifyResponse.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitModifyResponse()
+    {
+        super( "Init ModifyResponse" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<ModifyResponseDecorator> container )
+    {
+        // Now, we can allocate the ModifyResponse Object
+        ModifyResponseDecorator modifyResponse = new ModifyResponseDecorator(
+            container.getLdapCodecService(), new ModifyResponseImpl( container.getMessageId() ) );
+        container.setMessage( modifyResponse );
+
+        LOG.debug( "Modify response" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/InitSearchRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/InitSearchRequest.java
new file mode 100644
index 0000000..bad67b7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/InitSearchRequest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the SearchRequest message
+ * <pre>
+ * LdapMessage ::= ... SearchRequest ...
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitSearchRequest extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitSearchRequest.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitSearchRequest()
+    {
+        super( "Init SearchRequest" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container )
+    {
+        // Now, we can allocate the SearchRequest Object
+        TLV tlv = container.getCurrentTLV();
+
+        SearchRequest internalSearchRequest = new SearchRequestImpl();
+        internalSearchRequest.setMessageId( container.getMessageId() );
+        SearchRequestDecorator searchRequest = new SearchRequestDecorator(
+            container.getLdapCodecService(), internalSearchRequest );
+
+        searchRequest.setTlvId( tlv.getId() );
+        container.setMessage( searchRequest );
+
+        LOG.debug( "Search Request" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/InitSearchRequestAttributeDescList.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/InitSearchRequestAttributeDescList.java
new file mode 100644
index 0000000..4dbf9da
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/InitSearchRequestAttributeDescList.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the AttributeDesc list
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     ...
+ *     filter      Filter,
+ *     attributes  AttributeDescriptionList }
+ *
+ * AttributeDescriptionList ::= SEQUENCE OF
+ *     AttributeDescription
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitSearchRequestAttributeDescList extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitSearchRequestAttributeDescList.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init attribute desc list action.
+     */
+    public InitSearchRequestAttributeDescList()
+    {
+        super( "Initialize AttributeDesc list" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        // Here, we have to inject the decoded filter into the SearchRequest
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+        SearchRequest searchRequest = searchRequestDecorator.getDecorated();
+
+        searchRequest.setFilter( searchRequestDecorator.getFilterNode() );
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize AttributeDesc list" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestAttributeDesc.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestAttributeDesc.java
new file mode 100644
index 0000000..d60df4d
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestAttributeDesc.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the attribute description
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     ...
+ *     attributes  AttributeDescriptionList }
+ *
+ * AttributeDescriptionList ::= SEQUENCE OF
+ *     AttributeDescription
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchRequestAttributeDesc extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchRequestAttributeDesc.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new attribute desc action.
+     */
+    public StoreSearchRequestAttributeDesc()
+    {
+        super( "Store attribute description" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+        TLV tlv = container.getCurrentTLV();
+        String attributeDescription = null;
+
+        if ( tlv.getLength() != 0 )
+        {
+            attributeDescription = Strings.utf8ToString( tlv.getValue().getData() );
+
+            // If the attributeDescription is empty, we won't add it
+            if ( !Strings.isEmpty( attributeDescription.trim() ) )
+            {
+                searchRequestDecorator.getDecorated().addAttributes( attributeDescription );
+            }
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Decoded Attribute Description : {}", attributeDescription );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestBaseObject.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestBaseObject.java
new file mode 100644
index 0000000..ebf63ac
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestBaseObject.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchResultDoneImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchRequest base object
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     baseObject LDAPDN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchRequestBaseObject extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchRequestBaseObject.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSearchRequestBaseObject()
+    {
+        super( "Store SearchRequest object Name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+        SearchRequest searchRequest = searchRequestDecorator.getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to check that this is a correct Dn
+        Dn baseObject = null;
+
+        // We have to handle the special case of a 0 length base
+        // object,
+        // which means that the search is done from the default
+        // root.
+        if ( tlv.getLength() != 0 )
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                baseObject = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Invalid root Dn given : " + dnStr + " (" + Strings.dumpBytes( dnBytes )
+                    + ") is invalid";
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+
+                SearchResultDoneImpl response = new SearchResultDoneImpl( searchRequest.getMessageId() );
+                throw new ResponseCarryingException( msg, response, ResultCodeEnum.INVALID_DN_SYNTAX,
+                    Dn.EMPTY_DN, ine );
+            }
+        }
+        else
+        {
+            baseObject = Dn.EMPTY_DN;
+        }
+
+        searchRequest.setBase( baseObject );
+
+        LOG.debug( "Searching with root Dn : {}", baseObject );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestDerefAlias.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestDerefAlias.java
new file mode 100644
index 0000000..7f0b937
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestDerefAlias.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchRequest derefAlias flag
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     ...
+ *     derefAliases ENUMERATED {
+ *         neverDerefAliases   (0),
+ *         derefInSearching    (1),
+ *         derefFindingBaseObj (2),
+ *         derefAlways         (3) },
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchRequestDerefAlias extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchRequestDerefAlias.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSearchRequestDerefAlias()
+    {
+        super( "Store SearchRequest derefAlias flag" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequest searchRequest = container.getMessage().getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to check that this is a correct derefAliases
+        BerValue value = tlv.getValue();
+        int derefAliases = 0;
+
+        try
+        {
+            derefAliases = IntegerDecoder.parse( value, LdapCodecConstants.NEVER_DEREF_ALIASES,
+                LdapCodecConstants.DEREF_ALWAYS );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            String msg = I18n.err( I18n.ERR_04102, value.toString() );
+            LOG.error( msg );
+            throw new DecoderException( msg, ide );
+        }
+
+        searchRequest.setDerefAliases( AliasDerefMode.getDerefMode( derefAliases ) );
+
+        if ( IS_DEBUG )
+        {
+            switch ( derefAliases )
+            {
+                case LdapCodecConstants.NEVER_DEREF_ALIASES:
+                    LOG.debug( "Handling object strategy : NEVER_DEREF_ALIASES" );
+                    break;
+
+                case LdapCodecConstants.DEREF_IN_SEARCHING:
+                    LOG.debug( "Handling object strategy : DEREF_IN_SEARCHING" );
+                    break;
+
+                case LdapCodecConstants.DEREF_FINDING_BASE_OBJ:
+                    LOG.debug( "Handling object strategy : DEREF_FINDING_BASE_OBJ" );
+                    break;
+
+                case LdapCodecConstants.DEREF_ALWAYS:
+                    LOG.debug( "Handling object strategy : DEREF_ALWAYS" );
+                    break;
+
+                default:
+                    LOG.debug( "Handling object strategy : UNKNOWN" );
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestScope.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestScope.java
new file mode 100644
index 0000000..9c36b95
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestScope.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchRequest scope
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     ...
+ *     scope ENUMERATED {
+ *         baseObject   (0),
+ *         singleLevel  (1),
+ *         wholeSubtree (2) },
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchRequestScope extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchRequestScope.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSearchRequestScope()
+    {
+        super( "Store SearchRequest scope" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequest searchRequest = container.getMessage().getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // We have to check that this is a correct scope
+        BerValue value = tlv.getValue();
+        int scope = 0;
+
+        try
+        {
+            scope = IntegerDecoder.parse( value, LdapCodecConstants.SCOPE_BASE_OBJECT,
+                LdapCodecConstants.SCOPE_WHOLE_SUBTREE );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            String msg = I18n.err( I18n.ERR_04101, value.toString() );
+            LOG.error( msg );
+            throw new DecoderException( msg, ide );
+        }
+
+        searchRequest.setScope( SearchScope.getSearchScope( scope ) );
+
+        if ( IS_DEBUG )
+        {
+            switch ( scope )
+            {
+                case LdapCodecConstants.SCOPE_BASE_OBJECT:
+                    LOG.debug( "Searching within BASE_OBJECT scope " );
+                    break;
+
+                case LdapCodecConstants.SCOPE_SINGLE_LEVEL:
+                    LOG.debug( "Searching within SINGLE_LEVEL scope " );
+                    break;
+
+                case LdapCodecConstants.SCOPE_WHOLE_SUBTREE:
+                    LOG.debug( "Searching within WHOLE_SUBTREE scope " );
+                    break;
+
+                default:
+                    LOG.debug( "Searching within UNKNOWN scope " );
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestSizeLimit.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestSizeLimit.java
new file mode 100644
index 0000000..3d0fd86
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestSizeLimit.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.LongDecoder;
+import org.apache.directory.api.asn1.ber.tlv.LongDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchRequest sizeLimit
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     ...
+ *     sizeLimit INTEGER (0 .. maxInt),
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchRequestSizeLimit extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchRequestSizeLimit.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSearchRequestSizeLimit()
+    {
+        super( "Store SearchRequest sizeLimit" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequest searchRequest = container.getMessage().getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // The current TLV should be a integer
+        // We get it and store it in sizeLimit
+        BerValue value = tlv.getValue();
+        long sizeLimit = 0;
+
+        try
+        {
+            sizeLimit = LongDecoder.parse( value, 0, Integer.MAX_VALUE );
+        }
+        catch ( LongDecoderException lde )
+        {
+            String msg = I18n.err( I18n.ERR_04103, value.toString() );
+            LOG.error( msg );
+            throw new DecoderException( msg, lde );
+        }
+
+        searchRequest.setSizeLimit( sizeLimit );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The sizeLimit value is set to {} objects", Long.valueOf( sizeLimit ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestTimeLimit.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestTimeLimit.java
new file mode 100644
index 0000000..8530e59
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestTimeLimit.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchRequest timeLimit
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     ...
+ *     timeLimit INTEGER (0 .. maxInt),
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchRequestTimeLimit extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchRequestTimeLimit.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSearchRequestTimeLimit()
+    {
+        super( "Store SearchRequest timeLimit" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequest searchRequest = container.getMessage().getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // The current TLV should be a integer
+        // We get it and store it in timeLimit
+        BerValue value = tlv.getValue();
+
+        int timeLimit = 0;
+
+        try
+        {
+            timeLimit = IntegerDecoder.parse( value, 0, Integer.MAX_VALUE );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            String msg = I18n.err( I18n.ERR_04104, value.toString() );
+            LOG.error( msg );
+            throw new DecoderException( msg, ide );
+        }
+
+        searchRequest.setTimeLimit( timeLimit );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The timeLimit value is set to {} seconds", Integer.valueOf( timeLimit ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestTypesOnly.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestTypesOnly.java
new file mode 100644
index 0000000..8215246
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreSearchRequestTypesOnly.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchRequest typesOnly flag
+ * <pre>
+ * SearchRequest ::= [APPLICATION 3] SEQUENCE {
+ *     ...
+ *     typesOnly BOOLEAN,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchRequestTypesOnly extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchRequestTypesOnly.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSearchRequestTypesOnly()
+    {
+        super( "Store SearchRequest typesOnly flag" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequest searchRequest = container.getMessage().getDecorated();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // We get the value. If it's a 0, it's a FALSE. If it's
+        // a FF, it's a TRUE. Any other value should be an error,
+        // but we could relax this constraint. So if we have
+        // something
+        // which is not 0, it will be interpreted as TRUE, but we
+        // will generate a warning.
+        BerValue value = tlv.getValue();
+
+        try
+        {
+            searchRequest.setTypesOnly( BooleanDecoder.parse( value ) );
+        }
+        catch ( BooleanDecoderException bde )
+        {
+            LOG.error( I18n
+                .err( I18n.ERR_04105, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
+
+            throw new DecoderException( bde.getMessage(), bde );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The search will return {}", ( searchRequest.getTypesOnly() ? "only attributs type"
+                : "attributes types and values" ) );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreTypeMatchingRule.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreTypeMatchingRule.java
new file mode 100644
index 0000000..3c6ccb9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/StoreTypeMatchingRule.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a type matching rule
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreTypeMatchingRule extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreTypeMatchingRule.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new store type matching rule action.
+     */
+    public StoreTypeMatchingRule()
+    {
+        super( "Store matching type Value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequest = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04022 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+        else
+        {
+            // Store the value.
+            ExtensibleMatchFilter extensibleMatchFilter = ( ExtensibleMatchFilter ) searchRequest.getTerminalFilter();
+
+            String type = Strings.utf8ToString( tlv.getValue().getData() );
+            extensibleMatchFilter.setType( type );
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "Stored a type matching rule : {}", type );
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAndFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAndFilter.java
new file mode 100644
index 0000000..28a3ad7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAndFilter.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AndFilter;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the AND filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitAndFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitAndFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init AND filter action.
+     */
+    public InitAndFilter()
+    {
+        super( "Initialize AND filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04006 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the SearchRequest
+        Filter andFilter = new AndFilter( container.getTlvId() );
+
+        // Set the filter
+        searchRequestDecorator.addCurrentFilter( andFilter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize AND filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitApproxMatchFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitApproxMatchFilter.java
new file mode 100644
index 0000000..578f2db
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitApproxMatchFilter.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Approx Match filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitApproxMatchFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitApproxMatchFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init approx match filter action.
+     */
+    public InitApproxMatchFilter()
+    {
+        super( "Init Approx Match filter Value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the Attribute Value Assertion
+        Filter filter = new AttributeValueAssertionFilter( container.getTlvId(),
+            LdapCodecConstants.APPROX_MATCH_FILTER );
+
+        searchRequestDecorator.addCurrentFilter( filter );
+
+        // Store the filter structure that still has to be
+        // fulfilled
+        searchRequestDecorator.setTerminalFilter( filter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Approx Match filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAssertionValueFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAssertionValueFilter.java
new file mode 100644
index 0000000..47d9fa2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAssertionValueFilter.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.AttributeValueAssertion;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Assertion Value filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitAssertionValueFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitAssertionValueFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init assertion value filter action.
+     */
+    public InitAssertionValueFilter()
+    {
+        super( "Initialize Assertion Value filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // The value can be null.
+        Value<?> assertionValue = null;
+
+        if ( tlv.getLength() != 0 )
+        {
+            assertionValue = new BinaryValue( tlv.getValue().getData() );
+        }
+        else
+        {
+            assertionValue = new BinaryValue( StringConstants.EMPTY_BYTES );
+        }
+
+        AttributeValueAssertionFilter terminalFilter = ( AttributeValueAssertionFilter )
+            searchRequestDecorator.getTerminalFilter();
+        AttributeValueAssertion assertion = terminalFilter.getAssertion();
+
+        if ( container.isBinary( assertion.getAttributeDesc() ) )
+        {
+            if ( tlv.getLength() != 0 )
+            {
+                assertionValue = new BinaryValue( tlv.getValue().getData() );
+            }
+            else
+            {
+                assertionValue = new BinaryValue( StringConstants.EMPTY_BYTES );
+            }
+
+            assertion.setAssertionValue( assertionValue );
+        }
+        else
+        {
+            if ( tlv.getLength() != 0 )
+            {
+                assertionValue = new StringValue( Strings.utf8ToString( tlv.getValue().getData() ) );
+            }
+            else
+            {
+                assertionValue = new StringValue( "" );
+            }
+
+            assertion.setAssertionValue( assertionValue );
+        }
+
+        // We now have to get back to the nearest filter which is
+        // not terminal.
+        searchRequestDecorator.unstackFilters( container );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Assertion Value filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAttributeDescFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAttributeDescFilter.java
new file mode 100644
index 0000000..9315235
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitAttributeDescFilter.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.AttributeValueAssertion;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the AttributeDesc filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitAttributeDescFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitAttributeDescFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init attribute desc filter action.
+     */
+    public InitAttributeDescFilter()
+    {
+        super( "Initialize AttributeDesc filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        AttributeValueAssertion assertion = new AttributeValueAssertion();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04007 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+        else
+        {
+            String type = Strings.utf8ToString( tlv.getValue().getData() );
+            assertion.setAttributeDesc( type );
+
+            AttributeValueAssertionFilter terminalFilter = ( AttributeValueAssertionFilter )
+                searchRequestDecorator.getTerminalFilter();
+            terminalFilter.setAssertion( assertion );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize AttributeDesc filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitEqualityMatchFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitEqualityMatchFilter.java
new file mode 100644
index 0000000..f2a8273
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitEqualityMatchFilter.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Equality Match filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitEqualityMatchFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitEqualityMatchFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init equality match filter action.
+     */
+    public InitEqualityMatchFilter()
+    {
+        super( "Initialize Equality Match filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the Attribute Value Assertion
+        Filter filter = new AttributeValueAssertionFilter( container.getTlvId(),
+            LdapCodecConstants.EQUALITY_MATCH_FILTER );
+
+        searchRequestDecorator.addCurrentFilter( filter );
+
+        // Store the filter structure that still has to be
+        // fulfilled
+        searchRequestDecorator.setTerminalFilter( filter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Equality Match filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitExtensibleMatchFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitExtensibleMatchFilter.java
new file mode 100644
index 0000000..0db09c0
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitExtensibleMatchFilter.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
+import org.apache.directory.api.ldap.codec.search.Filter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Extensible Match filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitExtensibleMatchFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitExtensibleMatchFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init extensible match filter action.
+     */
+    public InitExtensibleMatchFilter()
+    {
+        super( "Init Extensible Match filter Value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the ExtensibleMatch Filter
+        Filter extensibleMatchFilter = new ExtensibleMatchFilter( container.getTlvId() );
+
+        searchRequestDecorator.addCurrentFilter( extensibleMatchFilter );
+        searchRequestDecorator.setTerminalFilter( extensibleMatchFilter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Extensible Match filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitGreaterOrEqualFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitGreaterOrEqualFilter.java
new file mode 100644
index 0000000..ba38691
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitGreaterOrEqualFilter.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Greater Or Equal filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitGreaterOrEqualFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitGreaterOrEqualFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init greater or equal filter action.
+     */
+    public InitGreaterOrEqualFilter()
+    {
+        super( "Initialize Greater Or Equal filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the Attribute Value Assertion
+        Filter filter = new AttributeValueAssertionFilter( container.getTlvId(),
+            LdapCodecConstants.GREATER_OR_EQUAL_FILTER );
+
+        searchRequestDecorator.addCurrentFilter( filter );
+
+        // Store the filter structure that still has to be
+        // fulfilled
+        searchRequestDecorator.setTerminalFilter( filter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Greater Or Equal filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitLessOrEqualFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitLessOrEqualFilter.java
new file mode 100644
index 0000000..030a99d
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitLessOrEqualFilter.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Less Or Equal filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitLessOrEqualFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitLessOrEqualFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init less or equal filter action.
+     */
+    public InitLessOrEqualFilter()
+    {
+        super( "Initialize Less Or Equal filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the Attribute Value Assertion
+        Filter filter = new AttributeValueAssertionFilter( container.getTlvId(),
+            LdapCodecConstants.LESS_OR_EQUAL_FILTER );
+
+        searchRequestDecorator.addCurrentFilter( filter );
+
+        // Store the filter structure that still has to be
+        // fulfilled
+        searchRequestDecorator.setTerminalFilter( filter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Less Or Equal filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitNotFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitNotFilter.java
new file mode 100644
index 0000000..f1ceb3a
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitNotFilter.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.apache.directory.api.ldap.codec.search.NotFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the NOT filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitNotFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitNotFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init NOT filter action.
+     */
+    public InitNotFilter()
+    {
+        super( "Initialize NOT filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04009 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the SearchRequest
+        Filter notFilter = new NotFilter( container.getTlvId() );
+
+        // Set the filter
+        searchRequestDecorator.addCurrentFilter( notFilter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize NOT filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitOrFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitOrFilter.java
new file mode 100644
index 0000000..80f335f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitOrFilter.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.apache.directory.api.ldap.codec.search.OrFilter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the OR filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitOrFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitOrFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init OR filter action.
+     */
+    public InitOrFilter()
+    {
+        super( "Initialize OR filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04010 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        // We can allocate the SearchRequest
+        Filter orFilter = new OrFilter( container.getTlvId() );
+
+        // Set the filter
+        searchRequestDecorator.addCurrentFilter( orFilter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize OR filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitPresentFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitPresentFilter.java
new file mode 100644
index 0000000..d629a03
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitPresentFilter.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.PresentFilter;
+import org.apache.directory.api.util.Strings;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Present filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitPresentFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitPresentFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init present filter action.
+     */
+    public InitPresentFilter()
+    {
+        super( "Init present filter Value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // We can allocate the Attribute Value Assertion
+        PresentFilter presentFilter = new PresentFilter( container.getTlvId() );
+
+        // add the filter to the request filter
+        searchRequestDecorator.addCurrentFilter( presentFilter );
+        searchRequestDecorator.setTerminalFilter( presentFilter );
+
+        String value = Strings.utf8ToString( tlv.getValue().getData() );
+
+        if ( Strings.isEmpty( value ) )
+        {
+            presentFilter.setAttributeDescription( "" );
+        }
+        else
+        {
+            // Store the value.
+            String type = Strings.utf8ToString( tlv.getValue().getData() );
+            presentFilter.setAttributeDescription( type );
+        }
+
+        // We now have to get back to the nearest filter which is
+        // not terminal.
+        searchRequestDecorator.unstackFilters( container );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Present filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitSubstringsFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitSubstringsFilter.java
new file mode 100644
index 0000000..c2518b6
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/InitSubstringsFilter.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.apache.directory.api.ldap.codec.search.SubstringFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the Substrings filter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitSubstringsFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitSubstringsFilter.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new init substrings filter action.
+     */
+    public InitSubstringsFilter()
+    {
+        super( "Initialize Substrings filter" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        int expectedLength = tlv.getLength();
+
+        if ( expectedLength == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04012 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        // We can allocate the SearchRequest
+        Filter substringFilter = new SubstringFilter( container.getTlvId() );
+
+        searchRequestDecorator.addCurrentFilter( substringFilter );
+        searchRequestDecorator.setTerminalFilter( substringFilter );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initialize Substrings filter" );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreAny.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreAny.java
new file mode 100644
index 0000000..be97578
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreAny.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.SubstringFilter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a any value into a substring filter
+ * <pre>
+ * SubstringFilter ::= SEQUENCE {
+ *     ...
+ *     substrings SEQUENCE OF CHOICE {
+ *         ...
+ *         any  [1] LDAPSTRING,
+ *         ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreAny extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreAny.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new store any action.
+     */
+    public StoreAny()
+    {
+        super( "Store a any value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator decorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value.
+        SubstringFilter substringFilter = ( SubstringFilter ) decorator.getTerminalFilter();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04019 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        String any = Strings.utf8ToString( tlv.getValue().getData() );
+        substringFilter.addAnySubstrings( any );
+
+        // We now have to get back to the nearest filter which is
+        // not terminal.
+        decorator.unstackFilters( container );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Stored a any substring : {}", any );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreFinal.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreFinal.java
new file mode 100644
index 0000000..c626155
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreFinal.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.SubstringFilter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a final value into a substring filter
+ * <pre>
+ * SubstringFilter ::= SEQUENCE {
+ *     ...
+ *     substrings SEQUENCE OF CHOICE {
+ *         ...
+ *         final  [2] LDAPSTRING }
+ * </pre>
+
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreFinal extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreFinal.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new store final action.
+     */
+    public StoreFinal()
+    {
+        super( "Store a final value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequest = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value.
+        SubstringFilter substringFilter = ( SubstringFilter ) searchRequest.getTerminalFilter();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04020 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        String finalValue = Strings.utf8ToString( tlv.getValue().getData() );
+        substringFilter.setFinalSubstrings( finalValue );
+
+        // We now have to get back to the nearest filter which is
+        // not terminal.
+        searchRequest.unstackFilters( container );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Stored a any substring : {}", finalValue );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreInitial.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreInitial.java
new file mode 100644
index 0000000..df2c428
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreInitial.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.SubstringFilter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store an initial value into a substring filter
+ * <pre>
+ * SubstringFilter ::= SEQUENCE {
+ *     ...
+ *     substrings SEQUENCE OF CHOICE {
+ *         initial  [0] LDAPSTRING,
+ *         ...
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreInitial extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreInitial.class );
+
+
+    /**
+     * Instantiates a new store any action.
+     */
+    public StoreInitial()
+    {
+        super( "Store an initial value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value.
+        SubstringFilter substringFilter = ( SubstringFilter ) searchRequestDecorator.getTerminalFilter();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04108 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        substringFilter.setInitialSubstrings( Strings.utf8ToString( tlv.getValue().getData() ) );
+
+        // We now have to get back to the nearest filter which is
+        // not terminal.
+        searchRequestDecorator.unstackFilters( container );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreMatchValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreMatchValue.java
new file mode 100644
index 0000000..840a3e5
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreMatchValue.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a match value
+ * <pre>
+ * Filter ::= CHOICE {
+ *     ...
+ *     extensibleMatch  [9] MatchingRuleAssertion }
+ *
+ * MatchingRuleAssertion ::= SEQUENCE {
+ *     ...
+ *     matchValue [3] AssertionValue,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreMatchValue extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreMatchValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new store match value action.
+     */
+    public StoreMatchValue()
+    {
+        super( "Store match Value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator decorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value.
+        ExtensibleMatchFilter extensibleMatchFilter = ( ExtensibleMatchFilter ) decorator.getTerminalFilter();
+
+        byte[] value = tlv.getValue().getData();
+        extensibleMatchFilter.setMatchValue( new BinaryValue( value ) );
+
+        // unstack the filters if needed
+        decorator.unstackFilters( container );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Stored a match value : {}", value );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreMatchingRuleDnAttributes.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreMatchingRuleDnAttributes.java
new file mode 100644
index 0000000..8bc602e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreMatchingRuleDnAttributes.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a matchingRuleAssertion dnAttributes
+ * <pre>
+ * Filter ::= CHOICE {
+ *     ...
+ *     extensibleMatch  [9] MatchingRuleAssertion }
+ *
+ * MatchingRuleAssertion ::= SEQUENCE {
+ *     ...
+ *     dnAttributes [4] BOOLEAN DEFAULT FALSE }
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreMatchingRuleDnAttributes extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreMatchingRuleDnAttributes.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new StoreMatchingRuleDnAttributes.
+     */
+    public StoreMatchingRuleDnAttributes()
+    {
+        super( "Store matchingRuleAssertion dnAttributes" );
+    }
+
+
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequest = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value.
+        ExtensibleMatchFilter extensibleMatchFilter = ( ExtensibleMatchFilter ) searchRequest.getTerminalFilter();
+
+        // We get the value. If it's a 0, it's a FALSE. If it's
+        // a FF, it's a TRUE. Any other value should be an error,
+        // but we could relax this constraint. So if we have
+        // something
+        // which is not 0, it will be interpreted as TRUE, but we
+        // will generate a warning.
+        BerValue value = tlv.getValue();
+
+        try
+        {
+            extensibleMatchFilter.setDnAttributes( BooleanDecoder.parse( value ) );
+        }
+        catch ( BooleanDecoderException bde )
+        {
+            LOG.error( I18n
+                .err( I18n.ERR_04110, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
+
+            throw new DecoderException( bde.getMessage(), bde );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Dn Attributes : {}", Boolean.valueOf( extensibleMatchFilter.isDnAttributes() ) );
+        }
+
+        // unstack the filters if needed
+        searchRequest.unstackFilters( container );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreSubstringFilterType.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreSubstringFilterType.java
new file mode 100644
index 0000000..8208813
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchRequest/filter/StoreSubstringFilterType.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.search.SubstringFilter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the Substring Filter type
+ * <pre>
+ * Filter ::= CHOICE {
+ *     ...
+ *     substrings  [4] SubstringFilter,
+ *     ...
+ *
+ * SubstringFilter ::= SEQUENCE {
+ *     type   AttributeDescription,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSubstringFilterType extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSubstringFilterType.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSubstringFilterType()
+    {
+        super( "Store Substring filter type" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
+    {
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value.
+        SubstringFilter substringFilter = ( SubstringFilter ) searchRequestDecorator.getTerminalFilter();
+
+        if ( tlv.getLength() == 0 )
+        {
+            String msg = I18n.err( I18n.ERR_04106 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+        else
+        {
+            String type = Strings.utf8ToString( tlv.getValue().getData() );
+            substringFilter.setType( type );
+
+            // We now have to get back to the nearest filter which
+            // is not terminal.
+            searchRequestDecorator.setTerminalFilter( substringFilter );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultDone/InitSearchResultDone.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultDone/InitSearchResultDone.java
new file mode 100644
index 0000000..4675fcb
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultDone/InitSearchResultDone.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchResultDone;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultDoneDecorator;
+import org.apache.directory.api.ldap.model.message.SearchResultDoneImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the SearchResultDone response
+ * <pre>
+ * LdapMessage ::= ... SearchResultDone ...
+ * SearchResultDone ::= [APPLICATION 5] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitSearchResultDone extends GrammarAction<LdapMessageContainer<SearchResultDoneDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitSearchResultDone.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitSearchResultDone()
+    {
+        super( "Init SearchResultDone" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchResultDoneDecorator> container )
+    {
+        // Now, we can allocate the SearchResultDone Object
+        SearchResultDoneDecorator searchResultDone = new SearchResultDoneDecorator(
+            container.getLdapCodecService(), new SearchResultDoneImpl( container.getMessageId() ) );
+        container.setMessage( searchResultDone );
+
+        LOG.debug( "Search Result Done found" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/AddAttributeType.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/AddAttributeType.java
new file mode 100644
index 0000000..0d85f14
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/AddAttributeType.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchResultEntry;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchResultEntry attributes
+ * <pre>
+ * SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+ *     ...
+ *     attributes PartialAttributeList }
+ *
+ * PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+ *     type  AttributeDescription,
+ *     ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddAttributeType extends GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AddAttributeType.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public AddAttributeType()
+    {
+        super( "Store the AttributeType" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchResultEntryDecorator> container ) throws DecoderException
+    {
+        SearchResultEntryDecorator searchResultEntry = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the type
+        if ( tlv.getLength() == 0 )
+        {
+            // The type can't be null
+            String msg = I18n.err( I18n.ERR_04081 );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+        else
+        {
+            try
+            {
+                searchResultEntry.addAttribute( tlv.getValue().getData() );
+            }
+            catch ( LdapException ine )
+            {
+                String type = Strings.utf8ToString( tlv.getValue().getData() );
+                // This is for the client side. We will never decode LdapResult on the server
+                String msg = "The Attribute type " + type + "is invalid : " + ine.getMessage();
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+                throw new DecoderException( msg, ine );
+            }
+        }
+
+        if ( IS_DEBUG )
+        {
+            String type = Strings.utf8ToString( tlv.getValue().getData() );
+            LOG.debug( "Attribute type : {}", type );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/InitSearchResultEntry.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/InitSearchResultEntry.java
new file mode 100644
index 0000000..1cc410f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/InitSearchResultEntry.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchResultEntry;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.api.ldap.model.message.SearchResultEntryImpl;
+
+
+/**
+ * The action used to initialize the SearchResultEntry response
+ * <pre>
+ * LdapMessage ::= ... SearchResultEntry ...
+ * SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitSearchResultEntry extends GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>
+{
+    /**
+     * Instantiates a new action.
+     */
+    public InitSearchResultEntry()
+    {
+        super( "Init SearchResultEntry" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchResultEntryDecorator> container )
+    {
+        // Now, we can allocate the SearchResultEntry Object
+        SearchResultEntryDecorator searchResultEntry = new SearchResultEntryDecorator(
+            container.getLdapCodecService(), new SearchResultEntryImpl( container.getMessageId() ) );
+        container.setMessage( searchResultEntry );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/StoreSearchResultAttributeValue.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/StoreSearchResultAttributeValue.java
new file mode 100644
index 0000000..c6089b2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/StoreSearchResultAttributeValue.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchResultEntry;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a Value to an search result entry
+ * <pre>
+ * PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+ *     ...
+ *     vals SET OF AttributeValue }
+ *
+ * AttributeValue ::= OCTET STRING
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchResultAttributeValue extends GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchResultAttributeValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new search result attribute value action.
+     */
+    public StoreSearchResultAttributeValue()
+    {
+        super( "Stores AttributeValue" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchResultEntryDecorator> container )
+    {
+        SearchResultEntryDecorator searchResultEntry = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        // Store the value
+        Object value = null;
+
+        try
+        {
+            if ( tlv.getLength() == 0 )
+            {
+                searchResultEntry.addAttributeValue( "" );
+
+                LOG.debug( "The attribute value is null" );
+            }
+            else
+            {
+                if ( container.isBinary( searchResultEntry.getCurrentAttribute().getId() ) )
+                {
+                    value = tlv.getValue().getData();
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Attribute value {}", Strings.dumpBytes( ( byte[] ) value ) );
+                    }
+                }
+                else
+                {
+                    value = Strings.utf8ToString( tlv.getValue().getData() );
+
+                    LOG.debug( "Attribute value {}", value );
+                }
+
+                searchResultEntry.addAttributeValue( value );
+            }
+        }
+        catch ( LdapException le )
+        {
+            // Just swallow the exception, it can't occur here
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/StoreSearchResultEntryObjectName.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/StoreSearchResultEntryObjectName.java
new file mode 100644
index 0000000..9b800ff
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultEntry/StoreSearchResultEntryObjectName.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchResultEntry;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store the SearchResultEntry name
+ * <pre>
+ * LdapMessage ::= ... SearchResultEntry ...
+ * SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+ *         objectName      LDAPDN,
+ *         ...
+ *
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSearchResultEntryObjectName extends GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchResultEntryObjectName.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public StoreSearchResultEntryObjectName()
+    {
+        super( "Store SearchResultEntry name" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchResultEntryDecorator> container ) throws DecoderException
+    {
+        SearchResultEntryDecorator searchResultEntry = container.getMessage();
+
+        TLV tlv = container.getCurrentTLV();
+
+        Dn objectName = Dn.EMPTY_DN;
+
+        // Store the value.
+        if ( tlv.getLength() == 0 )
+        {
+            searchResultEntry.setObjectName( objectName );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString( dnBytes );
+
+            try
+            {
+                objectName = new Dn( dnStr );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                // This is for the client side. We will never decode LdapResult on the server
+                String msg = "The Dn " + Strings.dumpBytes( dnBytes ) + "is invalid : "
+                    + ine.getMessage();
+                LOG.error( "{} : {}", msg, ine.getMessage() );
+                throw new DecoderException( msg, ine );
+            }
+
+            searchResultEntry.setObjectName( objectName );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Search Result Entry Dn found : {}", searchResultEntry.getObjectName() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultReference/InitSearchResultReference.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultReference/InitSearchResultReference.java
new file mode 100644
index 0000000..79cb021
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultReference/InitSearchResultReference.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchResultReference;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultReferenceDecorator;
+import org.apache.directory.api.ldap.model.message.SearchResultReferenceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the SearchResultReference response
+ * <pre>
+ * LdapMessage ::= ... SearchResultReference ...
+ * SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitSearchResultReference extends GrammarAction<LdapMessageContainer<SearchResultReferenceDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitSearchResultReference.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitSearchResultReference()
+    {
+        super( "Init SearchResultReference" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchResultReferenceDecorator> container ) throws DecoderException
+    {
+        // Now, we can allocate the SearchResultReference Object
+        SearchResultReferenceDecorator searchResultReference = new SearchResultReferenceDecorator(
+            container.getLdapCodecService(), new SearchResultReferenceImpl( container.getMessageId() ) );
+        container.setMessage( searchResultReference );
+
+        LOG.debug( "SearchResultReference response " );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultReference/StoreReference.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultReference/StoreReference.java
new file mode 100644
index 0000000..9d9c218
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/searchResultReference/StoreReference.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.searchResultReference;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultReferenceDecorator;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to store a reference into a searchResultReference
+ * <pre>
+ * LdapMessage ::= ... SearchResultReference ...
+ * SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreReference extends GrammarAction<LdapMessageContainer<SearchResultReferenceDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreReference.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new store reference action.
+     */
+    public StoreReference()
+    {
+        super( "Store a reference" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<SearchResultReferenceDecorator> container ) throws DecoderException
+    {
+        SearchResultReference searchResultReference = container.getMessage();
+
+        // Get the Value and store it in the BindRequest
+        TLV tlv = container.getCurrentTLV();
+
+        // Get the referral, or create it if not existing
+        Referral referral = searchResultReference.getReferral();
+
+        if ( referral == null )
+        {
+            referral = new ReferralImpl();
+            searchResultReference.setReferral( referral );
+        }
+
+        // We have to handle the special case of a 0 length list of referrals
+        LdapUrl url = LdapUrl.EMPTY_URL;
+
+        if ( tlv.getLength() == 0 )
+        {
+            referral.addLdapUrl( "" );
+        }
+        else
+        {
+            String urlStr = Strings.utf8ToString( tlv.getValue().getData() );
+
+            try
+            {
+                url = new LdapUrl( urlStr );
+                referral.addLdapUrl( urlStr );
+            }
+            catch ( LdapURLEncodingException luee )
+            {
+                LOG.error( I18n.err( I18n.ERR_04021, urlStr, luee.getMessage() ) );
+                throw new DecoderException( I18n.err( I18n.ERR_04016, luee.getMessage() ), luee );
+            }
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Search reference URL found : {}", url );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/unbindRequest/InitUnbindRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/unbindRequest/InitUnbindRequest.java
new file mode 100644
index 0000000..7368be6
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/unbindRequest/InitUnbindRequest.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.actions.unbindRequest;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.UnbindRequest;
+import org.apache.directory.api.ldap.model.message.UnbindRequestImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the UnbindRequest :
+ * <pre>
+ * LdapMessage ::= ... UnBindRequest ...
+ * unbindRequest ::= [APPLICATION 2] NULL
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitUnbindRequest extends GrammarAction<LdapMessageContainer<UnbindRequestDecorator>>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitUnbindRequest.class );
+
+
+    /**
+     * Instantiates a new action.
+     */
+    public InitUnbindRequest()
+    {
+        super( "Unbind Request initialization" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( LdapMessageContainer<UnbindRequestDecorator> container ) throws DecoderException
+    {
+        // Create the UnbindRequest LdapMessage instance and store it in the container
+        UnbindRequest unbindRequestInternal = new UnbindRequestImpl();
+        unbindRequestInternal.setMessageId( container.getMessageId() );
+        UnbindRequestDecorator unbindRequest = new UnbindRequestDecorator(
+            container.getLdapCodecService(), unbindRequestInternal );
+        container.setMessage( unbindRequest );
+
+        TLV tlv = container.getCurrentTLV();
+        int expectedLength = tlv.getLength();
+
+        // The Length should be null
+        if ( expectedLength != 0 )
+        {
+            LOG.error( I18n.err( I18n.ERR_04071, Integer.valueOf( expectedLength ) ) );
+
+            // This will generate a PROTOCOL_ERROR
+            throw new DecoderException( I18n.err( I18n.ERR_04072 ) );
+        }
+
+        // We can quit now
+        container.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/BinaryAttributeDetector.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/BinaryAttributeDetector.java
new file mode 100644
index 0000000..d541149
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/BinaryAttributeDetector.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+/**
+ * An interface used to abstract the means to detect whether or not an attribute
+ * identifier/descriptor represents a binary attributeType.
+ */
+public interface BinaryAttributeDetector
+{
+    /**
+     * Returns true if the attribute specified is not human readible.
+     *
+     * @param attributeId the identifier/descriptor for the attribute to be checked.
+     * @return true if the attribute specified is not human readible, false otherwise
+     */
+    boolean isBinary( String attributeId );
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/CodecControl.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/CodecControl.java
new file mode 100644
index 0000000..8ced9d3
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/CodecControl.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * The codec uses this interface to add additional information to LDAP Model
+ * Control objects during encoding and decoding.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CodecControl<E extends Control> extends Control, Decorator<E>
+{
+    /**
+     * Decodes raw ASN.1 encoded bytes into an Asn1Object for the control.
+     * 
+     * @param controlBytes the encoded control bytes
+     * @return the decoded Asn1Object for the control
+     * @throws DecoderException if anything goes wrong
+     */
+    Asn1Object decode( byte[] controlBytes ) throws DecoderException;
+
+
+    /**
+     * Checks to see if a value is set for this {@link CodecControl}.
+     *
+     * @return true, if this control has a value, false otherwise
+     */
+    boolean hasValue();
+
+
+    /**
+     * Gets the binary ASN.1 BER encoded representation of the control.
+     * 
+     * @return The control's encoded value
+     */
+    byte[] getValue();
+
+
+    /**
+     * Set the Control's encoded control value.
+     * 
+     * @param value The encoded control value to store.
+     */
+    void setValue( byte[] value );
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ConfigurableBinaryAttributeDetector.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ConfigurableBinaryAttributeDetector.java
new file mode 100644
index 0000000..bd9366a
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ConfigurableBinaryAttributeDetector.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+/**
+ * An interface used to abstract the means to detect whether or not an attribute
+ * identifier/descriptor represents a binary attributeType.
+ */
+public interface ConfigurableBinaryAttributeDetector extends BinaryAttributeDetector
+{
+    /**
+     * Add some binary Attributes Id to the list of attributes
+     * 
+     * @param binaryAttributes The added binary attributes Id
+     */
+    void addBinaryAttribute( String... binaryAttributes );
+
+
+    /**
+     * Remove some binary Attributes Id from the list of attributes
+     * 
+     * @param binaryAttributes The binary attributes Id to remove
+     */
+    void removeBinaryAttribute( String... binaryAttributes );
+
+
+    /**
+     * Inject a new set of binary attributes that will replace the old one.
+     * If one inject a null set of attributes, the list of attributes will be
+     * cleared, and reset to the default list of binary attributes. If one
+     * injects an empty String array, then all the attributes will be removed
+     * from the list, and we won't inject the default attributes into it.
+     * 
+     * @param binaryAttributes The new set of binary attributes
+     */
+    void setBinaryAttributes( String... binaryAttributes );
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlDecoder.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlDecoder.java
new file mode 100644
index 0000000..43c6d43
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlDecoder.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * An interface for decoders of controls.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ControlDecoder<E extends Control>
+{
+    /**
+     * Decodes raw ASN.1 encoded bytes into an Asn1Object for the control.
+     * 
+     * @param controlBytes the encoded control bytes
+     * @return the decoded Asn1Object for the control
+     * @throws DecoderException if anything goes wrong
+     */
+    Asn1Object decode( byte[] controlBytes ) throws DecoderException;
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlDecorator.java
new file mode 100644
index 0000000..acda736
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlDecorator.java
@@ -0,0 +1,215 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * Decorates Control objects by wrapping them, and enabling them as CodecControls
+ * so the codec to store transient information associated with the Control in the
+ * decorator while processing.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E>
+ */
+public abstract class ControlDecorator<E extends Control> implements CodecControl<E>, Asn1Object
+{
+    /** The decorated Control */
+    private E decorated;
+
+    /** The encoded value length */
+    protected int valueLength;
+
+    /** The encoded value of the control. */
+    protected byte[] value;
+
+    /** The codec service responsible for encoding decoding this object */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a ControlDecorator to codec enable it.
+     *
+     * @param decoratedControl The Control to decorate.
+     */
+    public ControlDecorator( LdapApiService codec, E decoratedControl )
+    {
+        this.decorated = decoratedControl;
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public E getDecorated()
+    {
+        return decorated;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDecorated( E decorated )
+    {
+        this.decorated = decorated;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Control Methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Get the OID
+     * 
+     * @return A string which represent the control oid
+     */
+    public String getOid()
+    {
+        return decorated.getOid();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasValue()
+    {
+        return value != null;
+    }
+
+
+    /**
+     * Get the control value
+     * 
+     * @return The control value
+     */
+    public byte[] getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Set the encoded control value
+     * 
+     * @param value The encoded control value to store
+     */
+    public void setValue( byte[] value )
+    {
+        if ( value != null )
+        {
+            byte[] copy = new byte[value.length];
+            System.arraycopy( value, 0, copy, 0, value.length );
+            this.value = copy;
+        }
+        else
+        {
+            this.value = null;
+        }
+    }
+
+
+    /**
+     * Get the criticality
+     * 
+     * @return <code>true</code> if the criticality flag is true.
+     */
+    public boolean isCritical()
+    {
+        return decorated.isCritical();
+    }
+
+
+    /**
+     * Set the criticality
+     * 
+     * @param criticality The criticality value
+     */
+    public void setCritical( boolean criticality )
+    {
+        decorated.setCritical( criticality );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // CodecControl Methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public int computeLength()
+    {
+        return 0;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Object Method Overrides
+    // ------------------------------------------------------------------------
+
+    /**
+     * @see Object#hashCode()
+     */
+    public int hashCode()
+    {
+        return decorated.hashCode();
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        if ( decorated == null )
+        {
+            return o == null;
+        }
+        else
+        {
+            return decorated.equals( o );
+        }
+    }
+
+
+    /**
+     * Return a String representing a Control
+     */
+    public String toString()
+    {
+        return decorated.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlFactory.java
new file mode 100644
index 0000000..cb863a2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ControlFactory.java
@@ -0,0 +1,63 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * Implementors of new codec control extensions must implement a factory using
+ * this factory interface, Factory implementations for specific controls are
+ * then registered with the codec and used by the codec to encode and decode
+ * those controls.
+ *
+ * @TODO must review this interface - too many methods - implementors should not
+ * have to implement so many methods.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface ControlFactory<C extends Control>
+{
+    /**
+     * @return The OID of the Control this factory creates.
+     */
+    String getOid();
+
+
+    /**
+     * Creates and returns a decorated version of the Control.
+     *
+     * @return The {@link CodecControl} decorated version of the Control.
+     */
+    CodecControl<C> newCodecControl();
+
+
+    /**
+     * Decorates an existing control. Implementors should check to make sure
+     * the supplied Control has not already been decorated to prevent needless
+     * decorator nesting.
+     *
+     * @param control The {@link Control} to be decorated.
+     * @return The decorator wrapping the Control.
+     */
+    CodecControl<C> newCodecControl( C control );
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/Decorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/Decorator.java
new file mode 100644
index 0000000..a04970e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/Decorator.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+
+
+/**
+ * The codec uses this interface to add additional information to LDAP Model
+ * objects during encoding and decoding,
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Decorator<E>
+{
+    /**
+     * Gets the object being decorated by this IDecorator.
+     *
+     * @return The decorated object
+     */
+    E getDecorated();
+
+
+    /**
+     * Compute the object length, which is the sum of all inner length.
+     * 
+     * @return The object's computed length
+     */
+    int computeLength();
+
+
+    /**
+     * Encode the object to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     * @throws EncoderException if the buffer can't be encoded
+     */
+    ByteBuffer encode( ByteBuffer buffer ) throws EncoderException;
+
+
+    /**
+     * Gets the codec service responsible for managing the encoding and 
+     * decoding of the decorated objects.
+     * 
+     * @return the codec service
+     */
+    LdapApiService getCodecService();
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/DefaultConfigurableBinaryAttributeDetector.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/DefaultConfigurableBinaryAttributeDetector.java
new file mode 100644
index 0000000..3f080fe
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/DefaultConfigurableBinaryAttributeDetector.java
@@ -0,0 +1,203 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.util.Set;
+
+import org.apache.directory.api.util.Strings;
+import org.apache.mina.util.ConcurrentHashSet;
+
+
+/**
+ * An implementation of the BinaryAttributeDetector interface. It's used
+ * on the client side to detect if an Attribute is HumanRedable.<br/>
+ * One can inject some new attributes, replace the existing list,
+ * remove some attributes. <br/>
+ * We provide a list of Attributes which are known to be binary :
+ * <ul>
+ * <li>entryACI</li>
+ * <li>prescriptiveACI</li>
+ * <li>subentryACI</li>
+ * <li>audio</li>
+ * <li>javaByteCode</li>
+ * <li>javaClassByteCode</li>
+ * <li>krb5key</li>
+ * <li>m-byteCode</li>
+ * <li>privateKey</li>
+ * <li>publicKey</li>
+ * <li>userPKCS12</li>
+ * <li>userSMIMECertificate</li>
+ * <li>cACertificate</li>
+ * <li>userCertificate</li>
+ * <li>authorityRevocationList</li>
+ * <li>certificateRevocationList</li>
+ * <li>deltaRevocationList</li>
+ * <li>crossCertificatePair</li>
+ * <li>personalSignature</li>
+ * <li>photo</li>
+ * <li>jpegPhoto</li>
+ * <li>supportedAlgorithms</li>
+ * </ul>
+ * <br/>
+ * In order to reset the detector to get back to those default value, it's enough
+ * to call the setBinaryAttributes() with null as a parameter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultConfigurableBinaryAttributeDetector extends SchemaBinaryAttributeDetector
+    implements ConfigurableBinaryAttributeDetector
+{
+    /** A set of binary Attribute ID */
+    private Set<String> binaryAttributes = new ConcurrentHashSet<String>();
+
+    /** A list of all the known binary attributes */
+    public static final String[] DEFAULT_BINARY_ATTRIBUTES = new String[]
+        {
+            // Syntax : ACI Item
+            "entryACI",
+            "prescriptiveACI",
+            "subentryACI",
+
+            // Syntax : AUDIO
+            "audio",
+
+            // Syntax : Binary
+            "javaByteCode",
+            "javaClassByteCode",
+            "krb5key",
+            "m-byteCode",
+            "privateKey",
+            "publicKey",
+            "userPKCS12",
+            "userSMIMECertificate",
+
+            // Syntax : Certificate
+            "cACertificate",
+            "userCertificate",
+
+            // Syntax : Certificate List
+            "authorityRevocationList",
+            "certificateRevocationList",
+            "deltaRevocationList",
+
+            // Syntax : Certificate Pair
+            "crossCertificatePair",
+
+            // Syntax : Fax
+            "personalSignature",
+            "photo",
+
+            // Syntax : JPEG
+            "jpegPhoto",
+
+            // Syntax : Supported Algorithm
+            "supportedAlgorithms",
+
+            // Syntax : Octet String
+            "javaSerializedData",
+            "userPassword",
+
+            // Active Directory specific attributes see DIRAPI-177
+            "objectSid",
+            "objectGUID",
+            "thumbnailLogo",
+            "thumbnailPhoto",
+            "x500uniqueIdentifier"
+    };
+
+
+    /**
+     * Creates a new instance of a ConfigurableBinaryAttributeDetector. This will
+     * load a set of default attribute ID that are known to be binary.
+     */
+    public DefaultConfigurableBinaryAttributeDetector()
+    {
+        setBinaryAttributes( DEFAULT_BINARY_ATTRIBUTES );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isBinary( String attributeId )
+    {
+        boolean isBinary = super.isBinary( attributeId );
+
+        if ( isBinary )
+        {
+            return true;
+        }
+
+        String attrId = Strings.toLowerCase( attributeId );
+
+        return binaryAttributes.contains( attrId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addBinaryAttribute( String... binaryAttributes )
+    {
+        if ( binaryAttributes != null )
+        {
+            for ( String binaryAttribute : binaryAttributes )
+            {
+                String attrId = Strings.toLowerCase( binaryAttribute );
+                this.binaryAttributes.add( attrId );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeBinaryAttribute( String... binaryAttributes )
+    {
+        if ( binaryAttributes != null )
+        {
+            for ( String binaryAttribute : binaryAttributes )
+            {
+                String attrId = Strings.toLowerCase( binaryAttribute );
+                this.binaryAttributes.remove( attrId );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setBinaryAttributes( String... binaryAttributes )
+    {
+        this.binaryAttributes.clear();
+
+        // Special case for 'null'
+        if ( binaryAttributes == null )
+        {
+            // Reseting to the default list of binary attributes
+            binaryAttributes = DEFAULT_BINARY_ATTRIBUTES;
+        }
+
+        addBinaryAttribute( binaryAttributes );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedOperationFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedOperationFactory.java
new file mode 100644
index 0000000..bdad6c8
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedOperationFactory.java
@@ -0,0 +1,81 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * The factory interface, defined by the codec API, for creating new 
+ * requests/responses for extended operations.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface ExtendedOperationFactory
+{
+    /**
+     * Gets the OID of the extended requests this factory generates.
+     *
+     * @return the extended request OID
+     */
+    String getOid();
+
+
+    /**
+     * Returns a new {@link ExtendedRequestDecorator} with the following encoded value.
+     * 
+     * @param value the encoded value
+     * @return the decorator for the extended request type
+     */
+    ExtendedRequest newRequest( byte[] value );
+
+
+    /**
+     * Decorates a non-decorated request.
+     *
+     * @param modelRequest the non decorated model request
+     * @return the decorated model request
+     */
+    ExtendedRequest decorate( ExtendedRequest modelRequest );
+
+
+    /**
+     * Creates a new ExtendedResponse, for the ExtendedRequest with a specific
+     * encoded value.
+     * 
+     * @param encodedValue The encoded value for the ExtendedResponse instance.
+     * @return The new ExtendedResponse.
+     */
+    ExtendedResponse newResponse( byte[] encodedValue ) throws DecoderException;
+
+
+    /**
+     * Decorates an ExtendedResponse which may or may not be of the expected 
+     * type. The factory implementor must check and handle appropriately.
+     *
+     * @param decoratedMessage the message to be decorated.
+     * @return The decorated message 
+     */
+    ExtendedResponse decorate( ExtendedResponse decoratedMessage );
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedRequestDecorator.java
new file mode 100644
index 0000000..703d1c9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedRequestDecorator.java
@@ -0,0 +1,232 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.decorators.SingleReplyRequestDecorator;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the ExtendedRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtendedRequestDecorator<Q extends ExtendedRequest>
+    extends SingleReplyRequestDecorator<Q> implements ExtendedRequest
+{
+    /** The extended request length */
+    private int extendedRequestLength;
+
+    /** The OID bytes */
+    private byte[] requestNameBytes;
+
+    /** The ExtendedRequest value */
+    protected byte[] requestValue;
+
+
+    /**
+     * Makes a ExtendedRequest a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated ExtendedRequest
+     */
+    public ExtendedRequestDecorator( LdapApiService codec, Q decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The ExtendedRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getRequestName()
+    {
+        return getDecorated().getRequestName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest setRequestName( String oid )
+    {
+        getDecorated().setRequestName( oid );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getRequestValue()
+    {
+        return requestValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRequestValue( byte[] requestValue )
+    {
+        this.requestValue = requestValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addControl( Control control )
+    {
+        return ( ExtendedRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addAllControls( Control[] controls )
+    {
+        return ( ExtendedRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest removeControl( Control control )
+    {
+        return ( ExtendedRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the ExtendedRequest length
+     * 
+     * ExtendedRequest :
+     * 
+     * 0x77 L1
+     *  |
+     *  +--> 0x80 L2 name
+     *  [+--> 0x81 L3 value]
+     * 
+     * L1 = Length(0x80) + Length(L2) + L2
+     *      [+ Length(0x81) + Length(L3) + L3]
+     * 
+     * Length(ExtendedRequest) = Length(0x77) + Length(L1) + L1
+     */
+    public int computeLength()
+    {
+        requestNameBytes = Strings.getBytesUtf8( getRequestName() );
+
+        extendedRequestLength = 1 + TLV.getNbBytes( requestNameBytes.length ) + requestNameBytes.length;
+
+        if ( getRequestValue() != null )
+        {
+            extendedRequestLength += 1 + TLV.getNbBytes( getRequestValue().length )
+                + getRequestValue().length;
+        }
+
+        return 1 + TLV.getNbBytes( extendedRequestLength ) + extendedRequestLength;
+    }
+
+
+    /**
+     * Encode the ExtendedRequest message to a PDU. 
+     * 
+     * ExtendedRequest :
+     * 
+     * 0x80 LL resquest name
+     * [0x81 LL request value]
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The BindResponse Tag
+            buffer.put( LdapCodecConstants.EXTENDED_REQUEST_TAG );
+            buffer.put( TLV.getBytes( extendedRequestLength ) );
+
+            // The requestName, if any
+            if ( requestNameBytes == null )
+            {
+                throw new EncoderException( I18n.err( I18n.ERR_04043 ) );
+            }
+
+            buffer.put( ( byte ) LdapCodecConstants.EXTENDED_REQUEST_NAME_TAG );
+            buffer.put( TLV.getBytes( requestNameBytes.length ) );
+
+            if ( requestNameBytes.length != 0 )
+            {
+                buffer.put( requestNameBytes );
+            }
+
+            // The requestValue, if any
+            if ( getRequestValue() != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.EXTENDED_REQUEST_VALUE_TAG );
+
+                buffer.put( TLV.getBytes( getRequestValue().length ) );
+
+                if ( getRequestValue().length != 0 )
+                {
+                    buffer.put( getRequestValue() );
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedResponseDecorator.java
new file mode 100644
index 0000000..b642786
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ExtendedResponseDecorator.java
@@ -0,0 +1,207 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.decorators.LdapResultDecorator;
+import org.apache.directory.api.ldap.codec.decorators.ResponseDecorator;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the ExtendedResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtendedResponseDecorator<R extends ExtendedResponse> extends ResponseDecorator<R>
+    implements ExtendedResponse
+{
+    /** The response name (OID) as a byte[] */
+    private byte[] responseNameBytes;
+
+    /** The encoded extendedResponse length */
+    private int extendedResponseLength;
+
+    /** The response value */
+    protected byte[] responseValue;
+
+
+    /**
+     * Makes a ExtendedResponse encodable.
+     *
+     * @param decoratedMessage the decorated ExtendedResponse
+     */
+    public ExtendedResponseDecorator( LdapApiService codec, R decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The ExtendedResponse methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getResponseName()
+    {
+        return getDecorated().getResponseName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setResponseName( String oid )
+    {
+        getDecorated().setResponseName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getResponseValue()
+    {
+        return responseValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setResponseValue( byte[] responseValue )
+    {
+        this.responseValue = responseValue;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the ExtendedResponse length
+     * 
+     * ExtendedResponse :
+     * 
+     * 0x78 L1
+     *  |
+     *  +--> LdapResult
+     * [+--> 0x8A L2 name
+     * [+--> 0x8B L3 response]]
+     * 
+     * L1 = Length(LdapResult)
+     *      [ + Length(0x8A) + Length(L2) + L2
+     *       [ + Length(0x8B) + Length(L3) + L3]]
+     * 
+     * Length(ExtendedResponse) = Length(0x78) + Length(L1) + L1
+     * 
+     * @return The ExtendedResponse length
+     */
+    public int computeLength()
+    {
+        int ldapResultLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        extendedResponseLength = ldapResultLength;
+
+        String id = getResponseName();
+
+        if ( !Strings.isEmpty( id ) )
+        {
+            responseNameBytes = Strings.getBytesUtf8( id );
+            int idLength = responseNameBytes.length;
+            extendedResponseLength += 1 + TLV.getNbBytes( idLength ) + idLength;
+        }
+
+        byte[] encodedValue = getResponseValue();
+
+        if ( encodedValue != null )
+        {
+            extendedResponseLength += 1 + TLV.getNbBytes( encodedValue.length ) + encodedValue.length;
+        }
+
+        return 1 + TLV.getNbBytes( extendedResponseLength ) + extendedResponseLength;
+    }
+
+
+    /**
+     * Encode the ExtendedResponse message to a PDU. 
+     * ExtendedResponse :
+     * LdapResult.encode()
+     * [0x8A LL response name]
+     * [0x8B LL response]
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The ExtendedResponse Tag
+            buffer.put( LdapCodecConstants.EXTENDED_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( extendedResponseLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+
+            // The ID, if any
+            if ( responseNameBytes != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG );
+                buffer.put( TLV.getBytes( responseNameBytes.length ) );
+
+                if ( responseNameBytes.length != 0 )
+                {
+                    buffer.put( responseNameBytes );
+                }
+            }
+
+            // The encodedValue, if any
+            byte[] encodedValue = getResponseValue();
+
+            if ( encodedValue != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.EXTENDED_RESPONSE_RESPONSE_TAG );
+
+                buffer.put( TLV.getBytes( encodedValue.length ) );
+
+                if ( encodedValue.length != 0 )
+                {
+                    buffer.put( encodedValue );
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapApiService.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapApiService.java
new file mode 100644
index 0000000..bcca409
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapApiService.java
@@ -0,0 +1,269 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+
+
+/**
+ * The service interface for the LDAP codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface LdapApiService
+{
+    String DEFAULT_PROTOCOL_CODEC_FACTORY =
+        "org.apache.directory.api.ldap.codec.protocol.mina.LdapProtocolCodecFactory";
+
+
+    // ------------------------------------------------------------------------
+    // Control Methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Returns an Iterator over the OID Strings of registered controls.
+     * 
+     * @return The registered control OID Strings
+     */
+    Iterator<String> registeredControls();
+
+
+    /**
+     * Checks if a control has been registered.
+     * 
+     * @return The OID of the control to check for registration
+     */
+    boolean isControlRegistered( String oid );
+
+
+    /**
+     * Registers an {@link ControlFactory} with this service.
+     * 
+     * @param factory The control factory
+     */
+    ControlFactory<?> registerControl( ControlFactory<?> factory );
+
+
+    /**
+     * Unregisters an {@link ControlFactory} with this service.
+     * 
+     * @param oid The oid of the control the factory is associated with.
+     */
+    ControlFactory<?> unregisterControl( String oid );
+
+
+    /**
+     * Creates a new codec control decorator of the specified type.
+     *
+     * @param oid The OID of the new control to create.
+     * @return The newly created codec control.
+     */
+    CodecControl<? extends Control> newControl( String oid );
+
+
+    /**
+     * Creates a new codec control decorator for the provided control.
+     *
+     * @param control The control the codec control is generated for.
+     * @return The newly created codec control.
+     */
+    CodecControl<? extends Control> newControl( Control control );
+
+
+    /**
+     * Creates a JNDI control from the ldap model's control.
+     *
+     * @param modelControl The model's control.
+     * @return The JNDI control.
+     * @throws EncoderException if there are problems encoding the modelControl.
+     */
+    javax.naming.ldap.Control toJndiControl( Control modelControl ) throws EncoderException;
+
+
+    /**
+     * Creates a model control from the JNDI control.
+     *
+     * @param jndiControl The JNDI control.
+     * @return The model control.
+     * @throws DecoderException if there are problems decoding the value of the JNDI control.
+     */
+    Control fromJndiControl( javax.naming.ldap.Control jndiControl ) throws DecoderException;
+
+
+    // ------------------------------------------------------------------------
+    // Extended Request Methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Returns an Iterator over the OID Strings of registered extended 
+     * requests.
+     *
+     * @return The registered extended request OID Strings
+     */
+    Iterator<String> registeredExtendedRequests();
+
+
+    /**
+     * Registers an {@link ExtendedOperationFactory} for generating extended request 
+     * response pairs.
+     * 
+     * @param factory The extended request factory
+     * @return The displaced factory if one existed for the oid
+     */
+    ExtendedOperationFactory registerExtendedRequest( ExtendedOperationFactory factory );
+
+
+    /**
+     * Unregisters an {@link ExtendedOperationFactory} for generating extended 
+     * request response pairs.
+     * 
+     * @param oid The extended request oid
+     * @return The displaced factory if one existed for the oid
+     */
+    ExtendedOperationFactory unregisterExtendedRequest( String oid );
+
+
+    /**
+     * Checks to see if an extended operation, either a standard request 
+     * response, pair or just an unsolicited response is registered.
+     *
+     * @param oid The object identifier for the extended operation
+     * @return true if registered, false if not
+     */
+    boolean isExtendedOperationRegistered( String oid );
+
+
+    // ------------------------------------------------------------------------
+    // Extended Response Methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Creates a model ExtendedResponse from the JNDI ExtendedResponse.
+     *
+     * @param jndiResponse The JNDI ExtendedResponse 
+     * @return The model ExtendedResponse
+     * @throws DecoderException if the response value cannot be decoded.
+     */
+    ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException;
+
+
+    /**
+     * Creates a JNDI {@link javax.naming.ldap.ExtendedResponse} from the model 
+     * {@link ExtendedResponse}.
+     * 
+     * @param modelResponse
+     * @return
+     * @throws EncoderException
+     */
+    javax.naming.ldap.ExtendedResponse toJndi( ExtendedResponse modelResponse ) throws EncoderException;
+
+
+    /**
+     * Creates a model ExtendedResponse from the JNDI ExtendedResponse.
+     *
+     * @param jndiResponse The JNDI ExtendedResponse 
+     * @return The model ExtendedResponse
+     * @throws DecoderException if the response value cannot be decoded.
+     */
+    ExtendedRequest fromJndi( javax.naming.ldap.ExtendedRequest jndiRequest ) throws DecoderException;
+
+
+    /**
+     * Creates a JNDI {@link javax.naming.ldap.ExtendedResponse} from the model 
+     * {@link ExtendedResponse}.
+     * 
+     * @param modelResponse
+     * @return
+     * @throws EncoderException
+     */
+    javax.naming.ldap.ExtendedRequest toJndi( ExtendedRequest modelRequest ) throws EncoderException;
+
+
+    // ------------------------------------------------------------------------
+    // Other Methods
+    // ------------------------------------------------------------------------
+
+    /**
+     * Creates a new LDAP {@link ProtocolCodecFactory}.
+     *
+     * @return the {@link ProtocolCodecFactory}
+     */
+    ProtocolCodecFactory getProtocolCodecFactory();
+
+
+    /**
+     * Registers a ProtocolCodecFactory with this LdapCodecService.
+     *
+     * @param factory The factory being registered.
+     * @return The previously set {@link ProtocolCodecFactory}, or null if 
+     * none had been set earlier.
+     */
+    ProtocolCodecFactory registerProtocolCodecFactory( ProtocolCodecFactory factory );
+
+
+    /**
+     * Creates a new MessageContainer.
+     *
+     * @TODO akarasulu - Wondering why is this not an LdapMessageContainer?
+     * @return The newly created LDAP MessageContainer instance.
+     */
+    Asn1Container newMessageContainer();
+
+
+    /**
+     * Create an instance of a ExtendedResponse, knowing its OID. Inject the payload
+     * into it.
+     * 
+     * @param responseName The extendedRespose OID
+     * @param messageId The original message ID
+     * @param serializedResponse The serialized response payload
+     * @return The extendedResponse instance
+     * 
+     * @throws DecoderException If the payload is incorrect
+     */
+    <E extends ExtendedResponse> E newExtendedResponse( String responseName, int messageId, byte[] serializedResponse )
+        throws DecoderException;
+
+
+    /**
+     * Creates a new ExtendedRequest instance.
+     * 
+     * @param oid the extended request's object identifier
+     * @param value the encoded value of the extended request
+     * @return The new extended request
+     */
+    ExtendedRequest newExtendedRequest( String oid, byte[] value );
+
+
+    ExtendedRequestDecorator<?> decorate( ExtendedRequest decoratedMessage );
+
+
+    ExtendedResponseDecorator<?> decorate( ExtendedResponse decoratedMessage );
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapApiServiceFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapApiServiceFactory.java
new file mode 100644
index 0000000..fd2b677
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapApiServiceFactory.java
@@ -0,0 +1,146 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A factory that allows callers a means to get a handle on an LdapCodecService
+ * implementation regardless of the environment in which they're accessing it.
+ * In an OSGi environment, the BundleActivator binds the LdapCodecService 
+ * class member forever to the {@link DefaultLdapCodecService}. If in 
+ * 
+ * In a standard standalone mode, the Bundle
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LdapApiServiceFactory
+{
+    /** Logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( LdapApiServiceFactory.class );
+
+    /** The LdapCodecService singleton bound to this factory */
+    private static LdapApiService ldapCodecService;
+
+    /** Whether or not the standalone implementation is being used */
+    private static boolean usingStandaloneImplementation;
+
+
+    private LdapApiServiceFactory()
+    {
+        // TODO Auto-generated constructor stub
+    }
+
+
+    /**
+     * Checks to see if the factory is initialized.
+     *
+     * @return true if initialized, false otherwise
+     */
+    public static boolean isInitialized()
+    {
+        return ldapCodecService != null;
+    }
+
+
+    /**
+     * Checks to see if the factory is using the standalone implementation.
+     *
+     * @return true if using the standalone implementation, false otherwise.
+     */
+    public static boolean isUsingStandaloneImplementation()
+    {
+        if ( !isInitialized() )
+        {
+            String msg = "Not initialized yet!";
+            LOG.error( msg );
+            throw new IllegalStateException( msg );
+        }
+
+        return usingStandaloneImplementation;
+    }
+
+
+    /**
+     * Gets the singleton instance of the LdapCodecService.
+     *
+     * @return a valid instance implementation based on environment and the 
+     * availability of bindings.
+     */
+    public static LdapApiService getSingleton()
+    {
+        if ( ldapCodecService == null )
+        {
+            initialize( null );
+        }
+
+        return ldapCodecService;
+    }
+
+
+    /**
+     * Initialization can only take place once. There after an exception 
+     * results.
+     * 
+     * @param ldapCodecService The LDAP Codec Service to initialize with.
+     */
+    public static void initialize( LdapApiService ldapCodecService )
+    {
+        /*
+         * If the class member is already set we have problems.
+         */
+
+        if ( LdapApiServiceFactory.ldapCodecService != null )
+        {
+            StringBuilder sb = new StringBuilder( "The LdapCodecService is already set to an instance of " );
+            sb.append( LdapApiServiceFactory.class.getName() );
+            LOG.error( sb.toString() );
+            throw new IllegalStateException( sb.toString() );
+        }
+
+        /*
+         * If the argument is null, then we attempt discovery
+         */
+
+        if ( ldapCodecService == null )
+        {
+            try
+            {
+                @SuppressWarnings("unchecked")
+                Class<? extends LdapApiService> serviceClass = ( Class<? extends LdapApiService> )
+                    Class.forName( "org.apache.directory.api.ldap.codec.standalone.StandaloneLdapApiService" );
+                LdapApiServiceFactory.ldapCodecService = serviceClass.newInstance();
+                usingStandaloneImplementation = true;
+            }
+            catch ( Exception e )
+            {
+                LOG.error( "Failed to instantiate a viable instance, instantiating new instance of ", e );
+            }
+        }
+        else
+        {
+            usingStandaloneImplementation = false;
+            LdapApiServiceFactory.ldapCodecService = ldapCodecService;
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapCodecConstants.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapCodecConstants.java
new file mode 100644
index 0000000..5a7a317
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapCodecConstants.java
@@ -0,0 +1,171 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+/**
+ * This class contains a list of constants used in the LDAP coder/decoder.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LdapCodecConstants
+{
+    /**
+     * Private constructor.
+     */
+    private LdapCodecConstants()
+    {
+    }
+
+    /** The scope constants */
+    public static final int SCOPE_BASE_OBJECT = 0;
+
+    public static final int SCOPE_SINGLE_LEVEL = 1;
+
+    public static final int SCOPE_WHOLE_SUBTREE = 2;
+
+    /** The DerefAlias constants */
+    public static final int NEVER_DEREF_ALIASES = 0;
+
+    public static final int DEREF_IN_SEARCHING = 1;
+
+    public static final int DEREF_FINDING_BASE_OBJ = 2;
+
+    public static final int DEREF_ALWAYS = 3;
+
+    /** The operations */
+    public static final int OPERATION_ADD = 0;
+
+    public static final int OPERATION_DELETE = 1;
+
+    public static final int OPERATION_REPLACE = 2;
+
+    /** The filters */
+    public static final int EQUALITY_MATCH_FILTER = 0;
+
+    public static final int GREATER_OR_EQUAL_FILTER = 1;
+
+    public static final int LESS_OR_EQUAL_FILTER = 2;
+
+    public static final int APPROX_MATCH_FILTER = 3;
+
+    /** LDAP contextual tags */
+    public static final byte UNBIND_REQUEST_TAG = 0x42;
+
+    public static final byte DEL_REQUEST_TAG = 0x4A;
+
+    public static final byte ABANDON_REQUEST_TAG = 0x50;
+
+    public static final byte BIND_REQUEST_TAG = 0x60;
+
+    public static final byte BIND_RESPONSE_TAG = 0x61;
+
+    public static final byte SEARCH_REQUEST_TAG = 0x63;
+
+    public static final byte SEARCH_RESULT_ENTRY_TAG = 0x64;
+
+    public static final byte SEARCH_RESULT_DONE_TAG = 0x65;
+
+    public static final byte MODIFY_REQUEST_TAG = 0x66;
+
+    public static final byte MODIFY_RESPONSE_TAG = 0x67;
+
+    public static final byte ADD_REQUEST_TAG = 0x68;
+
+    public static final byte ADD_RESPONSE_TAG = 0x69;
+
+    public static final byte DEL_RESPONSE_TAG = 0x6B;
+
+    public static final byte MODIFY_DN_REQUEST_TAG = 0x6C;
+
+    public static final byte MODIFY_DN_RESPONSE_TAG = 0x6D;
+
+    public static final byte COMPARE_REQUEST_TAG = 0x6E;
+
+    public static final byte COMPARE_RESPONSE_TAG = 0x6F;
+
+    public static final byte SEARCH_RESULT_REFERENCE_TAG = 0x73;
+
+    public static final byte EXTENDED_REQUEST_TAG = 0x77;
+
+    public static final byte EXTENDED_RESPONSE_TAG = 0x78;
+
+    public static final byte INTERMEDIATE_RESPONSE_TAG = 0x79;
+
+    // The following tags are ints, because bytes above 127 are negative
+    // numbers, and we can't use them as array indexes.
+    public static final int BIND_REQUEST_SIMPLE_TAG = 0x80;
+
+    public static final int EXTENDED_REQUEST_NAME_TAG = 0x80;
+
+    public static final int MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG = 0x80;
+
+    public static final int SUBSTRINGS_FILTER_INITIAL_TAG = 0x80;
+
+    public static final int EXTENDED_REQUEST_VALUE_TAG = 0x81;
+
+    public static final int MATCHING_RULE_ID_TAG = 0x81;
+
+    public static final int SUBSTRINGS_FILTER_ANY_TAG = 0x81;
+
+    public static final int MATCHING_RULE_TYPE_TAG = 0x82;
+
+    public static final int SUBSTRINGS_FILTER_FINAL_TAG = 0x82;
+
+    public static final int MATCH_VALUE_TAG = 0x83;
+
+    public static final int DN_ATTRIBUTES_FILTER_TAG = 0x84;
+
+    public static final int SERVER_SASL_CREDENTIAL_TAG = 0x87;
+
+    public static final int PRESENT_FILTER_TAG = 0x87;
+
+    public static final int EXTENDED_RESPONSE_RESPONSE_NAME_TAG = 0x8A;
+
+    public static final int EXTENDED_RESPONSE_RESPONSE_TAG = 0x8B;
+
+    public static final int CONTROLS_TAG = 0xA0;
+
+    public static final int AND_FILTER_TAG = 0xA0;
+
+    public static final int INTERMEDIATE_RESPONSE_NAME_TAG = 0x80;
+
+    public static final int INTERMEDIATE_RESPONSE_VALUE_TAG = 0x81;
+
+    public static final int OR_FILTER_TAG = 0xA1;
+
+    public static final int NOT_FILTER_TAG = 0xA2;
+
+    public static final int BIND_REQUEST_SASL_TAG = 0xA3;
+
+    public static final int LDAP_RESULT_REFERRAL_SEQUENCE_TAG = 0xA3;
+
+    public static final int EQUALITY_MATCH_FILTER_TAG = 0xA3;
+
+    public static final int SUBSTRINGS_FILTER_TAG = 0xA4;
+
+    public static final int GREATER_OR_EQUAL_FILTER_TAG = 0xA5;
+
+    public static final int LESS_OR_EQUAL_FILTER_TAG = 0xA6;
+
+    public static final int APPROX_MATCH_FILTER_TAG = 0xA8;
+
+    public static final int EXTENSIBLE_MATCH_FILTER_TAG = 0xA9;
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapDecoder.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapDecoder.java
new file mode 100644
index 0000000..aaa2fb4
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapDecoder.java
@@ -0,0 +1,199 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The LdapDecoder decodes ASN.1 BER encoded PDUs into LDAP messages
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapDecoder
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( LdapDecoder.class );
+
+    /** A speedup for logger */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The ASN 1 decoder instance */
+    private Asn1Decoder asn1Decoder;
+
+    /** The name of the LdapSession's attribute for the LDAP container used during the decoding */
+    public static final String MESSAGE_CONTAINER_ATTR = "LDAP-container";
+
+    /** The maximum PDU size, stored into the LDAPSession's attribute */
+    public static final String MAX_PDU_SIZE_ATTR = "LDAP-maxPduSize";
+
+
+    /**
+     * Creates an instance of a Ldap Decoder implementation.
+     */
+    public LdapDecoder()
+    {
+        asn1Decoder = new Asn1Decoder();
+    }
+
+
+    /**
+     * Decodes a PDU from an input stream into a Ldap message container. We can only
+     * decode one complete message.
+     *
+     * @param in The input stream to read and decode PDU bytes from
+     * @return return The decoded message
+     */
+    public Message decode( InputStream in, LdapMessageContainer<MessageDecorator<? extends Message>> container )
+        throws DecoderException
+    {
+        try
+        {
+            int amount;
+
+            while ( in.available() > 0 )
+            {
+                byte[] buf = new byte[in.available()];
+
+                amount = in.read( buf );
+                if ( amount == -1 )
+                {
+                    break;
+                }
+
+                asn1Decoder.decode( ByteBuffer.wrap( buf, 0, amount ), container );
+            }
+        }
+        catch ( Exception e )
+        {
+            String message = I18n.err( I18n.ERR_04060, e.getLocalizedMessage() );
+            LOG.error( message );
+            throw new DecoderException( message, e );
+        }
+
+        if ( container.getState() == TLVStateEnum.PDU_DECODED )
+        {
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "Decoded LdapMessage : " + container );
+            }
+
+            return container.getMessage();
+        }
+        else
+        {
+            LOG.error( I18n.err( I18n.ERR_04062 ) );
+            throw new DecoderException( I18n.err( I18n.ERR_04063 ) );
+        }
+    }
+
+    /**
+     * Decode an incoming buffer into LDAP messages. The result can be 0, 1 or many
+     * LDAP messages, which will be stored into the array the caller has created.
+     * 
+     * @param buffer The incoming byte buffer
+     * @param messageContainer The LdapMessageContainer which will be used to store the
+     * message being decoded. If the message is not fully decoded, the ucrrent state
+     * is stored into this container
+     * @param decodedMessages The list of decoded messages
+     * @throws Exception If the decoding failed
+     *
+    public void decode( ByteBuffer buffer, LdapMessageContainer<MessageDecorator<? extends Message>> messageContainer, List<Message> decodedMessages ) throws DecoderException
+    {
+        buffer.mark();
+
+        while ( buffer.hasRemaining() )
+        {
+            try
+            {
+                if ( IS_DEBUG )
+                {
+                    LOG.debug( "Decoding the PDU : " );
+
+                    int size = buffer.limit();
+                    int position = buffer.position();
+                    int pduLength = size - position;
+
+                    byte[] array = new byte[pduLength];
+
+                    System.arraycopy(buffer.array(), position, array, 0, pduLength);
+
+                    buffer.position( size );
+
+                    if ( array.length == 0 )
+                    {
+                        LOG.debug( "NULL buffer, what the HELL ???" );
+                    }
+                    else
+                    {
+                        LOG.debug( Strings.dumpBytes(array) );
+                    }
+
+                    buffer.reset();
+                }
+
+                asn1Decoder.decode( buffer, messageContainer );
+
+                if ( messageContainer.getState() == TLVStateEnum.PDU_DECODED )
+                {
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Decoded LdapMessage : " + messageContainer.getMessage() );
+                    }
+
+                    Message message = messageContainer.getMessage();
+
+                    decodedMessages.add( message );
+
+                    messageContainer.clean();
+                }
+            }
+            catch ( DecoderException de )
+            {
+                buffer.clear();
+                messageContainer.clean();
+
+                if ( de instanceof ResponseCarryingException )
+                {
+                    // Transform the DecoderException message to a MessageException
+                    ResponseCarryingMessageException rcme = new ResponseCarryingMessageException( de.getMessage() );
+                    rcme.setResponse( ( ( ResponseCarryingException ) de ).getResponse() );
+
+                    throw rcme;
+                }
+                else
+                {
+                    // TODO : This is certainly not the way we should handle such an exception !
+                    throw new ResponseCarryingException( de.getMessage() );
+                }
+            }
+        }
+    }*/
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapEncoder.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapEncoder.java
new file mode 100644
index 0000000..da3de2a
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapEncoder.java
@@ -0,0 +1,368 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * LDAP BER encoder.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapEncoder
+{
+    /** The LdapCodecService */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates an instance of Ldap message encoder
+     * 
+     * @param codec The Codec service to use to handle Controls and extended operations,
+     * plus to get access to the underlying services.
+     */
+    public LdapEncoder( LdapApiService codec )
+    {
+        if ( codec == null )
+        {
+            throw new NullPointerException( "codec argument cannot be null" );
+        }
+
+        this.codec = codec;
+    }
+
+
+    /**
+     * Compute the control's encoded length
+     */
+    private int computeControlLength( Control control )
+    {
+        // First, compute the control's value length
+        int controlValueLength = ( ( CodecControl<?> ) control ).computeLength();
+
+        // Now, compute the envelop length
+        // The OID
+        int oidLengh = Strings.getBytesUtf8( control.getOid() ).length;
+        int controlLength = 1 + TLV.getNbBytes( oidLengh ) + oidLengh;
+
+        // The criticality, only if true
+        if ( control.isCritical() )
+        {
+            // Always 3 for a boolean
+            controlLength += 1 + 1 + 1;
+        }
+
+        if ( controlValueLength != 0 )
+        {
+            controlLength += 1 + TLV.getNbBytes( controlValueLength ) + controlValueLength;
+        }
+
+        return controlLength;
+    }
+
+
+    /**
+     * Encode a control to a byte[]
+     */
+    private ByteBuffer encodeControl( ByteBuffer buffer, Control control ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The LdapMessage Sequence
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+
+            // The length has been calculated by the computeLength method
+            int controlLength = computeControlLength( control );
+            buffer.put( TLV.getBytes( controlLength ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        // The control type
+        BerValue.encode( buffer, Strings.getBytesUtf8( control.getOid() ) );
+
+        // The control criticality, if true
+        if ( control.isCritical() )
+        {
+            BerValue.encode( buffer, control.isCritical() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * Generate the PDU which contains the encoded object. 
+     * 
+     * The generation is done in two phases : 
+     * - first, we compute the length of each part and the
+     * global PDU length 
+     * - second, we produce the PDU. 
+     * 
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x02 L2 MessageId  
+     *   +--> ProtocolOp 
+     *   +--> Controls 
+     *   
+     * L2 = Length(MessageId)
+     * L1 = Length(0x02) + Length(L2) + L2 + Length(ProtocolOp) + Length(Controls)
+     * LdapMessageLength = Length(0x30) + Length(L1) + L1
+     * </pre>
+     * 
+     * @param message The message to encode
+     * @return A ByteBuffer that contains the PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    public ByteBuffer encodeMessage( Message message ) throws EncoderException
+    {
+        MessageDecorator<? extends Message> decorator = MessageDecorator.getDecorator( codec, message );
+        int length = computeMessageLength( decorator );
+        ByteBuffer buffer = ByteBuffer.allocate( length );
+
+        try
+        {
+            try
+            {
+                // The LdapMessage Sequence
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+
+                // The length has been calculated by the computeLength method
+                buffer.put( TLV.getBytes( decorator.getMessageLength() ) );
+            }
+            catch ( BufferOverflowException boe )
+            {
+                throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+            }
+
+            // The message Id
+            BerValue.encode( buffer, message.getMessageId() );
+
+            // Add the protocolOp part
+            decorator.encode( buffer );
+
+            // Do the same thing for Controls, if any.
+            Map<String, Control> controls = decorator.getControls();
+
+            if ( ( controls != null ) && ( controls.size() > 0 ) )
+            {
+                // Encode the controls
+                buffer.put( ( byte ) LdapCodecConstants.CONTROLS_TAG );
+                buffer.put( TLV.getBytes( decorator.getControlsLength() ) );
+
+                // Encode each control
+                for ( Control control : controls.values() )
+                {
+                    encodeControl( buffer, control );
+
+                    // The OctetString tag if the value is not null
+                    int controlValueLength = ( ( CodecControl<?> ) control ).computeLength();
+
+                    if ( controlValueLength > 0 )
+                    {
+                        buffer.put( UniversalTag.OCTET_STRING.getValue() );
+                        buffer.put( TLV.getBytes( controlValueLength ) );
+
+                        // And now, the value
+                        ( ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) control ).encode( buffer );
+                    }
+                }
+            }
+        }
+        catch ( EncoderException ee )
+        {
+            MessageEncoderException exception = new MessageEncoderException( message.getMessageId(), ee.getMessage(), ee );
+
+            throw exception;
+        }
+
+        buffer.flip();
+
+        return buffer;
+    }
+
+
+    /**
+     * Compute the LdapMessage length LdapMessage : 
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x02 0x0(1-4) [0..2^31-1] (MessageId) 
+     *   +--> protocolOp 
+     *   [+--> Controls] 
+     *   
+     * MessageId length = Length(0x02) + length(MessageId) + MessageId.length 
+     * L1 = length(ProtocolOp) 
+     * LdapMessage length = Length(0x30) + Length(L1) + MessageId length + L1
+     *
+     * @param messageDecorator the decorated Message who's length is to be encoded
+     */
+    private int computeMessageLength( MessageDecorator<? extends Message> messageDecorator )
+    {
+        // The length of the MessageId. It's the sum of
+        // - the tag (0x02), 1 byte
+        // - the length of the Id length, 1 byte
+        // - the Id length, 1 to 4 bytes
+        int ldapMessageLength = 1 + 1 + BerValue.getNbBytes( messageDecorator.getDecorated().getMessageId() );
+
+        // Get the protocolOp length
+        ldapMessageLength += messageDecorator.computeLength();
+
+        Map<String, Control> controls = messageDecorator.getControls();
+
+        // Do the same thing for Controls, if any.
+        if ( controls.size() > 0 )
+        {
+            // Controls :
+            // 0xA0 L3
+            //   |
+            //   +--> 0x30 L4
+            //   +--> 0x30 L5
+            //   +--> ...
+            //   +--> 0x30 Li
+            //   +--> ...
+            //   +--> 0x30 Ln
+            //
+            // L3 = Length(0x30) + Length(L5) + L5
+            // + Length(0x30) + Length(L6) + L6
+            // + ...
+            // + Length(0x30) + Length(Li) + Li
+            // + ...
+            // + Length(0x30) + Length(Ln) + Ln
+            //
+            // LdapMessageLength = LdapMessageLength + Length(0x90)
+            // + Length(L3) + L3
+            int controlsSequenceLength = 0;
+
+            // We may have more than one control. ControlsLength is L4.
+            for ( Control control : controls.values() )
+            {
+                int controlLength = computeControlLength( control );
+
+                controlsSequenceLength += 1 + TLV.getNbBytes( controlLength ) + controlLength;
+            }
+
+            // Computes the controls length
+            // 1 + Length.getNbBytes( controlsSequenceLength ) + controlsSequenceLength;
+            messageDecorator.setControlsLength( controlsSequenceLength );
+
+            // Now, add the tag and the length of the controls length
+            ldapMessageLength += 1 + TLV.getNbBytes( controlsSequenceLength ) + controlsSequenceLength;
+        }
+
+        // Store the messageLength
+        messageDecorator.setMessageLength( ldapMessageLength );
+
+        // finally, calculate the global message size :
+        // length(Tag) + Length(length) + length
+
+        return 1 + ldapMessageLength + TLV.getNbBytes( ldapMessageLength );
+    }
+
+
+    /**
+     * Encode the Referral message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @param referral The referral to encode
+     * @return The encoded referral
+     * @exception EncoderException If the encoding failed
+     */
+    public static void encodeReferral( ByteBuffer buffer, Referral referral ) throws EncoderException
+    {
+        Collection<byte[]> ldapUrlsBytes = referral.getLdapUrlsBytes();
+
+        if ( ( ldapUrlsBytes != null ) && ( ldapUrlsBytes.size() != 0 ) )
+        {
+            // Encode the referrals sequence
+            // The referrals length MUST have been computed before !
+            buffer.put( ( byte ) LdapCodecConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG );
+            buffer.put( TLV.getBytes( referral.getReferralLength() ) );
+
+            // Each referral
+            for ( byte[] ldapUrlBytes : ldapUrlsBytes )
+            {
+                // Encode the current referral
+                BerValue.encode( buffer, ldapUrlBytes );
+            }
+        }
+    }
+
+
+    /**
+     * Compute the referral's encoded length
+     * @param referral The referral to encode
+     * @return The length of the encoded PDU
+     */
+    public static int computeReferralLength( Referral referral )
+    {
+        if ( referral != null )
+        {
+            Collection<String> ldapUrls = referral.getLdapUrls();
+
+            if ( ( ldapUrls != null ) && ( ldapUrls.size() != 0 ) )
+            {
+                int referralLength = 0;
+
+                // Each referral
+                for ( String ldapUrl : ldapUrls )
+                {
+                    byte[] ldapUrlBytes = Strings.getBytesUtf8( ldapUrl );
+                    referralLength += 1 + TLV.getNbBytes( ldapUrlBytes.length ) + ldapUrlBytes.length;
+                    referral.addLdapUrlBytes( ldapUrlBytes );
+                }
+
+                referral.setReferralLength( referralLength );
+
+                return referralLength;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+        else
+        {
+            return 0;
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapMessageContainer.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapMessageContainer.java
new file mode 100644
index 0000000..72c5cd1
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapMessageContainer.java
@@ -0,0 +1,194 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.LdapMessageGrammar;
+import org.apache.directory.api.ldap.codec.LdapStatesEnum;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+
+
+/**
+ * The LdapMessage container stores all the messages decoded by the Asn1Decoder.
+ * When dealing with an encoding PDU, we will obtain a LdapMessage in the
+ * container.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapMessageContainer<E extends MessageDecorator<? extends Message>> extends AbstractContainer
+{
+    /** The Message decorator to store various temporary values */
+    private E messageDecorator;
+
+    /** checks if attribute is binary */
+    private BinaryAttributeDetector binaryAttributeDetector;
+
+    /** The message ID */
+    private int messageId;
+
+    /** The current control */
+    private ControlDecorator<? extends Control> currentControl;
+
+    /** The codec service */
+    private final LdapApiService codec;
+
+
+    /**
+     * Creates a new LdapMessageContainer object. We will store ten grammars,
+     * it's enough ...
+     */
+    public LdapMessageContainer( LdapApiService codec )
+    {
+        this( codec, new DefaultConfigurableBinaryAttributeDetector() );
+    }
+
+
+    /**
+     * Creates a new LdapMessageContainer object. We will store ten grammars,
+     * it's enough ...
+     *
+     * @param binaryAttributeDetector checks if an attribute is binary
+     */
+    public LdapMessageContainer( LdapApiService codec, BinaryAttributeDetector binaryAttributeDetector )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( LdapMessageGrammar.getInstance() );
+        this.binaryAttributeDetector = binaryAttributeDetector;
+        setTransition( LdapStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * Gets the {@link LdapApiService} associated with this Container.
+     *
+     * @return
+     */
+    public LdapApiService getLdapCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * @return Returns the ldapMessage.
+     */
+    public E getMessage()
+    {
+        return messageDecorator;
+    }
+
+
+    /**
+     * Set a Message Object into the container. It will be completed by the
+     * ldapDecoder.
+     *
+     * @param message The message to set.
+     */
+    public void setMessage( E messageDecorator )
+    {
+        this.messageDecorator = messageDecorator;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void clean()
+    {
+        super.clean();
+
+        messageDecorator = null;
+        messageId = 0;
+        currentControl = null;
+        setDecodedBytes( 0 );
+    }
+
+
+    /**
+     * @return Returns true if the attribute is binary.
+     * @param id checks if an attribute id is binary
+     */
+    public boolean isBinary( String id )
+    {
+        return binaryAttributeDetector.isBinary( id );
+    }
+
+
+    /**
+     * @return The message ID
+     */
+    public int getMessageId()
+    {
+        return messageId;
+    }
+
+
+    /**
+     * Set the message ID
+     * @param messageId the id of the message
+     */
+    public void setMessageId( int messageId )
+    {
+        this.messageId = messageId;
+    }
+
+
+    /**
+     * @return the current control being created
+     */
+    public ControlDecorator<? extends Control> getCurrentControl()
+    {
+        return currentControl;
+    }
+
+
+    /**
+     * Store a newly created control
+     * @param currentControl The control to store
+     */
+    public void setCurrentControl( ControlDecorator<? extends Control> currentControl )
+    {
+        this.currentControl = currentControl;
+    }
+
+
+    /**
+     * Sets the binary attribute detector
+     * 
+     * @param binaryAttributeDetector the binary attribute detector
+     */
+    public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector )
+    {
+        this.binaryAttributeDetector = binaryAttributeDetector;
+    }
+
+
+    /**
+     * @return the binary attribute detector
+     */
+    public BinaryAttributeDetector getBinaryAttributeDetector()
+    {
+        return binaryAttributeDetector;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/MessageDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/MessageDecorator.java
new file mode 100644
index 0000000..37ac924
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/MessageDecorator.java
@@ -0,0 +1,427 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.ldap.codec.decorators.AbandonRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.AddResponseDecorator;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.BindResponseDecorator;
+import org.apache.directory.api.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.CompareResponseDecorator;
+import org.apache.directory.api.ldap.codec.decorators.DeleteRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.DeleteResponseDecorator;
+import org.apache.directory.api.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnResponseDecorator;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.ModifyResponseDecorator;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultDoneDecorator;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultReferenceDecorator;
+import org.apache.directory.api.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.ldap.model.message.UnbindRequest;
+
+
+/**
+ * A decorator for the generic LDAP Message
+ *
+ * @TODO make this class abstract, after finishing switch and all types and make default blow an EncoderException
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class MessageDecorator<E extends Message> implements Message, Decorator<E>, Asn1Object
+{
+    /** The decorated Control */
+    private final E decoratedMessage;
+
+    /** Map of message controls using OID Strings for keys and Control values */
+    private final Map<String, Control> controls;
+
+    /** The current control */
+    private CodecControl<? extends Control> currentControl;
+
+    /** The encoded Message length */
+    protected int messageLength;
+
+    /** The length of the controls */
+    private int controlsLength;
+
+    /** The LdapCodecService */
+    private final LdapApiService codec;
+
+
+    public static MessageDecorator<? extends Message> getDecorator( LdapApiService codec, Message decoratedMessage )
+    {
+        if ( decoratedMessage instanceof MessageDecorator )
+        {
+            return ( MessageDecorator<?> ) decoratedMessage;
+        }
+
+        MessageDecorator<?> decorator = null;
+
+        switch ( decoratedMessage.getType() )
+        {
+            case ABANDON_REQUEST:
+                decorator = new AbandonRequestDecorator( codec, ( AbandonRequest ) decoratedMessage );
+                break;
+
+            case ADD_REQUEST:
+                decorator = new AddRequestDecorator( codec, ( AddRequest ) decoratedMessage );
+                break;
+
+            case ADD_RESPONSE:
+                decorator = new AddResponseDecorator( codec, ( AddResponse ) decoratedMessage );
+                break;
+
+            case BIND_REQUEST:
+                decorator = new BindRequestDecorator( codec, ( BindRequest ) decoratedMessage );
+                break;
+
+            case BIND_RESPONSE:
+                decorator = new BindResponseDecorator( codec, ( BindResponse ) decoratedMessage );
+                break;
+
+            case COMPARE_REQUEST:
+                decorator = new CompareRequestDecorator( codec, ( CompareRequest ) decoratedMessage );
+                break;
+
+            case COMPARE_RESPONSE:
+                decorator = new CompareResponseDecorator( codec, ( CompareResponse ) decoratedMessage );
+                break;
+
+            case DEL_REQUEST:
+                decorator = new DeleteRequestDecorator( codec, ( DeleteRequest ) decoratedMessage );
+                break;
+
+            case DEL_RESPONSE:
+                decorator = new DeleteResponseDecorator( codec, ( DeleteResponse ) decoratedMessage );
+                break;
+
+            case EXTENDED_REQUEST:
+                decorator = codec.decorate( ( ExtendedRequest ) decoratedMessage );
+                break;
+
+            case EXTENDED_RESPONSE:
+                decorator = codec.decorate( ( ExtendedResponse ) decoratedMessage );
+                break;
+
+            case INTERMEDIATE_RESPONSE:
+                decorator = new IntermediateResponseDecorator( codec, ( IntermediateResponse ) decoratedMessage );
+                break;
+
+            case MODIFY_REQUEST:
+                decorator = new ModifyRequestDecorator( codec, ( ModifyRequest ) decoratedMessage );
+                break;
+
+            case MODIFY_RESPONSE:
+                decorator = new ModifyResponseDecorator( codec, ( ModifyResponse ) decoratedMessage );
+                break;
+
+            case MODIFYDN_REQUEST:
+                decorator = new ModifyDnRequestDecorator( codec, ( ModifyDnRequest ) decoratedMessage );
+                break;
+
+            case MODIFYDN_RESPONSE:
+                decorator = new ModifyDnResponseDecorator( codec, ( ModifyDnResponse ) decoratedMessage );
+                break;
+
+            case SEARCH_REQUEST:
+                decorator = new SearchRequestDecorator( codec, ( SearchRequest ) decoratedMessage );
+                break;
+
+            case SEARCH_RESULT_DONE:
+                decorator = new SearchResultDoneDecorator( codec, ( SearchResultDone ) decoratedMessage );
+                break;
+
+            case SEARCH_RESULT_ENTRY:
+                decorator = new SearchResultEntryDecorator( codec, ( SearchResultEntry ) decoratedMessage );
+                break;
+
+            case SEARCH_RESULT_REFERENCE:
+                decorator = new SearchResultReferenceDecorator( codec, ( SearchResultReference ) decoratedMessage );
+                break;
+
+            case UNBIND_REQUEST:
+                decorator = new UnbindRequestDecorator( codec, ( UnbindRequest ) decoratedMessage );
+                break;
+
+            default:
+                return null;
+        }
+
+        Map<String, Control> controls = decoratedMessage.getControls();
+
+        if ( controls != null )
+        {
+            for ( Control control : controls.values() )
+            {
+                decorator.addControl( control );
+            }
+        }
+
+        return decorator;
+    }
+
+
+    /**
+     * Makes a Message an Decorator object.
+     */
+    protected MessageDecorator( LdapApiService codec, E decoratedMessage )
+    {
+        this.codec = codec;
+        this.decoratedMessage = decoratedMessage;
+        controls = new HashMap<String, Control>();
+    }
+
+
+    /**
+     * @param controlsLength the encoded controls length
+     */
+    public void setControlsLength( int controlsLength )
+    {
+        this.controlsLength = controlsLength;
+    }
+
+
+    /**
+     * @return the encoded controls length
+     */
+    public int getControlsLength()
+    {
+        return controlsLength;
+    }
+
+
+    /**
+     * @param messageLength The encoded message length
+     */
+    public void setMessageLength( int messageLength )
+    {
+        this.messageLength = messageLength;
+    }
+
+
+    /**
+     * @return The encoded message length
+     */
+    public int getMessageLength()
+    {
+        return messageLength;
+    }
+
+
+    /**
+     * Get the current Control Object
+     * 
+     * @return The current Control Object
+     */
+    public CodecControl<? extends Control> getCurrentControl()
+    {
+        return currentControl;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Message methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getType()
+    {
+        return decoratedMessage.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Control> getControls()
+    {
+        return controls;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Control getControl( String oid )
+    {
+        return controls.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasControl( String oid )
+    {
+        return controls.containsKey( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public Message addControl( Control control )
+    {
+        Control decorated;
+        CodecControl<? extends Control> controlDecorator;
+
+        if ( control instanceof ControlDecorator )
+        {
+            controlDecorator = ( org.apache.directory.api.ldap.codec.api.CodecControl<? extends Control> ) control;
+            decorated = controlDecorator.getDecorated();
+        }
+        else
+        {
+            controlDecorator = codec.newControl( control );
+            decorated = control;
+        }
+
+        decoratedMessage.addControl( decorated );
+        controls.put( control.getOid(), controlDecorator );
+        currentControl = controlDecorator;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message addAllControls( Control[] controls )
+    {
+        for ( Control control : controls )
+        {
+            addControl( control );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message removeControl( Control control )
+    {
+        decoratedMessage.removeControl( control );
+        controls.remove( control.getOid() );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getMessageId()
+    {
+        return decoratedMessage.getMessageId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object get( Object key )
+    {
+        return decoratedMessage.get( key );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object put( Object key, Object value )
+    {
+        return decoratedMessage.put( key, value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message setMessageId( int messageId )
+    {
+        decoratedMessage.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * Delegates to the toString() method of the decorated Message.
+     */
+    public String toString()
+    {
+        return decoratedMessage.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public E getDecorated()
+    {
+        return decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/MessageEncoderException.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/MessageEncoderException.java
new file mode 100644
index 0000000..497fe51
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/MessageEncoderException.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.asn1.EncoderException;
+
+
+/**
+ * Create an exception containing the messageId
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class MessageEncoderException extends EncoderException
+{
+    private static final long serialVersionUID = -4634398228257729537L;
+
+    /** The message ID */
+    private int messageId;
+
+
+    /**
+     * Creates a new instance of MessageEncoderException.
+     *
+     * @param messageId The message ID
+     * @param message The exception message
+     */
+    public MessageEncoderException( int messageId, String message )
+    {
+        super( message );
+        this.messageId = messageId;
+    }
+
+
+    /**
+     * Creates a new instance of MessageEncoderException.
+     *
+     * @param messageId The message ID
+     * @param message The exception message
+     * @param cause The parent exception
+     */
+    public MessageEncoderException( int messageId, String message, Exception cause )
+    {
+        super( message, cause );
+        this.messageId = messageId;
+    }
+
+
+    /**
+     * @return the messageId
+     */
+    public int getMessageId()
+    {
+        return messageId;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ResponseCarryingException.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ResponseCarryingException.java
new file mode 100644
index 0000000..3bd9ef7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/ResponseCarryingException.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.codec.api;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Thrown when a Decoder has encountered a failure condition during a decode.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ResponseCarryingException extends DecoderException
+{
+    /**
+     * Declares the Serial Version Uid.
+     * 
+     * @see <a
+     *      href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
+     *      Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /** The response with the error cause */
+    private Message response;
+
+
+    /**
+     * Creates a DecoderException
+     * 
+     * @param message A message with meaning to a human
+     */
+    public ResponseCarryingException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a DecoderException
+     * 
+     * @param message A message with meaning to a human
+     * @param cause The original cause
+     */
+    public ResponseCarryingException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+
+    /**
+     * Creates a DecoderException
+     * 
+     * @param message A message with meaning to a human
+     * @param cause The Exception which caused the error
+     */
+    public ResponseCarryingException( String message, ResultResponse response, ResultCodeEnum code,
+        Dn matchedDn, Throwable cause )
+    {
+        super( message, cause );
+
+        response.getLdapResult().setDiagnosticMessage( message );
+        response.getLdapResult().setResultCode( code );
+        response.getLdapResult().setMatchedDn( matchedDn );
+
+        this.response = response;
+    }
+
+
+    /**
+     * Set a response if we get an exception while parsing the message
+     * @param response the constructed response
+     */
+    public void setResponse( Message response )
+    {
+        this.response = response;
+    }
+
+
+    /**
+     * Get the constructed response
+     * @return The constructed response
+     */
+    public Message getResponse()
+    {
+        return response;
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/SchemaBinaryAttributeDetector.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/SchemaBinaryAttributeDetector.java
new file mode 100644
index 0000000..3a30cec
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/SchemaBinaryAttributeDetector.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.api;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Strings;
+
+/**
+ * An implementation of the BinaryAttributeDetector interface. It's not
+ * schema aware, so it only uses the list of binary Attributes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaBinaryAttributeDetector implements BinaryAttributeDetector
+{
+    /** The schemaManager to use */
+    private SchemaManager schemaManager;
+    
+    
+    protected SchemaBinaryAttributeDetector()
+    {
+    }
+    
+    
+    public SchemaBinaryAttributeDetector( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+
+    /**
+     * @param schemaManager the schemaManager to set
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isBinary( String attributeId )
+    {
+        String attrId = Strings.toLowerCase( attributeId );
+
+        if ( attrId.endsWith( ";binary" ) )
+        {
+            return true;
+        }
+
+        if ( schemaManager != null )
+        {
+            AttributeType attributeType =  schemaManager.getAttributeType( attrId );
+            
+            if ( attributeType == null )
+            {
+                return false;
+            }
+            
+            LdapSyntax ldapSyntax = attributeType.getSyntax();
+            
+            return ( ( ldapSyntax != null ) && !ldapSyntax.isHumanReadable() );
+        }
+
+        return false;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/cascade/CascadeDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/cascade/CascadeDecorator.java
new file mode 100644
index 0000000..10f88e0
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/cascade/CascadeDecorator.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.cascade;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.Cascade;
+
+
+/**
+ * The Cascade control decorator.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CascadeDecorator extends ControlDecorator<Cascade> implements CodecControl<Cascade>, Cascade
+{
+    /**
+     * Default constructor
+     */
+    public CascadeDecorator( LdapApiService codec, Cascade control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * Returns the default control length.
+     */
+    public int computeLength()
+    {
+        return 0;
+    }
+
+
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        return this;
+    }
+
+
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/cascade/CascadeFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/cascade/CascadeFactory.java
new file mode 100644
index 0000000..3d894d2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/cascade/CascadeFactory.java
@@ -0,0 +1,78 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.cascade;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.Cascade;
+import org.apache.directory.api.ldap.model.message.controls.CascadeImpl;
+
+
+/**
+ * A codec {@link ControlFactory} implementation for {@link Cascade} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class CascadeFactory implements ControlFactory<Cascade>
+{
+    /** The LDAP codec responsible for encoding and decoding Cascade Controls */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of CascadeFactory.
+     *
+     * @param codec The LDAP codec
+     */
+    public CascadeFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return Cascade.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<Cascade> newCodecControl()
+    {
+        return new CascadeDecorator( codec, new CascadeImpl() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<Cascade> newCodecControl( Cascade control )
+    {
+        return new CascadeDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/manageDsaIT/ManageDsaITDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/manageDsaIT/ManageDsaITDecorator.java
new file mode 100644
index 0000000..b2a7940
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/manageDsaIT/ManageDsaITDecorator.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.manageDsaIT;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.ManageDsaIT;
+
+
+/**
+ * A decorating wrapper for a ManageDsaIT Control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ManageDsaITDecorator extends ControlDecorator<ManageDsaIT> implements ManageDsaIT
+{
+
+    /**
+     * Default constructor
+     */
+    public ManageDsaITDecorator( LdapApiService codec, ManageDsaIT control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * Returns 0 every time.
+     */
+    public int computeLength()
+    {
+        return 0;
+    }
+
+
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        return this;
+    }
+
+
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/manageDsaIT/ManageDsaITFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/manageDsaIT/ManageDsaITFactory.java
new file mode 100644
index 0000000..c3ab18e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/manageDsaIT/ManageDsaITFactory.java
@@ -0,0 +1,78 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.manageDsaIT;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.ManageDsaIT;
+import org.apache.directory.api.ldap.model.message.controls.ManageDsaITImpl;
+
+
+/**
+ * A codec {@link ControlFactory} implementation for {@link ManageDsaIT} control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ManageDsaITFactory implements ControlFactory<ManageDsaIT>
+{
+    /** The LDAP codec responsible for encoding and decoding Cascade Controls */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of CascadeFactory.
+     *
+     * @param codec The LDAP codec
+     */
+    public ManageDsaITFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return ManageDsaIT.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<ManageDsaIT> newCodecControl()
+    {
+        return new ManageDsaITDecorator( codec, new ManageDsaITImpl() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<ManageDsaIT> newCodecControl( ManageDsaIT control )
+    {
+        return new ManageDsaITDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzDecorator.java
new file mode 100644
index 0000000..af55e06
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzDecorator.java
@@ -0,0 +1,185 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.proxiedauthz;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.ProxiedAuthz;
+import org.apache.directory.api.ldap.model.message.controls.ProxiedAuthzImpl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * An ProxiedAuthz implementation, that wraps and decorates the Control with codec
+ * specific functionality.
+ *
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ProxiedAuthzDecorator extends ControlDecorator<ProxiedAuthz> implements ProxiedAuthz
+{
+    /** A temporary storage for the authzId */
+    private byte[] authzIdBytes = null;
+
+
+    /**
+     * Creates a new instance of ProxiedAuthzDecoder wrapping a newly created
+     * ProxiedAuthz Control object.
+     */
+    public ProxiedAuthzDecorator( LdapApiService codec )
+    {
+        super( codec, new ProxiedAuthzImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of ProxiedAuthzDecorator wrapping the supplied
+     * ProxiedAuthz Control.
+     *
+     * @param control The ProxiedAuthz Control to be decorated.
+     */
+    public ProxiedAuthzDecorator( LdapApiService codec, ProxiedAuthz control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * Internally used to not have to cast the decorated Control.
+     *
+     * @return the decorated Control.
+     */
+    private ProxiedAuthz getProxiedAuthz()
+    {
+        return ( ProxiedAuthz ) getDecorated();
+    }
+
+
+    /**
+     * Compute the ProxiedAuthzControl length 
+     * 
+     *  0x04 L1 authzId] 
+     */
+    public int computeLength()
+    {
+        int valueLength = 0;
+
+        if ( getAuthzId() != null )
+        {
+            authzIdBytes = Strings.getBytesUtf8( getAuthzId() );
+            valueLength = authzIdBytes.length;
+        }
+
+        return valueLength;
+    }
+
+
+    /**
+     * Encodes the ProxiedAuthz control.
+     * 
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        if ( getAuthzId() != null )
+        {
+            buffer.put( authzIdBytes );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                if ( authzIdBytes != null )
+                {
+                    BerValue.encode( buffer, authzIdBytes );
+                }
+                else
+                {
+                    BerValue.encode( buffer, Strings.EMPTY_BYTES );
+                }
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getAuthzId()
+    {
+        return getProxiedAuthz().getAuthzId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAuthzId( String authzId )
+    {
+        getProxiedAuthz().setAuthzId( authzId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        getProxiedAuthz().setAuthzId( Strings.utf8ToString( controlBytes ) );
+
+        return this;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzFactory.java
new file mode 100644
index 0000000..89b87ba
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.proxiedauthz;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.ProxiedAuthz;
+
+
+/**
+ * A {@link ControlFactory} for {@link ProxiedAuthz} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ProxiedAuthzFactory implements ControlFactory<ProxiedAuthz>
+{
+    /** The LDAP codec service */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of ProxiedAuthzFactory.
+     *
+     * @param codec The LDAP codec.
+     */
+    public ProxiedAuthzFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return ProxiedAuthz.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<ProxiedAuthz> newCodecControl()
+    {
+        return new ProxiedAuthzDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<ProxiedAuthz> newCodecControl( ProxiedAuthz control )
+    {
+        return new ProxiedAuthzDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeContainer.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeContainer.java
new file mode 100644
index 0000000..2c31bf0e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeContainer.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.entryChange;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.EntryChange;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EntryChangeContainer extends AbstractContainer
+{
+    /** EntryChangeControl */
+    private EntryChangeDecorator control;
+
+    /** The codec that encodes and decodes */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new EntryChangeContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public EntryChangeContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( EntryChangeGrammar.getInstance() );
+        setTransition( EntryChangeStates.START_STATE );
+    }
+
+
+    /**
+     * Creates a container with decorator, optionally decorating the supplied
+     * Control if it is not a decorator implementation.
+     *
+     * @param control The EntryChange ControlDecorator, or a Control to be
+     * wrapped by a new decorator.
+     */
+    public EntryChangeContainer( LdapApiService codec, EntryChange control )
+    {
+        this( codec );
+        decorate( control );
+    }
+
+
+    /**
+     * @return Returns the EntryChangeControl.
+     */
+    public EntryChangeDecorator getEntryChangeDecorator()
+    {
+        return control;
+    }
+
+
+    /**
+     * Checks to see if the supplied EntryChange implementation is a decorator
+     * and if so just sets the EntryChangeDecorator to it. Otherwise the supplied
+     * control is decorated by creating a new EntryChangeDecorator to wrap the
+     * object.
+     *
+     * @param control The EntryChange Control to wrap, if it is not a decorator.
+     */
+    public void decorate( EntryChange control )
+    {
+        if ( control instanceof EntryChangeDecorator )
+        {
+            this.control = ( EntryChangeDecorator ) control;
+        }
+        else
+        {
+            this.control = new EntryChangeDecorator( codec, control );
+        }
+    }
+
+
+    /**
+     * Set a EntryChangeControl Object into the container. It will be completed
+     * by the ldapDecoder.
+     * 
+     * @param control the EntryChangeControl to set.
+     */
+    public void setEntryChangeDecorator( EntryChangeDecorator control )
+    {
+        this.control = control;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeDecorator.java
new file mode 100644
index 0000000..a69c47b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeDecorator.java
@@ -0,0 +1,271 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.entryChange;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.ChangeType;
+import org.apache.directory.api.ldap.model.message.controls.EntryChange;
+import org.apache.directory.api.ldap.model.message.controls.EntryChangeImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * An EntryChange implementation, that wraps and decorates the Control with codec
+ * specific functionality.
+ *
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EntryChangeDecorator extends ControlDecorator<EntryChange> implements EntryChange
+{
+
+    public static final int UNDEFINED_CHANGE_NUMBER = -1;
+
+    /** A temporary storage for the previous Dn */
+    private byte[] previousDnBytes = null;
+
+    /** The entry change global length */
+    private int eccSeqLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Creates a new instance of EntryChangeDecoder wrapping a newly created
+     * EntryChange Control object.
+     */
+    public EntryChangeDecorator( LdapApiService codec )
+    {
+        super( codec, new EntryChangeImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of EntryChangeDecorator wrapping the supplied
+     * EntryChange Control.
+     *
+     * @param control The EntryChange Control to be decorated.
+     */
+    public EntryChangeDecorator( LdapApiService codec, EntryChange control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * Internally used to not have to cast the decorated Control.
+     *
+     * @return the decorated Control.
+     */
+    private EntryChange getEntryChange()
+    {
+        return ( EntryChange ) getDecorated();
+    }
+
+
+    /**
+     * Compute the EntryChangeControl length 
+     * 
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x0A 0x0(1-4) [1|2|4|8] (changeType) 
+     *  [+--> 0x04 L2 previousDN] 
+     *  [+--> 0x02 0x0(1-4) [0..2^63-1] (changeNumber)]
+     */
+    public int computeLength()
+    {
+        int changeTypesLength = 1 + 1 + 1;
+
+        int previousDnLength = 0;
+        int changeNumberLength = 0;
+
+        if ( getPreviousDn() != null )
+        {
+            previousDnBytes = Strings.getBytesUtf8( getPreviousDn().getName() );
+            previousDnLength = 1 + TLV.getNbBytes( previousDnBytes.length ) + previousDnBytes.length;
+        }
+
+        if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
+        {
+            changeNumberLength = 1 + 1 + BerValue.getNbBytes( getChangeNumber() );
+        }
+
+        eccSeqLength = changeTypesLength + previousDnLength + changeNumberLength;
+        valueLength = 1 + TLV.getNbBytes( eccSeqLength ) + eccSeqLength;
+
+        return valueLength;
+    }
+
+
+    /**
+     * Encodes the entry change control.
+     * 
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( eccSeqLength ) );
+
+        buffer.put( UniversalTag.ENUMERATED.getValue() );
+        buffer.put( ( byte ) 1 );
+        buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
+
+        if ( getPreviousDn() != null )
+        {
+            BerValue.encode( buffer, previousDnBytes );
+        }
+
+        if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
+        {
+            BerValue.encode( buffer, getChangeNumber() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+                buffer.put( TLV.getBytes( eccSeqLength ) );
+
+                buffer.put( UniversalTag.ENUMERATED.getValue() );
+                buffer.put( ( byte ) 1 );
+                buffer.put( BerValue.getBytes( getChangeType().getValue() ) );
+
+                if ( getPreviousDn() != null )
+                {
+                    BerValue.encode( buffer, previousDnBytes );
+                }
+
+                if ( getChangeNumber() != UNDEFINED_CHANGE_NUMBER )
+                {
+                    BerValue.encode( buffer, getChangeNumber() );
+                }
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ChangeType getChangeType()
+    {
+        return getEntryChange().getChangeType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setChangeType( ChangeType changeType )
+    {
+        getEntryChange().setChangeType( changeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getPreviousDn()
+    {
+        return getEntryChange().getPreviousDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setPreviousDn( Dn previousDn )
+    {
+        getEntryChange().setPreviousDn( previousDn );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getChangeNumber()
+    {
+        return getEntryChange().getChangeNumber();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setChangeNumber( long changeNumber )
+    {
+        getEntryChange().setChangeNumber( changeNumber );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        EntryChangeContainer container = new EntryChangeContainer( getCodecService(), this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeFactory.java
new file mode 100644
index 0000000..7b80f17
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.search.entryChange;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.EntryChange;
+
+
+/**
+ * A {@link ControlFactory} for {@link EntryChange} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class EntryChangeFactory implements ControlFactory<EntryChange>
+{
+    /** The LDAP codec service */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of EntryChangeFactory.
+     *
+     * @param codec The LDAP codec.
+     */
+    public EntryChangeFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return EntryChange.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<EntryChange> newCodecControl()
+    {
+        return new EntryChangeDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<EntryChange> newCodecControl( EntryChange control )
+    {
+        return new EntryChangeDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeGrammar.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeGrammar.java
new file mode 100644
index 0000000..f7274df
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeGrammar.java
@@ -0,0 +1,269 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.entryChange;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.LongDecoder;
+import org.apache.directory.api.asn1.ber.tlv.LongDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.controls.ChangeType;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the EntryChangeControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class EntryChangeGrammar extends AbstractGrammar<EntryChangeContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( EntryChangeGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. EntryChangeGrammar is a singleton */
+    private static Grammar<?> instance = new EntryChangeGrammar();
+
+
+    /**
+     * Creates a new EntryChangeGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private EntryChangeGrammar()
+    {
+        setName( EntryChangeGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[EntryChangeStates.LAST_EC_STATE.ordinal()][256];
+
+        // ============================================================================================
+        // Transition from start state to Entry Change sequence
+        // ============================================================================================
+        // EntryChangeNotification ::= SEQUENCE {
+        //     ...
+        //
+        // Initialization of the structure
+        super.transitions[EntryChangeStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.START_STATE,
+                EntryChangeStates.EC_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        // ============================================================================================
+        // transition from Entry Change sequence to Change Type
+        // ============================================================================================
+        // EntryChangeNotification ::= SEQUENCE {
+        //     changeType ENUMERATED {
+        //     ...
+        //
+        // Evaluates the changeType
+        super.transitions[EntryChangeStates.EC_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] =
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.EC_SEQUENCE_STATE,
+                EntryChangeStates.CHANGE_TYPE_STATE,
+                UniversalTag.ENUMERATED.getValue(),
+                new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl changeType" )
+                {
+                    public void action( EntryChangeContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int change = IntegerDecoder.parse( value, 1, 8 );
+
+                            switch ( ChangeType.getChangeType( change ) )
+                            {
+                                case ADD:
+                                case DELETE:
+                                case MODDN:
+                                case MODIFY:
+                                    ChangeType changeType = ChangeType.getChangeType( change );
+
+                                    if ( IS_DEBUG )
+                                    {
+                                        LOG.debug( "changeType = " + changeType );
+                                    }
+
+                                    container.getEntryChangeDecorator().setChangeType( changeType );
+                                    break;
+
+                                default:
+                                    String msg = I18n.err( I18n.ERR_04044 );
+                                    LOG.error( msg );
+                                    throw new DecoderException( msg );
+                            }
+
+                            // We can have an END transition
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04044 );
+                            LOG.error( msg, ide );
+                            throw new DecoderException( msg, ide );
+                        }
+                        catch ( IllegalArgumentException iae )
+                        {
+                            throw new DecoderException( iae.getLocalizedMessage(), iae );
+                        }
+                    }
+                } );
+
+        // ============================================================================================
+        // Transition from Change Type to Previous Dn
+        // ============================================================================================
+        // EntryChangeNotification ::= SEQUENCE {
+        //     ...
+        //     previousDN LDAPDN OPTIONAL,
+        //     ...
+        //
+        // Set the previousDN into the structure. We first check that it's a
+        // valid Dn
+        super.transitions[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
+                EntryChangeStates.PREVIOUS_DN_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl previousDN" )
+                {
+                    public void action( EntryChangeContainer container ) throws DecoderException
+                    {
+                        ChangeType changeType = container.getEntryChangeDecorator().getChangeType();
+
+                        if ( changeType != ChangeType.MODDN )
+                        {
+                            LOG.error( I18n.err( I18n.ERR_04045 ) );
+                            throw new DecoderException( I18n.err( I18n.ERR_04046 ) );
+                        }
+                        else
+                        {
+                            BerValue value = container.getCurrentTLV().getValue();
+                            Dn previousDn;
+
+                            try
+                            {
+                                previousDn = new Dn( Strings.utf8ToString( value.getData() ) );
+                            }
+                            catch ( LdapInvalidDnException ine )
+                            {
+                                LOG.error( I18n.err( I18n.ERR_04047, Strings.dumpBytes( value.getData() ) ) );
+                                throw new DecoderException( I18n.err( I18n.ERR_04048 ), ine );
+                            }
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "previousDN = " + previousDn );
+                            }
+
+                            container.getEntryChangeDecorator().setPreviousDn( previousDn );
+
+                            // We can have an END transition
+                            container.setGrammarEndAllowed( true );
+                        }
+                    }
+                } );
+
+        // Change Number action
+        GrammarAction<EntryChangeContainer> setChangeNumberAction = new GrammarAction<EntryChangeContainer>(
+            "Set EntryChangeControl changeNumber" )
+        {
+            public void action( EntryChangeContainer container ) throws DecoderException
+            {
+                BerValue value = container.getCurrentTLV().getValue();
+
+                try
+                {
+                    long changeNumber = LongDecoder.parse( value );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "changeNumber = " + changeNumber );
+                    }
+
+                    container.getEntryChangeDecorator().setChangeNumber( changeNumber );
+
+                    // We can have an END transition
+                    container.setGrammarEndAllowed( true );
+                }
+                catch ( LongDecoderException lde )
+                {
+                    String msg = I18n.err( I18n.ERR_04049 );
+                    LOG.error( msg, lde );
+                    throw new DecoderException( msg, lde );
+                }
+            }
+        };
+
+        // ============================================================================================
+        // Transition from Previous Dn to Change Number
+        // ============================================================================================
+        // EntryChangeNotification ::= SEQUENCE {
+        //     ...
+        //     changeNumber INTEGER OPTIONAL
+        // }
+        //
+        // Set the changeNumber into the structure
+        super.transitions[EntryChangeStates.PREVIOUS_DN_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.PREVIOUS_DN_STATE,
+                EntryChangeStates.CHANGE_NUMBER_STATE,
+                UniversalTag.INTEGER.getValue(),
+                setChangeNumberAction );
+
+        // ============================================================================================
+        // Transition from Previous Dn to Change Number
+        // ============================================================================================
+        // EntryChangeNotification ::= SEQUENCE {
+        //     ...
+        //     changeNumber INTEGER OPTIONAL
+        // }
+        //
+        // Set the changeNumber into the structure
+        super.transitions[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
+                EntryChangeStates.CHANGE_NUMBER_STATE,
+                UniversalTag.INTEGER.getValue(),
+                setChangeNumberAction );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<?> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeStates.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeStates.java
new file mode 100644
index 0000000..b5f54d0
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeStates.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.entryChange;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the EntryChangeControl's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum EntryChangeStates implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // Entry change control grammar states
+    // =========================================================================
+
+    /** Sequence Tag */
+    START_STATE,
+
+    /** Sequence */
+    EC_SEQUENCE_STATE,
+
+    /** changeType */
+    CHANGE_TYPE_STATE,
+
+    /** previousDN */
+    PREVIOUS_DN_STATE,
+
+    /** changeNumber */
+    CHANGE_NUMBER_STATE,
+
+    /** terminal state */
+    LAST_EC_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @return The grammar name
+     */
+    public String getGrammarName()
+    {
+        return "EC_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof EntryChangeGrammar )
+        {
+            return "EC_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "EC_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryChangeStates getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsContainer.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsContainer.java
new file mode 100644
index 0000000..b9cff9a
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsContainer.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.pagedSearch;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.PagedResults;
+
+
+/**
+ * A container for the Paged Search Control.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PagedResultsContainer extends AbstractContainer
+{
+    /** PagedSearchControl */
+    private PagedResultsDecorator control;
+
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new PagedSearchControl container object. We will store one grammar,
+     * it's enough ...
+     * @param codec The encoder decoder for this container
+     */
+    public PagedResultsContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( PagedResultsGrammar.getInstance() );
+        setTransition( PagedResultsStates.START_STATE );
+    }
+
+
+    /**
+     * Creates a new PagedSearchControl container object to contain a PagedResults
+     * Control, which is optionally decorated if is not a decorator already. If it
+     * is a decorator then it is used as the decorator for this container.
+     *
+     * @param codec The encoder decoder for this container
+     * @param control A PagedResults Control to optionally be wrapped.
+     */
+    public PagedResultsContainer( LdapApiService codec, PagedResults control )
+    {
+        this( codec );
+        decorate( control );
+    }
+
+
+    /**
+     * @return Returns the paged search control.
+     */
+    public PagedResultsDecorator getDecorator()
+    {
+
+        return control;
+    }
+
+
+    public void decorate( PagedResults control )
+    {
+        if ( control instanceof PagedResultsDecorator )
+        {
+            this.control = ( PagedResultsDecorator ) control;
+        }
+        else
+        {
+            this.control = new PagedResultsDecorator( codec, control );
+        }
+    }
+
+
+    /**
+     * Set a PagedSearchControl Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param control the PagedSearchControl to set.
+     */
+    public void setPagedSearchControl( PagedResultsDecorator control )
+    {
+        this.control = control;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsDecorator.java
new file mode 100644
index 0000000..640a6ab
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsDecorator.java
@@ -0,0 +1,312 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.pagedSearch;
+
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.PagedResults;
+import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A codec decorator for the {@link PagedResultsImpl}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PagedResultsDecorator extends ControlDecorator<PagedResults> implements PagedResults
+{
+    /** The entry change global length */
+    private int pscSeqLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Creates a new instance of PagedResultsDecorator with a newly created decorated
+     * PagedResults Control.
+     */
+    public PagedResultsDecorator( LdapApiService codec )
+    {
+        this( codec, new PagedResultsImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of PagedResultsDecorator using the supplied PagedResults
+     * Control to be decorated.
+     *
+     * @param  pagedResults The PagedResults Control to be decorated.
+     */
+    public PagedResultsDecorator( LdapApiService codec, PagedResults pagedResults )
+    {
+        super( codec, pagedResults );
+    }
+
+
+    /**
+     * Compute the PagedSearchControl length, which is the sum
+     * of the control length and the value length.
+     * 
+     * <pre>
+     * PagedSearchControl value length :
+     * 
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x02 0x0(1-4) [0..2^63-1] (size) 
+     *   +--> 0x04 L2 (cookie)
+     * </pre> 
+     */
+    public int computeLength()
+    {
+        int sizeLength = 1 + 1 + BerValue.getNbBytes( getSize() );
+
+        int cookieLength;
+
+        if ( getCookie() != null )
+        {
+            cookieLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
+        }
+        else
+        {
+            cookieLength = 1 + 1;
+        }
+
+        pscSeqLength = sizeLength + cookieLength;
+        valueLength = 1 + TLV.getNbBytes( pscSeqLength ) + pscSeqLength;
+
+        return valueLength;
+    }
+
+
+    /**
+     * Encodes the paged search control.
+     * 
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Now encode the PagedSearch specific part
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( pscSeqLength ) );
+
+        BerValue.encode( buffer, getSize() );
+        BerValue.encode( buffer, getCookie() );
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                // Now encode the PagedSearch specific part
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+                buffer.put( TLV.getBytes( pscSeqLength ) );
+
+                BerValue.encode( buffer, getSize() );
+                BerValue.encode( buffer, getCookie() );
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * @return The requested or returned number of entries
+     */
+    public int getSize()
+    {
+        return getDecorated().getSize();
+    }
+
+
+    /**
+     * Set the number of entry requested or returned
+     *
+     * @param size The number of entries 
+     */
+    public void setSize( int size )
+    {
+        getDecorated().setSize( size );
+    }
+
+
+    /**
+     * @return The stored cookie
+     */
+    public byte[] getCookie()
+    {
+        return getDecorated().getCookie();
+    }
+
+
+    /**
+     * Set the cookie
+     *
+     * @param cookie The cookie to store in this control
+     */
+    public void setCookie( byte[] cookie )
+    {
+        // Copy the bytes
+        if ( !Strings.isEmpty( cookie ) )
+        {
+            byte[] copy = new byte[cookie.length];
+            System.arraycopy( cookie, 0, copy, 0, cookie.length );
+            getDecorated().setCookie( copy );
+        }
+        else
+        {
+            getDecorated().setCookie( null );
+        }
+    }
+
+
+    /**
+     * @return The integer value for the current cookie
+     */
+    public int getCookieValue()
+    {
+        int value = 0;
+
+        switch ( getCookie().length )
+        {
+            case 1:
+                value = getCookie()[0] & 0x00FF;
+                break;
+
+            case 2:
+                value = ( ( getCookie()[0] & 0x00FF ) << 8 ) + ( getCookie()[1] & 0x00FF );
+                break;
+
+            case 3:
+                value = ( ( getCookie()[0] & 0x00FF ) << 16 ) + ( ( getCookie()[1] & 0x00FF ) << 8 )
+                    + ( getCookie()[2] & 0x00FF );
+                break;
+
+            case 4:
+                value = ( ( getCookie()[0] & 0x00FF ) << 24 ) + ( ( getCookie()[1] & 0x00FF ) << 16 )
+                    + ( ( getCookie()[2] & 0x00FF ) << 8 ) + ( getCookie()[3] & 0x00FF );
+                break;
+
+            default:
+                break;
+
+        }
+
+        return value;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = super.hashCode();
+
+        hash = hash * 17 + pscSeqLength;
+
+        return hash;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        PagedResults otherControl = ( PagedResults ) o;
+
+        return ( getSize() == otherControl.getSize() ) && Arrays.equals( getCookie(), otherControl.getCookie() );
+    }
+
+
+    /**
+     * Return a String representing this PagedSearchControl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Paged Search Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        size   : '" ).append( getSize() ).append( "'\n" );
+        sb.append( "        cookie   : '" ).append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        PagedResultsContainer container = new PagedResultsContainer( getCodecService(), this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsFactory.java
new file mode 100644
index 0000000..5bf6a45
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.search.pagedSearch;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.PagedResults;
+
+
+/**
+ * A {@link ControlFactory} for {@link EntryChange} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class PagedResultsFactory implements ControlFactory<PagedResults>
+{
+    /** The LDAP codec service */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of PagedResultsFactory.
+     *
+     * @param codec The LDAP codec.
+     */
+    public PagedResultsFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return PagedResults.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<PagedResults> newCodecControl()
+    {
+        return new PagedResultsDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<PagedResults> newCodecControl( PagedResults control )
+    {
+        return new PagedResultsDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsGrammar.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsGrammar.java
new file mode 100644
index 0000000..b8f39e2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsGrammar.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.pagedSearch;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.StringConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the PagedSearchControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ * 
+ * The decoded grammar is the following :
+ * 
+ * realSearchControlValue ::= SEQUENCE {
+ *     size   INTEGER,
+ *     cookie OCTET STRING,
+ * }
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PagedResultsGrammar extends AbstractGrammar<PagedResultsContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( PagedResultsGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. PagedSearchControlGrammar is a singleton */
+    private static Grammar<?> instance = new PagedResultsGrammar();
+
+
+    /**
+     * Creates a new PagedSearchControlGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private PagedResultsGrammar()
+    {
+        setName( PagedResultsGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[PagedResultsStates.LAST_PAGED_SEARCH_STATE.ordinal()][256];
+
+        /** 
+         * Transition from initial state to PagedSearch sequence
+         * realSearchControlValue ::= SEQUENCE OF {
+         *     ...
+         *     
+         * Nothing to do
+         */
+        super.transitions[PagedResultsStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<PagedResultsContainer>( PagedResultsStates.START_STATE,
+                PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        /** 
+         * Transition from PagedSearch sequence to size
+         * 
+         * realSearchControlValue ::= SEQUENCE OF {
+         *     size  INTEGER,  -- INTEGER (0..maxInt),
+         *     ...
+         *     
+         * Stores the size value
+         */
+        super.transitions[PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<PagedResultsContainer>( PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
+                PagedResultsStates.SIZE_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl size" )
+                {
+                    public void action( PagedResultsContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            // Check that the value is into the allowed interval
+                            int size = IntegerDecoder.parse( value, Integer.MIN_VALUE, Integer.MAX_VALUE );
+
+                            // We allow negative value to absorb a bug in some M$ client.
+                            // Those negative values will be transformed to Integer.MAX_VALUE.
+                            if ( size < 0 )
+                            {
+                                size = Integer.MAX_VALUE;
+                            }
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "size = " + size );
+                            }
+
+                            container.getDecorator().setSize( size );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04050 );
+                            LOG.error( msg, ide );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+
+        /** 
+         * Transition from size to cookie
+         * realSearchControlValue ::= SEQUENCE OF {
+         *     ...
+         *     cookie   OCTET STRING
+         * }
+         *     
+         * Stores the cookie flag
+         */
+        super.transitions[PagedResultsStates.SIZE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<PagedResultsContainer>( PagedResultsStates.SIZE_STATE,
+                PagedResultsStates.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl cookie" )
+                {
+                    public void action( PagedResultsContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        if ( container.getCurrentTLV().getLength() == 0 )
+                        {
+                            container.getDecorator().setCookie( StringConstants.EMPTY_BYTES );
+                        }
+                        else
+                        {
+                            container.getDecorator().setCookie( value.getData() );
+                        }
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<?> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsStates.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsStates.java
new file mode 100644
index 0000000..2d49c32
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedResultsStates.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.pagedSearch;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the PagedSearchControl's grammar constants. It is also used for
+ * debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum PagedResultsStates implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // Paged search control grammar states
+    // =========================================================================
+    /** Initial state */
+    START_STATE,
+
+    /** Sequence Value */
+    PAGED_SEARCH_SEQUENCE_STATE,
+
+    /** Size Value */
+    SIZE_STATE,
+
+    /** Cookie Value */
+    COOKIE_STATE,
+
+    /** terminal state */
+    LAST_PAGED_SEARCH_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "PAGED_SEARCH_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof PagedResultsGrammar )
+        {
+            return "PAGEDSEARCH_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "PAGED_SEARCH_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PagedResultsStates getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchContainer.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchContainer.java
new file mode 100644
index 0000000..deb0962
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchContainer.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.persistentSearch;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PersistentSearchContainer extends AbstractContainer
+{
+    /** PSearchControl */
+    private PersistentSearchDecorator decorator;
+
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new PSearchControlContainer object. We will store one grammar,
+     * it's enough ...
+     */
+    public PersistentSearchContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( PersistentSearchGrammar.getInstance() );
+        setTransition( PersistentSearchStates.START_STATE );
+    }
+
+
+    /**
+     * Creates a new PSearchControlContainer object pre-populated with a
+     * decorator wrapping the supplied control, or using the supplied control if
+     * it already is a decorator.
+     *
+     * @param control The PersistentSearch Control or a decorating wrapper.
+     */
+    public PersistentSearchContainer( LdapApiService codec, PersistentSearch control )
+    {
+        this( codec );
+        decorate( control );
+    }
+
+
+    /**
+     * Conditionally decorates a control if is not a decorator already.
+     *
+     * @param control The PersistentSearch Control to decorate if it already is not
+     * a decorator, if it is then the object is set as this container's decorator.
+     */
+    public void decorate( PersistentSearch control )
+    {
+        if ( control instanceof PersistentSearchDecorator )
+        {
+            this.decorator = ( PersistentSearchDecorator ) control;
+        }
+        else
+        {
+            this.decorator = new PersistentSearchDecorator( codec, control );
+        }
+    }
+
+
+    /**
+     * @return Returns the persistent search decorator.
+     */
+    public PersistentSearchDecorator getPersistentSearchDecorator()
+    {
+
+        return decorator;
+    }
+
+
+    /**
+     * Set a PSearchControl Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param decorator the PSearchControl to set.
+     */
+    public void setPersistentSearchDecorator( PersistentSearchDecorator decorator )
+    {
+        this.decorator = decorator;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        decorator = null;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchDecorator.java
new file mode 100644
index 0000000..5b242a4
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchDecorator.java
@@ -0,0 +1,225 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.persistentSearch;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.ChangeType;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearchImpl;
+
+
+/**
+ * A persistence search object
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PersistentSearchDecorator extends ControlDecorator<PersistentSearch> implements PersistentSearch
+{
+    /** A temporary storage for a psearch length */
+    private int psearchSeqLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Default constructor creates a PersistentSearch Control automatically
+     * wrapped in a decorator object inside this container.
+     */
+    public PersistentSearchDecorator( LdapApiService codec )
+    {
+        this( codec, new PersistentSearchImpl() );
+    }
+
+
+    /**
+     * Creates a PersistentSearch Control wrapping a supplied PersistentSearch
+     * Control.
+     *
+     * @param control The PersistentSearch Control to wrap.
+     */
+    public PersistentSearchDecorator( LdapApiService codec, PersistentSearch control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * Compute the PagedSearchControl length, which is the sum
+     * of the control length and the value length.
+     * 
+     * <pre>
+     * PersistentSearchDecorator value length :
+     * 
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x02 0x0(1-4) [0..2^31-1] (changeTypes) 
+     *   +--> 0x01 0x01 [0x00 | 0xFF] (changeOnly) 
+     *   +--> 0x01 0x01 [0x00 | 0xFF] (returnRCs)
+     * </pre> 
+     */
+    public int computeLength()
+    {
+        int changeTypesLength = 1 + 1 + BerValue.getNbBytes( getChangeTypes() );
+        int changesOnlyLength = 1 + 1 + 1;
+        int returnRCsLength = 1 + 1 + 1;
+
+        psearchSeqLength = changeTypesLength + changesOnlyLength + returnRCsLength;
+        int valueLength = 1 + TLV.getNbBytes( psearchSeqLength ) + psearchSeqLength;
+
+        return valueLength;
+    }
+
+
+    /**
+     * Encodes the persistent search control.
+     * 
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Now encode the PagedSearch specific part
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( psearchSeqLength ) );
+
+        BerValue.encode( buffer, getChangeTypes() );
+        BerValue.encode( buffer, isChangesOnly() );
+        BerValue.encode( buffer, isReturnECs() );
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                // Now encode the PagedSearch specific part
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+                buffer.put( TLV.getBytes( psearchSeqLength ) );
+
+                BerValue.encode( buffer, getChangeTypes() );
+                BerValue.encode( buffer, isChangesOnly() );
+                BerValue.encode( buffer, isReturnECs() );
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    private PersistentSearch getPersistentSearch()
+    {
+        return ( PersistentSearch ) getDecorated();
+    }
+
+
+    public void setChangesOnly( boolean changesOnly )
+    {
+        getPersistentSearch().setChangesOnly( changesOnly );
+    }
+
+
+    public boolean isChangesOnly()
+    {
+        return getPersistentSearch().isChangesOnly();
+    }
+
+
+    public void setReturnECs( boolean returnECs )
+    {
+        getPersistentSearch().setReturnECs( returnECs );
+    }
+
+
+    public boolean isReturnECs()
+    {
+        return getPersistentSearch().isReturnECs();
+    }
+
+
+    public void setChangeTypes( int changeTypes )
+    {
+        getPersistentSearch().setChangeTypes( changeTypes );
+    }
+
+
+    public int getChangeTypes()
+    {
+        return getPersistentSearch().getChangeTypes();
+    }
+
+
+    public boolean isNotificationEnabled( ChangeType changeType )
+    {
+        return getPersistentSearch().isNotificationEnabled( changeType );
+    }
+
+
+    public void enableNotification( ChangeType changeType )
+    {
+        getPersistentSearch().enableNotification( changeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        PersistentSearchContainer container = new PersistentSearchContainer( getCodecService(), this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchFactory.java
new file mode 100644
index 0000000..66abe64
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchFactory.java
@@ -0,0 +1,71 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.search.persistentSearch;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+
+
+/**
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class PersistentSearchFactory implements ControlFactory<PersistentSearch>
+{
+    private LdapApiService codec;
+
+
+    public PersistentSearchFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return PersistentSearch.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<PersistentSearch> newCodecControl()
+    {
+        return new PersistentSearchDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<PersistentSearch> newCodecControl( PersistentSearch control )
+    {
+        return new PersistentSearchDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchGrammar.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchGrammar.java
new file mode 100644
index 0000000..6ac275a
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchGrammar.java
@@ -0,0 +1,226 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.persistentSearch;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the PSearchControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ * 
+ * The decoded grammar is the following :
+ * 
+ * PersistenceSearch ::= SEQUENCE {
+ *     changeTypes  INTEGER,  -- an OR combinaison of 0, 1, 2 and 4 --
+ *     changeOnly   BOOLEAN,
+ *     returnECs    BOOLEAN
+ * }
+ * 
+ * The changeTypes field is the logical OR of one or more of these values:
+ * add    (1), 
+ * delete (2), 
+ * modify (4), 
+ * modDN  (8).
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PersistentSearchGrammar extends AbstractGrammar<PersistentSearchContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( PersistentSearchGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. PSearchControlGrammar is a singleton */
+    private static Grammar<?> instance = new PersistentSearchGrammar();
+
+
+    /**
+     * Creates a new PSearchControlGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private PersistentSearchGrammar()
+    {
+        setName( PersistentSearchGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[PersistentSearchStates.LAST_PSEARCH_STATE.ordinal()][256];
+
+        /** 
+         * Transition from initial state to Psearch sequence
+         * PSearch ::= SEQUENCE OF {
+         *     ...
+         *     
+         * Initialize the persistence search object
+         */
+        super.transitions[PersistentSearchStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.START_STATE,
+                PersistentSearchStates.PSEARCH_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        /** 
+         * Transition from Psearch sequence to Change types
+         * PSearch ::= SEQUENCE OF {
+         *     changeTypes  INTEGER,  -- an OR combinaison of 0, 1, 2 and 4 --
+         *     ...
+         *     
+         * Stores the change types value
+         */
+        super.transitions[PersistentSearchStates.PSEARCH_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.PSEARCH_SEQUENCE_STATE,
+                PersistentSearchStates.CHANGE_TYPES_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new GrammarAction<PersistentSearchContainer>( "Set PSearchControl changeTypes" )
+                {
+                    public void action( PersistentSearchContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            // Check that the value is into the allowed interval
+                            int changeTypes = IntegerDecoder.parse( value,
+                                PersistentSearch.CHANGE_TYPES_MIN,
+                                PersistentSearch.CHANGE_TYPES_MAX );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "changeTypes = " + changeTypes );
+                            }
+
+                            container.getPersistentSearchDecorator().setChangeTypes( changeTypes );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04051 );
+                            LOG.error( msg, ide );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+
+        /** 
+         * Transition from Change types to Changes only
+         * PSearch ::= SEQUENCE OF {
+         *     ...
+         *     changeOnly   BOOLEAN,
+         *     ...
+         *     
+         * Stores the change only flag
+         */
+        super.transitions[PersistentSearchStates.CHANGE_TYPES_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.CHANGE_TYPES_STATE,
+                PersistentSearchStates.CHANGES_ONLY_STATE, UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<PersistentSearchContainer>( "Set PSearchControl changesOnly" )
+                {
+                    public void action( PersistentSearchContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean changesOnly = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "changesOnly = " + changesOnly );
+                            }
+
+                            container.getPersistentSearchDecorator().setChangesOnly( changesOnly );
+                        }
+                        catch ( BooleanDecoderException bde )
+                        {
+                            String msg = I18n.err( I18n.ERR_04052 );
+                            LOG.error( msg, bde );
+                            throw new DecoderException( msg, bde );
+                        }
+                    }
+                } );
+
+        /** 
+         * Transition from Change types to Changes only
+         * PSearch ::= SEQUENCE OF {
+         *     ...
+         *     returnECs    BOOLEAN 
+         * }
+         *     
+         * Stores the return ECs flag 
+         */
+        super.transitions[PersistentSearchStates.CHANGES_ONLY_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.CHANGES_ONLY_STATE,
+                PersistentSearchStates.RETURN_ECS_STATE, UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<PersistentSearchContainer>( "Set PSearchControl returnECs" )
+                {
+                    public void action( PersistentSearchContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean returnECs = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "returnECs = " + returnECs );
+                            }
+
+                            container.getPersistentSearchDecorator().setReturnECs( returnECs );
+
+                            // We can have an END transition
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException bde )
+                        {
+                            String msg = I18n.err( I18n.ERR_04053 );
+                            LOG.error( msg, bde );
+                            throw new DecoderException( msg, bde );
+                        }
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<?> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchStates.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchStates.java
new file mode 100644
index 0000000..6e9096b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PersistentSearchStates.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.persistentSearch;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the PSearchControl's grammar constants. It is also used for
+ * debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum PersistentSearchStates implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // Persistent search control grammar states
+    // =========================================================================
+    /** Initial state */
+    START_STATE,
+
+    /** Sequence Value */
+    PSEARCH_SEQUENCE_STATE,
+
+    /** changeTypes Value */
+    CHANGE_TYPES_STATE,
+
+    /** changesOnly Value */
+    CHANGES_ONLY_STATE,
+
+    /** returnECs Value */
+    RETURN_ECS_STATE,
+
+    /** terminal state */
+    LAST_PSEARCH_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @return The grammar name
+     */
+    public String getGrammarName()
+    {
+        return "PSEARCH_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof PersistentSearchGrammar )
+        {
+            return "PSEARCH_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "PSEARCH_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PersistentSearchStates getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesContainer.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesContainer.java
new file mode 100644
index 0000000..64379b4
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesContainer.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.subentries;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubentriesContainer extends AbstractContainer
+{
+    /** PSearchControl */
+    private SubentriesDecorator decorator;
+
+
+    /**
+     * Creates a new SubEntryControlContainer object.
+     */
+    public SubentriesContainer()
+    {
+        super();
+        setGrammar( SubentriesGrammar.getInstance() );
+        setTransition( SubentriesStates.START_STATE );
+    }
+
+
+    /**
+     * Creates a new SubEntryControlContainer object, pre-populating it with the
+     * supplied Subentries control, and optionally wrapping it with a decorator
+     * if it is not a decorator instance.
+     *
+     * @param control The Subentries Control to decorate and add to this
+     * container, or if the Control already is a ControlDecorator it is directly
+     * added.
+     */
+    public SubentriesContainer( SubentriesDecorator control )
+    {
+        this();
+        this.decorator = control;
+    }
+
+
+    /**
+     * @return Returns the persistent search control.
+     */
+    public SubentriesDecorator getSubentriesControl()
+    {
+        return decorator;
+    }
+
+
+    /**
+     * Set a SubEntryControl Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param decorator the SubEntryControl to set.
+     */
+    public void setSubentriesDecorator( SubentriesDecorator decorator )
+    {
+        this.decorator = decorator;
+    }
+
+
+    /**
+     * Clean the current container
+     */
+    public void clean()
+    {
+        super.clean();
+        decorator = null;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesDecorator.java
new file mode 100644
index 0000000..194b127
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesDecorator.java
@@ -0,0 +1,150 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.subentries;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.Subentries;
+import org.apache.directory.api.ldap.model.message.controls.SubentriesImpl;
+
+
+/**
+ * A Subentries Control implementation which wraps and decorates Subentries
+ * Controls to enable them to be encoded and decoded by the codec.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubentriesDecorator extends ControlDecorator<Subentries> implements Subentries
+{
+    /** The sub entry decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Default constructor
+     */
+    public SubentriesDecorator( LdapApiService codec )
+    {
+        this( codec, new SubentriesImpl() );
+    }
+
+
+    /**
+     * Creates a Subentries decorating implementation for use with the codec,
+     * while decorating the supplied Subentries control.
+     *
+     * @param control The Subentries Control to wrap with this decorator.
+     */
+    public SubentriesDecorator( LdapApiService codec, Subentries control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * Compute the SubEntryControl length 0x01 0x01 [0x00|0xFF]
+     */
+    public int computeLength()
+    {
+        return 1 + 1 + 1;
+    }
+
+
+    /**
+     * Encodes the Subentries control.
+     * 
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Now encode the Subentries specific part
+        BerValue.encode( buffer, isVisible() );
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                // Now encode the Subentries specific part
+                BerValue.encode( buffer, isVisible() );
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    public boolean isVisible()
+    {
+        return getDecorated().isVisible();
+    }
+
+
+    public void setVisibility( boolean visibility )
+    {
+        getDecorated().setVisibility( visibility );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        SubentriesContainer container = new SubentriesContainer( this );
+        DECODER.decode( bb, container );
+
+        return this;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesFactory.java
new file mode 100644
index 0000000..6644adf
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesFactory.java
@@ -0,0 +1,81 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.search.subentries;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.Subentries;
+
+
+/**
+ * A factory for creating {@link Subentries} Controls and their 
+ * {@link SubentriesDecorator} objects.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SubentriesFactory implements ControlFactory<Subentries>
+{
+    /** The LDAP codec service */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SubentriesFactory.
+     *
+     * @param codec
+     */
+    public SubentriesFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return Subentries.OID;
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public CodecControl<Subentries> newCodecControl()
+    {
+        return new SubentriesDecorator( codec );
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public CodecControl<Subentries> newCodecControl( Subentries control )
+    {
+        return new SubentriesDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesGrammar.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesGrammar.java
new file mode 100644
index 0000000..5e0ab6f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesGrammar.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.subentries;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the SubEntryControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SubentriesGrammar extends AbstractGrammar<SubentriesContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( SubentriesGrammar.class );
+
+    /** The instance of grammar. SubEntryControlGrammar is a singleton */
+    private static Grammar<SubentriesContainer> instance = new SubentriesGrammar();
+
+
+    /**
+     * Creates a new SubEntryGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private SubentriesGrammar()
+    {
+        setName( SubentriesGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[SubentriesStates.LAST_SUB_ENTRY_STATE.ordinal()][256];
+
+        super.transitions[SubentriesStates.START_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SubentriesContainer>( SubentriesStates.START_STATE,
+                SubentriesStates.SUB_ENTRY_VISIBILITY_STATE, UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SubentriesContainer>( "SubEntryControl visibility" )
+                {
+                    public void action( SubentriesContainer container ) throws DecoderException
+                    {
+                        TLV tlv = container.getCurrentTLV();
+
+                        // We get the value. If it's a 0, it's a FALSE. If it's
+                        // a FF, it's a TRUE. Any other value should be an error,
+                        // but we could relax this constraint. So if we have
+                        // something
+                        // which is not 0, it will be interpreted as TRUE, but we
+                        // will generate a warning.
+                        BerValue value = tlv.getValue();
+
+                        try
+                        {
+                            container.getSubentriesControl().setVisibility( BooleanDecoder.parse( value ) );
+
+                            // We can have an END transition
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException bde )
+                        {
+                            LOG.error( I18n.err( I18n.ERR_04054, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
+
+                            // This will generate a PROTOCOL_ERROR
+                            throw new DecoderException( bde.getMessage() );
+                        }
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<SubentriesContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesStates.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesStates.java
new file mode 100644
index 0000000..d4c2d61
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubentriesStates.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.subentries;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the SubEntryControl's grammar constants. It is also used for
+ * debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SubentriesStates implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // Sub entry control grammar states
+    // =========================================================================
+
+    /** Starting state */
+    START_STATE,
+
+    /** Visibility Value */
+    SUB_ENTRY_VISIBILITY_STATE,
+
+    /** terminal state */
+    LAST_SUB_ENTRY_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "SUB_ENTRY_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<SubentriesContainer> grammar )
+    {
+        if ( grammar instanceof SubentriesGrammar )
+        {
+            return "SUB_ENTRY_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "SUB_ENTRY_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SubentriesStates getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestContainer.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestContainer.java
new file mode 100644
index 0000000..5744663
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestContainer.java
@@ -0,0 +1,134 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.SortKey;
+import org.apache.directory.api.ldap.model.message.controls.SortRequest;
+
+
+/**
+ * Container for SortRequestControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortRequestContainer extends AbstractContainer
+{
+    /** the sort request control decorator */
+    private SortRequestDecorator control;
+
+    /** the LDAP codec */
+    private LdapApiService codec;
+
+    /** current key that is being decoded */
+    private SortKey currentKey;
+
+
+    /**
+     * Creates a new instance of SortRequestContainer.
+     *
+     * @param codec the LDAP codec
+     */
+    public SortRequestContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( SortRequestGrammar.getInstance() );
+        setTransition( SortRequestStates.START_STATE );
+    }
+
+
+    /**
+     * Creates a new instance of SortRequestContainer.
+     *
+     * @param codec the LDAP codec
+     * @param control the sort request control
+     */
+    public SortRequestContainer( LdapApiService codec, SortRequest control )
+    {
+        this( codec );
+        decorate( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void decorate( SortRequest control )
+    {
+        if ( control instanceof SortRequestDecorator )
+        {
+            this.control = ( SortRequestDecorator ) control;
+        }
+        else
+        {
+            this.control = new SortRequestDecorator( codec, control );
+        }
+    }
+
+
+    /**
+     * @return the control
+     */
+    public SortRequestDecorator getControl()
+    {
+        return control;
+    }
+
+
+    /**
+     * @param control the control to set
+     */
+    public void setControl( SortRequestDecorator control )
+    {
+        this.control = control;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+
+
+    /**
+     * @return the currentKey
+     */
+    public SortKey getCurrentKey()
+    {
+        return currentKey;
+    }
+
+
+    /**
+     * @param currentKey the currentKey to set
+     */
+    public void setCurrentKey( SortKey currentKey )
+    {
+        this.currentKey = currentKey;
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestDecorator.java
new file mode 100644
index 0000000..5be0a68
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestDecorator.java
@@ -0,0 +1,225 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.asn1.util.Asn1StringUtils;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.SortKey;
+import org.apache.directory.api.ldap.model.message.controls.SortRequest;
+import org.apache.directory.api.ldap.model.message.controls.SortRequestControlImpl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Decorator of SortRequestControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortRequestDecorator extends ControlDecorator<SortRequest> implements SortRequest
+{
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+    private int sortReqLen = 0;
+
+    private List<Integer> sortKeyLenList = new ArrayList<Integer>();
+
+    public static final int ORDERING_RULE_TAG = 0x80;
+
+    public static final int REVERSE_ORDER_TAG = 0x81;
+
+
+    /**
+     * Creates a new instance of SortRequestDecorator.
+     *
+     * @param codec the LDAP codec
+     */
+    public SortRequestDecorator( LdapApiService codec )
+    {
+        super( codec, new SortRequestControlImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of SortRequestDecorator.
+     *
+     * @param codec the LDAP codec
+     * @param control the control instance
+     */
+    public SortRequestDecorator( LdapApiService codec, SortRequest control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * 
+     */
+    @Override
+    public int computeLength()
+    {
+        sortReqLen = 0;
+        sortKeyLenList.clear();
+        valueLength = 0;
+
+        for ( SortKey sk : getSortKeys() )
+        {
+            int skLen = 0;
+
+            byte[] atBytes = Strings.getBytesUtf8( sk.getAttributeTypeDesc() );
+            skLen += 1 + TLV.getNbBytes( atBytes.length ) + atBytes.length;
+
+            if ( sk.getMatchingRuleId() != null )
+            {
+                byte[] mrBytes = Strings.getBytesUtf8( sk.getMatchingRuleId() );
+                skLen += 1 + TLV.getNbBytes( mrBytes.length ) + mrBytes.length;
+            }
+
+            if ( sk.isReverseOrder() )
+            {
+                // reverse order flag
+                skLen += 1 + 1 + 1;
+            }
+
+            sortKeyLenList.add( skLen );
+
+            // the sequence
+            sortReqLen += 1 + TLV.getNbBytes( skLen ) + skLen;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( sortReqLen ) + sortReqLen;
+
+        return valueLength;
+    }
+
+
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( sortReqLen ) );
+
+        List<SortKey> lst = getSortKeys();
+
+        for ( int i = 0; i < lst.size(); i++ )
+        {
+            SortKey sk = lst.get( i );
+            int skLen = sortKeyLenList.get( i );
+
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+            buffer.put( TLV.getBytes( skLen ) );
+
+            BerValue.encode( buffer, sk.getAttributeTypeDesc() );
+
+            String mrId = sk.getMatchingRuleId();
+            if ( mrId != null )
+            {
+                buffer.put( ( byte ) ORDERING_RULE_TAG );
+                byte[] value = Asn1StringUtils.getBytesUtf8( mrId );
+
+                buffer.put( TLV.getBytes( value.length ) );
+                buffer.put( value );
+            }
+
+            if ( sk.isReverseOrder() )
+            {
+                buffer.put( ( byte ) REVERSE_ORDER_TAG );
+                buffer.put( ( byte ) 0x01 );
+                buffer.put( BerValue.TRUE_VALUE );
+            }
+        }
+
+        return buffer;
+    }
+
+
+    @Override
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer buffer = ByteBuffer.wrap( controlBytes );
+        SortRequestContainer container = new SortRequestContainer( getCodecService(), this );
+        DECODER.decode( buffer, container );
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                value = encode( buffer ).array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    @Override
+    public void setSortKeys( List<SortKey> sortKeys )
+    {
+        getDecorated().setSortKeys( sortKeys );
+    }
+
+
+    @Override
+    public List<SortKey> getSortKeys()
+    {
+        return getDecorated().getSortKeys();
+    }
+
+
+    @Override
+    public void addSortKey( SortKey sortKey )
+    {
+        getDecorated().addSortKey( sortKey );
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestFactory.java
new file mode 100644
index 0000000..408de4f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.SortRequest;
+
+
+/**
+ * A {@link ControlFactory} for SortRequestControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SortRequestFactory implements ControlFactory<SortRequest>
+{
+    /** The LDAP codec service */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SortRequestFactory.
+     *
+     * @param codec The LDAP codec.
+     */
+    public SortRequestFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return SortRequest.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SortRequest> newCodecControl()
+    {
+        return new SortRequestDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SortRequest> newCodecControl( SortRequest control )
+    {
+        return new SortRequestDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestGrammar.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestGrammar.java
new file mode 100644
index 0000000..7d60d43
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestGrammar.java
@@ -0,0 +1,190 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import static org.apache.directory.api.ldap.codec.controls.sort.SortRequestDecorator.ORDERING_RULE_TAG;
+import static org.apache.directory.api.ldap.codec.controls.sort.SortRequestDecorator.REVERSE_ORDER_TAG;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.ldap.model.message.controls.SortKey;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Grammar used for decoding a SortRequestControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SortRequestGrammar extends AbstractGrammar<SortRequestContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( SortRequestGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. SortRequestGrammar is a singleton */
+    private static Grammar<SortRequestContainer> instance = new SortRequestGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    private SortRequestGrammar()
+    {
+        setName( SortRequestGrammar.class.getName() );
+
+        GrammarAction<SortRequestContainer> addSortKey = new GrammarAction<SortRequestContainer>()
+        {
+
+            @Override
+            public void action( SortRequestContainer container ) throws DecoderException
+            {
+                BerValue value = container.getCurrentTLV().getValue();
+
+                String atDesc = Strings.utf8ToString( value.getData() );
+                if ( IS_DEBUG )
+                {
+                    LOG.debug( "AttributeTypeDesc = " + atDesc );
+                }
+
+                SortKey sk = new SortKey( atDesc );
+                container.setCurrentKey( sk );
+                container.getControl().addSortKey( sk );
+                container.setGrammarEndAllowed( true );
+            }
+
+        };
+
+        GrammarAction<SortRequestContainer> storeReverseOrder = new GrammarAction<SortRequestContainer>()
+        {
+
+            @Override
+            public void action( SortRequestContainer container ) throws DecoderException
+            {
+                BerValue value = container.getCurrentTLV().getValue();
+
+                try
+                {
+                    boolean reverseOrder = BooleanDecoder.parse( value );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "ReverseOrder = " + reverseOrder );
+                    }
+
+                    container.getCurrentKey().setReverseOrder( reverseOrder );
+
+                    container.setGrammarEndAllowed( true );
+                }
+                catch ( BooleanDecoderException bde )
+                {
+                    //String msg = I18n.err( I18n.ERR_04050 );
+                    //LOG.error( msg, e );
+                    throw new DecoderException( bde.getMessage(), bde );
+                }
+            }
+
+        };
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[SortRequestStates.END_STATE.ordinal()][256];
+
+        super.transitions[SortRequestStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.START_STATE,
+                SortRequestStates.SEQUENCE_OF_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        super.transitions[SortRequestStates.SEQUENCE_OF_SEQUENCE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.SEQUENCE_OF_SEQUENCE_STATE,
+                SortRequestStates.SORT_KEY_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        super.transitions[SortRequestStates.SORT_KEY_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.SORT_KEY_SEQUENCE_STATE,
+                SortRequestStates.AT_DESC_STATE,
+                UniversalTag.OCTET_STRING.getValue(), addSortKey );
+
+        super.transitions[SortRequestStates.AT_DESC_STATE.ordinal()][ORDERING_RULE_TAG] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.AT_DESC_STATE,
+                SortRequestStates.ORDER_RULE_STATE,
+                ORDERING_RULE_TAG, new GrammarAction<SortRequestContainer>()
+                {
+
+                    @Override
+                    public void action( SortRequestContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        String matchingRuleOid = Strings.utf8ToString( value.getData() );
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "MatchingRuleOid = " + matchingRuleOid );
+                        }
+
+                        container.getCurrentKey().setMatchingRuleId( matchingRuleOid );
+                        container.setGrammarEndAllowed( true );
+                    }
+
+                } );
+
+        super.transitions[SortRequestStates.ORDER_RULE_STATE.ordinal()][REVERSE_ORDER_TAG] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.ORDER_RULE_STATE,
+                SortRequestStates.REVERSE_ORDER_STATE,
+                REVERSE_ORDER_TAG, storeReverseOrder );
+
+        super.transitions[SortRequestStates.AT_DESC_STATE.ordinal()][REVERSE_ORDER_TAG] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.AT_DESC_STATE,
+                SortRequestStates.REVERSE_ORDER_STATE,
+                REVERSE_ORDER_TAG, storeReverseOrder );
+
+        super.transitions[SortRequestStates.REVERSE_ORDER_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.REVERSE_ORDER_STATE,
+                SortRequestStates.SORT_KEY_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        super.transitions[SortRequestStates.AT_DESC_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<SortRequestContainer>( SortRequestStates.AT_DESC_STATE,
+                SortRequestStates.SORT_KEY_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<?> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestStates.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestStates.java
new file mode 100644
index 0000000..088d6f5
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestStates.java
@@ -0,0 +1,102 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * Codec states for SortRequestControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SortRequestStates implements States
+{
+    START_STATE,
+
+    SEQUENCE_OF_SEQUENCE_STATE,
+    
+    SORT_KEY_SEQUENCE_STATE,
+
+    AT_DESC_STATE,
+
+    ORDER_RULE_STATE,
+
+    REVERSE_ORDER_STATE,
+
+    END_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "SORT_REQUEST_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof SortRequestGrammar )
+        {
+            return "SORT_REQUEST_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "SORT_REQUEST_END_STATE" : name() );
+    }
+
+
+    @Override
+    public boolean isEndState()
+    {
+        return ( this == END_STATE );
+    }
+
+
+    @Override
+    public Enum<?> getStartState()
+    {
+        return START_STATE;
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseContainer.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseContainer.java
new file mode 100644
index 0000000..80014d2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseContainer.java
@@ -0,0 +1,112 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.SortResponse;
+
+
+/**
+ * Container for SortResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortResponseContainer extends AbstractContainer
+{
+    /** the decorator instance of sort response control */
+    private SortResponseDecorator control;
+
+    /** LDAP codec */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SortResponseContainer.
+     *
+     * @param codec the LDAP codec
+     */
+    public SortResponseContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( SortResponseGrammar.getInstance() );
+        setTransition( SortResponseStates.START_STATE );
+    }
+
+
+    /**
+     * Creates a new instance of SortResponseContainer.
+     *
+     * @param codec the LDAP codec
+     * @param control the sort response control
+     */
+    public SortResponseContainer( LdapApiService codec, SortResponse control )
+    {
+        this( codec );
+        decorate( control );
+    }
+
+
+    /**
+     * {@inheritDoc} 
+     */
+    public void decorate( SortResponse control )
+    {
+        if ( control instanceof SortResponseDecorator )
+        {
+            this.control = ( SortResponseDecorator ) control;
+        }
+        else
+        {
+            this.control = new SortResponseDecorator( codec, control );
+        }
+    }
+
+
+    /**
+     * @return the control
+     */
+    public SortResponseDecorator getControl()
+    {
+        return control;
+    }
+
+
+    /**
+     * @param control the control to set
+     */
+    public void setControl( SortResponseDecorator control )
+    {
+        this.control = control;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseDecorator.java
new file mode 100644
index 0000000..4fe4ead
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseDecorator.java
@@ -0,0 +1,186 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.SortResponse;
+import org.apache.directory.api.ldap.model.message.controls.SortResponseControlImpl;
+import org.apache.directory.api.ldap.model.message.controls.SortResultCode;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Decorator class for SortResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortResponseDecorator extends ControlDecorator<SortResponse> implements SortResponse
+{
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+    private int sortRespLen = 0;
+
+
+    /**
+     * Creates a new instance of SortResponseDecorator.
+     *
+     * @param codec the LDAP codec
+     */
+    public SortResponseDecorator( LdapApiService codec )
+    {
+        super( codec, new SortResponseControlImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of SortResponseDecorator.
+     *
+     * @param codec the LDAP codec
+     * @param control the sort response control
+     */
+    public SortResponseDecorator( LdapApiService codec, SortResponse control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * 
+     */
+    @Override
+    public int computeLength()
+    {
+        sortRespLen = 0;
+        valueLength = 0;
+
+        // result code value
+        sortRespLen += 1 + 1 + 1;
+
+        if ( getAttributeName() != null )
+        {
+            byte[] data = Strings.getBytesUtf8( getAttributeName() );
+            sortRespLen += 1 + TLV.getNbBytes( data.length ) + data.length;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( sortRespLen ) + sortRespLen;
+
+        return valueLength;
+    }
+
+
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( sortRespLen ) );
+
+        BerValue.encodeEnumerated( buffer, getSortResult().getVal() );
+
+        if ( getAttributeName() != null )
+        {
+            BerValue.encode( buffer, getAttributeName() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer buffer = ByteBuffer.wrap( controlBytes );
+        SortResponseContainer container = new SortResponseContainer( getCodecService(), this );
+        DECODER.decode( buffer, container );
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                value = encode( buffer ).array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    @Override
+    public void setSortResult( SortResultCode result )
+    {
+        getDecorated().setSortResult( result );
+    }
+
+
+    @Override
+    public SortResultCode getSortResult()
+    {
+        return getDecorated().getSortResult();
+    }
+
+
+    @Override
+    public void setAttributeName( String attributeName )
+    {
+        getDecorated().setAttributeName( attributeName );
+    }
+
+
+    @Override
+    public String getAttributeName()
+    {
+        return getDecorated().getAttributeName();
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseFactory.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseFactory.java
new file mode 100644
index 0000000..9e4146d
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.controls.SortResponse;
+
+
+/**
+ * A {@link ControlFactory} for SortResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SortResponseFactory implements ControlFactory<SortResponse>
+{
+    /** The LDAP codec service */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SortResponseFactory.
+     *
+     * @param codec The LDAP codec.
+     */
+    public SortResponseFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return SortResponse.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SortResponse> newCodecControl()
+    {
+        return new SortResponseDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SortResponse> newCodecControl( SortResponse control )
+    {
+        return new SortResponseDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseGrammar.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseGrammar.java
new file mode 100644
index 0000000..23121a0
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseGrammar.java
@@ -0,0 +1,104 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Grammar for decoding SortResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SortResponseGrammar extends AbstractGrammar<SortResponseContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( SortRequestGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. SortResponseGrammar is a singleton */
+    private static Grammar<SortResponseContainer> instance = new SortResponseGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    private SortResponseGrammar()
+    {
+        setName( SortResponseGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[SortResponseStates.END_STATE.ordinal()][256];
+
+        super.transitions[SortResponseStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<SortResponseContainer>( SortResponseStates.START_STATE,
+                SortResponseStates.SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+        
+        super.transitions[SortResponseStates.SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] =
+            new GrammarTransition<SortResponseContainer>( SortResponseStates.SEQUENCE_STATE,
+                SortResponseStates.RESULT_CODE_STATE,
+                UniversalTag.ENUMERATED.getValue(), new StoreSortResponseResultCode<SortResponseContainer>() );
+
+        super.transitions[SortResponseStates.RESULT_CODE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<SortResponseContainer>( SortResponseStates.RESULT_CODE_STATE,
+                SortResponseStates.AT_DESC_STATE,
+                UniversalTag.OCTET_STRING.getValue(), new GrammarAction<SortResponseContainer>()
+                {
+
+                    @Override
+                    public void action( SortResponseContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        String atType = Strings.utf8ToString( value.getData() );
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "AttributeType = " + atType );
+                        }
+                        
+                        container.getControl().setAttributeName( atType );
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<?> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseStates.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseStates.java
new file mode 100644
index 0000000..fa9155f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseStates.java
@@ -0,0 +1,98 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * Enumeration of states encountered while decoding a SortResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SortResponseStates implements States
+{
+    START_STATE,
+
+    SEQUENCE_STATE,
+
+    RESULT_CODE_STATE,
+    
+    AT_DESC_STATE,
+
+    END_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "SORT_RESPONSE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof SortResponseGrammar )
+        {
+            return "SORT_RESPONSE_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "SORT_REQUEST_END_STATE" : name() );
+    }
+
+
+    @Override
+    public boolean isEndState()
+    {
+        return ( this == END_STATE );
+    }
+
+
+    @Override
+    public Enum<?> getStartState()
+    {
+        return START_STATE;
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/StoreSortResponseResultCode.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/StoreSortResponseResultCode.java
new file mode 100644
index 0000000..2985ef7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/controls/sort/StoreSortResponseResultCode.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.ldap.model.message.controls.SortResultCode;
+
+
+/**
+ * The action used to store the result code of a SortResponseControl
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreSortResponseResultCode<C extends Asn1Container> extends AbstractReadInteger<C>
+{
+
+    /**
+     * Instantiates a new StoreSortResponseResultCode action.
+     */
+    public StoreSortResponseResultCode()
+    {
+        super( "SortResponse result code error" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, Asn1Container container )
+    {
+        SortResponseContainer sortRespContainer = ( SortResponseContainer ) container;
+
+        SortResultCode code = SortResultCode.get( value );
+        sortRespContainer.getControl().setSortResult( code );
+
+        sortRespContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonRequestDecorator.java
new file mode 100644
index 0000000..8ebcc33
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonRequestDecorator.java
@@ -0,0 +1,160 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A decorator for the AddRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class AbandonRequestDecorator extends RequestDecorator<AbandonRequest> implements AbandonRequest
+{
+    /**
+     * Makes a AddRequest a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated AddRequest
+     */
+    public AbandonRequestDecorator( LdapApiService codec, AbandonRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The AbandonRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getAbandoned()
+    {
+        return getDecorated().getAbandoned();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest setAbandoned( int requestId )
+    {
+        getDecorated().setAbandoned( requestId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest addControl( Control control )
+    {
+        return ( AbandonRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest addAllControls( Control[] controls )
+    {
+        return ( AbandonRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest removeControl( Control control )
+    {
+        return ( AbandonRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Encode the Abandon protocolOp part
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The tag
+            buffer.put( LdapCodecConstants.ABANDON_REQUEST_TAG );
+
+            // The length. It has to be evaluated depending on
+            // the abandoned messageId value.
+            buffer.put( ( byte ) BerValue.getNbBytes( getAbandoned() ) );
+
+            // The abandoned messageId
+            buffer.put( BerValue.getBytes( getAbandoned() ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            String msg = I18n.err( I18n.ERR_04005 );
+            throw new EncoderException( msg, boe );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * Compute the AbandonRequest length 
+     * 
+     * AbandonRequest : 
+     * 0x50 0x0(1..4) abandoned MessageId 
+     * 
+     * Length(AbandonRequest) = Length(0x50) + 1 + Length(abandoned MessageId)
+     */
+    public int computeLength()
+    {
+        int length = 1 + 1 + BerValue.getNbBytes( getAbandoned() );
+
+        return length;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableRequestDecorator.java
new file mode 100644
index 0000000..4751753
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableRequestDecorator.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.AbandonListener;
+import org.apache.directory.api.ldap.model.message.AbandonableRequest;
+
+
+/**
+ * A decorator for the LdapResultResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbandonableRequestDecorator<M extends AbandonableResultResponseRequest>
+    extends ResultResponseRequestDecorator<M>
+    implements AbandonableRequest
+{
+    /**
+     * Makes Request a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated message
+     */
+    public AbandonableRequestDecorator( LdapApiService codec, M decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * Gets the decorated AbandonableRequest.
+     *
+     * @return The decorated {@link AbandonableRequest}
+     */
+    public AbandonableRequest getAbandonableRequest()
+    {
+        return getDecorated();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void abandon()
+    {
+        getAbandonableRequest().abandon();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAbandoned()
+    {
+        return getAbandonableRequest().isAbandoned();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonableRequest addAbandonListener( AbandonListener listener )
+    {
+        getAbandonableRequest().addAbandonListener( listener );
+
+        return this;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableResultResponseRequest.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableResultResponseRequest.java
new file mode 100644
index 0000000..b25878f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableResultResponseRequest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import org.apache.directory.api.ldap.model.message.AbandonableRequest;
+import org.apache.directory.api.ldap.model.message.ResultResponseRequest;
+
+
+/**
+ * A composite interface needed for {@link AbandonableRequest} {@link ResultResponseRequest}s.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface AbandonableResultResponseRequest extends ResultResponseRequest, AbandonableRequest
+{
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableResultResponseRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableResultResponseRequestDecorator.java
new file mode 100644
index 0000000..da8399b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AbandonableResultResponseRequestDecorator.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.message.ResultResponseRequest;
+
+
+/**
+ * A decorator for the LdapResultResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbandonableResultResponseRequestDecorator<M extends AbandonableResultResponseRequest>
+    extends AbandonableRequestDecorator<M> implements ResultResponseRequest
+{
+    /**
+     * Makes Request a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated message
+     */
+    public AbandonableResultResponseRequestDecorator( LdapApiService codec, M decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasResponse()
+    {
+        return getDecorated().hasResponse();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ResultResponse getResultResponse()
+    {
+        return getDecorated().getResultResponse();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AddRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AddRequestDecorator.java
new file mode 100644
index 0000000..fe9051c
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AddRequestDecorator.java
@@ -0,0 +1,439 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the AddRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class AddRequestDecorator extends SingleReplyRequestDecorator<AddRequest> implements
+    AddRequest
+{
+    /** The add request length */
+    private int addRequestLength;
+
+    /** The Entry length */
+    private int entryLength;
+
+    /** The list of all attributes length */
+    private List<Integer> attributesLength;
+
+    /** The list of all attributes Id bytes */
+    private List<byte[]> attributeIds;
+
+    /** The list of all vals length */
+    private List<Integer> valuesLength;
+
+    /** The current attribute being decoded */
+    private Attribute currentAttribute;
+
+    /** The bytes containing the Dn */
+    private byte[] dnBytes;
+
+
+    /**
+     * Makes a AddRequest a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated AddRequest
+     */
+    public AddRequestDecorator( LdapApiService codec, AddRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest addControl( Control control )
+    {
+        return ( AddRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest addAllControls( Control[] controls )
+    {
+        return ( AddRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest removeControl( Control control )
+    {
+        return ( AddRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The AddRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getEntryDn()
+    {
+        return getDecorated().getEntryDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setEntryDn( Dn entry )
+    {
+        getDecorated().setEntryDn( entry );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry getEntry()
+    {
+        return getDecorated().getEntry();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setEntry( Entry entry )
+    {
+        getDecorated().setEntry( entry );
+
+        return this;
+    }
+
+
+    /**
+     * Create a new attributeValue
+     * 
+     * @param type The attribute's name (called 'type' in the grammar)
+     */
+    public void addAttributeType( String type ) throws LdapException
+    {
+        // do not create a new attribute if we have seen this attributeType before
+        if ( getDecorated().getEntry().get( type ) != null )
+        {
+            currentAttribute = getDecorated().getEntry().get( type );
+            return;
+        }
+
+        // fix this to use AttributeImpl(type.getString().toLowerCase())
+        currentAttribute = new DefaultAttribute( type );
+        getDecorated().getEntry().put( currentAttribute );
+    }
+
+
+    /**
+     * @return Returns the currentAttribute type.
+     */
+    public String getCurrentAttributeType()
+    {
+        return currentAttribute.getUpId();
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( String value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( Value<?> value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( byte[] value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the AddRequest length
+     * 
+     * AddRequest :
+     * 
+     * 0x68 L1
+     *  |
+     *  +--> 0x04 L2 entry
+     *  +--> 0x30 L3 (attributes)
+     *        |
+     *        +--> 0x30 L4-1 (attribute)
+     *        |     |
+     *        |     +--> 0x04 L5-1 type
+     *        |     +--> 0x31 L6-1 (values)
+     *        |           |
+     *        |           +--> 0x04 L7-1-1 value
+     *        |           +--> ...
+     *        |           +--> 0x04 L7-1-n value
+     *        |
+     *        +--> 0x30 L4-2 (attribute)
+     *        |     |
+     *        |     +--> 0x04 L5-2 type
+     *        |     +--> 0x31 L6-2 (values)
+     *        |           |
+     *        |           +--> 0x04 L7-2-1 value
+     *        |           +--> ...
+     *        |           +--> 0x04 L7-2-n value
+     *        |
+     *        +--> ...
+     *        |
+     *        +--> 0x30 L4-m (attribute)
+     *              |
+     *              +--> 0x04 L5-m type
+     *              +--> 0x31 L6-m (values)
+     *                    |
+     *                    +--> 0x04 L7-m-1 value
+     *                    +--> ...
+     *                    +--> 0x04 L7-m-n value
+     */
+    public int computeLength()
+    {
+        AddRequest addRequest = getDecorated();
+        Entry entry = addRequest.getEntry();
+
+        if ( entry == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04481_ENTRY_NULL_VALUE ) );
+        }
+
+        dnBytes = Strings.getBytesUtf8( entry.getDn().getName() );
+        int dnLen = dnBytes.length;
+
+        // The entry Dn
+        addRequestLength = 1 + TLV.getNbBytes( dnLen ) + dnLen;
+
+        // The attributes sequence
+        entryLength = 0;
+
+        if ( entry.size() != 0 )
+        {
+            attributesLength = new LinkedList<Integer>();
+            attributeIds = new LinkedList<byte[]>();
+            valuesLength = new LinkedList<Integer>();
+
+            // Compute the attributes length
+            for ( Attribute attribute : entry )
+            {
+                int localAttributeLength = 0;
+                int localValuesLength = 0;
+
+                // Get the type length
+                byte[] attributeIdBytes = Strings.getBytesUtf8( attribute.getUpId() );
+                attributeIds.add( attributeIdBytes );
+
+                int idLength = attributeIdBytes.length;
+                localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength;
+
+                // The values
+                if ( attribute.size() != 0 )
+                {
+                    localValuesLength = 0;
+
+                    for ( Value<?> value : attribute )
+                    {
+                        if ( value.getBytes() == null )
+                        {
+                            localValuesLength += 1 + 1;
+                        }
+                        else
+                        {
+                            int valueLength = value.getBytes().length;
+                            localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength;
+                        }
+                    }
+
+                    localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
+                }
+                else
+                {
+                    // No value : we still have to store the encapsulating Sequence
+                    localValuesLength = 1 + 1;
+                    localAttributeLength += 1 + 1 + localValuesLength;
+                }
+
+                // add the attribute length to the attributes length
+                entryLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength;
+
+                attributesLength.add( localAttributeLength );
+                valuesLength.add( localValuesLength );
+            }
+        }
+
+        addRequestLength += 1 + TLV.getNbBytes( entryLength ) + entryLength;
+
+        // Return the result.
+        return 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength;
+    }
+
+
+    /**
+     * Encode the AddRequest message to a PDU.
+     * 
+     * AddRequest :
+     * 
+     * 0x68 LL
+     *   0x04 LL entry
+     *   0x30 LL attributesList
+     *     0x30 LL attributeList
+     *       0x04 LL attributeDescription
+     *       0x31 LL attributeValues
+     *         0x04 LL attributeValue
+     *         ...
+     *         0x04 LL attributeValue
+     *     ...
+     *     0x30 LL attributeList
+     *       0x04 LL attributeDescription
+     *       0x31 LL attributeValue
+     *         0x04 LL attributeValue
+     *         ...
+     *         0x04 LL attributeValue
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The AddRequest Tag
+            buffer.put( LdapCodecConstants.ADD_REQUEST_TAG );
+            buffer.put( TLV.getBytes( addRequestLength ) );
+
+            // The entry
+            BerValue.encode( buffer, dnBytes );
+
+            // The attributes sequence
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+            buffer.put( TLV.getBytes( entryLength ) );
+
+            // The partial attribute list
+            Entry entry = getEntry();
+
+            if ( entry.size() != 0 )
+            {
+                int attributeNumber = 0;
+
+                // Compute the attributes length
+                for ( Attribute attribute : entry )
+                {
+                    // The attributes list sequence
+                    buffer.put( UniversalTag.SEQUENCE.getValue() );
+                    int localAttributeLength = attributesLength.get( attributeNumber );
+                    buffer.put( TLV.getBytes( localAttributeLength ) );
+
+                    // The attribute type
+                    BerValue.encode( buffer, attributeIds.get( attributeNumber ) );
+
+                    // The values
+                    buffer.put( UniversalTag.SET.getValue() );
+                    int localValuesLength = valuesLength.get( attributeNumber );
+                    buffer.put( TLV.getBytes( localValuesLength ) );
+
+                    if ( attribute.size() != 0 )
+                    {
+                        for ( Value<?> value : attribute )
+                        {
+                            BerValue.encode( buffer, value.getBytes() );
+                        }
+                    }
+                    else
+                    {
+                        BerValue.encode( buffer, Strings.EMPTY_BYTES );
+                    }
+
+                    // Go to the next attribute number;
+                    attributeNumber++;
+                }
+            }
+
+            return buffer;
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( "The PDU buffer size is too small !", boe );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AddResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AddResponseDecorator.java
new file mode 100644
index 0000000..b4a2219
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/AddResponseDecorator.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+
+
+/**
+ * A decorator for the AddResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddResponseDecorator extends ResponseDecorator<AddResponse> implements AddResponse
+{
+    /** The encoded addResponse length */
+    private int addResponseLength;
+
+
+    /**
+     * Makes a AddResponse a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated AddResponse
+     */
+    public AddResponseDecorator( LdapApiService codec, AddResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * @return The decorated AddResponse
+     */
+    public AddResponse getAddResponse()
+    {
+        return ( AddResponse ) getDecorated();
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the AddResponse length 
+     * 
+     * AddResponse : 
+     * 
+     * 0x69 L1
+     *  |
+     *  +--> LdapResult
+     * 
+     * L1 = Length(LdapResult)
+     * 
+     * Length(AddResponse) = Length(0x69) + Length(L1) + L1
+     */
+    public int computeLength()
+    {
+        AddResponse addResponse = getAddResponse();
+        setLdapResult( new LdapResultDecorator( getCodecService(), addResponse.getLdapResult() ) );
+        addResponseLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        return 1 + TLV.getNbBytes( addResponseLength ) + addResponseLength;
+    }
+
+
+    /**
+     * Encode the AddResponse message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @param addResponseDecorator the AddResponse decorator
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The AddResponse Tag
+            buffer.put( LdapCodecConstants.ADD_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( addResponseLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+
+            return buffer;
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/BindRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/BindRequestDecorator.java
new file mode 100644
index 0000000..6cd74a9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/BindRequestDecorator.java
@@ -0,0 +1,455 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the BindRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BindRequestDecorator extends SingleReplyRequestDecorator<BindRequest> implements BindRequest
+{
+    /** The bind request length */
+    private int bindRequestLength;
+
+    /** The SASL Mechanism length */
+    private int saslMechanismLength;
+
+    /** The SASL credentials length */
+    private int saslCredentialsLength;
+
+    /** The bytes containing the Dn */
+    private byte[] dnBytes;
+
+    /** The bytes containing the Name */
+    private byte[] nameBytes;
+
+    /** The bytes containing the SaslMechanism */
+    private byte[] mechanismBytes;
+
+
+    /**
+     * Makes a BindRequest a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated BindRequests.
+     */
+    public BindRequestDecorator( LdapApiService codec, BindRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest addControl( Control control )
+    {
+        return ( BindRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest addAllControls( Control[] controls )
+    {
+        return ( BindRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest removeControl( Control control )
+    {
+        return ( BindRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The BindRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSimple()
+    {
+        return getDecorated().isSimple();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getSimple()
+    {
+        return getDecorated().getSimple();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setSimple( boolean isSimple )
+    {
+        getDecorated().setSimple( isSimple );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCredentials()
+    {
+        return getDecorated().getCredentials();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setCredentials( String credentials )
+    {
+        getDecorated().setCredentials( credentials );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setCredentials( byte[] credentials )
+    {
+        getDecorated().setCredentials( credentials );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setName( String name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getDn()
+    {
+        return getDecorated().getDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setDn( Dn dn )
+    {
+        getDecorated().setDn( dn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isVersion3()
+    {
+        return getDecorated().isVersion3();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getVersion3()
+    {
+        return getDecorated().getVersion3();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setVersion3( boolean isVersion3 )
+    {
+        getDecorated().setVersion3( isVersion3 );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSaslMechanism()
+    {
+        return getDecorated().getSaslMechanism();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setSaslMechanism( String saslMechanism )
+    {
+        getDecorated().setSaslMechanism( saslMechanism );
+
+        return this;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the BindRequest length
+     * 
+     * BindRequest :
+     * <pre>
+     * 0x60 L1
+     *   |
+     *   +--> 0x02 0x01 (1..127) version
+     *   +--> 0x04 L2 name
+     *   +--> authentication
+     * 
+     * L2 = Length(name)
+     * L3/4 = Length(authentication)
+     * Length(BindRequest) = Length(0x60) + Length(L1) + L1 + Length(0x02) + 1 + 1 +
+     *      Length(0x04) + Length(L2) + L2 + Length(authentication)
+     * </pre>
+     */
+    public int computeLength()
+    {
+        // Initialized with version
+        bindRequestLength = 1 + 1 + 1;
+
+        Dn dn = getDn();
+
+        if ( !Dn.isNullOrEmpty( dn ) )
+        {
+            // A DN has been provided
+            dnBytes = Strings.getBytesUtf8( dn.getName() );
+            int dnLength = dnBytes.length;
+
+            bindRequestLength += 1 + TLV.getNbBytes( dnLength ) + dnLength;
+        }
+        else
+        {
+            // No DN has been provided, let's use the name as a string instead
+            String name = getName();
+
+            if ( Strings.isEmpty( name ) )
+            {
+                name = "";
+            }
+
+            nameBytes = Strings.getBytesUtf8( name );
+
+            bindRequestLength += 1 + TLV.getNbBytes( nameBytes.length ) + nameBytes.length;
+        }
+
+        byte[] credentials = getCredentials();
+
+        // The authentication
+        if ( isSimple() )
+        {
+            // Compute a SimpleBind operation
+            if ( credentials != null )
+            {
+                bindRequestLength += 1 + TLV.getNbBytes( credentials.length ) + credentials.length;
+            }
+            else
+            {
+                bindRequestLength += 1 + 1;
+            }
+        }
+        else
+        {
+            mechanismBytes = Strings.getBytesUtf8( getSaslMechanism() );
+            saslMechanismLength = 1 + TLV.getNbBytes( mechanismBytes.length ) + mechanismBytes.length;
+
+            if ( credentials != null )
+            {
+                saslCredentialsLength = 1 + TLV.getNbBytes( credentials.length ) + credentials.length;
+            }
+
+            int saslLength = 1 + TLV.getNbBytes( saslMechanismLength + saslCredentialsLength ) + saslMechanismLength
+                + saslCredentialsLength;
+
+            bindRequestLength += saslLength;
+        }
+
+        // Return the result.
+        return 1 + TLV.getNbBytes( bindRequestLength ) + bindRequestLength;
+    }
+
+
+    /**
+     * Encode the BindRequest message to a PDU.
+     * 
+     * BindRequest :
+     * <pre>
+     * 0x60 LL
+     *   0x02 LL version         0x80 LL simple
+     *   0x04 LL name           /
+     *   authentication.encode()
+     *                          \ 0x83 LL mechanism [0x04 LL credential]
+     * </pre>
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The BindRequest Tag
+            buffer.put( LdapCodecConstants.BIND_REQUEST_TAG );
+            buffer.put( TLV.getBytes( bindRequestLength ) );
+
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        // The version (LDAP V3 only)
+        BerValue.encode( buffer, 3 );
+
+        Dn dn = getDn();
+
+        if ( !Dn.isNullOrEmpty( dn ) )
+        {
+            // A DN has been provided
+            BerValue.encode( buffer, dnBytes );
+        }
+        else
+        {
+            // No DN has been provided, let's use the name as a string instead
+            BerValue.encode( buffer, nameBytes );
+        }
+
+        byte[] credentials = getCredentials();
+
+        // The authentication
+        if ( isSimple() )
+        {
+            // Simple authentication
+            try
+            {
+                // The simpleAuthentication Tag
+                buffer.put( ( byte ) LdapCodecConstants.BIND_REQUEST_SIMPLE_TAG );
+
+                if ( credentials != null )
+                {
+                    buffer.put( TLV.getBytes( credentials.length ) );
+
+                    if ( credentials.length != 0 )
+                    {
+                        buffer.put( credentials );
+                    }
+                }
+                else
+                {
+                    buffer.put( ( byte ) 0 );
+                }
+            }
+            catch ( BufferOverflowException boe )
+            {
+                String msg = I18n.err( I18n.ERR_04005 );
+                throw new EncoderException( msg, boe );
+            }
+        }
+        else
+        {
+            // SASL Bind
+            try
+            {
+                // The saslAuthentication Tag
+                buffer.put( ( byte ) LdapCodecConstants.BIND_REQUEST_SASL_TAG );
+
+                buffer.put( TLV
+                    .getBytes( saslMechanismLength + saslCredentialsLength ) );
+
+                BerValue.encode( buffer, mechanismBytes );
+
+                if ( credentials != null )
+                {
+                    BerValue.encode( buffer, credentials );
+                }
+            }
+            catch ( BufferOverflowException boe )
+            {
+                String msg = I18n.err( I18n.ERR_04005 );
+                throw new EncoderException( msg, boe );
+            }
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/BindResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/BindResponseDecorator.java
new file mode 100644
index 0000000..1063de2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/BindResponseDecorator.java
@@ -0,0 +1,161 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+
+
+/**
+ * A decorator for the BindResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BindResponseDecorator extends ResponseDecorator<BindResponse> implements BindResponse
+{
+    /** The encoded bindResponse length */
+    private int bindResponseLength;
+
+
+    /**
+     * Makes a BindResponse a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated BindResponse
+     */
+    public BindResponseDecorator( LdapApiService codec, BindResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The BindResponse methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getServerSaslCreds()
+    {
+        return getDecorated().getServerSaslCreds();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setServerSaslCreds( byte[] serverSaslCreds )
+    {
+        getDecorated().setServerSaslCreds( serverSaslCreds );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the BindResponse length 
+     * 
+     * BindResponse : 
+     * <pre>
+     * 0x61 L1 
+     *   | 
+     *   +--> LdapResult
+     *   +--> [serverSaslCreds] 
+     *   
+     * L1 = Length(LdapResult) [ + Length(serverSaslCreds) ] 
+     * Length(BindResponse) = Length(0x61) + Length(L1) + L1
+     * </pre>
+     */
+    public int computeLength()
+    {
+        BindResponse bindResponse = getDecorated();
+        int ldapResultLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        bindResponseLength = ldapResultLength;
+
+        byte[] serverSaslCreds = bindResponse.getServerSaslCreds();
+
+        if ( serverSaslCreds != null )
+        {
+            bindResponseLength += 1 + TLV.getNbBytes( serverSaslCreds.length ) + serverSaslCreds.length;
+        }
+
+        return 1 + TLV.getNbBytes( bindResponseLength ) + bindResponseLength;
+    }
+
+
+    /**
+     * Encode the BindResponse message to a PDU.
+     * 
+     * BindResponse :
+     * <pre>
+     * LdapResult.encode 
+     * [0x87 LL serverSaslCreds]
+     * </pre>
+     * 
+     * @param bb The buffer where to put the PDU
+     * @param bindResponseDecorator The decorated BindResponse to encode
+     * @throws EncoderException when encoding operations fail
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        BindResponse bindResponse = getDecorated();
+
+        try
+        {
+            // The BindResponse Tag
+            buffer.put( LdapCodecConstants.BIND_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( bindResponseLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+
+            // The serverSaslCredential, if any
+            byte[] serverSaslCreds = bindResponse.getServerSaslCreds();
+
+            if ( serverSaslCreds != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.SERVER_SASL_CREDENTIAL_TAG );
+
+                buffer.put( TLV.getBytes( serverSaslCreds.length ) );
+
+                if ( serverSaslCreds.length != 0 )
+                {
+                    buffer.put( serverSaslCreds );
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/CompareRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/CompareRequestDecorator.java
new file mode 100644
index 0000000..683c726
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/CompareRequestDecorator.java
@@ -0,0 +1,277 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the CompareRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CompareRequestDecorator extends SingleReplyRequestDecorator<CompareRequest>
+    implements CompareRequest
+{
+    /** The bytes of the attribute id used in the comparison */
+    private byte[] attrIdBytes;
+
+    /** The bytes of the attribute value used in the comparison */
+    private byte[] attrValBytes;
+
+    /** The compare request length */
+    private int compareRequestLength;
+
+    /** The attribute value assertion length */
+    private int avaLength;
+
+
+    /**
+     * Makes a CompareRequest a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated CompareRequest
+     */
+    public CompareRequestDecorator( LdapApiService codec, CompareRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The CompareRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setName( Dn name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> getAssertionValue()
+    {
+        return getDecorated().getAssertionValue();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAssertionValue( String value )
+    {
+        getDecorated().setAssertionValue( value );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAssertionValue( byte[] value )
+    {
+        getDecorated().setAssertionValue( value );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getAttributeId()
+    {
+        return getDecorated().getAttributeId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAttributeId( String attrId )
+    {
+        getDecorated().setAttributeId( attrId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest addControl( Control control )
+    {
+        return ( CompareRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest addAllControls( Control[] controls )
+    {
+        return ( CompareRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest removeControl( Control control )
+    {
+        return ( CompareRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the CompareRequest length
+     * 
+     * CompareRequest :
+     * 0x6E L1
+     *   |
+     *   +--> 0x04 L2 entry
+     *   +--> 0x30 L3 (ava)
+     *         |
+     *         +--> 0x04 L4 attributeDesc
+     *         +--> 0x04 L5 assertionValue
+     * 
+     * L3 = Length(0x04) + Length(L4) + L4 + Length(0x04) +
+     *      Length(L5) + L5
+     * Length(CompareRequest) = Length(0x6E) + Length(L1) + L1 +
+     *      Length(0x04) + Length(L2) + L2 + Length(0x30) + Length(L3) + L3
+     * 
+     * @return The CompareRequest PDU's length
+     */
+    public int computeLength()
+    {
+        // The entry Dn
+        Dn entry = getName();
+        compareRequestLength = 1 + TLV.getNbBytes( Dn.getNbBytes( entry ) ) + Dn.getNbBytes( entry );
+
+        // The attribute value assertion
+        attrIdBytes = Strings.getBytesUtf8( getAttributeId() );
+        avaLength = 1 + TLV.getNbBytes( attrIdBytes.length ) + attrIdBytes.length;
+
+        org.apache.directory.api.ldap.model.entry.Value<?> assertionValue = getAssertionValue();
+
+        if ( assertionValue instanceof BinaryValue )
+        {
+            attrValBytes = getAssertionValue().getBytes();
+            avaLength += 1 + TLV.getNbBytes( attrValBytes.length ) + attrValBytes.length;
+        }
+        else
+        {
+            attrValBytes = Strings.getBytesUtf8( getAssertionValue().getString() );
+            avaLength += 1 + TLV.getNbBytes( attrValBytes.length ) + attrValBytes.length;
+        }
+
+        compareRequestLength += 1 + TLV.getNbBytes( avaLength ) + avaLength;
+
+        return 1 + TLV.getNbBytes( compareRequestLength ) + compareRequestLength;
+    }
+
+
+    /**
+     * Encode the CompareRequest message to a PDU.
+     * 
+     * CompareRequest :
+     *   0x6E LL
+     *     0x04 LL entry
+     *     0x30 LL attributeValueAssertion
+     *       0x04 LL attributeDesc
+     *       0x04 LL assertionValue
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The CompareRequest Tag
+            buffer.put( LdapCodecConstants.COMPARE_REQUEST_TAG );
+            buffer.put( TLV.getBytes( compareRequestLength ) );
+
+            // The entry
+            BerValue.encode( buffer, Dn.getBytes( getName() ) );
+
+            // The attributeValueAssertion sequence Tag
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+            buffer.put( TLV.getBytes( avaLength ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        // The attributeDesc
+        BerValue.encode( buffer, attrIdBytes );
+
+        // The assertionValue
+        BerValue.encode( buffer, attrValBytes );
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/CompareResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/CompareResponseDecorator.java
new file mode 100644
index 0000000..2f13cc3
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/CompareResponseDecorator.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+
+
+/**
+ * A decorator for the CompareResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CompareResponseDecorator extends ResponseDecorator<CompareResponse>
+    implements CompareResponse
+{
+    /** The encoded compareResponse length */
+    private int compareResponseLength;
+
+
+    /**
+     * Makes a CompareResponse a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated CompareResponse
+     */
+    public CompareResponseDecorator( LdapApiService codec, CompareResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The CompareResponse methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isTrue()
+    {
+        return getDecorated().isTrue();
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the CompareResponse length 
+     * 
+     * CompareResponse :
+     * 
+     * 0x6F L1
+     *  |
+     *  +--> LdapResult
+     * 
+     * L1 = Length(LdapResult)
+     * 
+     * Length(CompareResponse) = Length(0x6F) + Length(L1) + L1
+     */
+    public int computeLength()
+    {
+        compareResponseLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        return 1 + TLV.getNbBytes( compareResponseLength ) + compareResponseLength;
+    }
+
+
+    /**
+     * Encode the CompareResponse message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer )
+        throws EncoderException
+    {
+        try
+        {
+            // The CompareResponse Tag
+            buffer.put( LdapCodecConstants.COMPARE_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( compareResponseLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/DeleteRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/DeleteRequestDecorator.java
new file mode 100644
index 0000000..4189771
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/DeleteRequestDecorator.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the DeleteRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DeleteRequestDecorator extends SingleReplyRequestDecorator<DeleteRequest>
+    implements DeleteRequest
+{
+    /** The bytes containing the Dn */
+    private byte[] dnBytes;
+
+
+    /**
+     * Makes a DeleteRequest a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated DeleteRequest
+     */
+    public DeleteRequestDecorator( LdapApiService codec, DeleteRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The DeleteRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest setName( Dn name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest addControl( Control control )
+    {
+        return ( DeleteRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest addAllControls( Control[] controls )
+    {
+        return ( DeleteRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest removeControl( Control control )
+    {
+        return ( DeleteRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the DelRequest length
+     * 
+     * DelRequest :
+     * 0x4A L1 entry
+     * 
+     * L1 = Length(entry)
+     * Length(DelRequest) = Length(0x4A) + Length(L1) + L1
+     */
+    public int computeLength()
+    {
+        dnBytes = Strings.getBytesUtf8( getName().getName() );
+        int dnLength = dnBytes.length;
+
+        // The entry
+        return 1 + TLV.getNbBytes( dnLength ) + dnLength;
+    }
+
+
+    /**
+     * Encode the DelRequest message to a PDU.
+     * 
+     * DelRequest :
+     * 0x4A LL entry
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The DelRequest Tag
+            buffer.put( LdapCodecConstants.DEL_REQUEST_TAG );
+
+            // The entry
+            buffer.put( TLV.getBytes( dnBytes.length ) );
+            buffer.put( dnBytes );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/DeleteResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/DeleteResponseDecorator.java
new file mode 100644
index 0000000..a8c9b94
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/DeleteResponseDecorator.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+
+
+/**
+ * A decorator for the DeleteRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DeleteResponseDecorator extends ResponseDecorator<DeleteResponse>
+    implements DeleteResponse
+{
+    /** The encoded deleteResponse length */
+    private int deleteResponseLength;
+
+
+    /**
+     * Makes a DeleteResponse a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated DeleteResponse
+     */
+    public DeleteResponseDecorator( LdapApiService codec, DeleteResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the DelResponse length 
+     * 
+     * DelResponse :
+     * 
+     * 0x6B L1
+     *  |
+     *  +--> LdapResult
+     * 
+     * L1 = Length(LdapResult)
+     * 
+     * Length(DelResponse) = Length(0x6B) + Length(L1) + L1
+     */
+    public int computeLength()
+    {
+        deleteResponseLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        return 1 + TLV.getNbBytes( deleteResponseLength ) + deleteResponseLength;
+    }
+
+
+    /**
+     * Encode the DelResponse message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The DelResponse Tag
+            buffer.put( LdapCodecConstants.DEL_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( deleteResponseLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/IntermediateResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/IntermediateResponseDecorator.java
new file mode 100644
index 0000000..5c858a2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/IntermediateResponseDecorator.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the IntermediateResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class IntermediateResponseDecorator extends MessageDecorator<IntermediateResponse>
+    implements IntermediateResponse
+{
+    /** The response name as a byte[] */
+    private byte[] responseNameBytes;
+
+    /** The encoded intermediateResponse length */
+    private int intermediateResponseLength;
+    
+    /** The encoded value as a byte[] */
+    private byte[] encodedValueBytes;
+
+
+    /**
+     * Makes a IntermediateResponse encodable.
+     *
+     * @param decoratedMessage the decorated IntermediateResponse
+     */
+    public IntermediateResponseDecorator( LdapApiService codec, IntermediateResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The IntermediateResponse methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getResponseName()
+    {
+        return getDecorated().getResponseName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setResponseName( String oid )
+    {
+        getDecorated().setResponseName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getResponseValue()
+    {
+        return getDecorated().getResponseValue();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setResponseValue( byte[] value )
+    {
+        getDecorated().setResponseValue( value );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the intermediateResponse length
+     * 
+     * intermediateResponse :
+     * 
+     * 0x79 L1
+     *  |
+     * [+--> 0x80 L2 name
+     * [+--> 0x81 L3 response]]
+     * 
+     * L1 = [ + Length(0x80) + Length(L2) + L2
+     *      [ + Length(0x81) + Length(L3) + L3]]
+     * 
+     * Length(IntermediateResponse) = Length(0x79) + Length(L1) + L1
+     * 
+     * @return The IntermediateResponse length
+     */
+    public int computeLength()
+    {
+        intermediateResponseLength = 0;
+
+        if ( !Strings.isEmpty( getResponseName() ) )
+        {
+            responseNameBytes = Strings.getBytesUtf8( getResponseName() );
+
+            int responseNameLength = responseNameBytes.length;
+            intermediateResponseLength += 1 + TLV.getNbBytes( responseNameLength ) + responseNameLength;
+        }
+
+        encodedValueBytes = getResponseValue();
+
+        if ( encodedValueBytes != null )
+        {
+            intermediateResponseLength += 1 + TLV.getNbBytes( encodedValueBytes.length ) + encodedValueBytes.length;
+        }
+
+        return 1 + TLV.getNbBytes( intermediateResponseLength ) + intermediateResponseLength;
+    }
+
+
+    /**
+     * Encode the IntermediateResponse message to a PDU. 
+     * IntermediateResponse :
+     *   0x79 LL
+     *     [0x80 LL response name]
+     *     [0x81 LL responseValue]
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The ExtendedResponse Tag
+            buffer.put( LdapCodecConstants.INTERMEDIATE_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( intermediateResponseLength ) );
+
+            // The responseName, if any
+            if ( ( responseNameBytes != null ) && ( responseNameBytes.length != 0 ) )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.INTERMEDIATE_RESPONSE_NAME_TAG );
+                buffer.put( TLV.getBytes( responseNameBytes.length ) );
+                buffer.put( responseNameBytes );
+            }
+
+            // The encodedValue, if any
+            if ( encodedValueBytes != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.INTERMEDIATE_RESPONSE_VALUE_TAG );
+
+                buffer.put( TLV.getBytes( encodedValueBytes.length ) );
+
+                if ( encodedValueBytes.length != 0 )
+                {
+                    buffer.put( encodedValueBytes );
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/LdapResultDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/LdapResultDecorator.java
new file mode 100644
index 0000000..6390c6b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/LdapResultDecorator.java
@@ -0,0 +1,310 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.Decorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapEncoder;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the LdapResultResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapResultDecorator implements LdapResult, Decorator<LdapResult>
+{
+    /** The decorated LdapResult */
+    private final LdapResult decoratedLdapResult;
+
+    /** Temporary storage for message bytes */
+    private byte[] errorMessageBytes;
+
+    /** Temporary storage of the byte[] representing the matchedDN */
+    private byte[] matchedDnBytes;
+
+    /** The codec responsible for encoding and decoding this object. */
+    private LdapApiService codec;
+
+    private static final byte[] DEFAULT_SUCCESS = new byte[]
+        { 0x0A, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00 };
+
+
+    /**
+     * Makes a LdapResult encodable.
+     *
+     * @param decoratedLdapResult the decorated LdapResult
+     */
+    public LdapResultDecorator( LdapApiService codec, LdapResult decoratedLdapResult )
+    {
+        this.decoratedLdapResult = decoratedLdapResult;
+        this.codec = codec;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The LdapResult methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return decoratedLdapResult.getResultCode();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setResultCode( ResultCodeEnum resultCode )
+    {
+        decoratedLdapResult.setResultCode( resultCode );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getMatchedDn()
+    {
+        return decoratedLdapResult.getMatchedDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMatchedDn( Dn dn )
+    {
+        decoratedLdapResult.setMatchedDn( dn );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDiagnosticMessage()
+    {
+        return decoratedLdapResult.getDiagnosticMessage();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDiagnosticMessage( String diagnosticMessage )
+    {
+        decoratedLdapResult.setDiagnosticMessage( diagnosticMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isReferral()
+    {
+        return decoratedLdapResult.isReferral();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Referral getReferral()
+    {
+        return decoratedLdapResult.getReferral();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReferral( Referral referral )
+    {
+        decoratedLdapResult.setReferral( referral );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return decoratedLdapResult.toString();
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the LdapResult length 
+     * 
+     * LdapResult : 
+     *   0x0A 01 resultCode (0..80)
+     *   0x04 L1 matchedDN (L1 = Length(matchedDN)) 
+     *   0x04 L2 errorMessage (L2 = Length(errorMessage)) 
+     *   [0x83 L3] referrals 
+     *     | 
+     *     +--> 0x04 L4 referral 
+     *     +--> 0x04 L5 referral 
+     *     +--> ... 
+     *     +--> 0x04 Li referral 
+     *     +--> ... 
+     *     +--> 0x04 Ln referral 
+     *     
+     * L1 = Length(matchedDN) 
+     * L2 = Length(errorMessage) 
+     * L3 = n*Length(0x04) + sum(Length(L4) .. Length(Ln)) + sum(L4..Ln) 
+     * L4..n = Length(0x04) + Length(Li) + Li 
+     * Length(LdapResult) = Length(0x0x0A) +
+     *      Length(0x01) + 1 + Length(0x04) + Length(L1) + L1 + Length(0x04) +
+     *      Length(L2) + L2 + Length(0x83) + Length(L3) + L3
+     */
+    public int computeLength()
+    {
+        if ( decoratedLdapResult.isDefaultSuccess() )
+        {
+            // The length of a default success PDU : 0xA0 0x01 0x00 0x04 0x00 0x04 0x00
+            return DEFAULT_SUCCESS.length;
+        }
+
+        int ldapResultLength = 0;
+
+        // The result code
+        ldapResultLength = 1 + 1 + BerValue.getNbBytes( getResultCode().getValue() );
+
+        // The matchedDN length
+        if ( getMatchedDn() == null )
+        {
+            ldapResultLength += 1 + 1;
+        }
+        else
+        {
+            matchedDnBytes = Strings.getBytesUtf8Ascii( Strings.trimLeft( getMatchedDn().getName() ) );
+            ldapResultLength += 1 + TLV.getNbBytes( matchedDnBytes.length ) + matchedDnBytes.length;
+        }
+
+        // The errorMessage length
+        errorMessageBytes = Strings.getBytesUtf8Ascii( getDiagnosticMessage() );
+        ldapResultLength += 1 + TLV.getNbBytes( errorMessageBytes.length ) + errorMessageBytes.length;
+
+        int referralLength = LdapEncoder.computeReferralLength( getReferral() );
+
+        if ( referralLength != 0 )
+        {
+            // The referrals
+            ldapResultLength += 1 + TLV.getNbBytes( referralLength ) + referralLength;
+        }
+
+        return ldapResultLength;
+    }
+
+
+    /**
+     * Encode the LdapResult message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        if ( decoratedLdapResult.isDefaultSuccess() )
+        {
+            // The length of a default success PDU : 0xA0 0x01 0x00 0x04 0x00 0x04 0x00
+            buffer.put( DEFAULT_SUCCESS );
+
+            return buffer;
+        }
+
+        try
+        {
+            // The result code
+            BerValue.encodeEnumerated( buffer, getResultCode().getValue() );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        // The matchedDN
+        BerValue.encode( buffer, matchedDnBytes );
+
+        // The error message
+        BerValue.encode( buffer, errorMessageBytes );
+
+        // The referrals, if any
+        Referral referral = getReferral();
+
+        if ( referral != null )
+        {
+            LdapEncoder.encodeReferral( buffer, referral );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapResult getDecorated()
+    {
+        return decoratedLdapResult;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDefaultSuccess()
+    {
+        return decoratedLdapResult.isDefaultSuccess();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyDnRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyDnRequestDecorator.java
new file mode 100644
index 0000000..eda5ce1
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyDnRequestDecorator.java
@@ -0,0 +1,293 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the ModifyDnRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyDnRequestDecorator extends SingleReplyRequestDecorator<ModifyDnRequest>
+    implements ModifyDnRequest
+{
+    /** The modify Dn request length */
+    private int modifyDnRequestLength;
+
+
+    /**
+     * Makes a ModifyDnRequest encodable.
+     *
+     * @param decoratedMessage the decorated ModifyDnRequest
+     */
+    public ModifyDnRequestDecorator( LdapApiService codec, ModifyDnRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The ModifyDnResponse methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setName( Dn name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Rdn getNewRdn()
+    {
+        return getDecorated().getNewRdn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setNewRdn( Rdn newRdn )
+    {
+        getDecorated().setNewRdn( newRdn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getDeleteOldRdn()
+    {
+        return getDecorated().getDeleteOldRdn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setDeleteOldRdn( boolean deleteOldRdn )
+    {
+        getDecorated().setDeleteOldRdn( deleteOldRdn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getNewSuperior()
+    {
+        return getDecorated().getNewSuperior();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setNewSuperior( Dn newSuperior )
+    {
+        getDecorated().setNewSuperior( newSuperior );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isMove()
+    {
+        return getDecorated().isMove();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest addControl( Control control )
+    {
+        return ( ModifyDnRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest addAllControls( Control[] controls )
+    {
+        return ( ModifyDnRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest removeControl( Control control )
+    {
+        return ( ModifyDnRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the ModifyDNRequest length
+     * 
+     * ModifyDNRequest :
+     * <pre>
+     * 0x6C L1
+     *  |
+     *  +--> 0x04 L2 entry
+     *  +--> 0x04 L3 newRDN
+     *  +--> 0x01 0x01 (true/false) deleteOldRDN (3 bytes)
+     * [+--> 0x80 L4 newSuperior ] 
+     * 
+     * L2 = Length(0x04) + Length(Length(entry)) + Length(entry) 
+     * L3 = Length(0x04) + Length(Length(newRDN)) + Length(newRDN) 
+     * L4 = Length(0x80) + Length(Length(newSuperior)) + Length(newSuperior)
+     * L1 = L2 + L3 + 3 [+ L4] 
+     * 
+     * Length(ModifyDNRequest) = Length(0x6C) + Length(L1) + L1
+     * </pre>
+     * 
+     * @return The PDU's length of a ModifyDN Request
+     */
+    public int computeLength()
+    {
+        int newRdnlength = Strings.getBytesUtf8( getNewRdn().getName() ).length;
+
+        // deleteOldRDN
+        modifyDnRequestLength = 1 + TLV.getNbBytes( Dn.getNbBytes( getName() ) )
+            + Dn.getNbBytes( getName() ) + 1 + TLV.getNbBytes( newRdnlength ) + newRdnlength + 1 + 1
+            + 1;
+
+        if ( getNewSuperior() != null )
+        {
+            modifyDnRequestLength += 1 + TLV.getNbBytes( Dn.getNbBytes( getNewSuperior() ) )
+                + Dn.getNbBytes( getNewSuperior() );
+        }
+
+        return 1 + TLV.getNbBytes( modifyDnRequestLength ) + modifyDnRequestLength;
+    }
+
+
+    /**
+     * Encode the ModifyDNRequest message to a PDU. 
+     * 
+     * ModifyDNRequest :
+     * <pre>
+     * 0x6C LL
+     *   0x04 LL entry
+     *   0x04 LL newRDN
+     *   0x01 0x01 deleteOldRDN
+     *   [0x80 LL newSuperior]
+     * </pre>
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The ModifyDNRequest Tag
+            buffer.put( LdapCodecConstants.MODIFY_DN_REQUEST_TAG );
+            buffer.put( TLV.getBytes( modifyDnRequestLength ) );
+
+            // The entry
+
+            BerValue.encode( buffer, Dn.getBytes( getName() ) );
+
+            // The newRDN
+            BerValue.encode( buffer, getNewRdn().getName() );
+
+            // The flag deleteOldRdn
+            BerValue.encode( buffer, getDeleteOldRdn() );
+
+            // The new superior, if any
+            if ( getNewSuperior() != null )
+            {
+                // Encode the reference
+                buffer.put( ( byte ) LdapCodecConstants.MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG );
+
+                int newSuperiorLength = Dn.getNbBytes( getNewSuperior() );
+
+                buffer.put( TLV.getBytes( newSuperiorLength ) );
+
+                if ( newSuperiorLength != 0 )
+                {
+                    buffer.put( Dn.getBytes( getNewSuperior() ) );
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyDnResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyDnResponseDecorator.java
new file mode 100644
index 0000000..f124541
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyDnResponseDecorator.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+
+
+/**
+ * A decorator for the ModifyDnResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyDnResponseDecorator extends ResponseDecorator<ModifyDnResponse>
+    implements ModifyDnResponse
+{
+    /** The encoded modifyDnResponse length */
+    private int modifyDnResponseLength;
+
+
+    /**
+     * Makes a ModifyDnResponse encodable.
+     *
+     * @param decoratedMessage the decorated ModifyDnResponse
+     */
+    public ModifyDnResponseDecorator( LdapApiService codec, ModifyDnResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+    /**
+     * Compute the ModifyDNResponse length 
+     * 
+     * ModifyDNResponse : 
+     * <pre>
+     * 0x6D L1 
+     *   | 
+     *   +--> LdapResult 
+     *   
+     * L1 = Length(LdapResult) 
+     * Length(ModifyDNResponse) = Length(0x6D) + Length(L1) + L1
+     * </pre>
+     */
+    public int computeLength()
+    {
+        modifyDnResponseLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        return 1 + TLV.getNbBytes( modifyDnResponseLength ) + modifyDnResponseLength;
+    }
+
+
+    /**
+     * Encode the ModifyDnResponse message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The ModifyResponse Tag
+            buffer.put( LdapCodecConstants.MODIFY_DN_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( modifyDnResponseLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyRequestDecorator.java
new file mode 100644
index 0000000..f005879
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyRequestDecorator.java
@@ -0,0 +1,580 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * A decorator for the ModifyRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyRequestDecorator extends SingleReplyRequestDecorator<ModifyRequest>
+    implements ModifyRequest
+{
+    /** The modify request length */
+    private int modifyRequestLength;
+
+    /** The changes length */
+    private int changesLength;
+
+    /** The list of all change lengths */
+    private List<Integer> changeLength;
+
+    /** The list of all the modification lengths */
+    private List<Integer> modificationLength;
+
+    /** The list of all the value lengths */
+    private List<Integer> valuesLength;
+
+    /** The current attribute being decoded */
+    private Attribute currentAttribute;
+
+    /** A local storage for the operation */
+    private ModificationOperation currentOperation;
+
+
+    /**
+     * Makes a ModifyRequest encodable.
+     *
+     * @param decoratedMessage the decorated ModifyRequest
+     */
+    public ModifyRequestDecorator( LdapApiService codec, ModifyRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * Store the current operation
+     * 
+     * @param currentOperation The currentOperation to set.
+     */
+    public void setCurrentOperation( int currentOperation )
+    {
+        this.currentOperation = ModificationOperation.getOperation( currentOperation );
+    }
+
+
+    /**
+     * Add a new attributeTypeAndValue
+     * 
+     * @param type The attribute's name
+     */
+    public void addAttributeTypeAndValues( String type )
+    {
+        currentAttribute = new DefaultAttribute( type );
+
+        Modification modification = new DefaultModification( currentOperation, currentAttribute );
+        getDecorated().addModification( modification );
+    }
+
+
+    /**
+     * Return the current attribute's type
+     */
+    public String getCurrentAttributeType()
+    {
+        return currentAttribute.getUpId();
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( byte[] value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( String value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The ModifyRequest methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return getDecorated().getName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest setName( Dn name )
+    {
+        getDecorated().setName( name );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<Modification> getModifications()
+    {
+        return getDecorated().getModifications();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addModification( Modification mod )
+    {
+        getDecorated().addModification( mod );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest removeModification( Modification mod )
+    {
+        getDecorated().removeModification( mod );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName, String... attributeValue )
+    {
+        getDecorated().remove( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName, byte[]... attributeValue )
+    {
+        getDecorated().remove( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( Attribute attr )
+    {
+        getDecorated().remove( attr );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName )
+    {
+        getDecorated().remove( attributeName );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addModification( Attribute attr, ModificationOperation modOp )
+    {
+        getDecorated().addModification( attr, modOp );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest add( String attributeName, String... attributeValue )
+    {
+        getDecorated().add( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest add( String attributeName, byte[]... attributeValue )
+    {
+        getDecorated().add( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest add( Attribute attr )
+    {
+        getDecorated().add( attr );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( String attributeName )
+    {
+        getDecorated().replace( attributeName );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( String attributeName, String... attributeValue )
+    {
+        getDecorated().replace( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( String attributeName, byte[]... attributeValue )
+    {
+        getDecorated().replace( attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest replace( Attribute attr )
+    {
+        getDecorated().replace( attr );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addControl( Control control )
+    {
+        return ( ModifyRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addAllControls( Control[] controls )
+    {
+        return ( ModifyRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest removeControl( Control control )
+    {
+        return ( ModifyRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the ModifyRequest length 
+     * 
+     * ModifyRequest :
+     * 
+     * 0x66 L1
+     *  |
+     *  +--> 0x04 L2 object
+     *  +--> 0x30 L3 modifications
+     *        |
+     *        +--> 0x30 L4-1 modification sequence
+     *        |     |
+     *        |     +--> 0x0A 0x01 (0..2) operation
+     *        |     +--> 0x30 L5-1 modification
+     *        |           |
+     *        |           +--> 0x04 L6-1 type
+     *        |           +--> 0x31 L7-1 vals
+     *        |                 |
+     *        |                 +--> 0x04 L8-1-1 attributeValue
+     *        |                 +--> 0x04 L8-1-2 attributeValue
+     *        |                 +--> ...
+     *        |                 +--> 0x04 L8-1-i attributeValue
+     *        |                 +--> ...
+     *        |                 +--> 0x04 L8-1-n attributeValue
+     *        |
+     *        +--> 0x30 L4-2 modification sequence
+     *        .     |
+     *        .     +--> 0x0A 0x01 (0..2) operation
+     *        .     +--> 0x30 L5-2 modification
+     *                    |
+     *                    +--> 0x04 L6-2 type
+     *                    +--> 0x31 L7-2 vals
+     *                          |
+     *                          +--> 0x04 L8-2-1 attributeValue
+     *                          +--> 0x04 L8-2-2 attributeValue
+     *                          +--> ...
+     *                          +--> 0x04 L8-2-i attributeValue
+     *                          +--> ...
+     *                          +--> 0x04 L8-2-n attributeValue
+     */
+    public int computeLength()
+    {
+        // Initialized with name
+        modifyRequestLength = 1 + TLV.getNbBytes( Dn.getNbBytes( getName() ) )
+            + Dn.getNbBytes( getName() );
+
+        // All the changes length
+        changesLength = 0;
+
+        Collection<Modification> modifications = getModifications();
+
+        if ( ( modifications != null ) && ( modifications.size() != 0 ) )
+        {
+            changeLength = new LinkedList<Integer>();
+            modificationLength = new LinkedList<Integer>();
+            valuesLength = new LinkedList<Integer>();
+
+            for ( Modification modification : modifications )
+            {
+                // Modification sequence length initialized with the operation
+                int localModificationSequenceLength = 1 + 1 + 1;
+                int localValuesLength = 0;
+
+                // Modification length initialized with the type
+                int typeLength = modification.getAttribute().getUpId().length();
+                int localModificationLength = 1 + TLV.getNbBytes( typeLength ) + typeLength;
+
+                // Get all the values
+                if ( modification.getAttribute().size() != 0 )
+                {
+                    for ( Value<?> value : modification.getAttribute() )
+                    {
+                        localValuesLength += 1 + TLV.getNbBytes( value.getBytes().length ) + value.getBytes().length;
+                    }
+                }
+
+                localModificationLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
+
+                // Compute the modificationSequenceLength
+                localModificationSequenceLength += 1 + TLV.getNbBytes( localModificationLength )
+                    + localModificationLength;
+
+                // Add the tag and the length
+                changesLength += 1 + TLV.getNbBytes( localModificationSequenceLength )
+                    + localModificationSequenceLength;
+
+                // Store the arrays of values
+                valuesLength.add( localValuesLength );
+                modificationLength.add( localModificationLength );
+                changeLength.add( localModificationSequenceLength );
+            }
+
+            // Add the modifications length to the modificationRequestLength
+            modifyRequestLength += 1 + TLV.getNbBytes( changesLength ) + changesLength;
+        }
+
+        return 1 + TLV.getNbBytes( modifyRequestLength ) + modifyRequestLength;
+    }
+
+
+    /**
+     * Encode the ModifyRequest message to a PDU. 
+     * 
+     * ModifyRequest : 
+     * <pre>
+     * 0x66 LL
+     *   0x04 LL object
+     *   0x30 LL modifiations
+     *     0x30 LL modification sequence
+     *       0x0A 0x01 operation
+     *       0x30 LL modification
+     *         0x04 LL type
+     *         0x31 LL vals
+     *           0x04 LL attributeValue
+     *           ... 
+     *           0x04 LL attributeValue
+     *     ... 
+     *     0x30 LL modification sequence
+     *       0x0A 0x01 operation
+     *       0x30 LL modification
+     *         0x04 LL type
+     *         0x31 LL vals
+     *           0x04 LL attributeValue
+     *           ... 
+     *           0x04 LL attributeValue
+     * </pre>
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The AddRequest Tag
+            buffer.put( LdapCodecConstants.MODIFY_REQUEST_TAG );
+            buffer.put( TLV.getBytes( modifyRequestLength ) );
+
+            // The entry
+            BerValue.encode( buffer, Dn.getBytes( getName() ) );
+
+            // The modifications sequence
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+            buffer.put( TLV.getBytes( changesLength ) );
+
+            // The modifications list
+            Collection<Modification> modifications = getModifications();
+
+            if ( ( modifications != null ) && ( modifications.size() != 0 ) )
+            {
+                int modificationNumber = 0;
+
+                // Compute the modifications length
+                for ( Modification modification : modifications )
+                {
+                    // The modification sequence
+                    buffer.put( UniversalTag.SEQUENCE.getValue() );
+                    int localModificationSequenceLength = changeLength.get( modificationNumber );
+                    buffer.put( TLV.getBytes( localModificationSequenceLength ) );
+
+                    // The operation. The value has to be changed, it's not
+                    // the same value in DirContext and in RFC 2251.
+                    buffer.put( UniversalTag.ENUMERATED.getValue() );
+                    buffer.put( ( byte ) 1 );
+                    buffer.put( ( byte ) modification.getOperation().getValue() );
+
+                    // The modification
+                    buffer.put( UniversalTag.SEQUENCE.getValue() );
+                    int localModificationLength = modificationLength.get( modificationNumber );
+                    buffer.put( TLV.getBytes( localModificationLength ) );
+
+                    // The modification type
+                    BerValue.encode( buffer, modification.getAttribute().getUpId() );
+
+                    // The values
+                    buffer.put( UniversalTag.SET.getValue() );
+                    int localValuesLength = valuesLength.get( modificationNumber );
+                    buffer.put( TLV.getBytes( localValuesLength ) );
+
+                    if ( modification.getAttribute().size() != 0 )
+                    {
+                        for ( org.apache.directory.api.ldap.model.entry.Value<?> value : modification.getAttribute() )
+                        {
+                            if ( value.isHumanReadable() )
+                            {
+                                BerValue.encode( buffer, value.getString() );
+                            }
+                            else
+                            {
+                                BerValue.encode( buffer, value.getBytes() );
+                            }
+                        }
+                    }
+
+                    // Go to the next modification number;
+                    modificationNumber++;
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyResponseDecorator.java
new file mode 100644
index 0000000..f017405
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ModifyResponseDecorator.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+
+
+/**
+ * A decorator for the ModifyResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyResponseDecorator extends ResponseDecorator<ModifyResponse>
+    implements ModifyResponse
+{
+    /** The encoded modifyResponse length */
+    private int modifyResponseLength;
+
+
+    /**
+     * Makes a ModifyResponse encodable.
+     *
+     * @param decoratedMessage the decorated ModifyResponse
+     */
+    public ModifyResponseDecorator( LdapApiService codec, ModifyResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the ModifyResponse length 
+     * 
+     * ModifyResponse : 
+     * <pre>
+     * 0x67 L1 
+     *   | 
+     *   +--> LdapResult 
+     *   
+     * L1 = Length(LdapResult) 
+     * Length(ModifyResponse) = Length(0x67) + Length(L1) + L1
+     * </pre>
+     */
+    public int computeLength()
+    {
+        modifyResponseLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        return 1 + TLV.getNbBytes( modifyResponseLength ) + modifyResponseLength;
+    }
+
+
+    /**
+     * Encode the ModifyResponse message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The ModifyResponse Tag
+            buffer.put( LdapCodecConstants.MODIFY_RESPONSE_TAG );
+            buffer.put( TLV.getBytes( modifyResponseLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/RequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/RequestDecorator.java
new file mode 100644
index 0000000..b79756e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/RequestDecorator.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Request;
+
+
+/**
+ * A decorator for the LdapResultResponse message
+ *
+ * @TODO make this extend AbstractDsmlMessageDecorator instead of codec's 
+ * MessageDecorator.
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class RequestDecorator<M extends Request> extends MessageDecorator<M> implements Request
+{
+    /**
+     * Makes Request a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated message
+     */
+    public RequestDecorator( LdapApiService codec, M decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasResponse()
+    {
+        return ( getDecorated() ).hasResponse();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ResponseDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ResponseDecorator.java
new file mode 100644
index 0000000..d1e0719
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ResponseDecorator.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+
+
+/**
+ * A decorator for the Response message. It will store the LdapResult.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class ResponseDecorator<M extends ResultResponse> extends MessageDecorator<M> implements ResultResponse
+{
+    /** The LdapResult decorator */
+    private LdapResultDecorator ldapResultDecorator;
+
+
+    /**
+     * Makes a AddRequest encodable.
+     *
+     * @param decoratedMessage the decorated AddRequest
+     */
+    public ResponseDecorator( LdapApiService codec, M decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+
+        ldapResultDecorator = new LdapResultDecorator( codec, ( ( ResultResponse ) decoratedMessage ).getLdapResult() );
+    }
+
+
+    /**
+     * @return the ldapResultDecorator
+     */
+    public LdapResult getLdapResult()
+    {
+        return ldapResultDecorator;
+    }
+
+
+    /**
+     * @param ldapResultDecorator the ldapResultDecorator to set
+     */
+    public void setLdapResult( LdapResultDecorator ldapResultDecorator )
+    {
+        this.ldapResultDecorator = ldapResultDecorator;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ResultResponseRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ResultResponseRequestDecorator.java
new file mode 100644
index 0000000..a250965
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/ResultResponseRequestDecorator.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.ResultResponse;
+import org.apache.directory.api.ldap.model.message.ResultResponseRequest;
+
+
+/**
+ * A decorator for the LdapResultResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class ResultResponseRequestDecorator<M extends ResultResponseRequest>
+    extends RequestDecorator<M> implements ResultResponseRequest
+{
+    /**
+     * Makes Request a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated message
+     */
+    public ResultResponseRequestDecorator( LdapApiService codec, M decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasResponse()
+    {
+        return getDecorated().hasResponse();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ResultResponse getResultResponse()
+    {
+        return getDecorated().getResultResponse();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchRequestDecorator.java
new file mode 100644
index 0000000..f60e169
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchRequestDecorator.java
@@ -0,0 +1,1125 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.AttributeValueAssertion;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.search.AndFilter;
+import org.apache.directory.api.ldap.codec.search.AttributeValueAssertionFilter;
+import org.apache.directory.api.ldap.codec.search.ConnectorFilter;
+import org.apache.directory.api.ldap.codec.search.ExtensibleMatchFilter;
+import org.apache.directory.api.ldap.codec.search.Filter;
+import org.apache.directory.api.ldap.codec.search.NotFilter;
+import org.apache.directory.api.ldap.codec.search.OrFilter;
+import org.apache.directory.api.ldap.codec.search.PresentFilter;
+import org.apache.directory.api.ldap.codec.search.SubstringFilter;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.ApproximateNode;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.BranchNormalizedVisitor;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.api.ldap.model.filter.LeafNode;
+import org.apache.directory.api.ldap.model.filter.LessEqNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.apache.directory.api.ldap.model.filter.SimpleNode;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.apache.directory.api.ldap.model.message.AbandonListener;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the SearchRequest message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchRequestDecorator extends MessageDecorator<SearchRequest> implements SearchRequest
+{
+    /** The searchRequest length */
+    private int searchRequestLength;
+
+    /** The attributeDescriptionList length */
+    private int attributeDescriptionListLength;
+
+    /** A temporary storage for a terminal Filter */
+    private Filter terminalFilter;
+
+    /** The current filter. This is used while decoding a PDU */
+    private Filter currentFilter;
+
+    /** The global filter. This is used while decoding a PDU */
+    private Filter topFilter;
+
+    /** The SearchRequest TLV id */
+    private int tlvId;
+
+    /** The bytes containing the Dn */
+    private byte[] dnBytes;
+
+
+    /**
+     * Makes a SearchRequest encodable.
+     *
+     * @param decoratedMessage the decorated SearchRequest
+     */
+    public SearchRequestDecorator( LdapApiService codec, SearchRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * Set the SearchRequest PDU TLV's Id
+     * @param tlvId The TLV id
+     */
+    public void setTlvId( int tlvId )
+    {
+        this.tlvId = tlvId;
+    }
+
+
+    public Filter getCurrentFilter()
+    {
+        return currentFilter;
+    }
+
+
+    /**
+     * Gets the search filter associated with this search request.
+     *
+     * @return the expression node for the root of the filter expression tree.
+     */
+    public Filter getCodecFilter()
+    {
+        return topFilter;
+    }
+
+
+    /**
+     * Gets the search filter associated with this search request.
+     *
+     * @return the expression node for the root of the filter expression tree.
+     */
+    public ExprNode getFilterNode()
+    {
+        return transform( topFilter );
+    }
+
+
+    /**
+     * Get the terminal filter
+     *
+     * @return Returns the terminal filter.
+     */
+    public Filter getTerminalFilter()
+    {
+        return terminalFilter;
+    }
+
+
+    /**
+     * Set the terminal filter
+     *
+     * @param terminalFilter the teminalFilter.
+     */
+    public void setTerminalFilter( Filter terminalFilter )
+    {
+        this.terminalFilter = terminalFilter;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setFilter( ExprNode filter )
+    {
+        topFilter = transform( filter );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setFilter( String filter ) throws LdapException
+    {
+        getDecorated().setFilter( filter );
+        this.currentFilter = transform( getDecorated().getFilter() );
+
+        return this;
+    }
+
+
+    /**
+     * Set the current filter
+     *
+     * @param filter The filter to set.
+     */
+    public void setCurrentFilter( Filter filter )
+    {
+        currentFilter = filter;
+    }
+
+
+    /**
+     * Add a current filter. We have two cases :
+     * - there is no previous current filter : the filter
+     * is the top level filter
+     * - there is a previous current filter : the filter is added
+     * to the currentFilter set, and the current filter is changed
+     *
+     * In any case, the previous current filter will always be a
+     * ConnectorFilter when this method is called.
+     *
+     * @param localFilter The filter to set.
+     */
+    public void addCurrentFilter( Filter localFilter ) throws DecoderException
+    {
+        if ( currentFilter != null )
+        {
+            // Ok, we have a parent. The new Filter will be added to
+            // this parent, and will become the currentFilter if it's a connector.
+            ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter );
+            localFilter.setParent( currentFilter, currentFilter.getTlvId() );
+
+            if ( localFilter instanceof ConnectorFilter )
+            {
+                currentFilter = localFilter;
+            }
+        }
+        else
+        {
+            // No parent. This Filter will become the root.
+            currentFilter = localFilter;
+            currentFilter.setParent( null, tlvId );
+            topFilter = localFilter;
+        }
+    }
+
+
+    /**
+     * This method is used to clear the filter's stack for terminated elements. An element
+     * is considered as terminated either if :
+     *  - it's a final element (ie an element which cannot contains a Filter)
+     *  - its current length equals its expected length.
+     *
+     * @param container The container being decoded
+     */
+    @SuppressWarnings("unchecked")
+    public void unstackFilters( Asn1Container container )
+    {
+        LdapMessageContainer<MessageDecorator<Message>> ldapMessageContainer =
+            ( LdapMessageContainer<MessageDecorator<Message>> ) container;
+
+        TLV tlv = ldapMessageContainer.getCurrentTLV();
+        TLV localParent = tlv.getParent();
+        Filter localFilter = terminalFilter;
+
+        // The parent has been completed, so fold it
+        while ( ( localParent != null ) && ( localParent.getExpectedLength() == 0 ) )
+        {
+            int parentTlvId = localFilter.getParent() != null ? localFilter.getParent().getTlvId() : localFilter
+                .getParentTlvId();
+
+            if ( localParent.getId() != parentTlvId )
+            {
+                localParent = localParent.getParent();
+            }
+            else
+            {
+                Filter filterParent = localFilter.getParent();
+
+                // We have a special case with PresentFilter, which has not been
+                // pushed on the stack, so we need to get its parent's parent
+                if ( localFilter instanceof PresentFilter )
+                {
+                    if ( filterParent == null )
+                    {
+                        // We don't have parent, get out
+                        break;
+                    }
+
+                    filterParent = filterParent.getParent();
+                }
+                else
+                {
+                    filterParent = filterParent.getParent();
+                }
+
+                if ( filterParent != null )
+                {
+                    // The parent is a filter ; it will become the new currentFilter
+                    // and we will loop again.
+                    localFilter = currentFilter;
+                    currentFilter = filterParent;
+                    localParent = localParent.getParent();
+                }
+                else
+                {
+                    // We can stop the recursion, we have reached the searchResult Object
+                    break;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Transform the Filter part of a SearchRequest to an ExprNode
+     *
+     * @param filter The filter to be transformed
+     * @return An ExprNode
+     */
+    @SuppressWarnings(
+        { "unchecked", "rawtypes" })
+    private ExprNode transform( Filter filter )
+    {
+        if ( filter != null )
+        {
+            // Transform OR, AND or NOT leaves
+            if ( filter instanceof ConnectorFilter )
+            {
+                BranchNode branch = null;
+
+                if ( filter instanceof AndFilter )
+                {
+                    branch = new AndNode();
+                }
+                else if ( filter instanceof OrFilter )
+                {
+                    branch = new OrNode();
+                }
+                else if ( filter instanceof NotFilter )
+                {
+                    branch = new NotNode();
+                }
+
+                List<Filter> filtersSet = ( ( ConnectorFilter ) filter ).getFilterSet();
+
+                // Loop on all AND/OR children
+                if ( filtersSet != null )
+                {
+                    for ( Filter node : filtersSet )
+                    {
+                        branch.addNode( transform( node ) );
+                    }
+                }
+
+                return branch;
+            }
+            else
+            {
+                // Transform PRESENT or ATTRIBUTE_VALUE_ASSERTION
+                LeafNode branch = null;
+
+                if ( filter instanceof PresentFilter )
+                {
+                    branch = new PresenceNode( ( ( PresentFilter ) filter ).getAttributeDescription() );
+                }
+                else if ( filter instanceof AttributeValueAssertionFilter )
+                {
+                    AttributeValueAssertion ava = ( ( AttributeValueAssertionFilter ) filter ).getAssertion();
+
+                    // Transform =, >=, <=, ~= filters
+                    int filterType = ( ( AttributeValueAssertionFilter ) filter ).getFilterType();
+                    switch ( filterType )
+                    {
+                        case LdapCodecConstants.EQUALITY_MATCH_FILTER:
+                            branch = new EqualityNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
+                            branch = new GreaterEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
+                            branch = new LessEqNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        case LdapCodecConstants.APPROX_MATCH_FILTER:
+                            branch = new ApproximateNode( ava.getAttributeDesc(), ava.getAssertionValue() );
+                            break;
+
+                        default:
+                            throw new IllegalArgumentException( "Unexpected filter type: " + filterType );
+                    }
+
+                }
+                else if ( filter instanceof SubstringFilter )
+                {
+                    // Transform Substring filters
+                    SubstringFilter substrFilter = ( SubstringFilter ) filter;
+                    String initialString = null;
+                    String finalString = null;
+                    List<String> anyString = null;
+
+                    if ( substrFilter.getInitialSubstrings() != null )
+                    {
+                        initialString = substrFilter.getInitialSubstrings();
+                    }
+
+                    if ( substrFilter.getFinalSubstrings() != null )
+                    {
+                        finalString = substrFilter.getFinalSubstrings();
+                    }
+
+                    if ( substrFilter.getAnySubstrings() != null )
+                    {
+                        anyString = new ArrayList<String>();
+
+                        for ( String any : substrFilter.getAnySubstrings() )
+                        {
+                            anyString.add( any );
+                        }
+                    }
+
+                    branch = new SubstringNode( anyString, substrFilter.getType(), initialString, finalString );
+                }
+                else if ( filter instanceof ExtensibleMatchFilter )
+                {
+                    // Transform Extensible Match Filter
+                    ExtensibleMatchFilter extFilter = ( ExtensibleMatchFilter ) filter;
+                    String matchingRule = null;
+
+                    Value<?> value = extFilter.getMatchValue();
+
+                    if ( extFilter.getMatchingRule() != null )
+                    {
+                        matchingRule = extFilter.getMatchingRule();
+                    }
+
+                    branch = new ExtensibleNode( extFilter.getType(), value, matchingRule, extFilter.isDnAttributes() );
+                }
+
+                return branch;
+            }
+        }
+        else
+        {
+            // We have found nothing to transform. Return null then.
+            return null;
+        }
+    }
+
+
+    /**
+     * Transform an ExprNode filter to a Filter
+     *
+     * @param exprNode The filter to be transformed
+     * @return A filter
+     */
+    private static Filter transform( ExprNode exprNode )
+    {
+        if ( exprNode != null )
+        {
+            Filter filter = null;
+
+            // Transform OR, AND or NOT leaves
+            if ( exprNode instanceof BranchNode )
+            {
+                if ( exprNode instanceof AndNode )
+                {
+                    filter = new AndFilter();
+                }
+                else if ( exprNode instanceof OrNode )
+                {
+                    filter = new OrFilter();
+                }
+                else if ( exprNode instanceof NotNode )
+                {
+                    filter = new NotFilter();
+                }
+
+                List<ExprNode> children = ( ( BranchNode ) exprNode ).getChildren();
+
+                // Loop on all AND/OR children
+                if ( children != null )
+                {
+                    for ( ExprNode child : children )
+                    {
+                        try
+                        {
+                            ( ( ConnectorFilter ) filter ).addFilter( transform( child ) );
+                        }
+                        catch ( DecoderException de )
+                        {
+                            return null;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if ( exprNode instanceof PresenceNode )
+                {
+                    // Transform Presence Node
+                    filter = new PresentFilter();
+                    ( ( PresentFilter ) filter ).setAttributeDescription( ( ( PresenceNode ) exprNode ).getAttribute() );
+                }
+                else if ( exprNode instanceof SimpleNode<?> )
+                {
+                    if ( exprNode instanceof EqualityNode<?> )
+                    {
+                        filter = new AttributeValueAssertionFilter( LdapCodecConstants.EQUALITY_MATCH_FILTER );
+                        AttributeValueAssertion assertion = new AttributeValueAssertion();
+                        assertion.setAttributeDesc( ( ( EqualityNode<?> ) exprNode ).getAttribute() );
+                        assertion.setAssertionValue( ( ( EqualityNode<?> ) exprNode ).getValue() );
+                        ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion );
+                    }
+                    else if ( exprNode instanceof GreaterEqNode<?> )
+                    {
+                        filter = new AttributeValueAssertionFilter( LdapCodecConstants.GREATER_OR_EQUAL_FILTER );
+                        AttributeValueAssertion assertion = new AttributeValueAssertion();
+                        assertion.setAttributeDesc( ( ( GreaterEqNode<?> ) exprNode ).getAttribute() );
+                        assertion.setAssertionValue( ( ( GreaterEqNode<?> ) exprNode ).getValue() );
+                        ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion );
+                    }
+                    else if ( exprNode instanceof LessEqNode<?> )
+                    {
+                        filter = new AttributeValueAssertionFilter( LdapCodecConstants.LESS_OR_EQUAL_FILTER );
+                        AttributeValueAssertion assertion = new AttributeValueAssertion();
+                        assertion.setAttributeDesc( ( ( LessEqNode<?> ) exprNode ).getAttribute() );
+                        assertion.setAssertionValue( ( ( LessEqNode<?> ) exprNode ).getValue() );
+                        ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion );
+                    }
+                    else if ( exprNode instanceof ApproximateNode<?> )
+                    {
+                        filter = new AttributeValueAssertionFilter( LdapCodecConstants.APPROX_MATCH_FILTER );
+                        AttributeValueAssertion assertion = new AttributeValueAssertion();
+                        assertion.setAttributeDesc( ( ( ApproximateNode<?> ) exprNode ).getAttribute() );
+                        assertion.setAssertionValue( ( ( ApproximateNode<?> ) exprNode ).getValue() );
+                        ( ( AttributeValueAssertionFilter ) filter ).setAssertion( assertion );
+                    }
+                }
+                else if ( exprNode instanceof SubstringNode )
+                {
+                    // Transform Substring Nodes
+                    filter = new SubstringFilter();
+
+                    ( ( SubstringFilter ) filter ).setType( ( ( SubstringNode ) exprNode ).getAttribute() );
+                    String initialString = ( ( SubstringNode ) exprNode ).getInitial();
+                    String finalString = ( ( SubstringNode ) exprNode ).getFinal();
+                    List<String> anyStrings = ( ( SubstringNode ) exprNode ).getAny();
+
+                    if ( initialString != null )
+                    {
+                        ( ( SubstringFilter ) filter ).setInitialSubstrings( initialString );
+                    }
+
+                    if ( finalString != null )
+                    {
+                        ( ( SubstringFilter ) filter ).setFinalSubstrings( finalString );
+                    }
+
+                    if ( anyStrings != null )
+                    {
+                        for ( String any : anyStrings )
+                        {
+                            ( ( SubstringFilter ) filter ).addAnySubstrings( any );
+                        }
+                    }
+                }
+                else if ( exprNode instanceof ExtensibleNode )
+                {
+                    // Transform Extensible Node
+                    filter = new ExtensibleMatchFilter();
+
+                    String attribute = ( ( ExtensibleNode ) exprNode ).getAttribute();
+                    String matchingRule = ( ( ExtensibleNode ) exprNode ).getMatchingRuleId();
+                    boolean dnAttributes = ( ( ExtensibleNode ) exprNode ).hasDnAttributes();
+                    Value<?> value = ( ( ExtensibleNode ) exprNode ).getValue();
+
+                    if ( attribute != null )
+                    {
+                        ( ( ExtensibleMatchFilter ) filter ).setType( attribute );
+                    }
+
+                    if ( matchingRule != null )
+                    {
+                        ( ( ExtensibleMatchFilter ) filter ).setMatchingRule( matchingRule );
+                    }
+
+                    ( ( ExtensibleMatchFilter ) filter ).setMatchValue( value );
+                    ( ( ExtensibleMatchFilter ) filter ).setDnAttributes( dnAttributes );
+                }
+            }
+
+            return filter;
+        }
+        else
+        {
+            // We have found nothing to transform. Return null then.
+            return null;
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+
+        if ( getDecorated().getBase() != null )
+        {
+            hash = hash * 17 + getDecorated().getBase().hashCode();
+        }
+
+        hash = hash * 17 + getDecorated().getDerefAliases().hashCode();
+        hash = hash * 17 + getDecorated().getScope().hashCode();
+        hash = hash * 17 + Long.valueOf( getDecorated().getSizeLimit() ).hashCode();
+        hash = hash * 17 + getDecorated().getTimeLimit();
+        hash = hash * 17 + ( getDecorated().getTypesOnly() ? 0 : 1 );
+
+        List<String> attributes = getDecorated().getAttributes();
+        if ( attributes != null )
+        {
+            hash = hash * 17 + attributes.size();
+
+            // Order doesn't matter, thus just add hashCode
+            for ( String attr : attributes )
+            {
+                hash = hash + attr.hashCode();
+            }
+        }
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+        getDecorated().getFilter().accept( visitor );
+        hash = hash * 17 + currentFilter.toString().hashCode();
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( ( o == null ) || ( o instanceof SearchRequestDecorator ) )
+        {
+            return false;
+        }
+
+        SearchRequestDecorator otherSearchRequestDecorator = ( SearchRequestDecorator ) o;
+
+        if ( ( getDecorated() != null ) && ( !getDecorated().equals( otherSearchRequestDecorator.getDecorated() ) ) )
+        {
+            return false;
+        }
+
+        if ( searchRequestLength != otherSearchRequestDecorator.searchRequestLength )
+        {
+            return false;
+        }
+
+        if ( attributeDescriptionListLength != otherSearchRequestDecorator.attributeDescriptionListLength )
+        {
+            return false;
+        }
+
+        if ( ( terminalFilter != null ) && ( terminalFilter.equals( otherSearchRequestDecorator.terminalFilter ) ) )
+        {
+            return false;
+        }
+
+        if ( ( currentFilter != null ) && ( currentFilter.equals( otherSearchRequestDecorator.currentFilter ) ) )
+        {
+            return false;
+        }
+
+        if ( ( topFilter != null ) && ( topFilter.equals( otherSearchRequestDecorator.topFilter ) ) )
+        {
+            return false;
+        }
+
+        if ( tlvId != otherSearchRequestDecorator.tlvId )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The SearchRequest methods
+    //-------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum[] getResponseTypes()
+    {
+        return getDecorated().getResponseTypes();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getBase()
+    {
+        return getDecorated().getBase();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setBase( Dn baseDn )
+    {
+        getDecorated().setBase( baseDn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchScope getScope()
+    {
+        return getDecorated().getScope();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setScope( SearchScope scope )
+    {
+        getDecorated().setScope( scope );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AliasDerefMode getDerefAliases()
+    {
+        return getDecorated().getDerefAliases();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
+    {
+        getDecorated().setDerefAliases( aliasDerefAliases );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getSizeLimit()
+    {
+        return getDecorated().getSizeLimit();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setSizeLimit( long entriesMax )
+    {
+        getDecorated().setSizeLimit( entriesMax );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeLimit()
+    {
+        return getDecorated().getTimeLimit();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setTimeLimit( int secondsMax )
+    {
+        getDecorated().setTimeLimit( secondsMax );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getTypesOnly()
+    {
+        return getDecorated().getTypesOnly();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setTypesOnly( boolean typesOnly )
+    {
+        getDecorated().setTypesOnly( typesOnly );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExprNode getFilter()
+    {
+        return getDecorated().getFilter();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getAttributes()
+    {
+        return getDecorated().getAttributes();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addAttributes( String... attributes )
+    {
+        getDecorated().addAttributes( attributes );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest removeAttribute( String attribute )
+    {
+        getDecorated().removeAttribute( attribute );
+
+        return this;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the SearchRequest length
+     * 
+     * SearchRequest :
+     * <pre>
+     * 0x63 L1
+     *  |
+     *  +--> 0x04 L2 baseObject
+     *  +--> 0x0A 0x01 scope
+     *  +--> 0x0A 0x01 derefAliases
+     *  +--> 0x02 0x0(1..4) sizeLimit
+     *  +--> 0x02 0x0(1..4) timeLimit
+     *  +--> 0x01 0x01 typesOnly
+     *  +--> filter.computeLength()
+     *  +--> 0x30 L3 (Attribute description list)
+     *        |
+     *        +--> 0x04 L4-1 Attribute description
+     *        +--> 0x04 L4-2 Attribute description
+     *        +--> ...
+     *        +--> 0x04 L4-i Attribute description
+     *        +--> ...
+     *        +--> 0x04 L4-n Attribute description
+     *        </pre>
+     */
+    public int computeLength()
+    {
+        searchRequestLength = 0;
+
+        // The baseObject
+        dnBytes = Strings.getBytesUtf8( getBase().getName() );
+        searchRequestLength += 1 + TLV.getNbBytes( dnBytes.length ) + dnBytes.length;
+
+        // The scope
+        searchRequestLength += 1 + 1 + 1;
+
+        // The derefAliases
+        searchRequestLength += 1 + 1 + 1;
+
+        // The sizeLimit
+        searchRequestLength += 1 + 1 + BerValue.getNbBytes( getSizeLimit() );
+
+        // The timeLimit
+        searchRequestLength += 1 + 1 + BerValue.getNbBytes( getTimeLimit() );
+
+        // The typesOnly
+        searchRequestLength += 1 + 1 + 1;
+
+        // The filter
+        setFilter( getFilter() );
+        searchRequestLength +=
+            getCodecFilter().computeLength();
+
+        // The attributes description list
+        attributeDescriptionListLength = 0;
+
+        if ( ( getAttributes() != null ) && ( getAttributes().size() != 0 ) )
+        {
+            // Compute the attributes length
+            for ( String attribute : getAttributes() )
+            {
+                // add the attribute length to the attributes length
+                int idLength = Strings.getBytesUtf8( attribute ).length;
+                attributeDescriptionListLength += 1 + TLV.getNbBytes( idLength ) + idLength;
+            }
+        }
+
+        searchRequestLength += 1 + TLV.getNbBytes( attributeDescriptionListLength ) + attributeDescriptionListLength;
+
+        // Return the result.
+        return 1 + TLV.getNbBytes( searchRequestLength ) + searchRequestLength;
+    }
+
+
+    /**
+     * Encode the SearchRequest message to a PDU.
+     * 
+     * SearchRequest :
+     * <pre>
+     * 0x63 LL
+     *   0x04 LL baseObject
+     *   0x0A 01 scope
+     *   0x0A 01 derefAliases
+     *   0x02 0N sizeLimit
+     *   0x02 0N timeLimit
+     *   0x01 0x01 typesOnly
+     *   filter.encode()
+     *   0x30 LL attributeDescriptionList
+     *     0x04 LL attributeDescription
+     *     ...
+     *     0x04 LL attributeDescription
+     * </pre>
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The SearchRequest Tag
+            buffer.put( LdapCodecConstants.SEARCH_REQUEST_TAG );
+            buffer.put( TLV.getBytes( searchRequestLength ) );
+
+            // The baseObject
+            BerValue.encode( buffer, dnBytes );
+
+            // The scope
+            BerValue.encodeEnumerated( buffer, getScope().getScope() );
+
+            // The derefAliases
+            BerValue.encodeEnumerated( buffer, getDerefAliases().getValue() );
+
+            // The sizeLimit
+            BerValue.encode( buffer, getSizeLimit() );
+
+            // The timeLimit
+            BerValue.encode( buffer, getTimeLimit() );
+
+            // The typesOnly
+            BerValue.encode( buffer, getTypesOnly() );
+
+            // The filter
+            getCodecFilter().encode( buffer );
+
+            // The attributeDescriptionList
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+            buffer.put( TLV.getBytes( attributeDescriptionListLength ) );
+
+            if ( ( getAttributes() != null ) && ( getAttributes().size() != 0 ) )
+            {
+                // encode each attribute
+                for ( String attribute : getAttributes() )
+                {
+                    BerValue.encode( buffer, attribute );
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+
+
+    public SearchResultDone getResultResponse()
+    {
+        return ( SearchResultDone ) getDecorated().getResultResponse();
+    }
+
+
+    public boolean hasResponse()
+    {
+        return getDecorated().hasResponse();
+    }
+
+
+    public void abandon()
+    {
+        getDecorated().abandon();
+    }
+
+
+    public boolean isAbandoned()
+    {
+        return getDecorated().isAbandoned();
+    }
+
+
+    public SearchRequest addAbandonListener( AbandonListener listener )
+    {
+        getDecorated().addAbandonListener( listener );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setMessageId( int messageId )
+    {
+        return ( SearchRequest ) super.setMessageId( messageId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addControl( Control control )
+    {
+        return ( SearchRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addAllControls( Control[] controls )
+    {
+        return ( SearchRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest removeControl( Control control )
+    {
+        return ( SearchRequest ) super.removeControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isFollowReferrals()
+    {
+        return getDecorated().isFollowReferrals();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest followReferrals()
+    {
+        return getDecorated().followReferrals();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isIgnoreReferrals()
+    {
+        return getDecorated().isIgnoreReferrals();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest ignoreReferrals()
+    {
+        return getDecorated().ignoreReferrals();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultDoneDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultDoneDecorator.java
new file mode 100644
index 0000000..ed8bf3b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultDoneDecorator.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+
+
+/**
+ * A decorator for the SearchResultDone message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultDoneDecorator extends ResponseDecorator<SearchResultDone> implements SearchResultDone
+{
+    /** The encoded searchResultDone length */
+    private int searchResultDoneLength;
+
+
+    /**
+     * Makes a SearchResultDone encodable.
+     *
+     * @param decoratedMessage the decorated SearchResultDone
+     */
+    public SearchResultDoneDecorator( LdapApiService codec, SearchResultDone decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the SearchResultDone length 
+     * 
+     * SearchResultDone : 
+     * <pre>
+     * 0x65 L1 
+     *   | 
+     *   +--> LdapResult 
+     *   
+     * L1 = Length(LdapResult) 
+     * Length(SearchResultDone) = Length(0x65) + Length(L1) + L1
+     * </pre>
+     */
+    public int computeLength()
+    {
+        searchResultDoneLength = ( ( LdapResultDecorator ) getLdapResult() ).computeLength();
+
+        return 1 + TLV.getNbBytes( searchResultDoneLength ) + searchResultDoneLength;
+    }
+
+
+    /**
+     * Encode the SearchResultDone message to a PDU.
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @param searchResultDoneDecorator The SearchResultDone decorator
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The searchResultDone Tag
+            buffer.put( LdapCodecConstants.SEARCH_RESULT_DONE_TAG );
+            buffer.put( TLV.getBytes( searchResultDoneLength ) );
+
+            // The LdapResult
+            ( ( LdapResultDecorator ) getLdapResult() ).encode( buffer );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultEntryDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultEntryDecorator.java
new file mode 100644
index 0000000..090b3f7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultEntryDecorator.java
@@ -0,0 +1,386 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A decorator for the SearchResultEntry message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultEntryDecorator extends MessageDecorator<SearchResultEntry> implements SearchResultEntry
+{
+    /** A temporary storage for the byte[] representing the objectName */
+    private byte[] objectNameBytes;
+
+    /** The search result entry length */
+    private int searchResultEntryLength;
+
+    /** The partial attributes length */
+    private int attributesLength;
+
+    /** The list of all attributes length */
+    private List<Integer> attributeLength;
+
+    /** The list of all attributes Id bytes */
+    private List<byte[]> attributeIds;
+
+    /** The list of all values length */
+    private List<Integer> valuesLength;
+
+    /** The current attribute being processed */
+    private Attribute currentAttribute;
+
+
+    /**
+     * Makes a SearchResultEntry encodable.
+     *
+     * @param decoratedMessage the decorated SearchResultEntry
+     */
+    public SearchResultEntryDecorator( LdapApiService codec, SearchResultEntry decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    public Attribute getCurrentAttribute()
+    {
+        return currentAttribute;
+    }
+
+
+    /**
+     * Create a new attribute
+     * 
+     * @param type The attribute's type
+     */
+    public void addAttribute( String type ) throws LdapException
+    {
+        currentAttribute = new DefaultAttribute( type );
+
+        getDecorated().getEntry().put( currentAttribute );
+    }
+
+
+    /**
+     * Create a new attribute
+     * 
+     * @param type The attribute's type
+     */
+    public void addAttribute( byte[] type ) throws LdapException
+    {
+        currentAttribute = new DefaultAttribute( type );
+
+        getDecorated().getEntry().put( currentAttribute );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The added value
+     */
+    public void addAttributeValue( Object value ) throws LdapException
+    {
+        if ( value instanceof String )
+        {
+            currentAttribute.add( ( String ) value );
+        }
+        else
+        {
+            currentAttribute.add( ( byte[] ) value );
+        }
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The IntermediateResponse methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getObjectName()
+    {
+        return getDecorated().getObjectName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setObjectName( Dn objectName )
+    {
+        getDecorated().setObjectName( objectName );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry getEntry()
+    {
+        return getDecorated().getEntry();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setEntry( Entry entry )
+    {
+        getDecorated().setEntry( entry );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the SearchResultEntry length
+     * 
+     * SearchResultEntry :
+     * <pre>
+     * 0x64 L1
+     *  |
+     *  +--> 0x04 L2 objectName
+     *  +--> 0x30 L3 (attributes)
+     *        |
+     *        +--> 0x30 L4-1 (partial attributes list)
+     *        |     |
+     *        |     +--> 0x04 L5-1 type
+     *        |     +--> 0x31 L6-1 (values)
+     *        |           |
+     *        |           +--> 0x04 L7-1-1 value
+     *        |           +--> ...
+     *        |           +--> 0x04 L7-1-n value
+     *        |
+     *        +--> 0x30 L4-2 (partial attributes list)
+     *        |     |
+     *        |     +--> 0x04 L5-2 type
+     *        |     +--> 0x31 L6-2 (values)
+     *        |           |
+     *        |           +--> 0x04 L7-2-1 value
+     *        |           +--> ...
+     *        |           +--> 0x04 L7-2-n value
+     *        |
+     *        +--> ...
+     *        |
+     *        +--> 0x30 L4-m (partial attributes list)
+     *              |
+     *              +--> 0x04 L5-m type
+     *              +--> 0x31 L6-m (values)
+     *                    |
+     *                    +--> 0x04 L7-m-1 value
+     *                    +--> ...
+     *                    +--> 0x04 L7-m-n value
+     * </pre>
+     */
+    public int computeLength()
+    {
+        Dn dn = getObjectName();
+
+        objectNameBytes = Strings.getBytesUtf8Ascii( dn.getName() );
+
+        // The entry
+        searchResultEntryLength = 1 + TLV.getNbBytes( objectNameBytes.length ) + objectNameBytes.length;
+
+        // The attributes sequence
+        attributesLength = 0;
+
+        Entry entry = getEntry();
+
+        if ( ( entry != null ) && ( entry.size() != 0 ) )
+        {
+            attributeLength = new LinkedList<Integer>();
+            attributeIds = new LinkedList<byte[]>();
+            valuesLength = new LinkedList<Integer>();
+
+            // Store those lists in the object
+            valuesLength = new LinkedList<Integer>();
+
+            // Compute the attributes length
+            for ( Attribute attribute : entry )
+            {
+                int localAttributeLength = 0;
+                int localValuesLength = 0;
+
+                // Get the type length
+                byte[] attributeIdBytes = Strings.getBytesUtf8Ascii( attribute.getUpId() );
+                attributeIds.add( attributeIdBytes );
+                int idLength = attributeIdBytes.length;
+                localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength;
+
+                if ( attribute.size() != 0 )
+                {
+                    // The values
+                    if ( attribute.size() > 0 )
+                    {
+                        localValuesLength = 0;
+
+                        for ( org.apache.directory.api.ldap.model.entry.Value<?> value : attribute )
+                        {
+                            byte[] binaryValue = value.getBytes();
+                            localValuesLength += 1 + TLV.getNbBytes( binaryValue.length ) + binaryValue.length;
+                        }
+
+                        localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength;
+                    }
+                    else
+                    {
+                        // We have to deal with the special case where
+                        // we don't have a value.
+                        // It will be encoded as an empty OCTETSTRING,
+                        // so it will be two bytes long (0x04 0x00)
+                        localAttributeLength += 1 + 1;
+                    }
+                }
+                else
+                {
+                    // We have no values. We will just have an empty SET OF :
+                    // 0x31 0x00
+                    localAttributeLength += 1 + 1;
+                }
+
+                // add the attribute length to the attributes length
+                attributesLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength;
+
+                // Store the lengths of the encoded attributes and values
+                attributeLength.add( localAttributeLength );
+                valuesLength.add( localValuesLength );
+            }
+        }
+
+        searchResultEntryLength += 1 + TLV.getNbBytes( attributesLength ) + attributesLength;
+
+        // Return the result.
+        return 1 + TLV.getNbBytes( searchResultEntryLength ) + searchResultEntryLength;
+    }
+
+
+    /**
+     * Encode the SearchResultEntry message to a PDU.
+     * 
+     * SearchResultEntry :
+     * <pre>
+     * 0x64 LL
+     *   0x04 LL objectName
+     *   0x30 LL attributes
+     *     0x30 LL partialAttributeList
+     *       0x04 LL type
+     *       0x31 LL vals
+     *         0x04 LL attributeValue
+     *         ...
+     *         0x04 LL attributeValue
+     *     ...
+     *     0x30 LL partialAttributeList
+     *       0x04 LL type
+     *       0x31 LL vals
+     *         0x04 LL attributeValue
+     *         ...
+     *         0x04 LL attributeValue
+     * </pre>
+     * @param buffer The buffer where to put the PDU
+     * @param searchResultEntryDecorator the SearchResultEntry decorator
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The SearchResultEntry Tag
+            buffer.put( LdapCodecConstants.SEARCH_RESULT_ENTRY_TAG );
+            buffer.put( TLV.getBytes( searchResultEntryLength ) );
+
+            // The objectName
+            BerValue.encode( buffer, objectNameBytes );
+
+            // The attributes sequence
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+            buffer.put( TLV.getBytes( attributesLength ) );
+
+            // The partial attribute list
+            Entry entry = getEntry();
+
+            if ( ( entry != null ) && ( entry.size() != 0 ) )
+            {
+                int attributeNumber = 0;
+
+                // Compute the attributes length
+                for ( Attribute attribute : entry )
+                {
+                    // The partial attribute list sequence
+                    buffer.put( UniversalTag.SEQUENCE.getValue() );
+                    int localAttributeLength = attributeLength.get( attributeNumber );
+                    buffer.put( TLV.getBytes( localAttributeLength ) );
+
+                    // The attribute type
+                    BerValue.encode( buffer, attributeIds.get( attributeNumber ) );
+
+                    // The values
+                    buffer.put( UniversalTag.SET.getValue() );
+                    int localValuesLength = valuesLength.get( attributeNumber );
+                    buffer.put( TLV.getBytes( localValuesLength ) );
+
+                    if ( attribute.size() > 0 )
+                    {
+                        for ( Value<?> value : attribute )
+                        {
+                            BerValue.encode( buffer, value.getBytes() );
+                        }
+                    }
+
+                    // Go to the next attribute number;
+                    attributeNumber++;
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultReferenceDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultReferenceDecorator.java
new file mode 100644
index 0000000..2b1750f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SearchResultReferenceDecorator.java
@@ -0,0 +1,168 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.codec.api.LdapEncoder;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+
+
+/**
+ * A decorator for the SearchResultReference message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultReferenceDecorator extends MessageDecorator<SearchResultReference>
+    implements SearchResultReference
+{
+    /** The search result reference length */
+    private int searchResultReferenceLength;
+
+
+    /**
+     * Makes a SearchResultReference encodable.
+     *
+     * @param decoratedMessage the decorated SearchResultReference
+     */
+    public SearchResultReferenceDecorator( LdapApiService codec, SearchResultReference decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The SearchResultReference methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public Referral getReferral()
+    {
+        return getDecorated().getReferral();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReferral( Referral referral )
+    {
+        getDecorated().setReferral( referral );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the SearchResultReference length
+     * 
+     * SearchResultReference :
+     * <pre>
+     * 0x73 L1
+     *  |
+     *  +--> 0x04 L2 reference
+     *  +--> 0x04 L3 reference
+     *  +--> ...
+     *  +--> 0x04 Li reference
+     *  +--> ...
+     *  +--> 0x04 Ln reference
+     * 
+     * L1 = n*Length(0x04) + sum(Length(Li)) + sum(Length(reference[i]))
+     * 
+     * Length(SearchResultReference) = Length(0x73 + Length(L1) + L1
+     * </pre>
+     */
+    public int computeLength()
+    {
+        searchResultReferenceLength = 0;
+
+        // We may have more than one reference.
+        Referral referral = getReferral();
+
+        int referralLength = LdapEncoder.computeReferralLength( referral );
+
+        if ( referralLength != 0 )
+        {
+            setReferral( referral );
+
+            searchResultReferenceLength = referralLength;
+        }
+
+        return 1 + TLV.getNbBytes( searchResultReferenceLength ) + searchResultReferenceLength;
+    }
+
+
+    /**
+     * Encode the SearchResultReference message to a PDU.
+     * 
+     * SearchResultReference :
+     * <pre>
+     * 0x73 LL
+     *   0x04 LL reference
+     *   [0x04 LL reference]*
+     * </pre>
+     * @param buffer The buffer where to put the PDU
+     * @param searchResultReferenceDecorator The SearchResultReference decorator
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        SearchResultReference searchResultReference = getDecorated();
+        try
+        {
+            // The SearchResultReference Tag
+            buffer.put( LdapCodecConstants.SEARCH_RESULT_REFERENCE_TAG );
+            buffer.put( TLV.getBytes( searchResultReferenceLength ) );
+
+            // The referrals, if any
+            Referral referral = searchResultReference.getReferral();
+
+            if ( referral != null )
+            {
+                // Each referral
+                for ( byte[] ldapUrlBytes : referral.getLdapUrlsBytes() )
+                {
+                    // Encode the current referral
+                    BerValue.encode( buffer, ldapUrlBytes );
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SingleReplyRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SingleReplyRequestDecorator.java
new file mode 100644
index 0000000..0e295f2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/SingleReplyRequestDecorator.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.message.AbandonListener;
+import org.apache.directory.api.ldap.model.message.AbandonableRequest;
+import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
+import org.apache.directory.api.ldap.model.message.SingleReplyRequest;
+
+
+/**
+ * A decorator for the LdapResultResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class SingleReplyRequestDecorator<M extends SingleReplyRequest>
+    extends ResultResponseRequestDecorator<M> implements SingleReplyRequest, AbandonableRequest
+{
+    /**
+     * Makes Request a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated message
+     */
+    public SingleReplyRequestDecorator( LdapApiService codec, M decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return getDecorated().getResponseType();
+    }
+
+
+    public void abandon()
+    {
+        ( ( AbandonableRequest ) getDecorated() ).abandon();
+    }
+
+
+    public boolean isAbandoned()
+    {
+        return ( ( AbandonableRequest ) getDecorated() ).isAbandoned();
+    }
+
+
+    public AbandonableRequest addAbandonListener( AbandonListener listener )
+    {
+        ( ( AbandonableRequest ) getDecorated() ).addAbandonListener( listener );
+
+        return this;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/UnbindRequestDecorator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/UnbindRequestDecorator.java
new file mode 100644
index 0000000..f2cd2b9
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/decorators/UnbindRequestDecorator.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.decorators;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.UnbindRequest;
+
+
+/**
+ * A decorator for the LdapResultResponse message
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UnbindRequestDecorator extends RequestDecorator<UnbindRequest> implements UnbindRequest
+{
+    /**
+     * Makes Request a MessageDecorator.
+     *
+     * @param decoratedMessage the decorated message
+     */
+    public UnbindRequestDecorator( LdapApiService codec, UnbindRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest addControl( Control control )
+    {
+        return ( UnbindRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest addAllControls( Control[] controls )
+    {
+        return ( UnbindRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest removeControl( Control control )
+    {
+        return ( UnbindRequest ) super.removeControl( control );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // The Decorator methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Compute the UnBindRequest length 
+     * 
+     * UnBindRequest : 
+     * 0x42 00
+     */
+    public int computeLength()
+    {
+        // Always 2
+        return 2;
+    }
+
+
+    /**
+     * Encode the Unbind protocolOp part
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        try
+        {
+            // The tag
+            buffer.put( LdapCodecConstants.UNBIND_REQUEST_TAG );
+
+            // The length is always null.
+            buffer.put( ( byte ) 0 );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            String msg = I18n.err( I18n.ERR_04005 );
+            throw new EncoderException( msg, boe );
+        }
+
+        return buffer;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/osgi/DefaultActivator.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/osgi/DefaultActivator.java
new file mode 100644
index 0000000..2ad9a14
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/osgi/DefaultActivator.java
@@ -0,0 +1,64 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.osgi;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * The {@link org.osgi.framework.BundleActivator} for the codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultActivator implements BundleActivator
+{
+    private DefaultLdapCodecService codec;
+    private ServiceRegistration<?> registration;
+
+
+    public DefaultActivator()
+    {
+        this.codec = new DefaultLdapCodecService();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start( BundleContext bundleContext ) throws Exception
+    {
+        registration = bundleContext.registerService( LdapApiService.class.getName(), codec, null );
+        LdapApiServiceFactory.initialize( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop( BundleContext bundleContext ) throws Exception
+    {
+        registration.unregister();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/osgi/DefaultLdapCodecService.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/osgi/DefaultLdapCodecService.java
new file mode 100644
index 0000000..a0cfe4a
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/osgi/DefaultLdapCodecService.java
@@ -0,0 +1,587 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.osgi;
+
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.naming.NamingException;
+import javax.naming.ldap.BasicControl;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.ldap.codec.BasicControlDecorator;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory;
+import org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
+import org.apache.directory.api.ldap.codec.controls.proxiedauthz.ProxiedAuthzFactory;
+import org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory;
+import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
+import org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
+import org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedRequestImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.controls.Cascade;
+import org.apache.directory.api.ldap.model.message.controls.EntryChange;
+import org.apache.directory.api.ldap.model.message.controls.ManageDsaIT;
+import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.api.ldap.model.message.controls.PagedResults;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+import org.apache.directory.api.ldap.model.message.controls.ProxiedAuthz;
+import org.apache.directory.api.ldap.model.message.controls.Subentries;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.exception.NotImplementedException;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The default {@link LdapApiService} implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class DefaultLdapCodecService implements LdapApiService
+{
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultLdapCodecService.class );
+
+    /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ControlFactory}'s */
+    private Map<String, ControlFactory<? extends Control>> controlFactories = new HashMap<String, ControlFactory<? extends Control>>();
+
+    /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory}'s by request OID */
+    private Map<String, ExtendedOperationFactory> extendedOperationsFactories = new HashMap<String, ExtendedOperationFactory>();
+
+    /** The registered ProtocolCodecFactory */
+    private ProtocolCodecFactory protocolCodecFactory;
+
+
+    /**
+     * Creates a new instance of DefaultLdapCodecService.
+     */
+    public DefaultLdapCodecService()
+    {
+        loadStockControls();
+    }
+
+
+    /**
+     * Loads the Controls implement out of the box in the codec.
+     */
+    private void loadStockControls()
+    {
+        ControlFactory<Cascade> cascadeFactory = new CascadeFactory( this );
+        controlFactories.put( cascadeFactory.getOid(), cascadeFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", cascadeFactory.getOid() );
+
+        ControlFactory<EntryChange> entryChangeFactory = new EntryChangeFactory( this );
+        controlFactories.put( entryChangeFactory.getOid(), entryChangeFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", entryChangeFactory.getOid() );
+
+        ControlFactory<ManageDsaIT> manageDsaItFactory = new ManageDsaITFactory( this );
+        controlFactories.put( manageDsaItFactory.getOid(), manageDsaItFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", manageDsaItFactory.getOid() );
+
+        ControlFactory<ProxiedAuthz> proxiedAuthzFactory = new ProxiedAuthzFactory( this );
+        controlFactories.put( proxiedAuthzFactory.getOid(), proxiedAuthzFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", proxiedAuthzFactory.getOid() );
+
+        ControlFactory<PagedResults> pageResultsFactory = new PagedResultsFactory( this );
+        controlFactories.put( pageResultsFactory.getOid(), pageResultsFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", pageResultsFactory.getOid() );
+
+        ControlFactory<PersistentSearch> persistentSearchFactory = new PersistentSearchFactory( this );
+        controlFactories.put( persistentSearchFactory.getOid(), persistentSearchFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", persistentSearchFactory.getOid() );
+
+        ControlFactory<Subentries> subentriesFactory = new SubentriesFactory( this );
+        controlFactories.put( subentriesFactory.getOid(), subentriesFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", subentriesFactory.getOid() );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // LdapCodecService implementation methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public ControlFactory<?> registerControl( ControlFactory<?> factory )
+    {
+        return controlFactories.put( factory.getOid(), factory );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ControlFactory<?> unregisterControl( String oid )
+    {
+        return controlFactories.remove( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> registeredControls()
+    {
+        return Collections.unmodifiableSet( controlFactories.keySet() ).iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isControlRegistered( String oid )
+    {
+        return controlFactories.containsKey( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> registeredExtendedRequests()
+    {
+        return Collections.unmodifiableSet( extendedOperationsFactories.keySet() ).iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedOperationFactory registerExtendedRequest( ExtendedOperationFactory factory )
+    {
+        return extendedOperationsFactories.put( factory.getOid(), factory );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ProtocolCodecFactory getProtocolCodecFactory()
+    {
+        return protocolCodecFactory;
+    }
+
+
+    public ProtocolCodecFactory registerProtocolCodecFactory( ProtocolCodecFactory protocolCodecFactory )
+    {
+        ProtocolCodecFactory oldFactory = this.protocolCodecFactory;
+        this.protocolCodecFactory = protocolCodecFactory;
+        return oldFactory;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<? extends Control> newControl( String oid )
+    {
+        ControlFactory<?> factory = controlFactories.get( oid );
+
+        if ( factory == null )
+        {
+            return new BasicControlDecorator<Control>( this, new OpaqueControl( oid ) );
+        }
+
+        return factory.newCodecControl();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public CodecControl<? extends Control> newControl( Control control )
+    {
+        if ( control == null )
+        {
+            throw new NullPointerException( "Control argument was null." );
+        }
+
+        // protect agains being multiply decorated
+        if ( control instanceof CodecControl )
+        {
+            return ( CodecControl<?> ) control;
+        }
+
+        @SuppressWarnings("rawtypes")
+        ControlFactory factory = controlFactories.get( control.getOid() );
+
+        if ( factory == null )
+        {
+            return new BasicControlDecorator<Control>( this, control );
+        }
+
+        return factory.newCodecControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public javax.naming.ldap.Control toJndiControl( Control control ) throws EncoderException
+    {
+        CodecControl<? extends Control> decorator = newControl( control );
+        ByteBuffer bb = ByteBuffer.allocate( decorator.computeLength() );
+        decorator.encode( bb );
+        bb.flip();
+        BasicControl jndiControl =
+            new BasicControl( control.getOid(), control.isCritical(), bb.array() );
+        return jndiControl;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Control fromJndiControl( javax.naming.ldap.Control control ) throws DecoderException
+    {
+        @SuppressWarnings("rawtypes")
+        ControlFactory factory = controlFactories.get( control.getID() );
+
+        if ( factory == null )
+        {
+            OpaqueControl ourControl = new OpaqueControl( control.getID() );
+            ourControl.setCritical( control.isCritical() );
+            BasicControlDecorator<Control> decorator =
+                new BasicControlDecorator<Control>( this, ourControl );
+            decorator.setValue( control.getEncodedValue() );
+            return decorator;
+        }
+
+        @SuppressWarnings("unchecked")
+        CodecControl<? extends Control> ourControl = factory.newCodecControl();
+        ourControl.setCritical( control.isCritical() );
+        ourControl.setValue( control.getEncodedValue() );
+        ourControl.decode( control.getEncodedValue() );
+
+        return ourControl;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Container newMessageContainer()
+    {
+        return new LdapMessageContainer<MessageDecorator<? extends Message>>( this );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedOperationFactory unregisterExtendedRequest( String oid )
+    {
+        return extendedOperationsFactories.remove( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public javax.naming.ldap.ExtendedResponse toJndi( final ExtendedResponse modelResponse ) throws EncoderException
+    {
+        throw new NotImplementedException( "Figure out how to transform" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException
+    {
+        throw new NotImplementedException( "Figure out how to transform" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest fromJndi( javax.naming.ldap.ExtendedRequest jndiRequest ) throws DecoderException
+    {
+        ExtendedRequestDecorator<?> decorator =
+            ( ExtendedRequestDecorator<?> ) newExtendedRequest( jndiRequest.getID(), jndiRequest.getEncodedValue() );
+        return decorator;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public javax.naming.ldap.ExtendedRequest toJndi( final ExtendedRequest modelRequest ) throws EncoderException
+    {
+        final String oid = modelRequest.getRequestName();
+        final byte[] value;
+
+        if ( modelRequest instanceof ExtendedRequestDecorator )
+        {
+            ExtendedRequestDecorator<?> decorator = ( ExtendedRequestDecorator<?> ) modelRequest;
+            value = decorator.getRequestValue();
+        }
+        else
+        {
+            // have to ask the factory to decorate for us - can't do it ourselves
+            ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( modelRequest
+                .getRequestName() );
+            ExtendedRequestDecorator<?> decorator = ( ExtendedRequestDecorator<?> ) extendedRequestFactory
+                .decorate( modelRequest );
+            value = decorator.getRequestValue();
+        }
+
+        javax.naming.ldap.ExtendedRequest jndiRequest = new javax.naming.ldap.ExtendedRequest()
+        {
+            private static final long serialVersionUID = -4160980385909987475L;
+
+
+            public String getID()
+            {
+                return oid;
+            }
+
+
+            public byte[] getEncodedValue()
+            {
+                return value;
+            }
+
+
+            public javax.naming.ldap.ExtendedResponse createExtendedResponse( String id, byte[] berValue, int offset,
+                int length ) throws NamingException
+            {
+                ExtendedOperationFactory factory = extendedOperationsFactories
+                    .get( modelRequest.getRequestName() );
+
+                try
+                {
+                    final ExtendedResponseDecorator<?> resp = ( ExtendedResponseDecorator<?> ) factory
+                        .newResponse( berValue );
+                    javax.naming.ldap.ExtendedResponse jndiResponse = new javax.naming.ldap.ExtendedResponse()
+                    {
+                        private static final long serialVersionUID = -7686354122066100703L;
+
+
+                        public String getID()
+                        {
+                            return oid;
+                        }
+
+
+                        public byte[] getEncodedValue()
+                        {
+                            return resp.getResponseValue();
+                        }
+                    };
+
+                    return jndiResponse;
+                }
+                catch ( DecoderException de )
+                {
+                    NamingException ne = new NamingException( "Unable to decode encoded response value: "
+                        + Strings.dumpBytes( berValue ) );
+                    ne.setRootCause( de );
+                    throw ne;
+                }
+            }
+        };
+
+        return jndiRequest;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws DecoderException 
+     */
+    @SuppressWarnings("unchecked")
+    public <E extends ExtendedResponse> E newExtendedResponse( String responseName, int messageId,
+        byte[] serializedResponse )
+        throws DecoderException
+    {
+        ExtendedResponseDecorator<ExtendedResponse> resp;
+
+        ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( responseName );
+
+        if ( extendedRequestFactory != null )
+        {
+            resp = ( ExtendedResponseDecorator<ExtendedResponse> ) extendedRequestFactory
+                .newResponse( serializedResponse );
+        }
+        else
+        {
+            resp = new ExtendedResponseDecorator<ExtendedResponse>( this,
+                new ExtendedResponseImpl( responseName ) );
+            resp.setResponseValue( serializedResponse );
+            resp.setResponseName( responseName );
+        }
+
+        resp.setMessageId( messageId );
+
+        return ( E ) resp;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest newExtendedRequest( String oid, byte[] value )
+    {
+        ExtendedRequest req = null;
+
+        ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( oid );
+
+        if ( extendedRequestFactory != null )
+        {
+            req = extendedRequestFactory.newRequest( value );
+        }
+        else
+        {
+            ExtendedRequestDecorator<ExtendedRequest> decorator =
+                new ExtendedRequestDecorator<ExtendedRequest>( this,
+                    new ExtendedRequestImpl() );
+            decorator.setRequestName( oid );
+            decorator.setRequestValue( value );
+            req = decorator;
+        }
+
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequestDecorator<?> decorate( ExtendedRequest decoratedMessage )
+    {
+        ExtendedRequestDecorator<?> req = null;
+
+        ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( decoratedMessage
+            .getRequestName() );
+
+        if ( extendedRequestFactory != null )
+        {
+            req = ( ExtendedRequestDecorator<?> ) extendedRequestFactory.decorate( decoratedMessage );
+        }
+        else
+        {
+            req = new ExtendedRequestDecorator<ExtendedRequest>( this, decoratedMessage );
+        }
+
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponseDecorator<?> decorate( ExtendedResponse decoratedMessage )
+    {
+        ExtendedResponseDecorator<?> resp = null;
+
+        ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( decoratedMessage
+            .getResponseName() );
+
+        if ( extendedRequestFactory != null )
+        {
+            resp = ( ExtendedResponseDecorator<?> ) extendedRequestFactory.decorate( decoratedMessage );
+        }
+        else
+        {
+            resp = new ExtendedResponseDecorator<ExtendedResponse>( this, decoratedMessage );
+        }
+
+        return resp;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isExtendedOperationRegistered( String oid )
+    {
+        return extendedOperationsFactories.containsKey( oid );
+    }
+
+
+    /**
+     * @return the controlFactories
+     */
+    public Map<String, ControlFactory<? extends Control>> getControlFactories()
+    {
+        return controlFactories;
+    }
+
+
+    /**
+     * @param controlFactories the controlFactories to set
+     */
+    public void setControlFactories( Map<String, ControlFactory<? extends Control>> controlFactories )
+    {
+        this.controlFactories = controlFactories;
+    }
+
+
+    /**
+     * @return the extendedOperationsFactories
+     */
+    public Map<String, ExtendedOperationFactory> getExtendedOperationsFactories()
+    {
+        return extendedOperationsFactories;
+    }
+
+
+    /**
+     * @param extendedOperationsFactories the extendedOperationsFactories to set
+     */
+    public void setExtendedOperationsFactories( Map<String, ExtendedOperationFactory> extendedOperationsFactories )
+    {
+        this.extendedOperationsFactories = extendedOperationsFactories;
+    }
+
+
+    /**
+     * @param protocolCodecFactory the protocolCodecFactory to set
+     */
+    public void setProtocolCodecFactory( ProtocolCodecFactory protocolCodecFactory )
+    {
+        this.protocolCodecFactory = protocolCodecFactory;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/AndFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/AndFilter.java
new file mode 100644
index 0000000..535cd32
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/AndFilter.java
@@ -0,0 +1,138 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+
+
+/**
+ * And Filter Object to store the And filter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AndFilter extends ConnectorFilter
+{
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * The constructor. We wont initialize the ArrayList as they may not be
+     * used.
+     */
+    public AndFilter( int tlvId )
+    {
+        super( tlvId );
+    }
+
+
+    /**
+     * The constructor. We wont initialize the ArrayList as they may not be
+     * used.
+     */
+    public AndFilter()
+    {
+        super();
+    }
+
+
+    /**
+     * Get the AndFilter.
+     * 
+     * @return Returns the andFilter.
+     */
+    public List<Filter> getAndFilter()
+    {
+        return filterSet;
+    }
+
+
+    /**
+     * Compute the AndFilter length 
+     * 
+     * AndFilter : 
+     * 0xA0 L1 super.computeLength()
+     * 
+     * Length(AndFilter) = Length(0xA0) + Length(super.computeLength()) +
+     *          super.computeLength()
+     */
+    public int computeLength()
+    {
+        filtersLength = super.computeLength();
+
+        return 1 + TLV.getNbBytes( filtersLength ) + filtersLength;
+    }
+
+
+    /**
+     * Encode the AndFilter message to a PDU. 
+     * 
+     * AndFilter : 
+     * 0xA0 LL
+     *  filter.encode() ... filter.encode()
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The AndFilter Tag
+            buffer.put( ( byte ) LdapCodecConstants.AND_FILTER_TAG );
+            buffer.put( TLV.getBytes( filtersLength ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        super.encode( buffer );
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing an AND filter
+     * 
+     * @return The AND filter string
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( '&' ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/AttributeValueAssertionFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/AttributeValueAssertionFilter.java
new file mode 100644
index 0000000..3ce492c
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/AttributeValueAssertionFilter.java
@@ -0,0 +1,249 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.AttributeValueAssertion;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+
+
+/**
+ * Object to store the filter. A filter is seen as a tree with a root.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeValueAssertionFilter extends Filter
+{
+    // ~ Instance fields
+    // ----------------------------------------------------------------------------
+
+    /** The assertion. */
+    private AttributeValueAssertion assertion;
+
+    /** The filter type */
+    private int filterType;
+
+    /** The attributeValueAssertion length */
+    private int avaLength;
+
+
+    // ~ Constructors
+    // -------------------------------------------------------------------------------
+
+    /**
+     * The constructor.
+     * 
+     * @param filterType The filter type
+     */
+    public AttributeValueAssertionFilter( int tlvId, int filterType )
+    {
+        super( tlvId );
+        this.filterType = filterType;
+    }
+
+
+    /**
+     * The constructor.
+     * 
+     * @param filterType The filter type
+     */
+    public AttributeValueAssertionFilter( int filterType )
+    {
+        super();
+        this.filterType = filterType;
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * Get the assertion
+     * 
+     * @return Returns the assertion.
+     */
+    public AttributeValueAssertion getAssertion()
+    {
+        return assertion;
+    }
+
+
+    /**
+     * Set the assertion
+     * 
+     * @param assertion The assertion to set.
+     */
+    public void setAssertion( AttributeValueAssertion assertion )
+    {
+        this.assertion = assertion;
+    }
+
+
+    /**
+     * Get the filter type
+     * 
+     * @return Returns the filterType.
+     */
+    public int getFilterType()
+    {
+        return filterType;
+    }
+
+
+    /**
+     * Set the filter type
+     * 
+     * @param filterType The filterType to set.
+     */
+    public void setFilterType( int filterType )
+    {
+        this.filterType = filterType;
+    }
+
+
+    /**
+     * Compute the AttributeValueFilter length
+     * 
+     * AttributeValueFilter :
+     * 
+     * 0xA(3, 5, 6, 8) L1
+     *  |
+     *  +--> 0x04 L2 attributeDesc
+     *  +--> 0x04 L3 assertionValue
+     * 
+     * 
+     * L2 = Length(attributeDesc)
+     * L3 = Length(assertionValue)
+     * L1 = 1 + Length(L2) + L2
+     *      + 1 + Length(L3) + L3
+     * 
+     * Length(AttributeValueFilter) = Length(0xA?) + Length(L1)
+     *                                + 1 + Length(L2) + L2
+     *                                + 1 + Length(L3) + L3
+     */
+    public int computeLength()
+    {
+        avaLength = 0;
+        int attributeDescLength = assertion.getAttributeDesc().length();
+
+        avaLength = 1 + TLV.getNbBytes( attributeDescLength ) + attributeDescLength;
+
+        org.apache.directory.api.ldap.model.entry.Value<?> assertionValue = assertion.getAssertionValue();
+
+        int assertionValueLength = 0;
+
+        assertionValueLength = assertionValue.getBytes().length;
+
+        avaLength += 1 + TLV.getNbBytes( assertionValueLength ) + assertionValueLength;
+
+        return 1 + TLV.getNbBytes( avaLength ) + avaLength;
+    }
+
+
+    /**
+     * Encode the AttributeValueAssertion Filters to a PDU. The
+     * following filters are to be encoded :
+     *  - equality match
+     *  - greater or equal
+     *  - less or equal
+     *  - approx match
+     * 
+     * AttributeValueAssertion filters :
+     * 
+     * 0xA[3, 5, 6, 8] LL
+     * 0x04 LL attributeDesc
+     * 0x04 LL assertionValue
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The AttributeValueAssertion Tag
+            switch ( filterType )
+            {
+                case LdapCodecConstants.EQUALITY_MATCH_FILTER:
+                    buffer.put( ( byte ) LdapCodecConstants.EQUALITY_MATCH_FILTER_TAG );
+                    break;
+
+                case LdapCodecConstants.LESS_OR_EQUAL_FILTER:
+                    buffer.put( ( byte ) LdapCodecConstants.LESS_OR_EQUAL_FILTER_TAG );
+                    break;
+
+                case LdapCodecConstants.GREATER_OR_EQUAL_FILTER:
+                    buffer.put( ( byte ) LdapCodecConstants.GREATER_OR_EQUAL_FILTER_TAG );
+                    break;
+
+                case LdapCodecConstants.APPROX_MATCH_FILTER:
+                    buffer.put( ( byte ) LdapCodecConstants.APPROX_MATCH_FILTER_TAG );
+                    break;
+
+                default:
+                    throw new IllegalArgumentException( "Unexpected filter type: " + filterType );
+            }
+
+            buffer.put( TLV.getBytes( avaLength ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        // The attribute desc
+        BerValue.encode( buffer, assertion.getAttributeDesc() );
+
+        // The assertion desc
+        if ( assertion.getAssertionValue().isHumanReadable() )
+        {
+            BerValue.encode( buffer, assertion.getAssertionValue().getString() );
+        }
+        else
+        {
+            BerValue.encode( buffer, assertion.getAssertionValue().getBytes() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing an item filter
+     * 
+     * @return The item filter string
+     */
+    public String toString()
+    {
+        return assertion != null ? assertion.toStringRFC2254( filterType ) : "";
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/ConnectorFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/ConnectorFilter.java
new file mode 100644
index 0000000..885780d
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/ConnectorFilter.java
@@ -0,0 +1,171 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * This Filter abstract class is used to store a set of filters used by
+ * OR/AND/NOT filters.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class ConnectorFilter extends Filter
+{
+    // ~ Instance fields
+    // ----------------------------------------------------------------------------
+
+    /** The set of filters used by And/Or filters */
+    protected List<Filter> filterSet;
+
+    /** The filters length */
+    protected int filtersLength;
+
+
+    // ~ Constructors
+    // -------------------------------------------------------------------------------
+
+    /**
+     * The constructor. We wont initialize the ArrayList as it may not be used.
+     */
+    public ConnectorFilter( int tlvId )
+    {
+        super( tlvId );
+    }
+
+
+    /**
+     * The constructor. We wont initialize the ArrayList as it may not be used.
+     */
+    public ConnectorFilter()
+    {
+        super();
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * Add a new Filter to the list.
+     * 
+     * @param filter The filter to add
+     */
+    public void addFilter( Filter filter ) throws DecoderException
+    {
+
+        if ( filterSet == null )
+        {
+            filterSet = new ArrayList<Filter>();
+        }
+
+        filterSet.add( filter );
+    }
+
+
+    /**
+     * Get the list of filters stored in the composite filter
+     * 
+     * @return And array of filters
+     */
+    public List<Filter> getFilterSet()
+    {
+        return filterSet;
+    }
+
+
+    /**
+     * Compute the ConnectorFilter length Length(ConnectorFilter) =
+     * sum(filterSet.computeLength())
+     */
+    public int computeLength()
+    {
+        int connectorFilterLength = 0;
+
+        if ( ( filterSet != null ) && ( filterSet.size() != 0 ) )
+        {
+            for ( Filter filter : filterSet )
+            {
+                connectorFilterLength += filter.computeLength();
+            }
+        }
+
+        return connectorFilterLength;
+    }
+
+
+    /**
+     * Encode the ConnectorFilter message to a PDU. 
+     * 
+     * ConnectorFilter :
+     * filter.encode() ... filter.encode()
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // encode each filter
+        if ( ( filterSet != null ) && ( filterSet.size() != 0 ) )
+        {
+            for ( Filter filter : filterSet )
+            {
+                filter.encode( buffer );
+            }
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a composite filter,
+     * one of AND, OR and NOT
+     * 
+     * @return The composite filter string
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        if ( ( filterSet != null ) && ( filterSet.size() != 0 ) )
+        {
+            for ( Filter filter : filterSet )
+            {
+                sb.append( '(' ).append( filter ).append( ')' );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/ExtensibleMatchFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/ExtensibleMatchFilter.java
new file mode 100644
index 0000000..35b5267
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/ExtensibleMatchFilter.java
@@ -0,0 +1,365 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * The search request filter Matching Rule assertion
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtensibleMatchFilter extends Filter
+{
+    // ~ Instance fields
+    // ----------------------------------------------------------------------------
+
+    /** The expected lenth of the Matching Rule Assertion */
+    private int expectedMatchingRuleLength;
+
+    /** Matching rule */
+    private String matchingRule;
+
+    /** Matching rule bytes */
+    private byte[] matchingRuleBytes;
+
+    /** Matching rule type */
+    private String type;
+
+    private byte[] typeBytes;
+
+    /** Matching rule value */
+    private org.apache.directory.api.ldap.model.entry.Value<?> matchValue;
+
+    /** The dnAttributes flag */
+    private boolean dnAttributes = false;
+
+    /** The extensible match length */
+    private int extensibleMatchLength;
+
+
+    // ~ Constructors
+    // -------------------------------------------------------------------------------
+    /**
+     * Creates a new ExtensibleMatchFilter object. The dnAttributes flag
+     * defaults to false.
+     */
+    public ExtensibleMatchFilter( int tlvId )
+    {
+        super( tlvId );
+    }
+
+
+    /**
+     * Creates a new ExtensibleMatchFilter object. The dnAttributes flag
+     * defaults to false.
+     */
+    public ExtensibleMatchFilter()
+    {
+        super();
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * Get the dnAttributes flag
+     * 
+     * @return Returns the dnAttributes.
+     */
+    public boolean isDnAttributes()
+    {
+        return dnAttributes;
+    }
+
+
+    /**
+     * Set the dnAttributes flag
+     * 
+     * @param dnAttributes The dnAttributes to set.
+     */
+    public void setDnAttributes( boolean dnAttributes )
+    {
+        this.dnAttributes = dnAttributes;
+    }
+
+
+    /**
+     * Get the matchingRule
+     * 
+     * @return Returns the matchingRule.
+     */
+    public String getMatchingRule()
+    {
+        return matchingRule;
+    }
+
+
+    /**
+     * Set the matchingRule
+     * 
+     * @param matchingRule The matchingRule to set.
+     */
+    public void setMatchingRule( String matchingRule )
+    {
+        this.matchingRule = matchingRule;
+    }
+
+
+    /**
+     * Get the matchValue
+     * 
+     * @return Returns the matchValue.
+     */
+    public org.apache.directory.api.ldap.model.entry.Value<?> getMatchValue()
+    {
+        return matchValue;
+    }
+
+
+    /**
+     * Set the matchValue
+     * 
+     * @param matchValue The matchValue to set.
+     */
+    public void setMatchValue( org.apache.directory.api.ldap.model.entry.Value<?> matchValue )
+    {
+        this.matchValue = matchValue;
+    }
+
+
+    /**
+     * Get the type
+     * 
+     * @return Returns the type.
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * Set the type
+     * 
+     * @param type The type to set.
+     */
+    public void setType( String type )
+    {
+        this.type = type;
+    }
+
+
+    /**
+     * get the expectedMatchingRuleLength
+     * 
+     * @return Returns the expectedMatchingRuleLength.
+     */
+    public int getExpectedMatchingRuleLength()
+    {
+        return expectedMatchingRuleLength;
+    }
+
+
+    /**
+     * Set the expectedMatchingRuleLength
+     * 
+     * @param expectedMatchingRuleLength The expectedMatchingRuleLength to set.
+     */
+    public void setExpectedMatchingRuleLength( int expectedMatchingRuleLength )
+    {
+        this.expectedMatchingRuleLength = expectedMatchingRuleLength;
+    }
+
+
+    /**
+     * Compute the ExtensibleMatchFilter length 
+     * ExtensibleMatchFilter : 
+     * 0xA9 L1 
+     *   |
+     *  [+--> 0x81 L3 matchingRule] 
+     *  [+--> 0x82 L4 type] 
+     *  [+--> 0x83 L5 matchValue]
+     *  [+--> 0x01 0x01 dnAttributes]
+     */
+    public int computeLength()
+    {
+        if ( matchingRule != null )
+        {
+            matchingRuleBytes = Strings.getBytesUtf8( matchingRule );
+            extensibleMatchLength = 1 + TLV.getNbBytes( matchingRuleBytes.length ) + matchingRuleBytes.length;
+        }
+
+        if ( type != null )
+        {
+            typeBytes = Strings.getBytesUtf8( type );
+            extensibleMatchLength += 1 + TLV.getNbBytes( typeBytes.length ) + typeBytes.length;
+        }
+
+        if ( matchValue != null )
+        {
+            int bytesLength = matchValue.getBytes().length;
+            extensibleMatchLength += 1 + TLV.getNbBytes( bytesLength ) + bytesLength;
+        }
+
+        if ( dnAttributes )
+        {
+            extensibleMatchLength += 1 + 1 + 1;
+        }
+
+        return 1 + TLV.getNbBytes( extensibleMatchLength ) + extensibleMatchLength;
+    }
+
+
+    /**
+     * Encode the ExtensibleMatch Filters to a PDU. 
+     * 
+     * ExtensibleMatch filter :
+     * 
+     * 0xA9 LL 
+     *  |     0x81 LL matchingRule
+     *  |    / |   0x82 LL Type  
+     *  |   /  |  /0x83 LL matchValue
+     *  +--+   +-+
+     *  |   \     \
+     *  |    \     0x83 LL MatchValue
+     *  |     0x82 LL type
+     *  |     0x83 LL matchValue
+     *  +--[0x84 0x01 dnAttributes]
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The ExtensibleMatch Tag
+            buffer.put( ( byte ) LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG );
+            buffer.put( TLV.getBytes( extensibleMatchLength ) );
+
+            if ( ( matchingRule == null ) && ( type == null ) )
+            {
+                throw new EncoderException( I18n.err( I18n.ERR_04056 ) );
+            }
+
+            // The matching rule
+            if ( matchingRule != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_ID_TAG );
+                buffer.put( TLV.getBytes( matchingRuleBytes.length ) );
+                buffer.put( matchingRuleBytes );
+            }
+
+            // The type
+            if ( type != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_TYPE_TAG );
+                buffer.put( TLV.getBytes( typeBytes.length ) );
+                buffer.put( typeBytes );
+            }
+
+            // The match value
+            if ( matchValue != null )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.MATCH_VALUE_TAG );
+
+                byte[] bytes = matchValue.getBytes();
+                int bytesLength = bytes.length;
+                buffer.put( TLV.getBytes( bytesLength ) );
+
+                if ( bytesLength != 0 )
+                {
+                    buffer.put( bytes );
+                }
+
+            }
+
+            // The dnAttributes flag, if true only
+            if ( dnAttributes )
+            {
+                buffer.put( ( byte ) LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG );
+                buffer.put( ( byte ) 1 );
+                buffer.put( BerValue.TRUE_VALUE );
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a String representing an extended filter as of RFC 2254
+     * 
+     * @return An Extened Filter String
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        if ( type != null )
+        {
+            sb.append( type );
+        }
+
+        if ( dnAttributes )
+        {
+            sb.append( ":dn" );
+        }
+
+        if ( matchingRule == null )
+        {
+
+            if ( type == null )
+            {
+                return "Extended Filter wrong syntax";
+            }
+        }
+        else
+        {
+            sb.append( ':' ).append( matchingRule );
+        }
+
+        sb.append( ":=" ).append( matchValue );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/Filter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/Filter.java
new file mode 100644
index 0000000..7861cd8
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/Filter.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+
+
+/**
+ * An abstract Asn1Object used to store the filter. A filter is seen as a tree
+ * with a root. This class does nothing, it's just the root of all the different
+ * filters.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class Filter
+{
+    /** The identifier of the associated TLV */
+    int tlvId;
+
+    /** The parent TLV id */
+    protected int parentTlvId;
+
+    /** The parent Filter */
+    protected Filter parent;
+
+
+    /**
+     * The constructor.
+     */
+    public Filter( int tlvId )
+    {
+        this.tlvId = tlvId;
+    }
+
+
+    /**
+     * The constructor.
+     */
+    public Filter()
+    {
+    }
+
+
+    /**
+     * Get the parent
+     * 
+     * @return Returns the parent.
+     */
+    public Filter getParent()
+    {
+        return parent;
+    }
+
+
+    /**
+     * Get the parent
+     * 
+     * @return Returns the parent.
+     */
+    public int getParentTlvId()
+    {
+        return parentTlvId;
+    }
+
+
+    /**
+     * Set the parent
+     * 
+     * @param parent The parent to set.
+     */
+    public void setParent( Filter parent, int parentTlvId )
+    {
+        this.parent = parent;
+        this.parentTlvId = parentTlvId;
+    }
+
+
+    public int getTlvId()
+    {
+        return tlvId;
+    }
+
+
+    /**
+     * Compute the Filter length 
+     */
+    public abstract int computeLength();
+
+
+    /**
+     * Encode the Filter message to a PDU. 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public abstract ByteBuffer encode( ByteBuffer buffer ) throws EncoderException;
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/NotFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/NotFilter.java
new file mode 100644
index 0000000..cd6f2c7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/NotFilter.java
@@ -0,0 +1,166 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+
+
+/**
+ * Not Filter Object to store the Not filter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NotFilter extends ConnectorFilter
+{
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * The constructor.
+     */
+    public NotFilter( int tlvId )
+    {
+        super( tlvId );
+    }
+
+
+    /**
+     * The constructor.
+     */
+    public NotFilter()
+    {
+        super();
+    }
+
+
+    /**
+     * Subclass the addFilterMethod, as this is specific for a NotFilter (we
+     * cannot have more than one elements).
+     * 
+     * @param filter The Filter to add
+     */
+    public void addFilter( Filter filter ) throws DecoderException
+    {
+        if ( filterSet != null )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_04057 ) );
+        }
+
+        super.addFilter( filter );
+    }
+
+
+    /**
+     * Get the NotFilter
+     * 
+     * @return Returns the notFilter.
+     */
+    public Filter getNotFilter()
+    {
+        return filterSet.get( 0 );
+    }
+
+
+    /**
+     * Set the NotFilter
+     * 
+     * @param notFilter The notFilter to set.
+     */
+    public void setNotFilter( Filter notFilter ) throws DecoderException
+    {
+        if ( filterSet != null )
+        {
+            throw new DecoderException( I18n.err( I18n.ERR_04057 ) );
+        }
+
+        super.addFilter( notFilter );
+    }
+
+
+    /**
+     * Compute the NotFilter length 
+     * NotFilter : 
+     * 0xA2 L1 super.computeLength()
+     * 
+     * Length(NotFilter) = Length(0xA2) + Length(super.computeLength()) +
+     *      super.computeLength()
+     */
+    public int computeLength()
+    {
+        filtersLength = super.computeLength();
+
+        return 1 + TLV.getNbBytes( filtersLength ) + filtersLength;
+    }
+
+
+    /**
+     * Encode the NotFilter message to a PDU. 
+     * NotFilter : 
+     * 0xA2 LL filter.encode()
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The NotFilter Tag
+            buffer.put( ( byte ) LdapCodecConstants.NOT_FILTER_TAG );
+            buffer.put( TLV.getBytes( filtersLength ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        super.encode( buffer );
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a NOT filter
+     * 
+     * @return The NOT filter string
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( '!' ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/OrFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/OrFilter.java
new file mode 100644
index 0000000..8b1ac03
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/OrFilter.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+
+
+/**
+ * Or Filter Object to store the Or filter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OrFilter extends ConnectorFilter
+{
+    // ~ Constructors
+    // -------------------------------------------------------------------------------
+
+    /**
+     * The constructor. We wont initialize the ArrayList as they may not be
+     * used.
+     */
+    public OrFilter( int tlvId )
+    {
+        super( tlvId );
+    }
+
+
+    /**
+     * The constructor. We wont initialize the ArrayList as they may not be
+     * used.
+     */
+    public OrFilter()
+    {
+        super();
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * Get the OrFilter
+     * 
+     * @return Returns the orFilter.
+     */
+    public List<Filter> getOrFilter()
+    {
+        return filterSet;
+    }
+
+
+    /**
+     * Compute the OrFilter length 
+     * 
+     * OrFilter : 
+     * 0xA1 L1 super.computeLength()
+     * 
+     * Length(OrFilter) = Length(0xA1) + Length(super.computeLength()) +
+     *      super.computeLength()
+     */
+    public int computeLength()
+    {
+        filtersLength = super.computeLength();
+
+        return 1 + TLV.getNbBytes( filtersLength ) + filtersLength;
+    }
+
+
+    /**
+     * Encode the OrFilter message to a PDU. 
+     * OrFilter : 
+     *   0xA1 LL filter.encode()
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The OrFilter Tag
+            buffer.put( ( byte ) LdapCodecConstants.OR_FILTER_TAG );
+            buffer.put( TLV.getBytes( filtersLength ) );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        super.encode( buffer );
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing an OR filter
+     * 
+     * @return The OR filter string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( '|' ).append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/PresentFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/PresentFilter.java
new file mode 100644
index 0000000..59557c0
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/PresentFilter.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Object to store the filter. A filter is seen as a tree with a root.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PresentFilter extends Filter
+{
+    // ~ Instance fields
+    // ----------------------------------------------------------------------------
+
+    /** The attribute description. */
+    private String attributeDescription;
+
+    /** Temporary storage for attribute description bytes */
+    private byte[] attributeDescriptionBytes;
+
+
+    // ~ Constructors
+    // -------------------------------------------------------------------------------
+
+    /**
+     * The constructor.
+     */
+    public PresentFilter( int tlvId )
+    {
+        super( tlvId );
+    }
+
+
+    /**
+     * The constructor.
+     */
+    public PresentFilter()
+    {
+        super();
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * Get the attribute
+     * 
+     * @return Returns the attributeDescription.
+     */
+    public String getAttributeDescription()
+    {
+        return attributeDescription;
+    }
+
+
+    /**
+     * Set the attributeDescription
+     * 
+     * @param attributeDescription The attributeDescription to set.
+     */
+    public void setAttributeDescription( String attributeDescription )
+    {
+        this.attributeDescription = attributeDescription;
+    }
+
+
+    /**
+     * Compute the PresentFilter length 
+     * PresentFilter : 
+     * 0x87 L1 present
+     * 
+     * Length(PresentFilter) = Length(0x87) + Length(super.computeLength()) +
+     *      super.computeLength()
+     */
+    public int computeLength()
+    {
+        attributeDescriptionBytes = Strings.getBytesUtf8( attributeDescription );
+        return 1 + TLV.getNbBytes( attributeDescriptionBytes.length ) + attributeDescriptionBytes.length;
+    }
+
+
+    /**
+     * Encode the PresentFilter message to a PDU. PresentFilter : 0x87 LL
+     * attributeDescription
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The PresentFilter Tag
+            buffer.put( ( byte ) LdapCodecConstants.PRESENT_FILTER_TAG );
+            buffer.put( TLV.getBytes( attributeDescriptionBytes.length ) );
+            buffer.put( attributeDescriptionBytes );
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a Present filter
+     * 
+     * @return The Present filter string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( attributeDescription ).append( "=*" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/SubstringFilter.java b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/SubstringFilter.java
new file mode 100644
index 0000000..008ab0d
--- /dev/null
+++ b/trunk/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/search/SubstringFilter.java
@@ -0,0 +1,382 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A Object that stores the substring filter. 
+ * 
+ * A substring filter follow this
+ * grammar : 
+ * 
+ * substring = attr "=" ( ([initial] any [final] | 
+ *                        (initial [any] [final) | 
+ *                        ([initial] [any] final) ) 
+ *                       
+ * initial = value 
+ * any = "*" *(value "*")
+ * final = value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubstringFilter extends Filter
+{
+    /** The substring filter type (an attributeDescription) */
+    private String type;
+
+    /**
+     * This member is used to control the length of the three parts of the
+     * substring filter
+     */
+    private int substringsLength;
+
+    /** The initial filter */
+    private String initialSubstrings;
+
+    /** The any filter. It's a list of LdapString */
+    private List<String> anySubstrings = new ArrayList<String>( 1 );
+
+    /** The final filter */
+    private String finalSubstrings;
+
+    /** Temporary storage for substringsFilter length */
+    private int substringsFilterLength;
+
+    /** Temporary storage for substringsFilter sequence length */
+    private int substringsFilterSequenceLength;
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * The constructor. We will create the 'any' subsring arraylist with only
+     * one element.
+     */
+    public SubstringFilter( int tlvId )
+    {
+        super( tlvId );
+    }
+
+
+    /**
+     * The constructor. We will create the 'any' subsring arraylist with only
+     * one element.
+     */
+    public SubstringFilter()
+    {
+        super();
+    }
+
+
+    /**
+     * Get the internal substrings
+     * 
+     * @return Returns the anySubstrings.
+     */
+    public List<String> getAnySubstrings()
+    {
+        return anySubstrings;
+    }
+
+
+    /**
+     * Add a internal substring
+     * 
+     * @param any The anySubstrings to set.
+     */
+    public void addAnySubstrings( String any )
+    {
+        this.anySubstrings.add( any );
+    }
+
+
+    /**
+     * Get the final substring
+     * 
+     * @return Returns the finalSubstrings.
+     */
+    public String getFinalSubstrings()
+    {
+        return finalSubstrings;
+    }
+
+
+    /**
+     * Set the final substring
+     * 
+     * @param finalSubstrings The finalSubstrings to set.
+     */
+    public void setFinalSubstrings( String finalSubstrings )
+    {
+        this.finalSubstrings = finalSubstrings;
+    }
+
+
+    /**
+     * Get the initial substring
+     * 
+     * @return Returns the initialSubstrings.
+     */
+    public String getInitialSubstrings()
+    {
+        return initialSubstrings;
+    }
+
+
+    /**
+     * Set the initial substring
+     * 
+     * @param initialSubstrings The initialSubstrings to set.
+     */
+    public void setInitialSubstrings( String initialSubstrings )
+    {
+        this.initialSubstrings = initialSubstrings;
+    }
+
+
+    /**
+     * Get the attribute
+     * 
+     * @return Returns the type.
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * Set the attribute to match
+     * 
+     * @param type The type to set.
+     */
+    public void setType( String type )
+    {
+        this.type = type;
+    }
+
+
+    /**
+     * @return Returns the substringsLength.
+     */
+    public int getSubstringsLength()
+    {
+        return substringsLength;
+    }
+
+
+    /**
+     * @param substringsLength The substringsLength to set.
+     */
+    public void setSubstringsLength( int substringsLength )
+    {
+        this.substringsLength = substringsLength;
+    }
+
+
+    /**
+     * Compute the SubstringFilter length 
+     * 
+     * SubstringFilter : 
+     * 0xA4 L1 
+     *   | 
+     *   +--> 0x04 L2 type 
+     *   +--> 0x30 L3 
+     *          | 
+     *         [+--> 0x80 L4 initial] 
+     *         [+--> 0x81 L5-1 any] 
+     *         [+--> 0x81 L5-2 any] 
+     *         [+--> ... 
+     *         [+--> 0x81 L5-i any] 
+     *         [+--> ... 
+     *         [+--> 0x81 L5-n any] 
+     *         [+--> 0x82 L6 final]
+     */
+    public int computeLength()
+    {
+        // The type
+        int typeLength = Strings.getBytesUtf8( type ).length;
+
+        substringsFilterLength = 1 + TLV.getNbBytes( typeLength ) + typeLength;
+        substringsFilterSequenceLength = 0;
+
+        if ( initialSubstrings != null )
+        {
+            int initialLength = Strings.getBytesUtf8( initialSubstrings ).length;
+            substringsFilterSequenceLength += 1 + TLV.getNbBytes( initialLength )
+                + initialLength;
+        }
+
+        if ( anySubstrings != null )
+        {
+            for ( String any : anySubstrings )
+            {
+                int anyLength = Strings.getBytesUtf8( any ).length;
+                substringsFilterSequenceLength += 1 + TLV.getNbBytes( anyLength ) + anyLength;
+            }
+        }
+
+        if ( finalSubstrings != null )
+        {
+            int finalLength = Strings.getBytesUtf8( finalSubstrings ).length;
+            substringsFilterSequenceLength += 1 + TLV.getNbBytes( finalLength )
+                + finalLength;
+        }
+
+        substringsFilterLength += 1 + TLV.getNbBytes( substringsFilterSequenceLength )
+            + substringsFilterSequenceLength;
+
+        return 1 + TLV.getNbBytes( substringsFilterLength ) + substringsFilterLength;
+    }
+
+
+    /**
+     * Encode the Substrings Filter to a PDU. 
+     * 
+     * Substrings Filter :
+     * 
+     * 0xA4 LL 
+     * 0x30 LL substringsFilter
+     *   0x04 LL type
+     *   0x30 LL substrings sequence
+     *    |  0x80 LL initial
+     *    | /  [0x81 LL any]* 
+     *    |/   [0x82 LL final]
+     *    +--[0x81 LL any]+
+     *     \   [0x82 LL final]
+     *      \
+     *       0x82 LL final
+     * 
+     * @param buffer The buffer where to put the PDU
+     * @return The PDU.
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        try
+        {
+            // The SubstringFilter Tag
+            buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_TAG );
+            buffer.put( TLV.getBytes( substringsFilterLength ) );
+
+            // The type
+            BerValue.encode( buffer, Strings.getBytesUtf8( type ) );
+
+            // The SubstringSequenceFilter Tag
+            buffer.put( UniversalTag.SEQUENCE.getValue() );
+            buffer.put( TLV.getBytes( substringsFilterSequenceLength ) );
+
+            if ( ( initialSubstrings == null ) && ( ( anySubstrings == null ) || ( anySubstrings.size() == 0 ) )
+                && ( finalSubstrings == null ) )
+            {
+                throw new EncoderException( I18n.err( I18n.ERR_04058 ) );
+            }
+
+            // The initial substring
+            if ( initialSubstrings != null )
+            {
+                byte[] initialBytes = Strings.getBytesUtf8( initialSubstrings );
+                buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_INITIAL_TAG );
+                buffer.put( TLV.getBytes( initialBytes.length ) );
+                buffer.put( initialBytes );
+            }
+
+            // The any substrings
+            if ( anySubstrings != null )
+            {
+                for ( String any : anySubstrings )
+                {
+                    byte[] anyBytes = Strings.getBytesUtf8( any );
+                    buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_ANY_TAG );
+                    buffer.put( TLV.getBytes( anyBytes.length ) );
+                    buffer.put( anyBytes );
+                }
+            }
+
+            // The final substring
+            if ( finalSubstrings != null )
+            {
+                byte[] finalBytes = Strings.getBytesUtf8( finalSubstrings );
+                buffer.put( ( byte ) LdapCodecConstants.SUBSTRINGS_FILTER_FINAL_TAG );
+                buffer.put( TLV.getBytes( finalBytes.length ) );
+                buffer.put( finalBytes );
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * Return a string compliant with RFC 2254 representing a Substring filter
+     * 
+     * @return The substring filter string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        if ( initialSubstrings != null )
+        {
+            sb.append( initialSubstrings );
+        }
+
+        sb.append( '*' );
+
+        if ( anySubstrings != null )
+        {
+            for ( String any : anySubstrings )
+            {
+                sb.append( any ).append( '*' );
+            }
+        }
+
+        if ( finalSubstrings != null )
+        {
+            sb.append( finalSubstrings );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/codec/core/src/site/site.xml b/trunk/ldap/codec/core/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/codec/core/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapControlTest.java
new file mode 100644
index 0000000..0dcbc10
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapControlTest.java
@@ -0,0 +1,462 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.decorators.AbandonRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapControlTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a Request with controls
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testDecodeRequestWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x64 );
+        stream.put( new byte[]
+            { 0x30, 0x62, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x50,
+                0x01,
+                0x02, // CHOICE { ..., abandonRequest
+                // AbandonRequest,...
+                ( byte ) 0xA0,
+                0x5A, // controls [0] Controls OPTIONAL }
+                0x30,
+                0x1A, // Control ::= SEQUENCE {
+                // controlType LDAPOID,
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '1',
+                // criticality BOOLEAN DEFAULT FALSE,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                // controlValue OCTET STRING OPTIONAL }
+                0x04,
+                0x06,
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f',
+                0x30,
+                0x17, // Control ::= SEQUENCE {
+                // controlType LDAPOID,
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // controlValue OCTET STRING OPTIONAL }
+                0x04,
+                0x06,
+                'g',
+                'h',
+                'i',
+                'j',
+                'k',
+                'l',
+                0x30,
+                0x12, // Control ::= SEQUENCE {
+                // controlType LDAPOID,
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '3',
+                // criticality BOOLEAN DEFAULT FALSE}
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                0x30,
+                0x0F, // Control ::= SEQUENCE {
+                // controlType LDAPOID}
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '4' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        LdapMessageContainer<AbandonRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<AbandonRequestDecorator>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check that everything is OK
+        AbandonRequestDecorator abandonRequest = ldapMessageContainer.getMessage();
+
+        // Copy the message
+        AbandonRequest internalAbandonRequest = new AbandonRequestImpl( abandonRequest.getAbandoned() );
+        internalAbandonRequest.setMessageId( abandonRequest.getMessageId() );
+
+        assertEquals( 3, abandonRequest.getMessageId() );
+        assertEquals( 2, abandonRequest.getAbandoned() );
+
+        // Check the Controls
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 4, controls.size() );
+
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "1.3.6.1.5.5.1" );
+        assertEquals( "1.3.6.1.5.5.1", control.getOid() );
+        assertEquals( "0x61 0x62 0x63 0x64 0x65 0x66 ", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertTrue( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls.get( "1.3.6.1.5.5.2" );
+        assertEquals( "1.3.6.1.5.5.2", control.getOid() );
+        assertEquals( "0x67 0x68 0x69 0x6A 0x6B 0x6C ", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertFalse( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls.get( "1.3.6.1.5.5.3" );
+        assertEquals( "1.3.6.1.5.5.3", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertTrue( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls.get( "1.3.6.1.5.5.4" );
+        assertEquals( "1.3.6.1.5.5.4", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertFalse( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalAbandonRequest );
+
+            // Check the length
+            assertEquals( 0x64, bb.limit() );
+
+            // Don't check the PDU, as control are in a Map, and can be in a different order
+            // So we decode the generated PDU, and we compare it with the initial message
+            try
+            {
+                ldapDecoder.decode( bb, ldapMessageContainer );
+            }
+            catch ( DecoderException de )
+            {
+                de.printStackTrace();
+                fail( de.getMessage() );
+            }
+
+            AbandonRequest abandonRequest2 = ldapMessageContainer.getMessage();
+
+            assertEquals( abandonRequest, abandonRequest2 );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a Request with null OID controls
+     */
+    @Test
+    public void testDecodeRequestWithControlsNullOID()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x19 );
+        stream.put( new byte[]
+            { 0x30, 0x17, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x50,
+                0x01,
+                0x02, // CHOICE { ..., abandonRequest
+                // AbandonRequest,...
+                ( byte ) 0xA0,
+                0x0F, // controls [0] Controls OPTIONAL }
+                0x30,
+                0x0D, // Control ::= SEQUENCE {
+                // controlType LDAPOID,
+                0x04,
+                0x00,
+                // criticality BOOLEAN DEFAULT FALSE,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                // controlValue OCTET STRING OPTIONAL }
+                0x04,
+                0x06,
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f', } );
+
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        Asn1Container ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a Request with bad OID controls
+     */
+    @Test
+    public void testDecodeRequestWithControlsBadOID()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x20 );
+        stream.put( new byte[]
+            { 0x30, 0x1E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x50,
+                0x01,
+                0x02, // CHOICE { ..., abandonRequest
+                // AbandonRequest,...
+                ( byte ) 0xA0,
+                0x16, // controls [0] Controls OPTIONAL }
+                0x30,
+                0x14, // Control ::= SEQUENCE {
+                // controlType LDAPOID,
+                0x04,
+                0x07,
+                'b',
+                'a',
+                'd',
+                ' ',
+                'o',
+                'i',
+                'd',
+                // criticality BOOLEAN DEFAULT FALSE,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                // controlValue OCTET STRING OPTIONAL }
+                0x04,
+                0x06,
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f', } );
+
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        Asn1Container ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a Request with bad criticality
+     */
+    @Test
+    public void testDecodeRequestWithControlsBadCriticality()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x25 );
+        stream.put( new byte[]
+            { 0x30, 0x23, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x50,
+                0x01,
+                0x02, // CHOICE { ..., abandonRequest
+                // AbandonRequest,...
+                ( byte ) 0xA0,
+                0x1B, // controls [0] Controls OPTIONAL }
+                0x30,
+                0x19, // Control ::= SEQUENCE {
+                // controlType LDAPOID,
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '1',
+                // criticality BOOLEAN DEFAULT FALSE,
+                0x01,
+                0x00,
+                // controlValue OCTET STRING OPTIONAL }
+                0x04,
+                0x06,
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f', } );
+
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        Asn1Container ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapDecoderTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapDecoderTest.java
new file mode 100644
index 0000000..c2049c7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapDecoderTest.java
@@ -0,0 +1,873 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.api.ldap.codec.api.LdapDecoder;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.exception.ResponseCarryingMessageException;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.apache.mina.core.session.DummySession;
+import org.apache.mina.core.session.IoSession;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A global Ldap Decoder test
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapDecoderTest extends AbstractCodecServiceTest
+{
+    /** The ASN 1 decoder instance */
+    private static Asn1Decoder asn1Decoder;
+
+
+    @BeforeClass
+    public static void init()
+    {
+        asn1Decoder = new Asn1Decoder();
+    }
+
+
+    /**
+     * Decode an incoming buffer into LDAP messages. The result can be 0, 1 or many
+     * LDAP messages, which will be stored into the array the caller has created.
+     * 
+     * @param buffer The incoming byte buffer
+     * @param messageContainer The LdapMessageContainer which will be used to store the
+     * message being decoded. If the message is not fully decoded, the ucrrent state
+     * is stored into this container
+     * @param decodedMessages The list of decoded messages
+     * @throws Exception If the decoding failed
+     */
+    private void decode( ByteBuffer buffer, LdapMessageContainer<MessageDecorator<? extends Message>> messageContainer,
+        List<Message> decodedMessages ) throws DecoderException
+    {
+        buffer.mark();
+
+        while ( buffer.hasRemaining() )
+        {
+            try
+            {
+                asn1Decoder.decode( buffer, messageContainer );
+
+                if ( messageContainer.getState() == TLVStateEnum.PDU_DECODED )
+                {
+                    Message message = messageContainer.getMessage();
+
+                    decodedMessages.add( message );
+
+                    messageContainer.clean();
+                }
+            }
+            catch ( DecoderException de )
+            {
+                buffer.clear();
+                messageContainer.clean();
+
+                if ( de instanceof ResponseCarryingException )
+                {
+                    // Transform the DecoderException message to a MessageException
+                    ResponseCarryingMessageException rcme = new ResponseCarryingMessageException( de.getMessage() );
+                    rcme.setResponse( ( ( ResponseCarryingException ) de ).getResponse() );
+
+                    throw rcme;
+                }
+                else
+                {
+                    // TODO : This is certainly not the way we should handle such an exception !
+                    throw new ResponseCarryingException( de.getMessage() );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full PDU
+     */
+    @Test
+    public void testDecodeFull()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+        LdapMessageContainer<MessageDecorator<? extends Message>> container =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+        stream.put( new byte[]
+            {
+                0x30, 0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                      // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication
+                      // AuthenticationChoice
+                      // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                      // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd'
+        } );
+
+        stream.flip();
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, container.getState() );
+
+        // Check the decoded PDU
+        BindRequest bindRequest = ( BindRequest ) container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName().toString() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "password", Strings.utf8ToString( bindRequest.getCredentials() ) );
+    }
+
+
+    /**
+     * Test the decoding of two messages in a PDU
+     */
+    @Test
+    public void testDecode2Messages() throws Exception
+    {
+        LdapMessageContainer<MessageDecorator<? extends Message>> container =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        IoSession dummySession = new DummySession();
+        dummySession.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR, container );
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x6A );
+        stream.put( new byte[]
+            {
+                0x30, 0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                      // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication
+                      // AuthenticationChoice
+                      // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                      // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd',
+                0x30,
+                0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x02, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                      // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication
+                      // AuthenticationChoice
+                      // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                      // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd'
+        } );
+
+        stream.flip();
+
+        List<Message> result = new ArrayList<Message>();
+
+        // Decode a BindRequest PDU
+        try
+        {
+            decode( stream, container, result );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        BindRequest bindRequest = ( BindRequest ) ( result.get( 0 ) );
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName().toString() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "password", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // The second message
+        bindRequest = ( BindRequest ) ( result.get( 1 ) );
+
+        assertEquals( 2, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName().toString() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "password", Strings.utf8ToString( bindRequest.getCredentials() ) );
+    }
+
+
+    /**
+     * Test the decoding of a partial PDU
+     */
+    @Test
+    public void testDecodePartial()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 16 );
+        stream.put( new byte[]
+            { 0x30, 0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.VALUE_STATE_PENDING, container.getState() );
+
+        // Check the decoded PDU
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( null, bindRequest.getName() );
+        assertTrue( bindRequest.isSimple() );
+    }
+
+
+    /**
+     * Test the decoding of a splitted PDU
+     */
+    @Test
+    public void testDecodeSplittedPDU()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 16 );
+        stream.put( new byte[]
+            { 0x30, 0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest PDU first block of data
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.VALUE_STATE_PENDING, container.getState() );
+
+        // Second block of data
+        stream = ByteBuffer.allocate( 37 );
+        stream.put( new byte[]
+            { 'a', 'k', 'a', 'r', 'a', 's', 'u', 'l', 'u', ',', 'd', 'c', '=', 'e', 'x', 'a', 'm', 'p', 'l', 'e', ',',
+                'd', 'c', '=', 'c', 'o', 'm', ( byte ) 0x80, 0x08, // authentication
+                // AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd' } );
+
+        stream.flip();
+
+        // Decode a BindRequest PDU second block of data
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( container.getState(), TLVStateEnum.PDU_DECODED );
+
+        // Check the decoded PDU
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName().toString() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "password", Strings.utf8ToString( bindRequest.getCredentials() ) );
+    }
+
+
+    /**
+     * Test the decoding of a PDU with a bad Length. The first TLV has a length
+     * of 0x32 when the PDU is 0x33 bytes long.
+     */
+    @Test
+    public void testDecodeBadLengthTooSmall()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+        stream.put( new byte[]
+            {
+                // Length should be 0x33...
+                0x30,
+                0x32, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication
+                // AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<MessageDecorator<? extends Message>> ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertEquals(
+                "ERR_00008_VALUE_LENGTH_ABOVE_EXPECTED_LENGTH The current Value length 48 is above the expected length 47",
+                de.getMessage() );
+            return;
+        }
+
+        fail( "Should never reach this point.." );
+    }
+
+
+    /**
+     * Test the decoding of a PDU with a bad primitive Length. The second TLV
+     * has a length of 0x02 when the PDU is 0x01 bytes long.
+     */
+    @Test
+    public void testDecodeBadPrimitiveLengthTooBig()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+        stream.put( new byte[]
+            { 0x30,
+                0x33, // LDAPMessage ::=SEQUENCE {
+                // Length should be 0x01...
+                0x02,
+                0x02,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertEquals( "ERR_00001_BAD_TRANSITION_FROM_STATE Bad transition from state MESSAGE_ID_STATE, tag 0x2E",
+                de.getMessage() );
+            return;
+        }
+
+        fail( "Should never reach this point." );
+    }
+
+
+    /**
+     * Test the decoding of a PDU with a bad primitive Length. The second TLV
+     * has a length of 0x02 when the PDU is 0x01 bytes long.
+     */
+    @Test
+    public void testDecodeBadTagTransition()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+        stream.put( new byte[]
+            { 0x30,
+                0x33, // LDAPMessage ::=SEQUENCE {
+                // Length should be 0x01...
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x2D,
+                0x2D, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication
+                // AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertEquals( "ERR_00001_BAD_TRANSITION_FROM_STATE Bad transition from state MESSAGE_ID_STATE, tag 0x2D",
+                de.getMessage() );
+            return;
+        }
+
+        fail( "Should never reach this point." );
+    }
+
+
+    /**
+     * Test the decoding of a split Length.
+     * 
+     * The length is 3 bytes long, but the PDU has been split
+     * just after the first byte
+     */
+    @Test
+    public void testDecodeSplittedLength()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 3 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x82, 0x01,// LDAPMessage ::=SEQUENCE {
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU first block of data
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.LENGTH_STATE_PENDING, ldapMessageContainer.getState() );
+
+        // Second block of data
+        stream = ByteBuffer.allocate( 1 );
+        stream.put( new byte[]
+            { ( byte ) 0x80 // End of the length
+        } );
+
+        stream.flip();
+
+        // Decode a BindRequest PDU second block of data
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.TAG_STATE_START, ldapMessageContainer.getState() );
+
+        // Check the decoded length
+        assertEquals( 384, ldapMessageContainer.getCurrentTLV().getLength() );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapMessageTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapMessageTest.java
new file mode 100644
index 0000000..c0aceb3
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapMessageTest.java
@@ -0,0 +1,353 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.UnbindRequest;
+import org.apache.directory.api.ldap.model.message.UnbindRequestImpl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A global Ldap Decoder test
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapMessageTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of null length messageId
+     */
+    @Test
+    public void testDecodeMessageLengthNull()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x02 );
+        stream.put( new byte[]
+            { 0x30, 0x00, // LDAPMessage ::=SEQUENCE {
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point !" );
+    }
+
+
+    /**
+     * Test the decoding of null length messageId
+     */
+    @Test
+    public void testDecodeMessageIdLengthNull()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x04 );
+        stream.put( new byte[]
+            { 0x30, 0x02, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x00 // messageID MessageID
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point !" );
+    }
+
+
+    /**
+     * Test the decoding of null length messageId
+     */
+    @Test
+    public void testDecodeMessageIdMinusOne()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x05 );
+        stream.put( new byte[]
+            { 0x30, 0x03, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                ( byte ) 0xff // messageID MessageID = -1
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point !" );
+    }
+
+
+    /**
+     * Test the decoding of messageId which value is -1
+     */
+    @Test
+    public void testDecodeMessageIdMaxInt()
+    {
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x08 );
+        stream.put( new byte[]
+            { 0x30, 0x06, // LDAPMessage ::=SEQUENCE {
+                // messageID MessageID = -1
+                0x02,
+                0x04,
+                ( byte ) 0x7f,
+                ( byte ) 0xff,
+                ( byte ) 0xff,
+                ( byte ) 0xff } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point !" );
+    }
+
+
+    /**
+     * Test the decoding of a message with a wrong protocol operation
+     */
+    @Test
+    public void testDecodeWrongProtocolOpMaxInt()
+    {
+
+        byte[] buffer = new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID = 1
+                0x42,
+                0x00 // ProtocolOp
+        };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        for ( int i = 0; i < 256; i++ )
+        {
+            buffer[5] = ( byte ) i;
+            stream.put( buffer );
+            stream.flip();
+
+            // Allocate a LdapMessage Container
+            Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+            // Decode a BindRequest PDU
+            try
+            {
+                ldapDecoder.decode( stream, ldapMessageContainer );
+            }
+            catch ( DecoderException de )
+            {
+                switch ( i )
+                {
+                    case 0x42:
+                    case 0x4A:
+                    case 0x50: // AbandonRequest
+                    case 0x60:
+                    case 0x61:
+                    case 0x63:
+                    case 0x64:
+                    case 0x65:
+                    case 0x66:
+                    case 0x67:
+                    case 0x68:
+                    case 0x69:
+                    case 0x6B:
+                    case 0x6C:
+                    case 0x6D:
+                    case 0x6E:
+                    case 0x6F:
+                    case 0x73:
+                    case 0x77:
+                    case 0x78:
+                        assertTrue( true );
+                        break;
+
+                    default:
+                        String res = de.getMessage();
+
+                        if ( res.startsWith( "ERR_00001_BAD_TRANSITION_FROM_STATE" )
+                            || res.startsWith( "Universal tag " )
+                            || res.startsWith( "ERR_00010_TRUNCATED_PDU Truncated PDU" ) )
+                        {
+                            assertTrue( true );
+                        }
+                        else
+                        {
+                            fail( "Bad exception : " + res );
+                            return;
+                        }
+
+                        break;
+                }
+            }
+
+            stream.clear();
+        }
+
+        assertTrue( true );
+    }
+
+
+    /**
+     * Test the decoding of a LdapMessage with a large MessageId
+     */
+    @Test
+    public void testDecodeUnBindRequestNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x08 );
+        stream.put( new byte[]
+            { 0x30, 0x06, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x02,
+                0x01,
+                ( byte ) 0xF4, // messageID MessageID (500)
+                0x42,
+                0x00, // CHOICE { ..., unbindRequest UnbindRequest,...
+            // UnbindRequest ::= [APPLICATION 2] NULL
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<UnbindRequestDecorator> container =
+            new LdapMessageContainer<UnbindRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        Message message = container.getMessage();
+
+        assertEquals( 500, message.getMessageId() );
+
+        // Check the length
+        UnbindRequest internalUnbindRequest = new UnbindRequestImpl();
+        internalUnbindRequest.setMessageId( message.getMessageId() );
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalUnbindRequest );
+
+            // Check the length
+            assertEquals( 0x08, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapResultTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapResultTest.java
new file mode 100644
index 0000000..9865cc4
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/LdapResultTest.java
@@ -0,0 +1,697 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.decorators.AddResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test for LdapResults. We will use a AddResponse message to test the
+ * LdapResult part
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapResultTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a AddResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCode()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x10 );
+
+        stream.put( new byte[]
+            { 0x30, 0x0E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x02, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x00 // Empty resultCode
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddResponse message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeAbove90()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x10 );
+
+        stream.put( new byte[]
+            { 0x30, 0x0E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x02, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x03,
+                0x01,
+                0x01 // resultCode too high
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddResponse message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with all the different result codes
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodesOK()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        byte[] buffer = new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x07, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x00, // resultCode success
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+        };
+
+        for ( int i = 0; i < 91; i++ )
+        {
+            buffer[9] = ( byte ) i;
+            stream.put( buffer );
+            stream.flip();
+
+            // Allocate a LdapMessage Container
+            Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+            // Decode a AddResponse PDU
+            try
+            {
+                ldapDecoder.decode( stream, ldapMessageContainer );
+            }
+            catch ( DecoderException de )
+            {
+                fail( "We should never reach this point" );
+            }
+
+            stream.clear();
+        }
+
+        assertTrue( true );
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with no matched Dn
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeNoMatchedDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0A );
+
+        stream.put( new byte[]
+            { 0x30, 0x08, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x03, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x00, // resultCode success
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddResponse message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with no error message
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeNoErrorMsg()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0C );
+
+        stream.put( new byte[]
+            { 0x30, 0x0A, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x05, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x00, // resultCode success
+                0x04,
+                0x00 // Empty matched Dn
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddResponse message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with a valid LdapResult
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeOK()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x07, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x00, // resultCode success
+                0x04,
+                0x00, // Empty matched Dn
+                0x04,
+                0x00 // Empty errorMessage
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddResponseDecorator> container =
+            new LdapMessageContainer<AddResponseDecorator>( codec );
+
+        // Decode the AddResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded AddResponse
+        AddResponse addResponse = container.getMessage();
+
+        assertEquals( 1, addResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, addResponse.getLdapResult().getResultCode() );
+        assertEquals( "", addResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", addResponse.getLdapResult().getDiagnosticMessage() );
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with a valid LdapResult with referral
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeOKReferral()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x1A );
+
+        stream.put( new byte[]
+            { 0x30, 0x18, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x13, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x0A, // resultCode success (Referral)
+                0x04,
+                0x00, // Empty matched Dn
+                0x04,
+                0x00, // Empty errorMessage
+                ( byte ) 0xA3,
+                0x0A,
+                0x04,
+                0x08,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                '/' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddResponseDecorator> container = new LdapMessageContainer<AddResponseDecorator>( codec );
+
+        // Decode the AddResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded AddResponse
+        AddResponse addResponse = container.getMessage();
+
+        assertEquals( 1, addResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.REFERRAL, addResponse.getLdapResult().getResultCode() );
+        assertEquals( "", addResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", addResponse.getLdapResult().getDiagnosticMessage() );
+
+        Referral referral = addResponse.getLdapResult().getReferral();
+
+        assertNotNull( referral );
+        assertEquals( 1, referral.getLdapUrls().size() );
+        Collection<String> ldapUrls = referral.getLdapUrls();
+
+        assertTrue( ldapUrls.contains( "ldap:///" ) );
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addResponse );
+
+            // Check the length
+            assertEquals( 0x1A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with a valid LdapResult with referrals
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeOKReferrals()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x24 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x22, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x1D, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x0A, // resultCode success (Referral)
+                0x04,
+                0x00, // Empty matched Dn
+                0x04,
+                0x00, // Empty errorMessage
+                ( byte ) 0xA3,
+                0x14,
+                0x04,
+                0x08,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                '/',
+                0x04,
+                0x08,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                '/' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddResponseDecorator> container = new LdapMessageContainer<AddResponseDecorator>( codec );
+
+        // Decode the AddResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded AddResponse
+        AddResponse addResponse = container.getMessage();
+
+        assertEquals( 1, addResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.REFERRAL, addResponse.getLdapResult().getResultCode() );
+        assertEquals( "", addResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", addResponse.getLdapResult().getDiagnosticMessage() );
+
+        Referral referral = addResponse.getLdapResult().getReferral();
+
+        assertNotNull( referral );
+
+        assertEquals( 2, referral.getLdapUrls().size() );
+
+        Collection<String> ldapUrls = referral.getLdapUrls();
+
+        for ( String ldapUrl : ldapUrls )
+        {
+            assertEquals( "ldap:///", ldapUrl );
+        }
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addResponse );
+
+            // Check the length
+            assertEquals( 0x24, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with a valid LdapResult with referrals
+     * and an empty referral
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeEmptyReferral()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x1C );
+
+        stream.put( new byte[]
+            { 0x30, 0x1A, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x15, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x0A, // resultCode success (Referral)
+                0x04,
+                0x00, // Empty matched Dn
+                0x04,
+                0x00, // Empty errorMessage
+                ( byte ) 0xA3,
+                0x0C,
+                0x04,
+                0x08,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                '/',
+                0x04,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddResponseDecorator> container = new LdapMessageContainer<AddResponseDecorator>( codec );
+
+        // Decode the AddResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded AddResponse
+        AddResponse addResponse = container.getMessage();
+
+        assertEquals( 1, addResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.REFERRAL, addResponse.getLdapResult().getResultCode() );
+        assertEquals( "", addResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", addResponse.getLdapResult().getDiagnosticMessage() );
+
+        Referral referral = addResponse.getLdapResult().getReferral();
+
+        assertNotNull( referral );
+
+        assertEquals( 2, referral.getLdapUrls().size() );
+
+        Collection<String> ldapUrls = referral.getLdapUrls();
+
+        String[] expected = new String[]
+            { "ldap:///", "" };
+        int i = 0;
+
+        for ( String ldapUrl : ldapUrls )
+        {
+            assertEquals( expected[i], ldapUrl );
+            i++;
+        }
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addResponse );
+
+            // Check the length
+            assertEquals( 0x1C, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with a valid LdapResult and an invalid
+     * transition after the referral sequence
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResultCodeEmptyReferrals()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x10 );
+
+        stream.put( new byte[]
+            { 0x30, 0x0E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x09, // CHOICE { ..., addResponse AddResponse, ...
+                0x0A,
+                0x01,
+                0x0A, // resultCode success (Referral)
+                0x04,
+                0x00, // Empty matched Dn
+                0x04,
+                0x00, // Empty errorMessage
+                ( byte ) 0xA3,
+                0x00, } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<MessageDecorator<? extends Message>> container =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the AddResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/abandon/AbandonRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/abandon/AbandonRequestTest.java
new file mode 100644
index 0000000..0527bd7
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/abandon/AbandonRequestTest.java
@@ -0,0 +1,418 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.abandon;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.decorators.AbandonRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.AbandonRequest;
+import org.apache.directory.api.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test an AbandonRequest
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AbandonRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a AbandonRequest with controls
+     */
+    @Test
+    public void testDecodeAbandonRequestWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x64 );
+        stream.put( new byte[]
+            { 0x30, 0x62, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x50,
+                0x01,
+                0x02, // CHOICE { ..., abandonRequest
+                // AbandonRequest,...
+                ( byte ) 0xA0,
+                0x5A, // controls [0] Controls OPTIONAL }
+                0x30,
+                0x1A, // Control ::= SEQUENCE {
+                      // controlType LDAPOID,
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '1',
+                // criticality BOOLEAN DEFAULT FALSE,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                // controlValue OCTET STRING OPTIONAL }
+                0x04,
+                0x06,
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f',
+                0x30,
+                0x17, // Control ::= SEQUENCE {
+                      // controlType LDAPOID,
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // controlValue OCTET STRING OPTIONAL }
+                0x04,
+                0x06,
+                'g',
+                'h',
+                'i',
+                'j',
+                'k',
+                'l',
+                0x30,
+                0x12, // Control ::= SEQUENCE {
+                      // controlType LDAPOID,
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '3',
+                // criticality BOOLEAN DEFAULT FALSE }
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                0x30,
+                0x0F, // Control ::= SEQUENCE {
+                      // controlType LDAPOID}
+                0x04,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '4' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        LdapMessageContainer<AbandonRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<AbandonRequestDecorator>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check that everything is OK
+        AbandonRequestDecorator abandonRequest = ldapMessageContainer.getMessage();
+
+        // Copy the message
+        AbandonRequest internalAbandonRequest = new AbandonRequestImpl( abandonRequest.getAbandoned() );
+        internalAbandonRequest.setMessageId( abandonRequest.getMessageId() );
+
+        assertEquals( 3, abandonRequest.getMessageId() );
+        assertEquals( 2, abandonRequest.getAbandoned() );
+
+        // Check the Controls
+        Map<String, Control> controls = abandonRequest.getControls();
+
+        assertEquals( 4, controls.size() );
+
+        CodecControl<? extends Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) controls
+            .get( "1.3.6.1.5.5.1" );
+        assertEquals( "1.3.6.1.5.5.1", control.getOid() );
+        assertEquals( "0x61 0x62 0x63 0x64 0x65 0x66 ", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertTrue( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        control = ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) controls.get( "1.3.6.1.5.5.2" );
+        assertEquals( "1.3.6.1.5.5.2", control.getOid() );
+        assertEquals( "0x67 0x68 0x69 0x6A 0x6B 0x6C ", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertFalse( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        control = ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) controls.get( "1.3.6.1.5.5.3" );
+        assertEquals( "1.3.6.1.5.5.3", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertTrue( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        control = ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) controls.get( "1.3.6.1.5.5.4" );
+        assertEquals( "1.3.6.1.5.5.4", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+        assertFalse( control.isCritical() );
+        internalAbandonRequest.addControl( control );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalAbandonRequest );
+
+            // Check the length
+            assertEquals( 0x64, bb.limit() );
+
+            // Don't check the PDU, as control are in a Map, and can be in a different order
+            // So we decode the generated PDU, and we compare it with the initial message
+            try
+            {
+                ldapDecoder.decode( bb, ldapMessageContainer );
+            }
+            catch ( DecoderException de )
+            {
+                de.printStackTrace();
+                fail( de.getMessage() );
+            }
+
+            AbandonRequest abandonRequest2 = ldapMessageContainer.getMessage();
+            assertEquals( abandonRequest, abandonRequest2 );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AbandonRequest with no controls
+     */
+    @Test
+    public void testDecodeAbandonRequestNoControlsHighMessageId()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0A );
+        stream.put( new byte[]
+            { 0x30, 0x08, // LDAPMessage ::=SEQUENCE {
+                // messageID MessageID
+                0x02,
+                0x03,
+                0x00,
+                ( byte ) 0x80,
+                0x13,
+                0x50,
+                0x01,
+                0x02 // CHOICE { ..., abandonRequest
+            // AbandonRequest,...
+            // AbandonRequest ::= [APPLICATION 16] MessageID
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        LdapMessageContainer<AbandonRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<AbandonRequestDecorator>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check that everything is OK
+        AbandonRequest abandonRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 32787, abandonRequest.getMessageId() );
+        assertEquals( 2, abandonRequest.getAbandoned() );
+
+        // Check the length
+        AbandonRequest internalAbandonRequest = new AbandonRequestImpl( abandonRequest.getAbandoned() );
+        internalAbandonRequest.setMessageId( abandonRequest.getMessageId() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalAbandonRequest );
+
+            // Check the length
+            assertEquals( 0x0A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AbandonRequest with a null messageId
+     */
+    @Test
+    public void testDecodeAbandonRequestNoMessageId()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0A );
+        stream.put( new byte[]
+            { 0x30, 0x08, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x50,
+                0x00 // CHOICE { ..., abandonRequest AbandonRequest,...
+            // AbandonRequest ::= [APPLICATION 16] MessageID
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        LdapMessageContainer<MessageDecorator<? extends Message>> ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AbandonRequest with a bad Message Id
+     */
+    @Test
+    public void testDecodeAbandonRequestBadMessageId()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0B );
+        stream.put( new byte[]
+            { 0x30, 0x09, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x50,
+                0x01,
+                ( byte ) 0xFF // CHOICE { ..., abandonRequest AbandonRequest,...
+            // AbandonRequest ::= [APPLICATION 16] MessageID
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessageContainer Container
+        LdapMessageContainer<MessageDecorator<? extends Message>> ldapMessageContainer =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/add/AddRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/add/AddRequestTest.java
new file mode 100644
index 0000000..b02f70e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/add/AddRequestTest.java
@@ -0,0 +1,1260 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.add;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.NamingException;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.message.AddRequest;
+import org.apache.directory.api.ldap.model.message.AddResponseImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the AddRequest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AddRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a AddRequest
+     */
+    @Test
+    public void testDecodeAddRequestSuccess() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x59 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x57, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x52, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x2E, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x0c, // attribute 1
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x07, // vals SET OF AttributeValue }
+                0x04,
+                0x05,
+                'P',
+                'a',
+                'r',
+                'i',
+                's',
+
+                0x30,
+                0x1E, // attribute 2
+                // type AttributeDescription,
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                's',
+                0x31,
+                0x15, // vals SET
+                // OF
+                // AttributeValue
+                // }
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '1',
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '2',
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '3', } );
+
+        Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddRequestDecorator> container =
+            new LdapMessageContainer<AddRequestDecorator>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        AddRequest addRequest = container.getMessage();
+
+        // Check the decoded message
+        assertEquals( 1, addRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", addRequest.getEntryDn().toString() );
+
+        Entry entry = addRequest.getEntry();
+
+        assertEquals( 2, entry.size() );
+
+        Set<String> expectedTypes = new HashSet<String>();
+
+        expectedTypes.add( "l" );
+        expectedTypes.add( "attrs" );
+
+        Map<String, Set<String>> typesVals = new HashMap<String, Set<String>>();
+
+        Set<String> lVal1 = new HashSet<String>();
+        lVal1.add( "Paris" );
+        typesVals.put( "l", lVal1 );
+
+        Set<String> lVal2 = new HashSet<String>();
+        lVal2.add( "test1" );
+        lVal2.add( "test2" );
+        lVal2.add( "test3" );
+        typesVals.put( "attrs", lVal2 );
+
+        Attribute attribute = entry.get( "l" );
+
+        assertTrue( expectedTypes.contains( Strings.toLowerCase( attribute.getId() ) ) );
+
+        Set<String> vals = ( Set<String> ) typesVals.get( Strings.toLowerCase( attribute.getId() ) );
+
+        for ( Value<?> value : attribute )
+        {
+            assertTrue( vals.contains( value.getValue() ) );
+
+            vals.remove( value.getValue() );
+        }
+
+        attribute = entry.get( "attrs" );
+
+        assertTrue( expectedTypes.contains( Strings.toLowerCase( attribute.getId() ) ) );
+
+        vals = ( Set<String> ) typesVals.get( Strings.toLowerCase( attribute.getId() ) );
+
+        for ( Value<?> value : attribute )
+        {
+            assertTrue( vals.contains( value.getValue() ) );
+
+            vals.remove( value.getValue() );
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addRequest );
+
+            // Check the length
+            assertEquals( 0x59, bb.limit() );
+
+            // We cannot compare the PDU, as the attributes order is not
+            // kept. Let's decode again and compare the resulting AddRequest
+            try
+            {
+                ldapDecoder.decode( bb, container );
+            }
+            catch ( DecoderException de )
+            {
+                de.printStackTrace();
+                fail( de.getMessage() );
+            }
+
+            AddRequest addRequest2 = container.getMessage();
+            assertEquals( addRequest, addRequest2 );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a null body
+     */
+    @Test
+    public void testDecodeAddRequestNullBody()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x00 // CHOICE { ..., addRequest AddRequest, ...
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a null entry
+     */
+    @Test
+    public void testDecodeAddRequestNullEntry()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x39 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x37, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x26, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x00,
+                // attributes AttributeList }
+                0x30,
+                0x2E, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x0c, // attribute 1
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x07, // vals SET OF AttributeValue }
+                0x04,
+                0x05,
+                'P',
+                'a',
+                'r',
+                'i',
+                's',
+
+                0x30,
+                0x1E, // attribute 2
+                // type AttributeDescription,
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                's',
+                0x31,
+                0x15, // vals SET
+                // OF
+                // AttributeValue
+                // }
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '1',
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '2',
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '3', } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof AddResponseImpl );
+            assertEquals( ResultCodeEnum.NAMING_VIOLATION, ( ( AddResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest
+     */
+    @Test
+    public void testDecodeAddRequestbadDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x59 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x57, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x52, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                ':',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x2E, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x0c, // attribute 1
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x07, // vals SET OF AttributeValue }
+                0x04,
+                0x05,
+                'P',
+                'a',
+                'r',
+                'i',
+                's',
+
+                0x30,
+                0x1E, // attribute 2
+                // type AttributeDescription,
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                's',
+                0x31,
+                0x15, // vals SET
+                // OF
+                // AttributeValue
+                // }
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '1',
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '2',
+                0x04,
+                0x05,
+                't',
+                'e',
+                's',
+                't',
+                '3', } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof AddResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( AddResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a null attributeList
+     */
+    @Test
+    public void testDecodeAddRequestNullAttributes()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x24, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x00, // AttributeList ::= SEQUENCE OF SEQUENCE {
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a empty attributeList
+     */
+    @Test
+    public void testDecodeAddRequestNullAttributeList()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2D );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x2B, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x26, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x02, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x00, // AttributeList ::= SEQUENCE OF SEQUENCE {
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a empty attributeList
+     */
+    @Test
+    public void testDecodeAddRequestNullType()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2F );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x2D, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x28, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x04, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x02, // attribute 1
+                0x04,
+                0x00, // type AttributeDescription,
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof AddResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, ( ( AddResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a empty attributeList
+     */
+    @Test
+    public void testDecodeAddRequestNoVals()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x30 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x2E, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x29, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x05, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x03, // attribute 1
+                0x04,
+                0x01,
+                'A', // type AttributeDescription,
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a empty attributeList
+     */
+    @Test
+    public void testDecodeAddRequestNullVals()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x32 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x30, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x2B, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x07, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x05, // attribute 1
+                0x04,
+                0x01,
+                'A', // type AttributeDescription,
+                0x31,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a empty attributeList
+     */
+    @Test
+    public void testDecodeAddRequestEmptyAttributeValue() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x34 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x32, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x2D, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x09, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x07, // attribute 1
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x02,
+                0x04,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddRequestDecorator> container = new LdapMessageContainer<AddRequestDecorator>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        AddRequest addRequest = container.getMessage();
+
+        // Check the decoded message
+        assertEquals( 1, addRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", addRequest.getEntryDn().toString() );
+
+        Entry entry = addRequest.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        Attribute attribute = entry.get( "l" );
+
+        assertEquals( "l", Strings.toLowerCase( attribute.getId() ) );
+
+        for ( Value<?> value : attribute )
+        {
+            assertEquals( "", value.getString() );
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addRequest );
+
+            // Check the length
+            assertEquals( 0x34, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AddRequest with a empty attributeList and a
+     * control
+     */
+    @Test
+    public void testDecodeAddRequestEmptyAttributeValueWithControl() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x51 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x4F, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x68,
+                0x2D, // CHOICE { ..., addRequest AddRequest, ...
+                // AddRequest ::= [APPLICATION 8] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes AttributeList }
+                0x30,
+                0x09, // AttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x07, // attribute 1
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x02,
+                0x04,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddRequestDecorator> container = new LdapMessageContainer<AddRequestDecorator>( codec );
+
+        // Decode a AddRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        AddRequest addRequest = container.getMessage();
+
+        // Check the decoded message
+        assertEquals( 1, addRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", addRequest.getEntryDn().toString() );
+
+        Entry entry = addRequest.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        Attribute attribute = entry.get( "l" );
+
+        assertEquals( "l", Strings.toLowerCase( attribute.getId() ) );
+
+        for ( Value<?> value : attribute )
+        {
+            assertEquals( "", value.getString() );
+        }
+
+        // Check the Control
+        Map<String, Control> controls = addRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        assertTrue( addRequest.hasControl( "2.16.840.1.113730.3.4.2" ) );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addRequest );
+
+            // Check the length
+            assertEquals( 0x51, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/add/AddResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/add/AddResponseTest.java
new file mode 100644
index 0000000..36e0633
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/add/AddResponseTest.java
@@ -0,0 +1,288 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.add;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.decorators.AddResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.AddResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AddResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a AddResponse
+     */
+    @Test
+    public void testDecodeAddResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x07, // CHOICE { ..., addResponse AddResponse, ...
+                // AddResponse ::= [APPLICATION 9] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddResponseDecorator> container = new LdapMessageContainer<AddResponseDecorator>( codec );
+
+        // Decode the AddResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded AddResponse
+        AddResponse addResponse = container.getMessage();
+
+        assertEquals( 1, addResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, addResponse.getLdapResult().getResultCode() );
+        assertEquals( "", addResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", addResponse.getLdapResult().getDiagnosticMessage() );
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( addResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResult()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x00, // CHOICE { ..., addResponse AddResponse, ...
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container ldapMessageContainer = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a AddResponse message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a AddResponse with a control
+     */
+    @Test
+    public void testDecodeAddResponseSuccessWithControl()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x69,
+                0x07, // CHOICE { ..., addResponse AddResponse, ...
+                // AddResponse ::= [APPLICATION 9] LDAPResult
+                0x0A,
+                0x01,
+                0x00,// LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<AddResponseDecorator> container = new LdapMessageContainer<AddResponseDecorator>( codec );
+
+        // Decode the AddResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded AddResponse
+        AddResponse addResponse = container.getMessage();
+
+        assertEquals( 1, addResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, addResponse.getLdapResult().getResultCode() );
+        assertEquals( "", addResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", addResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = addResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        try
+        {
+            /** The encoder instance */
+            ByteBuffer bb = encoder.encodeMessage( addResponse );
+
+            // Check the length
+            assertEquals( 0x02B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindRequestPerfTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindRequestPerfTest.java
new file mode 100644
index 0000000..cf04cc8
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindRequestPerfTest.java
@@ -0,0 +1,269 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.bind;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindRequestImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+@Ignore("Ignore performance tests: should not be with integration tests")
+public class BindRequestPerfTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a BindRequest with Simple authentication and no
+     * controls
+     */
+    @Test
+    @Ignore
+    public void testDecodeBindRequestSimpleNoControlsPerf()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x52 );
+        stream.put( new byte[]
+            {
+                0x30,
+                0x50, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            int nbLoops = 1000000;
+            long t0 = System.currentTimeMillis();
+
+            for ( int i = 0; i < nbLoops; i++ )
+            {
+                ldapDecoder.decode( stream, container );
+                container.clean();
+                stream.flip();
+            }
+
+            long t1 = System.currentTimeMillis();
+            System.out.println( "testDecodeBindRequestSimpleNoControlsPerf, " + nbLoops + " loops, Delta = "
+                + ( t1 - t0 ) );
+
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName().toString() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "password", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the Control
+        Map<String, Control> controls = bindRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x52, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with Simple authentication and no
+     * controls
+     */
+    @Test
+    @Ignore
+    public void testEncodeBindRequestPerf() throws Exception
+    {
+        Dn dn = new Dn( "uid=akarasulu,dc=example,dc=com" );
+        int nbLoops = 1000000;
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < nbLoops; i++ )
+        {
+            // Check the decoded BindRequest
+            BindRequest bindRequest = new BindRequestImpl();
+            bindRequest.setMessageId( 1 );
+
+            bindRequest.setSimple( true );
+            bindRequest.setDn( dn );
+            bindRequest.setCredentials( Strings.getBytesUtf8( "password" ) );
+            Control control = new OpaqueControl( "2.16.840.1.113730.3.4.2" );
+
+            bindRequest.addControl( control );
+
+            // Check the encoding
+            try
+            {
+                encoder.encodeMessage( bindRequest );
+            }
+            catch ( EncoderException ee )
+            {
+                ee.printStackTrace();
+                fail( ee.getMessage() );
+            }
+        }
+
+        long t1 = System.currentTimeMillis();
+        System.out.println( "BindRequest testEncodeBindRequestPerf, " + nbLoops + " loops, Delta = " + ( t1 - t0 ) );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindRequestTest.java
new file mode 100644
index 0000000..b787318
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindRequestTest.java
@@ -0,0 +1,1736 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.bind;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.BindRequest;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BindRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a BindRequest with Simple authentication and no
+     * controls
+     */
+    /* Not used in unit tests
+    @Test
+    public void testDecodeBindRequestSimpleNoControlsPerf()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x52 );
+        stream.put( new byte[]
+             { 
+             0x30, 0x50,                 // LDAPMessage ::=SEQUENCE {
+               0x02, 0x01, 0x01,         // messageID MessageID
+               0x60, 0x2E,               // CHOICE { ..., bindRequest BindRequest, ...
+                                         // BindRequest ::= APPLICATION[0] SEQUENCE {
+                 0x02, 0x01, 0x03,       // version INTEGER (1..127),
+                 0x04, 0x1F,             // name LDAPDN,
+                 'u', 'i', 'd', '=', 'a', 'k', 'a', 'r', 'a', 's', 'u', 'l', 'u', ',', 'd', 'c', '=', 'e', 'x', 'a',
+                 'm', 'p', 'l', 'e', ',', 'd', 'c', '=', 'c', 'o', 'm', 
+                 ( byte ) 0x80, 0x08,    // authentication AuthenticationChoice
+                                         // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                                         // ...
+                   'p', 'a', 's', 's', 'w', 'o', 'r', 'd', 
+               ( byte ) 0xA0, 0x1B, // A control
+                 0x30, 0x19, 
+                   0x04, 0x17, 
+                     0x32, 0x2E, 0x31, 0x36, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x2E, 0x31, 0x31, 0x33, 0x37, 0x33, 
+                     0x30, 0x2E, 0x33, 0x2E, 0x34, 0x2E, 0x32 
+             } );
+
+        String decodedPdu = StringTools.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container container = new LdapMessageContainer();
+
+        // Decode the BindRequest PDU
+        try
+        {
+            long t0 = System.currentTimeMillis();
+            for ( int i = 0; i < 10000; i++ )
+            {
+                ldapDecoder.decode( stream, container );
+                container).clean();
+                stream.flip();
+            }
+            long t1 = System.currentTimeMillis();
+            System.out.println( "Delta = " + ( t1 - t0 ) );
+            
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        LdapMessage message = container.getLdapMessage();
+        BindRequest br = message.getMessage();
+
+        assertEquals( 1, message.getMessageId() );
+        assertEquals( 3, br.getVersion() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", br.getName().toString() );
+        assertEquals( true, ( br.getAuthentication() instanceof SimpleAuthentication ) );
+        assertEquals( "password", StringTools.utf8ToString( ( ( SimpleAuthentication ) br.getAuthentication() )
+            .getSimple() ) );
+
+        // Check the Control
+        List controls = message.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        Control control = message.getControls( 0 );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", StringTools.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the length
+        assertEquals( 0x52, message.computeLength() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = message.encode();
+
+            String encodedPdu = StringTools.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+    */
+
+    /**
+     * Test the decoding of a BindRequest with Simple authentication and
+     * controls
+     */
+    @Test
+    public void testDecodeBindRequestSimpleWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+        stream.put( new byte[]
+            { 0x30,
+                0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "password", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x35, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with Simple authentication and
+     * controls
+     */
+    @Test
+    public void testDecodeBindRequestBadDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+        stream.put( new byte[]
+            { 0x30,
+                0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x2E, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                ':',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0x80,
+                0x08, // authentication AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<MessageDecorator<? extends Message>> container =
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof BindResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( BindResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with Simple authentication, no name
+     * and no controls
+     */
+    @Test
+    public void testDecodeBindRequestSimpleNoName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x15 );
+        stream.put( new byte[]
+            { 0x30, 0x13, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x0D, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                ( byte ) 0x80,
+                0x08, // authentication AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container container = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertEquals( "ERR_00001_BAD_TRANSITION_FROM_STATE Bad transition from state VERSION_STATE, tag 0x80",
+                de.getMessage() );
+            return;
+        }
+
+        fail( "Should never reach this point." );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with Simple authentication, empty name
+     * (an anonymous bind) and no controls
+     */
+    @Test
+    public void testDecodeBindRequestSimpleEmptyName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x16 );
+        stream.put( new byte[]
+            { 0x30, 0x14, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x0F, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00, // name LDAPDN,
+                ( byte ) 0x80,
+                0x08, // authentication AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING,
+                // ...
+                'p',
+                'a',
+                's',
+                's',
+                'w',
+                'o',
+                'r',
+                'd' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "", bindRequest.getName() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "password", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x16, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with Sasl authentication, no
+     * credentials and no controls
+     */
+    @Test
+    public void testDecodeBindRequestSaslNoCredsNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3A );
+        stream.put( new byte[]
+            { 0x30,
+                0x38, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x33, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0xA3,
+                0x0D, // authentication AuthenticationChoice
+                // AuthenticationChoice ::= CHOICE { ... sasl [3]
+                // SaslCredentials }
+                // SaslCredentials ::= SEQUENCE {
+                // mechanism LDAPSTRING,
+                // ...
+                0x04,
+                0x0B,
+                'K',
+                'E',
+                'R',
+                'B',
+                'E',
+                'R',
+                'O',
+                'S',
+                '_',
+                'V',
+                '4' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName().toString() );
+        assertFalse( bindRequest.isSimple() );
+        assertEquals( "KERBEROS_V4", bindRequest.getSaslMechanism() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x3A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with Sasl authentication, a
+     * credentials and no controls
+     */
+    @Test
+    public void testDecodeBindRequestSaslCredsNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x42 );
+        stream.put( new byte[]
+            { 0x30,
+                0x40, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x3B, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x1F, // name LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                ( byte ) 0xA3,
+                0x15, // authentication AuthenticationChoice
+                // }
+                // AuthenticationChoice ::= CHOICE { ... sasl [3]
+                // SaslCredentials }
+                // SaslCredentials ::= SEQUENCE {
+                // mechanism LDAPSTRING,
+                // ...
+                0x04,
+                0x0B,
+                'K',
+                'E',
+                'R',
+                'B',
+                'E',
+                'R',
+                'O',
+                'S',
+                '_',
+                'V',
+                '4',
+                ( byte ) 0x04,
+                0x06, // SaslCredentials ::= SEQUENCE {
+                // ...
+                // credentials OCTET STRING OPTIONAL }
+                // 
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", bindRequest.getName() );
+        assertFalse( bindRequest.isSimple() );
+        assertEquals( "KERBEROS_V4", bindRequest.getSaslMechanism() );
+        assertEquals( "abcdef", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x42, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with Sasl authentication, no name, a
+     * credentials and no controls
+     */
+    @Test
+    public void testDecodeBindRequestSaslNoNameCredsNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x23 );
+        stream.put( new byte[]
+            { 0x30, 0x21, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x1C, // CHOICE { ..., bindRequest BindRequest, ...
+                // BindRequest ::= APPLICATION[0] SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00, // name LDAPDN,
+                ( byte ) 0xA3,
+                0x15, // authentication AuthenticationChoice
+                // }
+                // AuthenticationChoice ::= CHOICE { ... sasl [3]
+                // SaslCredentials }
+                // SaslCredentials ::= SEQUENCE {
+                // mechanism LDAPSTRING,
+                // ...
+                0x04,
+                0x0B,
+                'K',
+                'E',
+                'R',
+                'B',
+                'E',
+                'R',
+                'O',
+                'S',
+                '_',
+                'V',
+                '4',
+                ( byte ) 0x04,
+                0x06, // SaslCredentials ::= SEQUENCE {
+                // ...
+                // credentials OCTET STRING OPTIONAL }
+                // 
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "", bindRequest.getName() );
+        assertFalse( bindRequest.isSimple() );
+        assertEquals( "KERBEROS_V4", bindRequest.getSaslMechanism() );
+        assertEquals( "abcdef", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x23, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty body
+     */
+    @Test
+    public void testDecodeBindRequestEmptyBody()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x00 // CHOICE { ..., bindRequest BindRequest, ...
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty version
+     */
+    @Test
+    public void testDecodeBindRequestEmptyVersion()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+        stream.put( new byte[]
+            { 0x30, 0x07, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x02, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x00 // version INTEGER (1..127),
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with a bad version (0)
+     */
+    @Test
+    public void testDecodeBindRequestBadVersion0()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0A );
+        stream.put( new byte[]
+            { 0x30, 0x08, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x03, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x00 // version INTEGER (1..127),
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with a bad version (4)
+     */
+    @Test
+    public void testDecodeBindRequestBadVersion4()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0A );
+        stream.put( new byte[]
+            { 0x30, 0x08, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x03, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x04 // version INTEGER (1..127),
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with a bad version (128)
+     */
+    @Test
+    public void testDecodeBindRequestBadVersion128()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0C );
+        stream.put( new byte[]
+            { 0x30, 0x0A, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x04, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x02,
+                0x00,
+                ( byte ) 0x80 // version INTEGER (1..127),
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with no name
+     */
+    @Test
+    public void testDecodeBindRequestNoName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0A );
+        stream.put( new byte[]
+            { 0x30, 0x08, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x03, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03 // version INTEGER (1..127),
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty name
+     */
+    @Test
+    public void testDecodeBindRequestEmptyName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0C );
+        stream.put( new byte[]
+            { 0x30, 0x0A, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x05, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty simple
+     */
+    @Test
+    public void testDecodeBindRequestEmptySimple()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x07, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00,
+                ( byte ) 0x80,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "", bindRequest.getName() );
+        assertTrue( bindRequest.isSimple() );
+        assertEquals( "", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty sasl
+     */
+    @Test
+    public void testDecodeBindRequestEmptySasl()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x07, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00,
+                ( byte ) 0xA3,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode a BindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof BindResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_CREDENTIALS, ( ( BindResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty mechanism
+     */
+    @Test
+    public void testDecodeBindRequestEmptyMechanism()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x10 );
+        stream.put( new byte[]
+            { 0x30, 0x0E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x09, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00,
+                ( byte ) 0xA3,
+                0x02,
+                0x04,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "", bindRequest.getName() );
+        assertFalse( bindRequest.isSimple() );
+        assertEquals( "", bindRequest.getSaslMechanism() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x10, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an bad mechanism
+     */
+    /* This test is not valid. I don't know how to generate a UnsupportedEncodingException ...
+    @Test
+    public void testDecodeBindRequestBadMechanism()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x11 );
+        stream.put( new byte[]
+            { 
+            0x30, 0x0F,                 // LDAPMessage ::=SEQUENCE {
+              0x02, 0x01, 0x01,         // messageID MessageID
+              0x60, 0x0A,               // CHOICE { ..., bindRequest BindRequest, ...
+                0x02, 0x01, 0x03,       // version INTEGER (1..127),
+                0x04, 0x00, 
+                ( byte ) 0xA3, 0x03, 
+                  0x04, 0x01, (byte)0xFF
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container container = new LdapMessageContainer();
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ((ResponseCarryingException)de).getResponse();
+            assertTrue( response instanceof BindResponseImpl );
+            assertEquals( ResultCodeEnum.INAPPROPRIATEAUTHENTICATION, ((BindResponseImpl)response).getLdapResult().getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+    */
+
+    /**
+     * Test the decoding of a BindRequest with an empty credentials
+     */
+    @Test
+    public void testDecodeBindRequestEmptyCredentials()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x12 );
+        stream.put( new byte[]
+            { 0x30, 0x10, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x0B, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00,
+                ( byte ) 0xA3,
+                0x04,
+                0x04,
+                0x00,
+                0x04,
+                0x00, } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "", bindRequest.getName() );
+        assertFalse( bindRequest.isSimple() );
+        assertEquals( "", bindRequest.getSaslMechanism() );
+        assertEquals( "", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x12, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty credentials with
+     * controls
+     */
+    @Test
+    public void testDecodeBindRequestEmptyCredentialsWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2F );
+        stream.put( new byte[]
+            { 0x30,
+                0x2D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x0B, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00,
+                ( byte ) 0xA3,
+                0x04,
+                0x04,
+                0x00,
+                0x04,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "", bindRequest.getName() );
+        assertFalse( bindRequest.isSimple() );
+        assertEquals( "", bindRequest.getSaslMechanism() );
+        assertEquals( "", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the Control
+        Map<String, Control> controls = bindRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x2F, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindRequest with an empty mechanisms with controls
+     */
+    @Test
+    public void testDecodeBindRequestEmptyMechanismWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2D );
+        stream.put( new byte[]
+            { 0x30,
+                0x2B, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x60,
+                0x09, // CHOICE { ..., bindRequest BindRequest, ...
+                0x02,
+                0x01,
+                0x03, // version INTEGER (1..127),
+                0x04,
+                0x00,
+                ( byte ) 0xA3,
+                0x02,
+                0x04,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindRequestDecorator> container = new LdapMessageContainer<BindRequestDecorator>( codec );
+
+        // Decode the BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindRequest
+        BindRequest bindRequest = container.getMessage();
+
+        assertEquals( 1, bindRequest.getMessageId() );
+        assertTrue( bindRequest.isVersion3() );
+        assertEquals( "", bindRequest.getName() );
+        assertFalse( bindRequest.isSimple() );
+        assertEquals( "", bindRequest.getSaslMechanism() );
+        assertEquals( "", Strings.utf8ToString( bindRequest.getCredentials() ) );
+
+        // Check the Control
+        Map<String, Control> controls = bindRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindRequest );
+
+            // Check the length
+            assertEquals( 0x2D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+    /**
+     * Test the decoding of a BindRequest with Simple authentication and no
+     * controls
+     */
+    /* No used by unit tests
+    @Test
+    public void testPerf() throws Exception
+    {
+        Dn name = new Dn( "uid=akarasulu,dc=example,dc=com" );
+        long t0 = System.currentTimeMillis();
+        
+        for ( int i = 0; i< 10000; i++)
+        {
+            // Check the decoded BindRequest
+            LdapMessage message = new LdapMessage();
+            message.setMessageId( 1 );
+            
+            BindRequest br = new BindRequest();
+            br.setMessageId( 1 );
+            br.setName( name );
+            
+            Control control = new Control();
+            control.setControlType( "2.16.840.1.113730.3.4.2" );
+
+            LdapAuthentication authentication = new SimpleAuthentication();
+            ((SimpleAuthentication)authentication).setSimple( StringTools.getBytesUtf8( "password" ) );
+
+            br.addControl( control );
+            br.setAuthentication( authentication );
+            message.setProtocolOP( br );
+    
+            // Check the encoding
+            try
+            {
+                message.encode();
+            }
+            catch ( EncoderException ee )
+            {
+                ee.printStackTrace();
+                fail( ee.getMessage() );
+            }
+        }
+
+        long t1 = System.currentTimeMillis();
+        System.out.println( "Delta = " + (t1 - t0));
+    }
+    */
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindResponseTest.java
new file mode 100644
index 0000000..3d99c6c
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/bind/BindResponseTest.java
@@ -0,0 +1,599 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.bind;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsDecorator;
+import org.apache.directory.api.ldap.codec.decorators.BindResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.BindResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BindResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a BindResponse
+     */
+    @Test
+    public void testDecodeBindResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x61,
+                0x07, // CHOICE { ..., bindResponse BindResponse, ...
+                // BindResponse ::= APPLICATION[1] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // serverSaslCreds [7] OCTET STRING OPTIONAL }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindResponseDecorator> container = new LdapMessageContainer<BindResponseDecorator>( codec );
+
+        // Decode the BindResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindResponse
+        BindResponse bindResponse = container.getMessage();
+
+        assertEquals( 1, bindResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, bindResponse.getLdapResult().getResultCode() );
+        assertEquals( "", bindResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", bindResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindResponse with a control
+     */
+    @Test
+    public void testDecodeBindResponseWithControlSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3C );
+
+        stream.put( new byte[]
+            { 0x30, 0x3A, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x61,
+                0x07, // CHOICE { ..., bindResponse BindResponse, ...
+                      // BindResponse ::= APPLICATION[1] SEQUENCE {
+                      // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                      // resultCode ENUMERATED {
+                      // success (0), ...
+                      // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                      // referral [3] Referral OPTIONAL }
+                      // serverSaslCreds [7] OCTET STRING OPTIONAL }
+                ( byte ) 0xa0,
+                0x2C, // controls
+                0x30,
+                0x2A, // The PagedSearchControl
+                0x04,
+                0x16, // Oid : 1.2.840.113556.1.4.319
+                0x31,
+                0x2e,
+                0x32,
+                0x2e,
+                0x38,
+                0x34,
+                0x30,
+                0x2e,
+                0x31,
+                0x31,
+                0x33,
+                0x35,
+                0x35,
+                0x36,
+                0x2e,
+                0x31,
+                0x2e,
+                0x34,
+                0x2e,
+                0x33,
+                0x31,
+                0x39,
+                0x01,
+                0x01,
+                ( byte ) 0xff, // criticality: false
+                0x04,
+                0x0D,
+                0x30,
+                0x0B,
+                0x02,
+                0x01,
+                0x05, // Size = 5, cookie = "abcdef" 
+                0x04,
+                0x06,
+                'a',
+                'b',
+                'c',
+                'd',
+                'e',
+                'f' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindResponseDecorator> container = new LdapMessageContainer<BindResponseDecorator>( codec );
+
+        // Decode the BindResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindResponse
+        BindResponse bindResponse = container.getMessage();
+
+        assertEquals( 1, bindResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, bindResponse.getLdapResult().getResultCode() );
+        assertEquals( "", bindResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", bindResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = bindResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        Control control = controls.get( "1.2.840.113556.1.4.319" );
+        assertEquals( "1.2.840.113556.1.4.319", control.getOid() );
+        assertTrue( control instanceof PagedResultsDecorator );
+
+        PagedResultsDecorator pagedSearchControl = ( PagedResultsDecorator ) control;
+
+        assertEquals( 5, pagedSearchControl.getSize() );
+        assertTrue( Arrays.equals( "abcdef".getBytes(), pagedSearchControl.getCookie() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindResponse );
+
+            // Check the length
+            assertEquals( 0x3C, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindResponse with an empty credentials
+     */
+    @Test
+    public void testDecodeBindResponseServerSASLEmptyCredentials()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x10 );
+
+        stream.put( new byte[]
+            { 0x30, 0x0E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x61,
+                0x09, // CHOICE { ..., bindResponse BindResponse, ...
+                // BindResponse ::= APPLICATION[1] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                ( byte ) 0x87,
+                0x00 // serverSaslCreds [7] OCTET STRING OPTIONAL
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindResponseDecorator> container = new LdapMessageContainer<BindResponseDecorator>( codec );
+
+        // Decode the BindResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindResponse
+        BindResponse bindResponse = container.getMessage();
+
+        assertEquals( 1, bindResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, bindResponse.getLdapResult().getResultCode() );
+        assertEquals( "", bindResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", bindResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "", Strings.utf8ToString( bindResponse.getServerSaslCreds() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindResponse );
+
+            // Check the length
+            assertEquals( 0x10, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindResponse with an empty credentials with
+     * controls
+     */
+    @Test
+    public void testDecodeBindResponseServerSASLEmptyCredentialsWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2D );
+
+        stream.put( new byte[]
+            { 0x30, 0x2B, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x61,
+                0x09, // CHOICE { ..., bindResponse BindResponse, ...
+                // BindResponse ::= APPLICATION[1] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                ( byte ) 0x87,
+                0x00, // serverSaslCreds [7] OCTET STRING
+                // OPTIONAL }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindResponseDecorator> container = new LdapMessageContainer<BindResponseDecorator>( codec );
+
+        // Decode the BindResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindResponse
+        BindResponse bindResponse = container.getMessage();
+
+        assertEquals( 1, bindResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, bindResponse.getLdapResult().getResultCode() );
+        assertEquals( "", bindResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", bindResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "", Strings.utf8ToString( bindResponse.getServerSaslCreds() ) );
+
+        // Check the Control
+        Map<String, Control> controls = bindResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindResponse );
+
+            // Check the length
+            assertEquals( 0x2D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindResponse with a credentials
+     */
+    @Test
+    public void testDecodeBindResponseServerSASL()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x12 );
+
+        stream.put( new byte[]
+            { 0x30, 0x10, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x61,
+                0x0B, // CHOICE { ..., bindResponse BindResponse, ...
+                // BindResponse ::= APPLICATION[1] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                ( byte ) 0x87,
+                0x02,
+                'A',
+                'B' // serverSaslCreds [7] OCTET
+            // STRING OPTIONAL }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<BindResponseDecorator> container =
+            new LdapMessageContainer<BindResponseDecorator>( codec );
+
+        // Decode the BindResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded BindResponse
+        BindResponse bindResponse = container.getMessage();
+
+        assertEquals( 1, bindResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, bindResponse.getLdapResult().getResultCode() );
+        assertEquals( "", bindResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", bindResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "AB", Strings.utf8ToString( bindResponse.getServerSaslCreds() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( bindResponse );
+
+            // Check the length
+            assertEquals( 0x12, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a BindResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeAddResponseEmptyResult()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x61,
+                0x00, // CHOICE { ..., bindResponse BindResponse, ...
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        Asn1Container container = new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+
+        // Decode a BindResponse message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/compare/CompareRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/compare/CompareRequestTest.java
new file mode 100644
index 0000000..44d0c85
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/compare/CompareRequestTest.java
@@ -0,0 +1,793 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.compare;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.CompareRequest;
+import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the CompareRequest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CompareRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a full CompareRequest
+     */
+    @Test
+    public void testDecodeCompareRequestSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x38 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x36, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x31, // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // ava AttributeValueAssertion }
+                0x30,
+                0x0D, // AttributeValueAssertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                // assertionValue AssertionValue }
+                0x04,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded CompareRequest PDU
+        CompareRequest compareRequest = container.getMessage();
+
+        assertEquals( 1, compareRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", compareRequest.getName().toString() );
+        assertEquals( "test", compareRequest.getAttributeId() );
+        assertEquals( "value", compareRequest.getAssertionValue().toString() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( compareRequest );
+
+            // Check the length
+            assertEquals( 0x38, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty CompareRequest
+     */
+    @Test
+    public void testDecodeCompareRequestEmptyRequest()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x00 // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty entry CompareRequest
+     */
+    @Test
+    public void testDecodeCompareRequestEmptyEntry()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x18 );
+
+        stream.put( new byte[]
+            { 0x30, 0x16, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x11, // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+                0x04,
+                0x00, // entry LDAPDN,
+                // ava AttributeValueAssertion }
+                0x30,
+                0x0D, // AttributeValueAssertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                // assertionValue AssertionValue }
+                0x04,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty ava
+     */
+    @Test
+    public void testDecodeCompareRequestEmptyAVA()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x24, // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // ava AttributeValueAssertion }
+                0x30,
+                0x00 // AttributeValueAssertion ::= SEQUENCE {
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty ava
+     */
+    @Test
+    public void testDecodeCompareRequestInvalidDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x24, // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                ':',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // ava AttributeValueAssertion }
+                0x30,
+                0x00 // AttributeValueAssertion ::= SEQUENCE {
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof CompareResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( CompareResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty attributeDesc ava
+     */
+    @Test
+    public void testDecodeCompareRequestEmptyAttributeDesc()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2D );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x2B, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x26, // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // ava AttributeValueAssertion }
+                0x30,
+                0x02, // AttributeValueAssertion ::= SEQUENCE {
+                0x04,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof CompareResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, ( ( CompareResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty attributeValue ava
+     */
+    @Test
+    public void testDecodeCompareRequestEmptyAttributeValue()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x33 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x31, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x2C, // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // ava AttributeValueAssertion }
+                0x30,
+                0x08, // AttributeValueAssertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                // assertionValue AssertionValue }
+                0x04,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded CompareRequest PDU
+        CompareRequest compareRequest = container.getMessage();
+
+        assertEquals( 1, compareRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", compareRequest.getName().toString() );
+        assertEquals( "test", compareRequest.getAttributeId() );
+        assertEquals( "", compareRequest.getAssertionValue().toString() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( compareRequest );
+
+            // Check the length
+            assertEquals( 0x33, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an compare request with controls
+     */
+    @Test
+    public void testDecodeCompareRequestWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x55 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x53, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., compareRequest CompareRequest, ...
+                0x6E,
+                0x31, // CompareRequest ::= [APPLICATION 14] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // ava AttributeValueAssertion }
+                0x30,
+                0x0D, // AttributeValueAssertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                // assertionValue AssertionValue }
+                0x04,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareRequestDecorator> container = new LdapMessageContainer<CompareRequestDecorator>(
+            codec );
+
+        // Decode the CompareRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Ceck the decoded CompareRequest PDU
+        CompareRequest compareRequest = container.getMessage();
+
+        assertEquals( 1, compareRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", compareRequest.getName().toString() );
+        assertEquals( "test", compareRequest.getAttributeId() );
+        assertEquals( "value", compareRequest.getAssertionValue().toString() );
+
+        // Check the Control
+        Map<String, Control> controls = compareRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( compareRequest );
+
+            // Check the length
+            assertEquals( 0x55, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/compare/CompareResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/compare/CompareResponseTest.java
new file mode 100644
index 0000000..8b2019c
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/compare/CompareResponseTest.java
@@ -0,0 +1,294 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.compare;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.CompareResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.CompareResponse;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the CompareResponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CompareResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a CompareResponse
+     */
+    @Test
+    public void testDecodeCompareResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6F,
+                0x07, // CHOICE { ..., compareResponse CompareResponse,
+                // ...
+                // CompareResponse ::= [APPLICATION 15] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareResponseDecorator> container =
+            new LdapMessageContainer<CompareResponseDecorator>( codec );
+
+        // Decode the CompareResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded CompareResponse PDU
+        CompareResponse compareResponse = container.getMessage();
+
+        assertEquals( 1, compareResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, compareResponse.getLdapResult().getResultCode() );
+        assertEquals( "", compareResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", compareResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( compareResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a CompareResponse with controls
+     */
+    @Test
+    public void testDecodeCompareResponseSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6F,
+                0x07, // CHOICE { ..., compareResponse CompareResponse,
+                // ...
+                // CompareResponse ::= [APPLICATION 15] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareResponseDecorator> container =
+            new LdapMessageContainer<CompareResponseDecorator>( codec );
+
+        // Decode the CompareResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded CompareResponse PDU
+        CompareResponse compareResponse = container.getMessage();
+
+        assertEquals( 1, compareResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, compareResponse.getLdapResult().getResultCode() );
+        assertEquals( "", compareResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", compareResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = compareResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( compareResponse );
+
+            // Check the length
+            assertEquals( 0x2B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a CompareResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeCompareResponseEmptyResult()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6F,
+                0x00 // CHOICE { ..., compareResponse CompareResponse,
+            // ...
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<CompareResponseDecorator> container =
+            new LdapMessageContainer<CompareResponseDecorator>( codec );
+
+        // Decode a CompareResponse message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzControlTest.java
new file mode 100644
index 0000000..a38fb8f
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/proxiedauthz/ProxiedAuthzControlTest.java
@@ -0,0 +1,226 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.proxiedauthz;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.controls.ProxiedAuthz;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the ProxiedAuthzControlTest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProxiedAuthzControlTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a ProxiedAuthzControl with a DN user
+     */
+    @Test
+    public void testDecodeProxiedAuthzControlDnSuccess() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x14 );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= dn:dc=example,dc=com
+                'd', 'n', ':', 'd', 'c', '=', 'e', 'x', 'a', 'm', 'p', 'l', 'e', ',', 'd', 'c', '=', 'c', 'o', 'm'
+        } );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        ProxiedAuthz proxiedAuthz = ( ProxiedAuthz ) decorator.decode( bb.array() );
+
+        assertEquals( "dn:dc=example,dc=com", proxiedAuthz.getAuthzId() );
+    }
+
+
+    /**
+     * Test the decoding of a ProxiedAuthzControl with a normal user
+     */
+    @Test
+    public void testDecodeProxiedAuthzControlUSuccess() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0C );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= u:elecharny
+                'u', ':', 'e', 'l', (byte)0xc3, (byte)0xa9, 'c', 'h', 'a', 'r', 'n', 'y'
+        } );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        ProxiedAuthz proxiedAuthz = ( ProxiedAuthz ) decorator.decode( bb.array() );
+
+        assertEquals( "u:el\u00e9charny", proxiedAuthz.getAuthzId() );
+    }
+
+
+    /**
+     * Test the decoding of a ProxiedAuthzControl with a anonymous user
+     */
+    @Test
+    public void testDecodeProxiedAuthzControlAnonymousSuccess() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x00 );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= anonymous
+        } );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        ProxiedAuthz proxiedAuthz = ( ProxiedAuthz ) decorator.decode( bb.array() );
+
+        assertEquals( "", proxiedAuthz.getAuthzId() );
+    }
+    
+    
+    /**
+     * Test the decoding of a ProxiedAuthzControl with a wrong DN user
+     */
+    @Test( expected = RuntimeException.class)
+    public void testDecodeProxiedAuthzControlWrongDn() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x10 );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= dn:dc=example,dc=com
+                'd', 'n', ':', 'd', 'c', '=', 'e', 'x', 'a', 'm', 'p', 'l', 'e', ',', 'd', 'c'
+        } );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+    
+    
+    /**
+     * Test the decoding of a ProxiedAuthzControl with a wrong user
+     */
+    @Test( expected = RuntimeException.class)
+    public void testDecodeProxiedAuthzControlWrongAuthzId() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= dn:dc=example,dc=com
+                'v', 'n', ':', 'w', 'r', 'o', 'n', 'g'
+        } );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test encoding of a ProxiedAuthzControl.
+     */
+    @Test
+    public void testEncodeProxiedDnAuthzControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x14 );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= dn:dc=example,dc=com
+                  'd', 'n', ':', 'd', 'c', '=', 'e', 'x', 'a', 'm', 'p', 'l', 'e', ',', 'd', 'c', '=', 'c', 'o', 'm'
+            } );
+
+        String expected = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        ProxiedAuthz proxiedAuthz = ( ProxiedAuthz ) decorator.getDecorated();
+        proxiedAuthz.setAuthzId( "dn:dc=example,dc=com" );
+        bb = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+        String decoded = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+
+
+    /**
+     * Test encoding of a ProxiedAuthzControl.
+     */
+    @Test
+    public void testEncodeProxiedUserAuthzControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0C );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= u:elecharny
+                'u', ':', 'e', 'l', (byte)0xc3, (byte)0xa9, 'c', 'h', 'a', 'r', 'n', 'y'
+        } );
+
+        String expected = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        ProxiedAuthz proxiedAuthz = ( ProxiedAuthz ) decorator.getDecorated();
+        proxiedAuthz.setAuthzId( "u:el\u00e9charny" );
+        bb = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+        String decoded = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+
+
+    /**
+     * Test encoding of a ProxiedAuthzControl.
+     */
+    @Test
+    public void testEncodeProxiedAnonymousAuthzControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x00 );
+        bb.put( new byte[]
+            {
+                // ProxiedAuthzNotification ::= anonymous
+        } );
+
+        String expected = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        ProxiedAuthzDecorator decorator = new ProxiedAuthzDecorator( codec );
+
+        ProxiedAuthz proxiedAuthz = ( ProxiedAuthz ) decorator.getDecorated();
+        proxiedAuthz.setAuthzId( "" );
+        bb = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+        String decoded = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeControlTest.java
new file mode 100644
index 0000000..c6822c2
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/entryChange/EntryChangeControlTest.java
@@ -0,0 +1,383 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.entryChange;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.nio.ByteBuffer;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.controls.ChangeType;
+import org.apache.directory.api.ldap.model.message.controls.EntryChange;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the EntryChangeControlTest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class EntryChangeControlTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a EntryChangeControl
+     */
+    @Test
+    public void testDecodeEntryChangeControlSuccess() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0D );
+        bb.put( new byte[]
+            {
+                0x30, 0x0B, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x08, //     changeType ENUMERATED {
+                      //         modDN (8)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                '=',
+                'b', //     previousDN LDAPDN OPTIONAL, -- modifyDN ops. only
+                0x02,
+                0x01,
+                0x10 //     changeNumber INTEGER OPTIONAL } -- if supported
+        } );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        EntryChange entryChange = ( EntryChange ) decorator.decode( bb.array() );
+
+        assertEquals( ChangeType.MODDN, entryChange.getChangeType() );
+        assertEquals( "a=b", entryChange.getPreviousDn().toString() );
+        assertEquals( 16, entryChange.getChangeNumber() );
+    }
+
+
+    /**
+     * Test the decoding of a EntryChangeControl
+     */
+    @Test
+    public void testDecodeEntryChangeControlSuccessLongChangeNumber() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x13 );
+        bb.put( new byte[]
+            {
+                0x30, 0x11, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x08, //     changeType ENUMERATED {
+                      //         modDN (8)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                '=',
+                'b', //     previousDN LDAPDN OPTIONAL, -- modifyDN ops. only
+                0x02,
+                0x07, //     changeNumber INTEGER OPTIONAL } -- if supported
+                0x12,
+                0x34,
+                0x56,
+                0x78,
+                ( byte ) 0x9A,
+                ( byte ) 0xBC,
+                ( byte ) 0xDE
+        } );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        EntryChange entryChange = ( EntryChange ) decorator.decode( bb.array() );
+
+        assertEquals( ChangeType.MODDN, entryChange.getChangeType() );
+        assertEquals( "a=b", entryChange.getPreviousDn().toString() );
+        assertEquals( 5124095576030430L, entryChange.getChangeNumber() );
+    }
+
+
+    /**
+     * Test the decoding of a EntryChangeControl with a add and a change number
+     */
+    @Test
+    public void testDecodeEntryChangeControlWithADDAndChangeNumber() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            {
+                0x30, 0x06, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x01, //     changeType ENUMERATED {
+                      //         Add (1)
+                      //     }
+                0x02,
+                0x01,
+                0x10 //     changeNumber INTEGER OPTIONAL -- if supported
+                     // }
+        } );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        EntryChange entryChange = ( EntryChange ) decorator.decode( bb.array() );
+
+        assertEquals( ChangeType.ADD, entryChange.getChangeType() );
+        assertNull( entryChange.getPreviousDn() );
+        assertEquals( 16, entryChange.getChangeNumber() );
+    }
+
+
+    /**
+     * Test the decoding of a EntryChangeControl with a add so we should not
+     * have a PreviousDN
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeEntryChangeControlWithADDAndPreviousDNBad() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0D );
+        bb.put( new byte[]
+            {
+                0x30, 0x0B, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x01, //     changeType ENUMERATED {
+                      //         ADD (1)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                '=',
+                'b', //     previousDN LDAPDN OPTIONAL, --
+                     //     modifyDN ops. only
+                0x02,
+                0x01,
+                0x10 //     changeNumber INTEGER OPTIONAL -- if supported
+                     // }
+        } );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a EntryChangeControl with a add and nothing else
+     */
+    @Test
+    public void testDecodeEntryChangeControlWithADD() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                0x30, 0x03, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x01, //     changeType ENUMERATED {
+                      //         ADD (1)
+                      //     }
+                      // }
+            } );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        EntryChange entryChange = ( EntryChange ) decorator.decode( bb.array() );
+
+        assertEquals( ChangeType.ADD, entryChange.getChangeType() );
+        assertNull( entryChange.getPreviousDn() );
+        assertEquals( EntryChangeDecorator.UNDEFINED_CHANGE_NUMBER, entryChange.getChangeNumber() );
+    }
+
+
+    /**
+     * Test the decoding of a EntryChangeControl with a wrong changeType and
+     * nothing else
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeEntryChangeControlWithWrongChangeType() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                0x30, 0x03, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x03, //     changeType ENUMERATED {
+                      //         BAD Change Type
+                      //     }
+                      // }
+            } );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a EntryChangeControl with a wrong changeNumber
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeEntryChangeControlWithWrongChangeNumber() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x1C );
+        bb.put( new byte[]
+            {
+                0x30, 0x1A, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x08, //     changeType ENUMERATED {
+                      //         modDN (8)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                '=',
+                'b', //     previousDN LDAPDN OPTIONAL, -- modifyDN ops. only
+                0x02,
+                0x10, //     changeNumber INTEGER OPTIONAL -- if supported
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00,
+                0x00
+        } );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test encoding of a EntryChangeControl.
+     */
+    @Test
+    public void testEncodeEntryChangeControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0D );
+        bb.put( new byte[]
+            {
+                0x30, 0x0B, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x08, //     changeType ENUMERATED {
+                      //         modDN (8)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                '=',
+                'b', //     previousDN LDAPDN OPTIONAL, -- modifyDN ops. only
+                0x02,
+                0x01,
+                0x10, //     changeNumber INTEGER OPTIONAL -- if supported
+            } );
+
+        String expected = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        EntryChange entryChange = ( EntryChange ) decorator.getDecorated();
+        entryChange.setChangeType( ChangeType.MODDN );
+        entryChange.setChangeNumber( 16 );
+        entryChange.setPreviousDn( new Dn( "a=b" ) );
+        bb = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+        String decoded = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+
+
+    /**
+     * Test encoding of a EntryChangeControl with a long changeNumber.
+     */
+    @Test
+    public void testEncodeEntryChangeControlLong() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x13 );
+        bb.put( new byte[]
+            {
+                0x30, 0x11, // EntryChangeNotification ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x08, //     changeType ENUMERATED {
+                      //         modDN (8)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                '=',
+                'b', //     previousDN LDAPDN OPTIONAL, -- modifyDN ops. only
+                0x02,
+                0x07, //     changeNumber INTEGER OPTIONAL -- if supported
+                0x12,
+                0x34,
+                0x56,
+                0x78,
+                ( byte ) 0x9a,
+                ( byte ) 0xbc,
+                ( byte ) 0xde
+        } );
+
+        String expected = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        EntryChangeDecorator decorator = new EntryChangeDecorator( codec );
+
+        EntryChange entryChange = ( EntryChange ) decorator.getDecorated();
+
+        entryChange.setChangeType( ChangeType.MODDN );
+        entryChange.setChangeNumber( 5124095576030430L );
+        entryChange.setPreviousDn( new Dn( "a=b" ) );
+        bb = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+        String decoded = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedSearchControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedSearchControlTest.java
new file mode 100644
index 0000000..425e6b3
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/pagedSearch/PagedSearchControlTest.java
@@ -0,0 +1,264 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.pagedSearch;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.controls.PagedResults;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the PagedSearchControlTest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PagedSearchControlTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test encoding of a PagedSearchControl.
+     */
+    @Test
+    public void testEncodePagedSearchControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0B );
+        bb.put( new byte[]
+            {
+                0x30, 0x09, // realSearchControlValue ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x20, // size INTEGER,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't' // cookie OCTET STRING,
+        } );
+        bb.flip();
+
+        PagedResultsDecorator decorator = new PagedResultsDecorator( codec );
+
+        PagedResults pagedSearch = ( PagedResults ) decorator.decode( bb.array() );
+
+        assertEquals( 32, pagedSearch.getSize() );
+        assertTrue( Arrays.equals( Strings.getBytesUtf8( "test" ),
+            pagedSearch.getCookie() ) );
+
+        bb.flip();
+
+        PagedResultsDecorator ctrl = new PagedResultsDecorator( codec );
+        ctrl.setSize( 32 );
+        ctrl.setCookie( Strings.getBytesUtf8( "test" ) );
+
+        ByteBuffer buffer = ctrl.encode( ByteBuffer.allocate( ctrl.computeLength() ) );
+        String decoded = Strings.dumpBytes( buffer.array() );
+        String expected = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+
+
+    /**
+     * Test the decoding of a PagedSearchControl with no cookie
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodePagedSearchRequestNoCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                0x30, 0x03, // realSearchControlValue ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x20 // size INTEGER,
+        } );
+        bb.flip();
+
+        PagedResultsDecorator decorator = new PagedResultsDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a PagedSearchControl with no size
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodePagedSearchRequestNoSize() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            {
+                0x30, 0x06, // realSearchControlValue ::= SEQUENCE {
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't' // cookie OCTET STRING,
+        } );
+        bb.flip();
+
+        PagedResultsDecorator decorator = new PagedResultsDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a PagedSearchControl with no size  and no cookie
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodePagedSearchRequestNoSizeNoCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                0x30, 0x00, // realSearchControlValue ::= SEQUENCE 
+            } );
+        bb.flip();
+
+        PagedResultsDecorator decorator = new PagedResultsDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test encoding of a PagedSearchControl with a negative size
+     */
+    @Test
+    public void testEncodePagedSearchControlNegativeSize() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x09, // realSearchControlValue ::= SEQUENCE {
+                0x02,
+                0x01,
+                ( byte ) 0xFF, // size INTEGER,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't' // cookie OCTET STRING,
+        } );
+        bb.flip();
+
+        PagedResultsDecorator decorator = new PagedResultsDecorator( codec );
+
+        PagedResults pagedSearch = ( PagedResults ) decorator.decode( bb.array() );
+
+        assertEquals( Integer.MAX_VALUE, pagedSearch.getSize() );
+        assertTrue( Arrays.equals( Strings.getBytesUtf8( "test" ),
+            pagedSearch.getCookie() ) );
+
+        bb.flip();
+
+        PagedResultsDecorator ctrl = new PagedResultsDecorator( codec );
+        ctrl.setSize( -1 );
+        ctrl.setCookie( Strings.getBytesUtf8( "test" ) );
+
+        ByteBuffer buffer = ctrl.encode( ByteBuffer.allocate( ctrl.computeLength() ) );
+        String decoded = Strings.dumpBytes( buffer.array() );
+        String expected = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+
+
+    /**
+     * Test encoding of a PagedSearchControl with a empty size
+     */
+    @Test(expected = DecoderException.class)
+    public void testEncodePagedSearchControlEmptySize() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0a );
+        bb.put( new byte[]
+            {
+                0x30, 0x08, // realSearchControlValue ::= SEQUENCE {
+                0x02,
+                0x00, // size INTEGER,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't' // cookie OCTET STRING,
+        } );
+        bb.flip();
+
+        PagedResultsDecorator decorator = new PagedResultsDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test encoding of a PagedSearchControl with a empty cookie
+     */
+    @Test
+    public void testEncodePagedSearchControlEmptyCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                0x30, 0x05, // realSearchControlValue ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x20, // size INTEGER,
+                0x04,
+                0x00 // cookie OCTET STRING,
+        } );
+        bb.flip();
+
+        PagedResultsDecorator decorator = new PagedResultsDecorator( codec );
+
+        PagedResults pagedSearch = ( PagedResults ) decorator.decode( bb.array() );
+
+        assertEquals( 32, pagedSearch.getSize() );
+        assertNull( pagedSearch.getCookie() );
+
+        PagedResultsDecorator ctrl = new PagedResultsDecorator( codec );
+        ctrl.setSize( 32 );
+        ctrl.setCookie( null );
+
+        ByteBuffer buffer = ctrl.encode( ByteBuffer.allocate( ctrl.computeLength() ) );
+        String decoded = Strings.dumpBytes( buffer.array() );
+        String expected = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PSearchControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PSearchControlTest.java
new file mode 100644
index 0000000..b38669e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/persistentSearch/PSearchControlTest.java
@@ -0,0 +1,270 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.persistentSearch;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.controls.ChangeType;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the PSearchControlTest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PSearchControlTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test encoding of a PSearchControl.
+     * @throws Exception on error
+     */
+    @Test
+    public void testEncodePSearchControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0B );
+        bb.put( new byte[]
+            {
+                0x30, 0x09, // PersistentSearch ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // changeTypes INTEGER,
+                0x01,
+                0x01,
+                0x00, // changesOnly BOOLEAN,
+                0x01,
+                0x01,
+                0x00 // returnECs BOOLEAN
+        } );
+
+        String expected = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+        PersistentSearch ctrl = ( PersistentSearch ) decorator.getDecorated();
+        ctrl.setChangesOnly( false );
+        ctrl.setReturnECs( false );
+        ctrl.setChangeTypes( 1 );
+        bb = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+        String decoded = Strings.dumpBytes( bb.array() );
+        assertEquals( expected, decoded );
+    }
+
+
+    /**
+     * Test the decoding of a PSearchControl with combined changes types
+     */
+    @Test
+    public void testDecodeModifyDNRequestSuccessChangeTypesAddModDN() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x09, // PersistentSearch ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x09, // changeTypes INTEGER,
+                0x01,
+                0x01,
+                0x00, // changesOnly BOOLEAN,
+                0x01,
+                0x01,
+                0x00 // returnECs BOOLEAN
+        } );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+
+        PersistentSearch ctrl = ( PersistentSearch ) decorator.decode( bb.array() );
+
+        int changeTypes = ctrl.getChangeTypes();
+        assertTrue( ChangeType.ADD.presentIn( changeTypes ) );
+        assertTrue( ChangeType.MODDN.presentIn( changeTypes ) );
+        assertEquals( false, ctrl.isChangesOnly() );
+        assertEquals( false, ctrl.isReturnECs() );
+    }
+
+
+    /**
+     * Test the decoding of a PSearchControl with a changes types which
+     * value is 0
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeModifyDNRequestSuccessChangeTypes0() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x09, // PersistentSearch ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x00, // changeTypes INTEGER,
+                0x01,
+                0x01,
+                0x00, // changesOnly BOOLEAN,
+                0x01,
+                0x01,
+                0x00 // returnECs BOOLEAN
+        } );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a PSearchControl with a changes types which
+     * value is above 15
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeModifyDNRequestSuccessChangeTypes22() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            {
+                0x30, 0x09, // PersistentSearch ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x22, // changeTypes INTEGER,
+                0x01,
+                0x01,
+                0x00, // changesOnly BOOLEAN,
+                0x01,
+                0x01,
+                0x00 // returnECs BOOLEAN
+        } );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a PSearchControl with a null sequence
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeModifyDNRequestSuccessNullSequence() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                0x30, 0x00, // PersistentSearch ::= SEQUENCE {
+            } );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a PSearchControl without changeTypes
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeModifyDNRequestSuccessWithoutChangeTypes() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            {
+                0x30, 0x06, // PersistentSearch ::= SEQUENCE {
+                0x01,
+                0x01,
+                0x00, // changesOnly BOOLEAN,
+                0x01,
+                0x01,
+                0x00 // returnECs BOOLEAN
+        } );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a PSearchControl without changeOnly
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeModifyDNRequestSuccessWithoutChangesOnly() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            {
+                0x30, 0x06, // PersistentSearch ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // changeTypes INTEGER,
+                0x01,
+                0x01,
+                0x00 // returnECs BOOLEAN
+        } );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a PSearchControl without returnECs
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeModifyDNRequestSuccessWithoutReturnECs() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            {
+                0x30, 0x06, // PersistentSearch ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // changeTypes INTEGER,
+                0x01,
+                0x01,
+                0x00, // changesOnly BOOLEAN,
+            } );
+        bb.flip();
+
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubEntryControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubEntryControlTest.java
new file mode 100644
index 0000000..179c9e1
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/search/subentries/SubEntryControlTest.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.controls.search.subentries;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.controls.Subentries;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the SubEntryControlTest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SubEntryControlTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a SubEntryControl with a true visibility
+     */
+    @Test
+    public void testDecodeSubEntryVisibilityTrue() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x03 );
+        bb.put( new byte[]
+            {
+                0x01, 0x01, ( byte ) 0xFF // Visibility ::= BOOLEAN
+        } );
+        bb.flip();
+
+        SubentriesDecorator decorator = new SubentriesDecorator( codec );
+
+        Subentries subentries = ( Subentries ) decorator.decode( bb.array() );
+
+        assertTrue( subentries.isVisible() );
+
+        // test encoding
+        try
+        {
+            ByteBuffer buffer = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+            String expected = Strings.dumpBytes( bb.array() );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SubEntryControl with a false visibility
+     */
+    @Test
+    public void testDecodeSubEntryVisibilityFalse() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x03 );
+        bb.put( new byte[]
+            {
+                0x01, 0x01, 0x00 // Visibility ::= BOOLEAN
+        } );
+        bb.flip();
+
+        SubentriesDecorator decorator = new SubentriesDecorator( codec );
+
+        Subentries subentries = ( Subentries ) decorator.decode( bb.array() );
+
+        assertFalse( subentries.isVisible() );
+
+        // test encoding
+        try
+        {
+            ByteBuffer buffer = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+            String expected = Strings.dumpBytes( bb.array() );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SubEntryControl with an empty visibility
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeSubEntryEmptyVisibility() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+
+        bb.put( new byte[]
+            {
+                0x01, 0x00 // Visibility ::= BOOLEAN
+        } );
+
+        bb.flip();
+
+        // Allocate a LdapMessage Container
+        SubentriesDecorator decorator = new SubentriesDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a bad SubEntryControl
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeSubEntryBad() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x03 );
+
+        bb.put( new byte[]
+            {
+                0x02, 0x01, 0x01 // Visibility ::= BOOLEAN
+        } );
+
+        bb.flip();
+
+        // Allocate a LdapMessage Container
+        SubentriesDecorator decorator = new SubentriesDecorator( codec );
+
+        decorator.decode( bb.array() );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestControlTest.java
new file mode 100644
index 0000000..ede0fd1
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/sort/SortRequestControlTest.java
@@ -0,0 +1,231 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.controls.SortKey;
+import org.apache.directory.api.ldap.model.message.controls.SortRequest;
+import org.junit.Test;
+
+/**
+ * Tests for SortRequestControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortRequestControlTest extends AbstractCodecServiceTest
+{
+    @Test
+    public void testDecodeControl() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 16 );
+        buffer.put( new byte[]
+            {
+               0x30, 0x0E,
+                0x30, 0x0C,
+                   0x04, 0x02, 'c', 'n',
+                   (byte)0x80, 0x03, 'o', 'i', 'd',
+                   (byte)0x81, 0x01, 0x00
+            } );
+        buffer.flip();
+        
+        SortRequestDecorator decorator = new SortRequestDecorator( codec );
+        SortRequest control = ( SortRequest ) decorator.decode( buffer.array() );
+        
+        assertEquals( 1, control.getSortKeys().size() );
+        
+        SortKey sk = control.getSortKeys().get( 0 );
+        assertEquals( "cn", sk.getAttributeTypeDesc() );
+        assertEquals( "oid", sk.getMatchingRuleId() );
+        assertFalse( sk.isReverseOrder() );
+        
+        // default value of false reverseOrder will not be encoded
+        int skipBytes = 3;
+        ByteBuffer encoded = ByteBuffer.allocate( buffer.capacity() - skipBytes );
+        decorator.computeLength();
+        decorator.encode( encoded );
+        assertFalse( Arrays.equals( buffer.array(), encoded.array() ) );
+        assertEquals( buffer.array().length - skipBytes, encoded.array().length );
+    }
+    
+    
+    @Test
+    public void testDecodeControlWithMultipleSortKeys() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 0x1E );
+        buffer.put( new byte[]
+            {
+               0x30, 0x1C,
+
+                0x30, 0x0C,
+                   0x04, 0x02, 'c', 'n',
+                   (byte)0x80, 0x03, 'o', 'i', 'd',
+                   (byte)0x81, 0x01, (byte)0xFF,
+
+                0x30, 0x0C,
+                   0x04, 0x02, 's', 'n',
+                   (byte)0x80, 0x03, 'i', 'o', 'd',
+                   (byte)0x81, 0x01, (byte)0xFF
+            } );
+        buffer.flip();
+        
+        SortRequestDecorator decorator = new SortRequestDecorator( codec );
+        SortRequest control = ( SortRequest ) decorator.decode( buffer.array() );
+        
+        assertEquals( 2, control.getSortKeys().size() );
+
+        SortKey sk = control.getSortKeys().get( 0 );
+        assertEquals( "cn", sk.getAttributeTypeDesc() );
+        assertEquals( "oid", sk.getMatchingRuleId() );
+        assertTrue( sk.isReverseOrder() );
+        
+        sk = control.getSortKeys().get( 1 );
+        assertEquals( "sn", sk.getAttributeTypeDesc() );
+        assertEquals( "iod", sk.getMatchingRuleId() );
+        assertTrue( sk.isReverseOrder() );
+        
+        ByteBuffer encoded = ByteBuffer.allocate( buffer.capacity() );
+        decorator.computeLength();
+        decorator.encode( encoded );
+        assertTrue( Arrays.equals( buffer.array(), encoded.array() ) );
+    }
+
+    
+    @Test(expected = DecoderException.class)
+    public void testDecodeWithoutAtDesc() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 7 );
+        buffer.put( new byte[]
+            {
+               0x30, 0x05,
+                0x30, 0x03,
+                (byte)0x81, 0x01, 0x00
+            } );
+        buffer.flip();
+        
+        SortRequestDecorator decorator = new SortRequestDecorator( codec );
+        decorator.decode( buffer.array() );
+    }
+    
+    
+    @Test
+    public void testDecodeControlWithoutMrOid() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 11 );
+        buffer.put( new byte[]
+            {
+               0x30, 0x09,
+                0x30, 0x07,
+                   0x04, 0x02, 'c', 'n',
+                   (byte)0x81, 0x01, (byte)0xFF
+            } );
+        buffer.flip();
+        
+        SortRequestDecorator decorator = new SortRequestDecorator( codec );
+        SortRequest control = ( SortRequest ) decorator.decode( buffer.array() );
+        
+        assertEquals( 1, control.getSortKeys().size() );
+        
+        SortKey sk = control.getSortKeys().get( 0 );
+        assertEquals( "cn", sk.getAttributeTypeDesc() );
+        assertNull( sk.getMatchingRuleId() );
+        assertTrue( sk.isReverseOrder() );
+        
+        ByteBuffer encoded = ByteBuffer.allocate( buffer.capacity() );
+        decorator.computeLength();
+        decorator.encode( encoded );
+        assertTrue( Arrays.equals( buffer.array(), encoded.array() ) );
+    }
+    
+    
+    @Test
+    public void testDecodeControlWithAtDescOnly() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 8 );
+        buffer.put( new byte[]
+            {
+               0x30, 0x06,
+                0x30, 0x04,
+                0x04, 0x02, 'c', 'n'
+            } );
+        buffer.flip();
+        
+        SortRequestDecorator decorator = new SortRequestDecorator( codec );
+        SortRequest control = ( SortRequest ) decorator.decode( buffer.array() );
+        
+        assertEquals( 1, control.getSortKeys().size() );
+        
+        SortKey sk = control.getSortKeys().get( 0 );
+        assertEquals( "cn", sk.getAttributeTypeDesc() );
+        assertNull( sk.getMatchingRuleId() );
+        assertFalse( sk.isReverseOrder() );
+        
+        ByteBuffer encoded = ByteBuffer.allocate( buffer.capacity() );
+        decorator.computeLength();
+        decorator.encode( encoded );
+        assertTrue( Arrays.equals( buffer.array(), encoded.array() ) );
+    }
+
+    
+    @Test
+    public void testDecodeControlWithMultipleAtDescOnly() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 0x0E );
+        buffer.put( new byte[]
+            {
+               0x30, 0x0C,
+                0x30, 0x04,
+                 0x04, 0x02, 'c', 'n',
+                0x30, 0x04,
+                 0x04, 0x02, 's', 'n'
+            } );
+        buffer.flip();
+        
+        SortRequestDecorator decorator = new SortRequestDecorator( codec );
+        SortRequest control = ( SortRequest ) decorator.decode( buffer.array() );
+        
+        assertEquals( 2, control.getSortKeys().size() );
+        
+        SortKey sk = control.getSortKeys().get( 0 );
+        assertEquals( "cn", sk.getAttributeTypeDesc() );
+        assertNull( sk.getMatchingRuleId() );
+        assertFalse( sk.isReverseOrder() );
+        
+        sk = control.getSortKeys().get( 1 );
+        assertEquals( "sn", sk.getAttributeTypeDesc() );
+        assertNull( sk.getMatchingRuleId() );
+        assertFalse( sk.isReverseOrder() );
+        
+        ByteBuffer encoded = ByteBuffer.allocate( buffer.capacity() );
+        decorator.computeLength();
+        decorator.encode( encoded );
+        assertTrue( Arrays.equals( buffer.array(), encoded.array() ) );
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseControlTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseControlTest.java
new file mode 100644
index 0000000..3bb6ded
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/controls/sort/SortResponseControlTest.java
@@ -0,0 +1,107 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.controls.sort;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.codec.controls.sort.SortResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.controls.SortResponse;
+import org.apache.directory.api.ldap.model.message.controls.SortResultCode;
+import org.junit.Test;
+
+/**
+ * Tests for SortResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortResponseControlTest extends AbstractCodecServiceTest
+{
+    @Test
+    public void testDecodeControl() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 0x09 );
+        buffer.put( new byte[]
+            {
+               0x30, 0x07,
+                0x0A, 0x01, 0x00,
+                0x04, 0x02, 'c', 'n'
+            } );
+        buffer.flip();
+        
+        SortResponseDecorator decorator = new SortResponseDecorator( codec );
+        SortResponse control = ( SortResponse ) decorator.decode( buffer.array() );
+        
+        assertEquals( SortResultCode.SUCCESS, control.getSortResult() );
+        assertEquals( "cn", control.getAttributeName() );
+        
+        ByteBuffer encoded = ByteBuffer.allocate( buffer.capacity() );
+        decorator.computeLength();
+        decorator.encode( encoded );
+        assertTrue( Arrays.equals( buffer.array(), encoded.array() ) );
+    }
+
+    
+    @Test
+    public void testDecodeControlWithoutAtType() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 0x05 );
+        buffer.put( new byte[]
+            {
+               0x30, 0x03,
+                0x0A, 0x01, 0x10
+            } );
+        buffer.flip();
+        
+        SortResponseDecorator decorator = new SortResponseDecorator( codec );
+        SortResponse control = ( SortResponse ) decorator.decode( buffer.array() );
+        
+        assertEquals( SortResultCode.NOSUCHATTRIBUTE, control.getSortResult() );
+        assertNull( control.getAttributeName() );
+        
+        ByteBuffer encoded = ByteBuffer.allocate( buffer.capacity() );
+        decorator.computeLength();
+        decorator.encode( encoded );
+        assertTrue( Arrays.equals( buffer.array(), encoded.array() ) );
+    }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testDecodeControlWithWrongResultCode() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 0x05 );
+        buffer.put( new byte[]
+            {
+               0x30, 0x03,
+                0x0A, 0x01, 0x0A
+            } );
+        buffer.flip();
+        
+        SortResponseDecorator decorator = new SortResponseDecorator( codec );
+        decorator.decode( buffer.array() );
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/del/DelRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/del/DelRequestTest.java
new file mode 100644
index 0000000..9e5f4a3
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/del/DelRequestTest.java
@@ -0,0 +1,423 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.del;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.DeleteRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteRequest;
+import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
+import org.apache.directory.api.ldap.model.message.DeleteResponseImpl;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the DelRequest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DelRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a full DelRequest
+     */
+    @Test
+    public void testDecodeDelRequestSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x27 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x25, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., delRequest DelRequest, ...
+                // DelRequest ::= [APPLICATION 10] LDAPDN;
+                0x4A,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<DeleteRequestDecorator> container = new LdapMessageContainer<DeleteRequestDecorator>(
+            codec );
+
+        // Decode a DelRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded DelRequest PDU
+        DeleteRequest delRequest = container.getMessage();
+
+        assertEquals( 1, delRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", delRequest.getName().toString() );
+
+        // Check the length
+        DeleteRequest internalDeleteRequest = new DeleteRequestImpl();
+        internalDeleteRequest.setMessageId( delRequest.getMessageId() );
+        internalDeleteRequest.setName( delRequest.getName() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalDeleteRequest );
+
+            // Check the length
+            assertEquals( 0x27, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full DelRequest
+     */
+    @Test
+    public void testDecodeDelRequestBadDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x27 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x25, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., delRequest DelRequest, ...
+                // DelRequest ::= [APPLICATION 10] LDAPDN;
+                0x4A,
+                0x20,
+                'c',
+                'n',
+                ':',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<DeleteRequestDecorator> container = new LdapMessageContainer<DeleteRequestDecorator>(
+            codec );
+
+        // Decode a DelRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof DeleteResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( DeleteResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of an empty DelRequest
+     */
+    @Test
+    public void testDecodeDelRequestEmpty()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., delRequest DelRequest, ...
+                // DelRequest ::= [APPLICATION 10] LDAPDN;
+                0x4A,
+                0x00 // Empty Dn
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<DeleteRequestDecorator> container = new LdapMessageContainer<DeleteRequestDecorator>(
+            codec );
+
+        // Decode a DelRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full DelRequest with controls
+     */
+    @Test
+    public void testDecodeDelRequestSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x44 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x42, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., delRequest DelRequest, ...
+                // DelRequest ::= [APPLICATION 10] LDAPDN;
+                0x4A,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<DeleteRequestDecorator> container = new LdapMessageContainer<DeleteRequestDecorator>(
+            codec );
+
+        // Decode a DelRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded DelRequest PDU
+        DeleteRequest delRequest = container.getMessage();
+
+        assertEquals( 1, delRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", delRequest.getName().toString() );
+
+        // Check the Control
+        Map<String, Control> controls = delRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        DeleteRequest internalDeleteRequest = new DeleteRequestImpl();
+        internalDeleteRequest.setMessageId( delRequest.getMessageId() );
+        internalDeleteRequest.setName( delRequest.getName() );
+        internalDeleteRequest.addControl( control );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalDeleteRequest );
+
+            // Check the length
+            assertEquals( 0x44, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/del/DelResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/del/DelResponseTest.java
new file mode 100644
index 0000000..49a6589
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/del/DelResponseTest.java
@@ -0,0 +1,359 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.del;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.DeleteResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.DeleteResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the DelResponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DelResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a DelResponse
+     */
+    @Test
+    public void testDecodeDelResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2D );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x2B, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6B,
+                0x26, // CHOICE { ..., delResponse DelResponse, ...
+                // DelResponse ::= [APPLICATION 11] LDAPResult
+                0x0A,
+                0x01,
+                0x21, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x1F, // matchedDN LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x04,
+                0x00 // errorMessage
+            // LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<DeleteResponseDecorator> container =
+            new LdapMessageContainer<DeleteResponseDecorator>( codec );
+
+        // Decode the DelResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded DelResponse PDU
+        DeleteResponse delResponse = container.getMessage();
+
+        assertEquals( 1, delResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.ALIAS_PROBLEM, delResponse.getLdapResult().getResultCode() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", delResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", delResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( delResponse );
+
+            // Check the length
+            assertEquals( 0x2D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a DelResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeDelResponseEmptyResult()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6B,
+                0x00, // CHOICE { ..., delResponse DelResponse, ...
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<DeleteResponseDecorator> container =
+            new LdapMessageContainer<DeleteResponseDecorator>( codec );
+
+        // Decode a DelResponse message
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a DelResponse with controls
+     */
+    @Test
+    public void testDecodeDelResponseSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x4A );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x48, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6B,
+                0x26, // CHOICE { ..., delResponse DelResponse, ...
+                      // DelResponse ::= [APPLICATION 11] LDAPResult
+                0x0A,
+                0x01,
+                0x21, // LDAPResult ::= SEQUENCE {
+                      // resultCode ENUMERATED {
+                      // success (0), ...
+                      // },
+                0x04,
+                0x1F, // matchedDN LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x04,
+                0x00, // errorMessage
+                      // LDAPString,
+                      // referral [3] Referral OPTIONAL }
+                      // }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32
+
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<DeleteResponseDecorator> container =
+            new LdapMessageContainer<DeleteResponseDecorator>( codec );
+
+        // Decode the DelResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded DelResponse PDU
+        DeleteResponse delResponse = container.getMessage();
+
+        assertEquals( 1, delResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.ALIAS_PROBLEM, delResponse.getLdapResult().getResultCode() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", delResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", delResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = delResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( delResponse );
+
+            // Check the length
+            assertEquals( 0x4A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/extended/ExtendedRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/extended/ExtendedRequestTest.java
new file mode 100644
index 0000000..0ebac60
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/extended/ExtendedRequestTest.java
@@ -0,0 +1,689 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.extended;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the ExtendedRequest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ExtendedRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a full ExtendedRequest
+     */
+    @Test
+    public void testDecodeExtendedRequestSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x1D );
+
+        stream.put( new byte[]
+            { 0x30, 0x1B, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x16, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+                // requestName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // requestValue [1] OCTET STRING OPTIONAL }
+                ( byte ) 0x81,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode the ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedRequest PDU
+        ExtendedRequestDecorator<?> extendedRequest = container.getMessage();
+
+        assertEquals( 1, extendedRequest.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", extendedRequest.getRequestName() );
+        assertEquals( "value", Strings.utf8ToString( extendedRequest.getRequestValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedRequest );
+
+            // Check the length
+            assertEquals( 0x1D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full ExtendedRequest with controls
+     */
+    @Test
+    public void testDecodeExtendedRequestWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3A );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x38, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x16, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+                // requestName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // requestValue [1] OCTET STRING OPTIONAL }
+                ( byte ) 0x81,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode the ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedRequest PDU
+        ExtendedRequestDecorator<?> extendedRequest = container.getMessage();
+
+        assertEquals( 1, extendedRequest.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", extendedRequest.getRequestName() );
+        assertEquals( "value", Strings.utf8ToString( extendedRequest.getRequestValue() ) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+        assertTrue( extendedRequest.hasControl( "2.16.840.1.113730.3.4.2" ) );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) extendedRequest
+            .getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "", Strings.dumpBytes( control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedRequest );
+
+            // Check the length
+            assertEquals( 0x3A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full ExtendedRequest with no value and with
+     * controls
+     */
+    @Test
+    public void testDecodeExtendedRequestNoValueWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x33 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x31, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x0F, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+                // requestName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // requestValue [1] OCTET STRING OPTIONAL }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode the ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedRequest PDU
+        ExtendedRequestDecorator<?> extendedRequest = container.getMessage();
+
+        assertEquals( 1, extendedRequest.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", extendedRequest.getRequestName() );
+        assertEquals( "", Strings.utf8ToString( extendedRequest.getRequestValue() ) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        assertTrue( extendedRequest.hasControl( "2.16.840.1.113730.3.4.2" ) );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) extendedRequest
+            .getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "", Strings.dumpBytes( control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedRequest );
+
+            // Check the length
+            assertEquals( 0x33, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty ExtendedRequest
+     */
+    @Test
+    public void testDecodeExtendedRequestEmpty()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x00, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode a ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty OID
+     */
+    @Test
+    public void testDecodeEmptyOID()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+
+        stream.put( new byte[]
+            { 0x30, 0x07, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x02, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+                ( byte ) 0x80,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode a ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a bad name 
+     */
+    @Test
+    public void testDecodeExtendedBadRequestName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x16 );
+
+        stream.put( new byte[]
+            { 0x30, 0x14, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x0F, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+                // requestName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '-',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2', } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode a ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a name only ExtendedRequest
+     */
+    @Test
+    public void testDecodeExtendedRequestName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x16 );
+
+        stream.put( new byte[]
+            { 0x30, 0x14, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x0F, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+                // requestName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2', } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode the ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedRequest PDU
+        ExtendedRequestDecorator<?> extendedRequest = container.getMessage();
+
+        assertEquals( 1, extendedRequest.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", extendedRequest.getRequestName() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedRequest );
+
+            // Check the length
+            assertEquals( 0x16, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty name ExtendedRequest
+     */
+    @Test
+    public void testDecodeExtendedRequestEmptyName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x18 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x16, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedReq ExtendedRequest, ...
+                0x77,
+                0x11, // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+                // requestName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                ( byte ) 0x81,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedRequestDecorator<?>> container =
+            new LdapMessageContainer<ExtendedRequestDecorator<?>>( codec );
+
+        // Decode the ExtendedRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedRequest PDU
+        ExtendedRequestDecorator<?> extendedRequest = container.getMessage();
+
+        assertEquals( 1, extendedRequest.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", extendedRequest.getRequestName() );
+        assertEquals( "", Strings.utf8ToString( extendedRequest.getRequestValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedRequest );
+
+            // Check the length
+            assertEquals( 0x18, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/extended/ExtendedResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/extended/ExtendedResponseTest.java
new file mode 100644
index 0000000..2022a9a
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/extended/ExtendedResponseTest.java
@@ -0,0 +1,1119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.extended;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the ExtendedResponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ExtendedResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a full ExtendedResponse
+     */
+    @Test
+    public void testDecodeExtendedResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x24 );
+
+        stream.put( new byte[]
+            { 0x30, 0x22, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp ExtendedResponse, ...
+                0x78,
+                0x1D, // ExtendedResponse ::= [APPLICATION 23] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [10] LDAPOID OPTIONAL,
+                ( byte ) 0x8A,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // response [11] OCTET STRING OPTIONAL }
+                ( byte ) 0x8B,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponseDecorator<?> extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( Dn.EMPTY_DN, extendedResponse.getLdapResult().getMatchedDn() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getResponseName() );
+        assertEquals( "value", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x24, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full ExtendedResponse with controls
+     */
+    @Test
+    public void testDecodeExtendedResponseSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x41 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x3F, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { 
+                //    ..., 
+                //    extendedResp ExtendedResponse, 
+                //    ...
+                0x78,
+                0x1D, // ExtendedResponse ::= [APPLICATION 23] SEQUENCE {
+                //   COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, //   LDAPResult ::= SEQUENCE {
+                //     resultCode ENUMERATED {
+                //         success (0), ...
+                //     },
+                0x04,
+                0x00, //     matchedDN LDAPDN,
+                0x04,
+                0x00, //     errorMessage LDAPString,
+                //     referral [3] Referral OPTIONAL }
+                ( byte ) 0x8A,
+                0x0D, //   responseName [10] LDAPOID OPTIONAL,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                ( byte ) 0x8B,
+                0x05, // response [11] OCTET STRING OPTIONAL } 
+                'v',
+                'a',
+                'l',
+                'u',
+                'e',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponseDecorator<?> extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( Dn.EMPTY_DN, extendedResponse.getLdapResult().getMatchedDn() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getResponseName() );
+        assertEquals( "value", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x41, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ExtendedRequest with no name
+     */
+    @Test
+    public void testDecodeExtendedRequestNoName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x07, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // responseName [0] LDAPOID,
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ExtendedRequest with no name and a control
+     */
+    @Test
+    public void testDecodeExtendedRequestNoNameWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x07, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [0] LDAPOID,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x2B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty ExtendedResponse
+     */
+    @Test
+    public void testDecodeExtendedResponseEmpty()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x00 // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode a DelRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an ExtendedResponse with an empty ResponseName
+     */
+    @Test
+    public void testDecodeExtendedResponseEmptyResponseName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x10 );
+
+        stream.put( new byte[]
+            { 0x30, 0x0E, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x09, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [0] LDAPOID,
+                ( byte ) 0x8A,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode a DelRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an ExtendedResponse with a bad responseName
+     */
+    @Test
+    public void testDecodeExtendedResponseBadOIDResponseName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x12 );
+
+        stream.put( new byte[]
+            { 0x30, 0x10, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x0B, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [0] LDAPOID,
+                ( byte ) 0x8A,
+                0x02,
+                'a',
+                'b' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode a DelRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an ExtendedResponse with no response
+     */
+    @Test
+    public void testDecodeExtendedResponseNoResponse()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x1D );
+
+        stream.put( new byte[]
+            { 0x30, 0x1B, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x16, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [0] LDAPOID,
+                ( byte ) 0x8A,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2', } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponseDecorator<?> extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( Dn.EMPTY_DN, extendedResponse.getLdapResult().getMatchedDn() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getResponseName() );
+        assertEquals( "", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x1D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an ExtendedResponse with no response with controls
+     */
+    @Test
+    public void testDecodeExtendedResponseNoResponseWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3A );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x38, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x16, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [0] LDAPOID,
+                ( byte ) 0x8A,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponseDecorator<?> extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( Dn.EMPTY_DN, extendedResponse.getLdapResult().getMatchedDn() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getResponseName() );
+        assertEquals( "", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x3A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an ExtendedResponse with an empty response
+     */
+    @Test
+    public void testDecodeExtendedResponseEmptyResponse()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x1F );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x1D, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x18, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [0] LDAPOID,
+                ( byte ) 0x8A,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                ( byte ) 0x8B,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponseDecorator<?> extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( Dn.EMPTY_DN, extendedResponse.getLdapResult().getMatchedDn() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getResponseName() );
+        assertEquals( "", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x1F, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an ExtendedResponse with an empty response with
+     * controls
+     */
+    @Test
+    public void testDecodeExtendedResponseEmptyResponseWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3C );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x3A, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., extendedResp Response, ...
+                0x78,
+                0x18, // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+                // COMPONENTS OF LDAPResult,
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // responseName [0] LDAPOID,
+                ( byte ) 0x8A,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                ( byte ) 0x8B,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ExtendedResponseDecorator<?>> container =
+            new LdapMessageContainer<ExtendedResponseDecorator<?>>( codec );
+
+        // Decode the ExtendedResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ExtendedResponse PDU
+        ExtendedResponseDecorator<?> extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( Dn.EMPTY_DN, extendedResponse.getLdapResult().getMatchedDn() );
+        assertEquals( "", extendedResponse.getLdapResult().getDiagnosticMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getResponseName() );
+        assertEquals( "", Strings.utf8ToString( extendedResponse.getResponseValue() ) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( extendedResponse );
+
+            // Check the length
+            assertEquals( 0x3C, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/intermediate/IntermediateResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/intermediate/IntermediateResponseTest.java
new file mode 100644
index 0000000..8989e68
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/intermediate/IntermediateResponseTest.java
@@ -0,0 +1,841 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.intermediate;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the IntermediateResponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class IntermediateResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a full IntermediateResponse
+     */
+    @Test
+    public void testDecodeIntermediateResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x1D );
+
+        stream.put( new byte[]
+            { 0x30, 0x1B, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x16, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // responseValue [1] OCTET STRING OPTIONAL }
+                ( byte ) 0x81,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode the IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded IntermediateResponse PDU
+        IntermediateResponse intermediateResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, intermediateResponse.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", intermediateResponse.getResponseName() );
+        assertEquals( "value", Strings.utf8ToString( intermediateResponse.getResponseValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( intermediateResponse );
+
+            // Check the length
+            assertEquals( 0x1D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full IntermediateResponse with controls
+     */
+    @Test
+    public void testDecodeIntermediateResponseWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3A );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x38, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x16, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // requestValue [1] OCTET STRING OPTIONAL }
+                ( byte ) 0x81,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode the IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded IntermediateResponse PDU
+        IntermediateResponse intermediateResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, intermediateResponse.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", intermediateResponse.getResponseName() );
+        assertEquals( "value", Strings.utf8ToString( intermediateResponse.getResponseValue() ) );
+
+        // Check the Control
+        Map<String, Control> controls = intermediateResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( intermediateResponse );
+
+            // Check the length
+            assertEquals( 0x3A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a full IntermediateResponse with no value and with
+     * controls
+     */
+    @Test
+    public void testDecodeIntermediateResponseNoValueWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x33 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x31, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x0F, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                // requestValue [1] OCTET STRING OPTIONAL }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode the IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded IntermediateResponse PDU
+        IntermediateResponse intermediateResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, intermediateResponse.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", intermediateResponse.getResponseName() );
+        assertEquals( "", Strings.utf8ToString( intermediateResponse.getResponseValue() ) );
+
+        // Check the Control
+        Map<String, Control> controls = intermediateResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( intermediateResponse );
+
+            // Check the length
+            assertEquals( 0x33, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty IntermediateResponse
+     */
+    @Test
+    public void testDecodeIntermediateResponseEmpty()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x00, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode a IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty OID
+     */
+    @Test
+    public void testDecodeEmptyOID()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+
+        stream.put( new byte[]
+            { 0x30, 0x07, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x02, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                ( byte ) 0x80,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode a IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a bad name 
+     */
+    @Test
+    public void testDecodeExtendedBadRequestName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x16 );
+
+        stream.put( new byte[]
+            { 0x30, 0x14, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x0F, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '-',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2', } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode a IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a name only IntermediateResponse
+     */
+    @Test
+    public void testDecodeIntermediateResponseName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x16 );
+
+        stream.put( new byte[]
+            { 0x30, 0x14, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x0F, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2', } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode the IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded IntermediateResponse PDU
+        IntermediateResponse intermediateResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, intermediateResponse.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", intermediateResponse.getResponseName() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( intermediateResponse );
+
+            // Check the length
+            assertEquals( 0x16, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an empty value IntermediateResponse
+     */
+    @Test
+    public void testDecodeIntermediateResponseEmptyValue()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x18 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x16, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x11, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2',
+                ( byte ) 0x81,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode the IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded IntermediateResponse PDU
+        IntermediateResponse intermediateResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, intermediateResponse.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", intermediateResponse.getResponseName() );
+        assertEquals( "", Strings.utf8ToString( intermediateResponse.getResponseValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( intermediateResponse );
+
+            // Check the length
+            assertEquals( 0x18, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an IntermediateResponse without name
+     */
+    @Test
+    public void testDecodeIntermediateResponseNoName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x07, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseValue [1] OCTET STRING OPTIONAL,
+                ( byte ) 0x81,
+                0x05,
+                'v',
+                'a',
+                'l',
+                'u',
+                'e' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode the IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded IntermediateResponse PDU
+        IntermediateResponse intermediateResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, intermediateResponse.getMessageId() );
+        assertEquals( "", intermediateResponse.getResponseName() );
+        assertEquals( "value", Strings.utf8ToString( intermediateResponse.getResponseValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( intermediateResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an IntermediateResponse with no value
+     */
+    @Test
+    public void testDecodeIntermediateResponseNoValue()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x16 );
+
+        stream.put( new byte[]
+            { 0x30, 0x14, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                // CHOICE { ..., intermediateResponse IntermediateResponse, ...
+                0x79,
+                0x0F, // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
+                // responseName [0] LDAPOID,
+                ( byte ) 0x80,
+                0x0D,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '5',
+                '.',
+                '5',
+                '.',
+                '2', } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<IntermediateResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<IntermediateResponseDecorator>( codec );
+
+        // Decode the IntermediateResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded IntermediateResponse PDU
+        IntermediateResponse intermediateResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, intermediateResponse.getMessageId() );
+        assertEquals( "1.3.6.1.5.5.2", intermediateResponse.getResponseName() );
+        assertEquals( "", Strings.utf8ToString( intermediateResponse.getResponseValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( intermediateResponse );
+
+            // Check the length
+            assertEquals( 0x16, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyRequestTest.java
new file mode 100644
index 0000000..74d1d50
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyRequestTest.java
@@ -0,0 +1,2275 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.modify;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the ModifyRequest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a ModifyRequest
+     */
+    @Test
+    public void testDecodeModifyRequest2AttrsSuccess() throws LdapException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x54 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x52, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x66,
+                0x4d, // CHOICE { ..., modifyRequest ModifyRequest, ...
+                // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+                // object LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x29,
+                // modification SEQUENCE OF SEQUENCE {
+                0x30,
+                0x11,
+                0x0A,
+                0x01,
+                0x02, // operation ENUMERATED {
+                // add (0),
+                // delete (1),
+                // replace (2) },
+                // modification AttributeTypeAndValues } }
+                0x30,
+                0x0c, // AttributeTypeAndValues ::= SEQUENCE {
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x07, // vals SET OF AttributeValue }
+                0x04,
+                0x05,
+                'P',
+                'a',
+                'r',
+                'i',
+                's',
+
+                0x30,
+                0x14, // modification SEQUENCE OF *SEQUENCE* {
+                0x0A,
+                0x01,
+                0x00, // operation ENUMERATED {
+                // add (0),
+                // delete (1),
+                // replace (2) },
+                // modification AttributeTypeAndValues } }
+                0x30,
+                0x0f, // AttributeTypeAndValues ::= SEQUENCE {
+                // type AttributeDescription,
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                's',
+                0x31,
+                0x06, // vals SET OF AttributeValue }
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyRequest.getName().toString() );
+
+        Collection<Modification> modifications = modifyRequest.getModifications();
+
+        assertEquals( 2, modifications.size() );
+
+        for ( Modification modification : modifications )
+        {
+            Attribute attribute = modification.getAttribute();
+
+            if ( "l".equalsIgnoreCase( attribute.getUpId() ) )
+            {
+                String attrValue = attribute.getString();
+                assertEquals( "Paris", attrValue );
+            }
+            else if ( "attrs".equalsIgnoreCase( attribute.getUpId() ) )
+            {
+                String attrValue = attribute.getString();
+                assertEquals( "test", attrValue );
+            }
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyRequest );
+
+            // Check the length
+            assertEquals( 0x54, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest
+     */
+    @Test
+    public void testDecodeModifyRequestBadDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x54 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x52, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x66,
+                0x4d, // CHOICE { ..., modifyRequest ModifyRequest, ...
+                // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+                // object LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                ':',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x29,
+                // modification SEQUENCE OF SEQUENCE {
+                0x30,
+                0x11,
+                0x0A,
+                0x01,
+                0x02, // operation ENUMERATED {
+                // add (0),
+                // delete (1),
+                // replace (2) },
+                // modification AttributeTypeAndValues } }
+                0x30,
+                0x0c, // AttributeTypeAndValues ::= SEQUENCE {
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x07, // vals SET OF AttributeValue }
+                0x04,
+                0x05,
+                'P',
+                'a',
+                'r',
+                'i',
+                's',
+
+                0x30,
+                0x14, // modification SEQUENCE OF *SEQUENCE* {
+                0x0A,
+                0x01,
+                0x00, // operation ENUMERATED {
+                // add (0),
+                // delete (1),
+                // replace (2) },
+                // modification AttributeTypeAndValues } }
+                0x30,
+                0x0f, // AttributeTypeAndValues ::= SEQUENCE {
+                // type AttributeDescription,
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                's',
+                0x31,
+                0x06, // vals SET OF AttributeValue }
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof ModifyResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( ModifyResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest, with different operations
+     */
+    @Test
+    public void testDecodeModifyRequestManyOperations() throws LdapException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x18C );
+
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81, ( byte ) 0x89, 0x02, 0x01, 0x15, 0x66,
+                0x67,
+                0x04,
+                0x2B, // ModifyRequest object : cn=Tori Amos,ou=playground,dc=apache,dc=org
+                'c',
+                'n',
+                '=',
+                'T',
+                'o',
+                'r',
+                'i',
+                ' ',
+                'A',
+                'm',
+                'o',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                'p',
+                'l',
+                'a',
+                'y',
+                'g',
+                'r',
+                'o',
+                'u',
+                'n',
+                'd',
+                ',',
+                'd',
+                'c',
+                '=',
+                'a',
+                'p',
+                'a',
+                'c',
+                'h',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'o',
+                'r',
+                'g',
+                0x30,
+                0x38, // Modifications
+                0x30,
+                0x24, // Modification
+                0x0A,
+                0x01,
+                0x00, // Operation = ADD
+                0x30,
+                0x1F, // type : telephoneNumber
+                0x04,
+                0x0F,
+                't',
+                'e',
+                'l',
+                'e',
+                'p',
+                'h',
+                'o',
+                'n',
+                'e',
+                'N',
+                'u',
+                'm',
+                'b',
+                'e',
+                'r',
+                0x31,
+                0x0C, // vals : 1234567890
+                0x04,
+                0x0A,
+                '1',
+                '2',
+                '3',
+                '4',
+                '5',
+                '6',
+                '7',
+                '8',
+                '9',
+                '0',
+                0x30,
+                0x10, // Modification
+                0x0A,
+                0x01,
+                0x02, // Operation = REPLACE
+                0x30,
+                0x0B, // type : cn
+                0x04,
+                0x02,
+                'c',
+                'n',
+                0x31,
+                0x05, // vals : XXX
+                0x04,
+                0x03,
+                'X',
+                'X',
+                'X',
+                ( byte ) 0xA0,
+                0x1B, // Control : 2.16.840.1.113730.3.4.2
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 21, modifyRequest.getMessageId() );
+        assertEquals( "cn=Tori Amos,ou=playground,dc=apache,dc=org", modifyRequest.getName().toString() );
+
+        Object[] modifications = modifyRequest.getModifications().toArray();
+
+        assertEquals( 2, modifications.length );
+
+        Modification modification = ( Modification ) modifications[0];
+        Attribute attributeValue = modification.getAttribute();
+
+        assertEquals( "telephonenumber", Strings.toLowerCase( attributeValue.getId() ) );
+
+        String attrValue = attributeValue.getString();
+        assertEquals( "1234567890", attrValue );
+
+        modification = ( Modification ) modifications[1];
+        attributeValue = modification.getAttribute();
+
+        assertEquals( "cn", Strings.toLowerCase( attributeValue.getUpId() ) );
+
+        attrValue = attributeValue.getString();
+        assertEquals( "XXX", attrValue );
+
+        // Check the encoding, by decoding and re-encoding the result
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyRequest );
+
+            // Check the length
+            assertEquals( 0x8C, bb.limit() );
+
+            String decodedPdu1 = Strings.dumpBytes( bb.array() );
+
+            try
+            {
+                ldapDecoder.decode( bb, ldapMessageContainer );
+            }
+            catch ( DecoderException de )
+            {
+                de.printStackTrace();
+                fail( de.getMessage() );
+            }
+
+            ModifyRequest modifyRequest2 = ldapMessageContainer.getMessage();
+
+            bb = encoder.encodeMessage( modifyRequest2 );
+            String decodedPdu2 = Strings.dumpBytes( bb.array() );
+
+            assertEquals( decodedPdu1, decodedPdu2 );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest, with different operations, take 2
+     */
+    @Test
+    public void testDecodeModifyRequestManyOperations2() throws LdapException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x18C );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                ( byte ) 0x81,
+                ( byte ) 0xB6, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                ( byte ) 0x81,
+                ( byte ) 0x93, // ModifyRequest
+                0x04,
+                0x2B, // object : cn=Tori Amos,ou=playground,dc=apache,dc=org
+                'c',
+                'n',
+                '=',
+                'T',
+                'o',
+                'r',
+                'i',
+                ' ',
+                'A',
+                'm',
+                'o',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                'p',
+                'l',
+                'a',
+                'y',
+                'g',
+                'r',
+                'o',
+                'u',
+                'n',
+                'd',
+                ',',
+                'd',
+                'c',
+                '=',
+                'a',
+                'p',
+                'a',
+                'c',
+                'h',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'o',
+                'r',
+                'g',
+                0x30,
+                0x64, // Modifications
+                0x30,
+                0x14, // Modification
+                0x0A,
+                0x01,
+                0x01, // Operation : Delete
+                0x30,
+                0x0F, // type : description
+                0x04,
+                0x0B,
+                0x64,
+                0x65,
+                0x73,
+                0x63,
+                0x72,
+                0x69,
+                0x70,
+                0x74,
+                0x69,
+                0x6F,
+                0x6E,
+                0x31,
+                0x00, // Vals = null
+                0x30,
+                0x25, // Modification
+                0x0A,
+                0x01,
+                0x00, // Operation : Add
+                0x30,
+                0x20, // type : telephoneNumber
+                0x04,
+                0x0F,
+                't',
+                'e',
+                'l',
+                'e',
+                'p',
+                'h',
+                'o',
+                'n',
+                'e',
+                'N',
+                'u',
+                'm',
+                'b',
+                'e',
+                'r',
+                0x31,
+                0x0D, // Vals : 01234567890
+                0x04,
+                0x0B,
+                '0',
+                '1',
+                '2',
+                '3',
+                '4',
+                '5',
+                '6',
+                '7',
+                '8',
+                '9',
+                '0',
+                0x30,
+                0x25, // Modification
+                0x0A,
+                0x01,
+                0x00, // Operation : Add
+                0x30,
+                0x20, // type : telephoneNumber
+                0x04,
+                0x0F,
+                't',
+                'e',
+                'l',
+                'e',
+                'p',
+                'h',
+                'o',
+                'n',
+                'e',
+                'N',
+                'u',
+                'm',
+                'b',
+                'e',
+                'r',
+                0x31,
+                0x0D, // Vals : 01234567890
+                0x04,
+                0x0B,
+                '0',
+                '1',
+                '2',
+                '3',
+                '4',
+                '5',
+                '6',
+                '7',
+                '8',
+                '9',
+                '0',
+                ( byte ) 0xA0,
+                0x1B, // Controls : 2.16.840.1.113730.3.4.2
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 49, modifyRequest.getMessageId() );
+        assertEquals( "cn=Tori Amos,ou=playground,dc=apache,dc=org", modifyRequest.getName().toString() );
+
+        Object[] modifications = modifyRequest.getModifications().toArray();
+
+        assertEquals( 3, modifications.length );
+
+        Modification modification = ( Modification ) modifications[0];
+        Attribute attributeValue = modification.getAttribute();
+
+        assertEquals( "description", Strings.toLowerCase( attributeValue.getUpId() ) );
+        assertEquals( 0, attributeValue.size() );
+
+        modification = ( Modification ) modifications[1];
+        attributeValue = modification.getAttribute();
+
+        String attrValue = attributeValue.getString();
+
+        assertEquals( "telephonenumber", Strings.toLowerCase( attributeValue.getUpId() ) );
+
+        assertEquals( "01234567890", attrValue );
+
+        modification = ( Modification ) modifications[2];
+        attributeValue = modification.getAttribute();
+
+        attrValue = attributeValue.getString();
+
+        assertEquals( "telephonenumber", Strings.toLowerCase( attributeValue.getUpId() ) );
+
+        attrValue = attributeValue.getString();
+        assertEquals( "01234567890", attrValue );
+
+        // Check the encoding, by decoding and re-encoding the result
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyRequest );
+
+            // Check the length
+            assertEquals( 0xB9, bb.limit() );
+
+            String decodedPdu1 = Strings.dumpBytes( bb.array() );
+
+            try
+            {
+                ldapDecoder.decode( bb, ldapMessageContainer );
+            }
+            catch ( DecoderException de )
+            {
+                de.printStackTrace();
+                fail( de.getMessage() );
+            }
+
+            ModifyRequest modifyRequest2 = ldapMessageContainer.getMessage();
+
+            bb = encoder.encodeMessage( modifyRequest2 );
+            String decodedPdu2 = Strings.dumpBytes( bb.array() );
+
+            assertEquals( decodedPdu1, decodedPdu2 );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest
+     */
+    @Test
+    public void testDecodeModifyRequest2Attrs3valsSuccess() throws LdapException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x5C );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x5A, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x66,
+                0x55, // CHOICE { ..., modifyRequest ModifyRequest, ...
+                // ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+                // object LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x31, // modification SEQUENCE OF SEQUENCE {
+                0x30,
+                0x19,
+                0x0A,
+                0x01,
+                0x02, // operation ENUMERATED {
+                // add (0),
+                // delete (1),
+                // replace (2) },
+                // modification AttributeTypeAndValues } }
+                0x30,
+                0x14, // AttributeTypeAndValues ::= SEQUENCE {
+                0x04,
+                0x01,
+                'l', // type AttributeDescription,
+                0x31,
+                0x0F, // vals SET OF AttributeValue }
+                0x04,
+                0x05,
+                'P',
+                'a',
+                'r',
+                'i',
+                's',
+                0x04,
+                0x06,
+                'L',
+                'o',
+                'n',
+                'd',
+                'o',
+                'n',
+                0x30,
+                0x14, // modification SEQUENCE OF *SEQUENCE*  {
+                0x0A,
+                0x01,
+                0x00, // operation ENUMERATED {
+                // add (0),
+                // delete (1),
+                // replace (2) },
+                // modification AttributeTypeAndValues } }
+                0x30,
+                0x0f, // AttributeTypeAndValues ::= SEQUENCE {
+                // type AttributeDescription,
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                's',
+                0x31,
+                0x06, // vals SET OF AttributeValue }
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyRequest.getName().toString() );
+
+        Object[] modifications = modifyRequest.getModifications().toArray();
+
+        assertEquals( 2, modifications.length );
+
+        Modification modification = ( Modification ) modifications[0];
+        Attribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", Strings.toLowerCase( attributeValue.getUpId() ) );
+
+        assertTrue( attributeValue.contains( "Paris" ) );
+        assertTrue( attributeValue.contains( "London" ) );
+
+        modification = ( Modification ) modifications[1];
+        attributeValue = modification.getAttribute();
+
+        assertEquals( "attrs", Strings.toLowerCase( attributeValue.getUpId() ) );
+
+        String attrValue = attributeValue.getString();
+        assertEquals( "test", attrValue );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyRequest );
+
+            // Check the length
+            assertEquals( 0x5C, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    // Defensive tests
+
+    /**
+     * Test the decoding of a ModifyRequest with an empty body
+     */
+    @Test
+    public void testDecodeModifyRequestEmptyBody()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x00 // ModifyRequest
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an empty object
+     */
+    @Test
+    public void testDecodeModifyRequestEmptyObject()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+
+        stream.put( new byte[]
+            { 0x30, 0x07, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x02, // ModifyRequest
+                0x04,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an object and nothing else
+     */
+    @Test
+    public void testDecodeModifyRequestObjectAlone()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x29 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x27, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x22, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an empty modification
+     */
+    @Test
+    public void testDecodeModifyRequestEmptyModification()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x24, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an empty operation
+     */
+    @Test
+    public void testDecodeModifyRequestEmptyOperation()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2D );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x2B, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x26, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x02,
+                0x30,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an wrong empty operation
+     */
+    @Test
+    public void testDecodeModifyRequestWrongOperationEmpty()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2F );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x2D, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x28, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x04,
+                0x30,
+                0x02,
+                0x0A,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an wrong operation
+     */
+    @Test
+    public void testDecodeModifyRequestWrongOperation()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x30 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x2E, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x29, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x05,
+                0x30,
+                0x03,
+                0x0A,
+                0x01,
+                0x04 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an add operation, and nothing
+     * more
+     */
+    @Test
+    public void testDecodeModifyRequestAddOperationEnd()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x30 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x2E, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x29, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x05,
+                0x30,
+                0x03,
+                0x0A,
+                0x01,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an add operation, and an empty
+     * modification
+     */
+    @Test
+    public void testDecodeModifyRequestAddOperationEmptyModification()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x32 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x30, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x2B, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x07,
+                0x30,
+                0x05,
+                0x0A,
+                0x01,
+                0x00,
+                0x30,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an add operation, and a
+     * modification with an empty type
+     */
+    @Test
+    public void testDecodeModifyRequestAddOperationModificationEmptyType()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x34 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x32, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x2D, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x09,
+                0x30,
+                0x07,
+                0x0A,
+                0x01,
+                0x00,
+                0x30,
+                0x02,
+                0x04,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof ModifyResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, ( ( ModifyResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an add operation, and a
+     * modification with a type and no vals
+     */
+    @Test
+    public void testDecodeModifyRequestAddOperationModificationTypeNoVals()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x33, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x2E, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x0A,
+                0x30,
+                0x08,
+                0x0A,
+                0x01,
+                0x00,
+                0x30,
+                0x03,
+                0x04,
+                0x01,
+                'l' } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an add operation, and a
+     * modification with a type and an empty vals
+     */
+    @Test
+    public void testDecodeModifyRequestAddOperationModificationTypeEmptyVals()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x37 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x35, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x30, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x0C,
+                0x30,
+                0x0A,
+                0x0A,
+                0x01,
+                0x00,
+                0x30,
+                0x05,
+                0x04,
+                0x01,
+                'l',
+                0x31,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 49, modifyRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyRequest.getName().toString() );
+
+        Object[] modifications = modifyRequest.getModifications().toArray();
+
+        assertEquals( 1, modifications.length );
+
+        Modification modification = ( Modification ) modifications[0];
+        Attribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", Strings.toLowerCase( attributeValue.getUpId() ) );
+        assertEquals( 0, attributeValue.size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyRequest );
+
+            // Check the length
+            assertEquals( 0x37, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an add operation, and a
+     * modification with a type and an empty vals wuth controls
+     */
+    @Test
+    public void testDecodeModifyRequestAddOperationModificationTypeEmptyValsWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x54 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x52, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x30, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x0C,
+                0x30,
+                0x0A,
+                0x0A,
+                0x01,
+                0x00,
+                0x30,
+                0x05,
+                0x04,
+                0x01,
+                'l',
+                0x31,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 49, modifyRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyRequest.getName().toString() );
+
+        Object[] modifications = modifyRequest.getModifications().toArray();
+
+        assertEquals( 1, modifications.length );
+
+        Modification modification = ( Modification ) modifications[0];
+        Attribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", Strings.toLowerCase( attributeValue.getUpId() ) );
+        assertEquals( 0, attributeValue.size() );
+
+        // Check the Control
+        Map<String, Control> controls = modifyRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) modifyRequest
+            .getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyRequest );
+
+            // Check the length
+            assertEquals( 0x54, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyRequest with an add operation, and a
+     * modification with a type and two vals
+     */
+    @Test
+    public void testDecodeModifyRequestAddOperationModificationType2Vals() throws LdapException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3D );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x3B, // LdapMessage
+                0x02,
+                0x01,
+                0x31, // Message ID : 49
+                0x66,
+                0x36, // ModifyRequest
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x30,
+                0x12,
+                0x30,
+                0x10,
+                0x0A,
+                0x01,
+                0x00,
+                0x30,
+                0x0B,
+                0x04,
+                0x01,
+                'l',
+                0x31,
+                0x06,
+                0x04,
+                0x01,
+                'a',
+                0x04,
+                0x01,
+                'b' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyRequestDecorator>( codec );
+
+        // Decode a ModifyRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        ModifyRequest modifyRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 49, modifyRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyRequest.getName().toString() );
+
+        Object[] modifications = modifyRequest.getModifications().toArray();
+
+        assertEquals( 1, modifications.length );
+
+        Modification modification = ( Modification ) modifications[0];
+        Attribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", Strings.toLowerCase( attributeValue.getUpId() ) );
+        assertEquals( 2, attributeValue.size() );
+
+        assertTrue( attributeValue.contains( "a" ) );
+        assertTrue( attributeValue.contains( "b" ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyRequest );
+
+            // Check the length
+            assertEquals( 0x3D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyResponseTest.java
new file mode 100644
index 0000000..b987df1
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modify/ModifyResponseTest.java
@@ -0,0 +1,291 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.modify;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ModifyResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the ModifyResponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a ModifyResponse
+     */
+    @Test
+    public void testDecodeModifyResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x67,
+                0x07, // CHOICE { ..., modifyResponse ModifyResponse, ...
+                // ModifyResponse ::= [APPLICATION 7] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyResponseDecorator>( codec );
+
+        // Decode a ModifyResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ModifyResponse PDU
+        ModifyResponse modifyResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, modifyResponse.getLdapResult().getResultCode() );
+        assertEquals( "", modifyResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", modifyResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyResponse with controls
+     */
+    @Test
+    public void testDecodeModifyResponseSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x67,
+                0x07, // CHOICE { ..., modifyResponse ModifyResponse, ...
+                // ModifyResponse ::= [APPLICATION 7] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyResponseDecorator>( codec );
+
+        // Decode a ModifyResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ModifyResponse PDU
+        ModifyResponse modifyResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, modifyResponse.getLdapResult().getResultCode() );
+        assertEquals( "", modifyResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", modifyResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = modifyResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyResponse );
+
+            // Check the length
+            assertEquals( 0x2B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeModifyResponseEmptyResult()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x67,
+                0x00, // CHOICE { ..., modifyResponse ModifyResponse, ...
+            } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyResponseDecorator>( codec );
+
+        // Decode a ModifyResponse message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modifyDn/ModifyDNRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modifyDn/ModifyDNRequestTest.java
new file mode 100644
index 0000000..b94a9a0
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modifyDn/ModifyDNRequestTest.java
@@ -0,0 +1,1248 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.modifyDn;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the ModifyDNRequest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyDNRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a full ModifyDNRequest
+     */
+    @Test
+    public void testDecodeModifyDNRequestSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x48 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x46, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x41, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // newrdn RelativeLDAPDN,
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x01,
+                0x00, // deleteoldrdn BOOLEAN,
+                // newSuperior [0] LDAPDN OPTIONAL }
+                ( byte ) 0x80,
+                0x09,
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a ModifyRequest Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        ModifyDnRequest modifyDnRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyDnRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyDnRequest.getName().toString() );
+        assertEquals( false, modifyDnRequest.getDeleteOldRdn() );
+        assertEquals( "cn=testDNModify", modifyDnRequest.getNewRdn().toString() );
+        assertEquals( "ou=system", modifyDnRequest.getNewSuperior().toString() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyDnRequest );
+
+            // Check the length
+            assertEquals( 0x48, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a bad Dn ModifyDNRequest
+     */
+    @Test
+    public void testDecodeModifyDNRequestBadDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x48 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x46, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x41, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                ':',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // newrdn RelativeLDAPDN,
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x01,
+                0x00, // deleteoldrdn BOOLEAN,
+                // newSuperior [0] LDAPDN OPTIONAL }
+                ( byte ) 0x80,
+                0x09,
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm' } );
+
+        stream.flip();
+
+        // Allocate a ModifyRequest Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof ModifyDnResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( ModifyDnResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a bad Rdn ModifyDNRequest
+     */
+    @Test
+    public void testDecodeModifyDNRequestBadRDN()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x48 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x46, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x41, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // newrdn RelativeLDAPDN,
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                ':',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x01,
+                0x00, // deleteoldrdn BOOLEAN,
+                // newSuperior [0] LDAPDN OPTIONAL }
+                ( byte ) 0x80,
+                0x09,
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm' } );
+
+        stream.flip();
+
+        // Allocate a ModifyRequest Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof ModifyDnResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( ModifyDnResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a bad Rdn ModifyDNRequest
+     */
+    @Test
+    public void testDecodeModifyDNRequestBadNewSuperior()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x48 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x46, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x41, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // newrdn RelativeLDAPDN,
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x01,
+                0x00, // deleteoldrdn BOOLEAN,
+                // newSuperior [0] LDAPDN OPTIONAL }
+                ( byte ) 0x80,
+                0x09,
+                'o',
+                'u',
+                ':',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm' } );
+
+        stream.flip();
+
+        // Allocate a ModifyRequest Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof ModifyDnResponseImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( ModifyDnResponseImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a full ModifyDNRequest with controls
+     */
+    @Test
+    public void testDecodeModifyDNRequestSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x65 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x63, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x41, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // newrdn RelativeLDAPDN,
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x01,
+                0x00, // deleteoldrdn BOOLEAN,
+                // newSuperior [0] LDAPDN OPTIONAL }
+                ( byte ) 0x80,
+                0x09,
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a ModifyRequest Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        ModifyDnRequest modifyDnRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyDnRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyDnRequest.getName().toString() );
+        assertEquals( false, modifyDnRequest.getDeleteOldRdn() );
+        assertEquals( "cn=testDNModify", modifyDnRequest.getNewRdn().toString() );
+        assertEquals( "ou=system", modifyDnRequest.getNewSuperior().toString() );
+
+        // Check the Control
+        Map<String, Control> controls = modifyDnRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) modifyDnRequest
+            .getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyDnRequest );
+
+            // Check the length
+            assertEquals( 0x65, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyDNRequest without a superior
+     */
+    @Test
+    public void testDecodeModifyDNRequestWithoutSuperior()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3D );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x3B, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x36, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // newrdn RelativeLDAPDN,
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x01,
+                0x00 // deleteoldrdn BOOLEAN,
+            // newSuperior [0] LDAPDN OPTIONAL }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a ModifyRequest Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        ModifyDnRequest modifyDnRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyDnRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyDnRequest.getName().toString() );
+        assertEquals( false, modifyDnRequest.getDeleteOldRdn() );
+        assertEquals( "cn=testDNModify", modifyDnRequest.getNewRdn().toString() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyDnRequest );
+
+            // Check the length
+            assertEquals( 0x3D, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyDNRequest without a superior with controls
+     */
+    @Test
+    public void testDecodeModifyDNRequestWithoutSuperiorWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x5A );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x58, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x36, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+                // entry LDAPDN,
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // newrdn RelativeLDAPDN,
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x01,
+                0x00, // deleteoldrdn BOOLEAN,
+                // newSuperior [0] LDAPDN OPTIONAL }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a ModifyRequest Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        ModifyDnRequest modifyDnRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyDnRequest.getMessageId() );
+        assertEquals( "cn=testModify,ou=users,ou=system", modifyDnRequest.getName().toString() );
+        assertEquals( false, modifyDnRequest.getDeleteOldRdn() );
+        assertEquals( "cn=testDNModify", modifyDnRequest.getNewRdn().toString() );
+
+        // Check the Control
+        Map<String, Control> controls = modifyDnRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        assertTrue( modifyDnRequest.hasControl( "2.16.840.1.113730.3.4.2" ) );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) modifyDnRequest
+            .getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyDnRequest );
+
+            // Check the length
+            assertEquals( 0x5A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    // Defensive tests
+
+    /**
+     * Test the decoding of a ModifyDNRequest with an empty body
+     */
+    @Test
+    public void testDecodeModifyDNRequestEmptyBody()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x00 // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+            // ...
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        // Decode a ModifyDNRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyDNRequest with an empty entry
+     */
+    @Test
+    public void testDecodeModifyDNRequestEmptyEntry()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+
+        stream.put( new byte[]
+            { 0x30, 0x07, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x02, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                0x04,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        // Decode a ModifyDNRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyDNRequest with an empty newRdn
+     */
+    @Test
+    public void testDecodeModifyDNRequestEmptyNewRdn()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2D );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x2B, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x26, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x04,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        // Decode a ModifyDNRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyDNRequest with an empty deleteOldRdn
+     */
+    @Test
+    public void testDecodeModifyDNRequestEmptyDeleteOldRdnn()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3C );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x3A, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6C,
+                0x35, // CHOICE { ..., modifyDNRequest ModifyDNRequest,
+                // ...
+                0x04,
+                0x20,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                ',',
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x04,
+                0x0F,
+                'c',
+                'n',
+                '=',
+                't',
+                'e',
+                's',
+                't',
+                'D',
+                'N',
+                'M',
+                'o',
+                'd',
+                'i',
+                'f',
+                'y',
+                0x01,
+                0x00 // deleteoldrdn BOOLEAN
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyDnRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnRequestDecorator>( codec );
+
+        // Decode a ModifyDNRequest PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+            fail( "We should never reach this point !!!" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modifyDn/ModifyDNResponseTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modifyDn/ModifyDNResponseTest.java
new file mode 100644
index 0000000..20553fb
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/modifyDn/ModifyDNResponseTest.java
@@ -0,0 +1,294 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.modifyDn;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.ModifyDnResponseDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the ModifyDNResponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyDNResponseTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a ModifyDNResponse
+     */
+    @Test
+    public void testDecodeModifyResponseSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6D,
+                0x07, // CHOICE { ..., modifyDNResponse ModifyDNResponse,
+                // ...
+                // ModifyDNResponse ::= [APPLICATION 13] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyDnResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnResponseDecorator>( codec );
+
+        // Decode the ModifyDNResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ModifyDNResponse PDU
+        ModifyDnResponse modifyDnResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyDnResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, modifyDnResponse.getLdapResult().getResultCode() );
+        assertEquals( "", modifyDnResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", modifyDnResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyDnResponse );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyDNResponse with controls
+     */
+    @Test
+    public void testDecodeModifyResponseSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6D,
+                0x07, // CHOICE { ..., modifyDNResponse ModifyDNResponse,
+                // ...
+                // ModifyDNResponse ::= [APPLICATION 13] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyDnResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnResponseDecorator>( codec );
+
+        // Decode the ModifyDNResponse PDU
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded ModifyDNResponse PDU
+        ModifyDnResponse modifyDnResponse = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, modifyDnResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, modifyDnResponse.getLdapResult().getResultCode() );
+        assertEquals( "", modifyDnResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", modifyDnResponse.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = modifyDnResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( modifyDnResponse );
+
+            // Check the length
+            assertEquals( 0x2B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a ModifyDNResponse with no LdapResult
+     */
+    @Test
+    public void testDecodeModifyDNResponseEmptyResult()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x6D,
+                0x00 // CHOICE { ..., modifyDNResponse ModifyDNResponse,
+            // ...
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<ModifyDnResponseDecorator> ldapMessageContainer =
+            new LdapMessageContainer<ModifyDnResponseDecorator>( codec );
+
+        // Decode a ModifyDNResponse message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/osgi/AbstractCodecServiceTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/osgi/AbstractCodecServiceTest.java
new file mode 100644
index 0000000..2a00ad5
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/osgi/AbstractCodecServiceTest.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.osgi;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.api.LdapEncoder;
+import org.apache.directory.api.ldap.codec.osgi.DefaultLdapCodecService;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+
+/**
+ * Initialize the Codec service. This can later be removed.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractCodecServiceTest
+{
+    protected static DefaultLdapCodecService codec;
+
+    /** The encoder instance */
+    protected static LdapEncoder encoder;
+
+
+    /**
+     * Initialize the codec service
+     */
+    @BeforeClass
+    public static void setupLdapCodecService()
+    {
+        codec = new DefaultLdapCodecService();
+
+        codec.registerProtocolCodecFactory( new ProtocolCodecFactory()
+        {
+            public ProtocolEncoder getEncoder( IoSession session ) throws Exception
+            {
+                return null;
+            }
+
+
+            public ProtocolDecoder getDecoder( IoSession session ) throws Exception
+            {
+                return null;
+            }
+        } );
+
+        if ( LdapApiServiceFactory.isInitialized() == false )
+        {
+            LdapApiServiceFactory.initialize( codec );
+        }
+        encoder = new LdapEncoder( codec );
+    }
+
+
+    /**
+     * Shutdown the codec service
+     */
+    @AfterClass
+    public static void tearDownLdapCodecService()
+    {
+        codec = null;
+        encoder = null;
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java
new file mode 100644
index 0000000..2eec58b
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java
@@ -0,0 +1,1249 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * A test case for SearchRequest messages
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchRequestMatchingRuleAssertionTest extends AbstractCodecServiceTest
+{
+    /** An oid normalizer map */
+    static Map<String, OidNormalizer> oids = new HashMap<String, OidNormalizer>();
+
+
+    @BeforeClass
+    public static void setUp() throws Exception
+    {
+        // DC normalizer
+        OidNormalizer dcOidNormalizer = new OidNormalizer( "dc", new DeepTrimToLowerNormalizer(
+            SchemaConstants.DOMAIN_COMPONENT_AT_OID ) );
+
+        oids.put( "dc", dcOidNormalizer );
+        oids.put( "domaincomponent", dcOidNormalizer );
+        oids.put( "0.9.2342.19200300.100.1.25", dcOidNormalizer );
+
+        // OU normalizer
+        OidNormalizer ouOidNormalizer = new OidNormalizer( "ou", new DeepTrimToLowerNormalizer(
+            SchemaConstants.OU_AT_OID ) );
+
+        oids.put( "ou", ouOidNormalizer );
+        oids.put( "organizationalUnitName", ouOidNormalizer );
+        oids.put( "2.5.4.11", ouOidNormalizer );
+
+        // ObjectClass normalizer
+        OidNormalizer objectClassOidNormalizer = new OidNormalizer( "objectClass", new DeepTrimToLowerNormalizer(
+            SchemaConstants.OBJECT_CLASS_AT_OID ) );
+
+        oids.put( "objectclass", objectClassOidNormalizer );
+        oids.put( "2.5.4.0", objectClassOidNormalizer );
+    }
+
+
+    /**
+     * Tests an search request decode with a simple equality match filter.
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatch()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x63 );
+        stream.put( new byte[]
+            {
+                0x30,
+                0x61, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, //   messageID       MessageID,
+                0x63,
+                0x5C, //   protocolOp      CHOICE {
+                //     searchRequest   SearchRequest,
+                //
+                // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+                0x04,
+                0x11, //   baseObject      LDAPDN, (dc=example,dc=com)
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                //   scope           ENUMERATED {
+                0x0A,
+                0x01,
+                0x00, //      baseObject              (0), ...
+                //   derefAliases    ENUMERATED {
+                0x0A,
+                0x01,
+                0x02, //     derefFindingBaseObj     (2),...
+                0x02,
+                0x01,
+                0x02, //   sizeLimit       INTEGER (0 .. maxInt), (2)
+                0x02,
+                0x01,
+                0x03, //   timeLimit       INTEGER (0 .. maxInt), (3)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, //   typesOnly       BOOLEAN, (true)
+                ( byte ) 0xA9,
+                0x21, //   filter          Filter,
+                //
+                // Filter ::= CHOICE {
+                //   extensibleMatch [9] MatchingRuleAssertion }
+                //
+                // MatchingRuleAssertion ::= SEQUENCE {
+                ( byte ) 0x81,
+                0x02, //   matchingRule    [1] MatchingRuleId OPTIONAL,
+                'c',
+                'n',
+                ( byte ) 0x82,
+                0x13, //    type            [2] AttributeDescription OPTIONAL,
+                '1',
+                '.',
+                '2',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '4',
+                '8',
+                '0',
+                '1',
+                '8',
+                '.',
+                '1',
+                '.',
+                '2',
+                '.',
+                '2',
+                ( byte ) 0x83,
+                0x03, //    matchValue      [3] AssertionValue,
+                'a',
+                'o',
+                'k',
+                //    dnAttributes    [4] BOOLEAN DEFAULT FALSE  }
+                ( byte ) 0x84,
+                0x01,
+                ( byte ) 0xFF,
+                0x30,
+                0x15, // attributes      AttributeDescriptionList }
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0',
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1',
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.OBJECT, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_FINDING_BASE_OBJ, searchRequest.getDerefAliases() );
+        assertEquals( 2, searchRequest.getSizeLimit() );
+        assertEquals( 3, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x63, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x56 ), decodedPdu.substring( 0, 0x56 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty extensible match
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyExtensibleMatch()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3B, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x36, // baseObject LDAPDN,
+                0x04,
+                0x1F,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and an
+     * empty matching rule
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchEmptyMatchingRule()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3D, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x38,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x02,
+                ( byte ) 0x81,
+                0x00, // matchingRule    [1] MatchingRuleId OPTIONAL,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and an
+     * empty type
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchEmptyType()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3D, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x38,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x02,
+                ( byte ) 0x82,
+                0x00, //    type            [2] AttributeDescription OPTIONAL
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and an
+     * empty matchValue
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchEmptyMatchValue()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x43,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3E,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x08,
+                ( byte ) 0x81,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                ( byte ) 0x83,
+                0x00, //    matchValue      [3] AssertionValue,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 4, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // Extended
+        ExprNode filter = searchRequest.getFilter();
+        ExtensibleNode extensibleNode = ( ExtensibleNode ) filter;
+        assertNotNull( extensibleNode );
+
+        assertEquals( "test", extensibleNode.getMatchingRuleId() );
+        assertNull( extensibleNode.getAttribute() );
+        assertNull( extensibleNode.getValue().getValue() );
+        assertFalse( extensibleNode.hasDnAttributes() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 0, attributes.size() );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and an
+     * matching rule and an empty type
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchMatchingRuleEmptyType()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x43,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3E,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x08,
+                ( byte ) 0x81,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                ( byte ) 0x82,
+                0x00, //    type            [2] AttributeDescription OPTIONAL,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and an
+     * matching rule and an empty dnAttributes
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchDnAttributesEmptyType()
+    {
+        byte[] asn1BER = new byte[]
+            {
+                0x30,
+                0x60, // LDAPMessage ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, //   messageID       MessageID,
+                0x63,
+                0x5B, //   protocolOp      CHOICE {
+                //     searchRequest   SearchRequest,
+                //
+                // SearchRequest ::= [APPLICATION 3] SEQUENCE {
+                0x04,
+                0x11, //   baseObject      LDAPDN, (dc=example,dc=com)
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                //   scope           ENUMERATED {
+                0x0A,
+                0x01,
+                0x00, //      baseObject              (0), ...
+                //   derefAliases    ENUMERATED {
+                0x0A,
+                0x01,
+                0x02, //     derefFindingBaseObj     (2),...
+                0x02,
+                0x01,
+                0x02, //   sizeLimit       INTEGER (0 .. maxInt), (2)
+                0x02,
+                0x01,
+                0x03, //   timeLimit       INTEGER (0 .. maxInt), (3)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, //   typesOnly       BOOLEAN, (true)
+                ( byte ) 0xA9,
+                0x20, //   filter          Filter,
+                //
+                // Filter ::= CHOICE {
+                //   extensibleMatch [9] MatchingRuleAssertion }
+                //
+                // MatchingRuleAssertion ::= SEQUENCE {
+                ( byte ) 0x81,
+                0x02, //   matchingRule    [1] MatchingRuleId OPTIONAL,
+                'c',
+                'n',
+                ( byte ) 0x82,
+                0x13, //    type            [2] AttributeDescription OPTIONAL,
+                '1',
+                '.',
+                '2',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '4',
+                '8',
+                '0',
+                '1',
+                '8',
+                '.',
+                '1',
+                '.',
+                '2',
+                '.',
+                '2',
+                ( byte ) 0x83,
+                0x03, //    matchValue      [3] AssertionValue,
+                'a',
+                'o',
+                'k',
+                //    dnAttributes    [4] BOOLEAN DEFAULT FALSE  }
+                ( byte ) 0x84,
+                0x00,
+                0x30,
+                0x15, // attributes      AttributeDescriptionList }
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0',
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1',
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and a
+     * matching rule and nothing else
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchMatchingRuleAlone()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x41,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3C,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x06,
+                ( byte ) 0x81,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and a type
+     * and nothing else
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchTypeAlone()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x43,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3E,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x06,
+                ( byte ) 0x82,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an extensible match and a match
+     * Value and nothing else
+     */
+    @Test
+    public void testDecodeSearchRequestExtensibleMatchMatchValueAlone()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x43,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3E,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA9,
+                0x06,
+                ( byte ) 0x83,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 4, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // Extended
+        ExprNode filter = searchRequest.getFilter();
+        ExtensibleNode extensibleNode = ( ExtensibleNode ) filter;
+        assertNotNull( extensibleNode );
+
+        assertNull( extensibleNode.getMatchingRuleId() );
+        assertNull( extensibleNode.getAttribute() );
+        assertEquals( "test", extensibleNode.getValue().getString() );
+        assertFalse( extensibleNode.hasDnAttributes() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 0, attributes.size() );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestSubstringTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestSubstringTest.java
new file mode 100644
index 0000000..7a60dc0
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestSubstringTest.java
@@ -0,0 +1,3431 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * A test case for SearchRequest messages
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchRequestSubstringTest extends AbstractCodecServiceTest
+{
+    /** An oid normalizer map */
+    static Map<String, OidNormalizer> oids = new HashMap<String, OidNormalizer>();
+
+
+    @BeforeClass
+    public static void setUp() throws Exception
+    {
+        // DC normalizer
+        OidNormalizer dcOidNormalizer = new OidNormalizer( "dc", new DeepTrimToLowerNormalizer(
+            SchemaConstants.DOMAIN_COMPONENT_AT_OID ) );
+
+        oids.put( "dc", dcOidNormalizer );
+        oids.put( "domaincomponent", dcOidNormalizer );
+        oids.put( "0.9.2342.19200300.100.1.25", dcOidNormalizer );
+
+        // OU normalizer
+        OidNormalizer ouOidNormalizer = new OidNormalizer( "ou", new DeepTrimToLowerNormalizer(
+            SchemaConstants.OU_AT_OID ) );
+
+        oids.put( "ou", ouOidNormalizer );
+        oids.put( "organizationalUnitName", ouOidNormalizer );
+        oids.put( "2.5.4.11", ouOidNormalizer );
+
+        // ObjectClass normalizer
+        OidNormalizer objectClassOidNormalizer = new OidNormalizer( "objectClass", new DeepTrimToLowerNormalizer(
+            SchemaConstants.OBJECT_CLASS_AT_OID ) );
+
+        oids.put( "objectclass", objectClassOidNormalizer );
+        oids.put( "2.5.4.0", objectClassOidNormalizer );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=t*)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringInitialAny()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x64 );
+        stream.put( new byte[]
+            { 0x30,
+                0x62, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, //      messageID MessageID
+                0x63,
+                0x5D, //      CHOICE { ..., 
+                //          searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, //      baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, //      scope ENUMERATED {
+                //          baseObject      (0),
+                //          singleLevel     (1),
+                //          wholeSubtree    (2) },
+                0x0A,
+                0x01,
+                0x03, //      derefAliases ENUMERATED {
+                //          neverDerefAliases   (0),
+                //          derefInSearching    (1),
+                //          derefFindingBaseObj (2),
+                //          derefAlways         (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, //      sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000) 
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x12, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x03,
+                ( byte ) 0x80,
+                0x01,
+                't', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( "t", substringNode.getInitial() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x64, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x53 ), decodedPdu.substring( 0, 0x53 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=t*) With controls
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringInitialAnyWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0081 );
+        stream.put( new byte[]
+            {
+                0x30,
+                0x7F, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x5D, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x12, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x03,
+                ( byte ) 0x80,
+                0x01,
+                't', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2', // AttributeDescription
+                // ::= LDAPString
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( "t", substringNode.getInitial() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the Control
+        Map<String, Control> controls = searchRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) searchRequest
+            .getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x0081, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x53 ), decodedPdu.substring( 0, 0x53 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * any filter : (objectclass=*t*)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringAny()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x64 );
+        stream.put( new byte[]
+            { 0x30,
+                0x62, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x5D, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x12, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x03,
+                ( byte ) 0x81,
+                0x01,
+                't', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( null, substringNode.getInitial() );
+        assertEquals( "t", substringNode.getAny().get( 0 ) );
+        assertEquals( null, substringNode.getFinal() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x64, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x53 ), decodedPdu.substring( 0, 0x53 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=*t*t)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringAnyFinal()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x67 );
+        stream.put( new byte[]
+            { 0x30,
+                0x65, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x60, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x15, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x06,
+                ( byte ) 0x81,
+                0x01,
+                't', //
+                ( byte ) 0x82,
+                0x01,
+                't', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( null, substringNode.getInitial() );
+        assertEquals( "t", substringNode.getAny().get( 0 ) );
+        assertEquals( "t", substringNode.getFinal() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x67, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x58 ), decodedPdu.substring( 0, 0x58 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=t*t*t)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringInitialAnyFinal()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x6A );
+        stream.put( new byte[]
+            { 0x30,
+                0x68, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x63, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x18, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x09,
+                ( byte ) 0x80,
+                0x01,
+                't', //
+                ( byte ) 0x81,
+                0x01,
+                't', //
+                ( byte ) 0x82,
+                0x01,
+                't', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( "t", substringNode.getInitial() );
+        assertEquals( "t", substringNode.getAny().get( 0 ) );
+        assertEquals( "t", substringNode.getFinal() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x6A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x5B ), decodedPdu.substring( 0, 0x5B ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=t*t*)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringInitialAnyAnyFinal()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x67 );
+        stream.put( new byte[]
+            { 0x30,
+                0x65, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x60, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x15, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x06,
+                ( byte ) 0x80,
+                0x01,
+                't', //
+                ( byte ) 0x81,
+                0x01,
+                't', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( "t", substringNode.getInitial() );
+        assertEquals( "t", substringNode.getAny().get( 0 ) );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x67, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x58 ), decodedPdu.substring( 0, 0x58 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=t*t*t)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringAnyAnyFinal()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x6A );
+        stream.put( new byte[]
+            {
+                0x30,
+                0x68, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x63, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x18, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x09,
+                ( byte ) 0x81,
+                0x01,
+                't',
+                ( byte ) 0x81,
+                0x01,
+                't',
+                ( byte ) 0x82,
+                0x01,
+                't',
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( null, substringNode.getInitial() );
+        assertEquals( "t", substringNode.getAny().get( 0 ) );
+        assertEquals( "t", substringNode.getAny().get( 1 ) );
+        assertEquals( "t", substringNode.getFinal() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x6A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x5B ), decodedPdu.substring( 0, 0x5B ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=t*)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringInitialAnyAny()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x67 );
+        stream.put( new byte[]
+            { 0x30,
+                0x65, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x60, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x15, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x06,
+                ( byte ) 0x80,
+                0x01,
+                't', //
+                ( byte ) 0x81,
+                0x01,
+                '*', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( "t", substringNode.getInitial() );
+        assertEquals( "*", substringNode.getAny().get( 0 ) );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x67, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x58 ), decodedPdu.substring( 0, 0x58 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=*t*t*t*)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringAnyAnyAny()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x6A );
+        stream.put( new byte[]
+            { 0x30,
+                0x68, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x63, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x18, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x09,
+                ( byte ) 0x81,
+                0x01,
+                't', //
+                ( byte ) 0x81,
+                0x01,
+                't', //
+                ( byte ) 0x81,
+                0x01,
+                't', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( null, substringNode.getInitial() );
+        assertEquals( "t", substringNode.getAny().get( 0 ) );
+        assertEquals( "t", substringNode.getAny().get( 1 ) );
+        assertEquals( "t", substringNode.getAny().get( 2 ) );
+        assertEquals( null, substringNode.getFinal() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x6A, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x5B ), decodedPdu.substring( 0, 0x5B ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a substring filter. Test the
+     * initial filter : (objectclass=*t*t*t*)
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFinal()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x67 );
+        stream.put( new byte[]
+            {
+                0x30,
+                0x65, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x60, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA4,
+                0x15, // Filter ::= CHOICE {
+                // substrings [4] SubstringFilter
+                // }
+                // SubstringFilter ::= SEQUENCE {
+                0x04,
+                0x0B, // type AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x06,
+                ( byte ) 0x82,
+                0x04,
+                'A',
+                'm',
+                'o',
+                's', //
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        ExprNode node = searchRequest.getFilter();
+        SubstringNode substringNode = ( SubstringNode ) node;
+        assertNotNull( substringNode );
+
+        assertEquals( "objectclass", substringNode.getAttribute() );
+        assertEquals( null, substringNode.getInitial() );
+        assertEquals( 0, substringNode.getAny().size() );
+        assertEquals( "Amos", substringNode.getFinal() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x67, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x5B ), decodedPdu.substring( 0, 0x5B ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty Substring filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptySubstringFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3B, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x36,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter and an empty
+     * Substring
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterEmptyType()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3D, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x38,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x02,
+                0x04,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter and an empty
+     * Substring
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterNoSubstrings()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x41,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3D,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x06,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter and an empty
+     * Substring
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterEmptySubstrings()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x43,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3E,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x08,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter and an empty
+     * Substring Initial
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterEmptyInitial()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x45,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x40,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0A,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x02,
+                ( byte ) 0x80,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter and an empty
+     * Substring Any
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterEmptyAny()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x45,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x40,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0A,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x02,
+                ( byte ) 0x81,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter and an empty
+     * Substring Initial
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterEmptyFinal()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x45,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x40,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0A,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x02,
+                ( byte ) 0x82,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter Any before
+     * initial
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterAnyInitial()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x49,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x44,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0E,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x06,
+                ( byte ) 0x81,
+                0x01,
+                'a',
+                ( byte ) 0x80,
+                0x01,
+                'b',
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter Final before
+     * initial
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterFinalInitial()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x49,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x44,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0E,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x06,
+                ( byte ) 0x82,
+                0x01,
+                'a',
+                ( byte ) 0x80,
+                0x01,
+                'b',
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter Final before
+     * any
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterFinalAny()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x49,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x44,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0E,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x06,
+                ( byte ) 0x82,
+                0x01,
+                'a',
+                ( byte ) 0x81,
+                0x01,
+                'b',
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter Two initials
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterTwoInitials()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x49,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x44,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0E,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x06,
+                ( byte ) 0x80,
+                0x01,
+                'a',
+                ( byte ) 0x80,
+                0x01,
+                'b',
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Substring filter Two finals
+     */
+    @Test
+    public void testDecodeSearchRequestSubstringFilterTwoFinals()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x49,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x44,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA4,
+                0x0E,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x30,
+                0x06,
+                ( byte ) 0x82,
+                0x01,
+                'a',
+                ( byte ) 0x82,
+                0x01,
+                'b',
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestTest.java
new file mode 100644
index 0000000..bd83edf
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchRequestTest.java
@@ -0,0 +1,7863 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesDecorator;
+import org.apache.directory.api.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.ApproximateNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.api.ldap.model.filter.LessEqNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchResultDoneImpl;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.util.Strings;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test case for SearchRequest messages
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchRequestTest extends AbstractCodecServiceTest
+{
+    /** An oid normalizer map */
+    static Map<String, OidNormalizer> oids = new HashMap<String, OidNormalizer>();
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        // DC normalizer
+        OidNormalizer dcOidNormalizer = new OidNormalizer( "dc", new DeepTrimToLowerNormalizer(
+            SchemaConstants.DOMAIN_COMPONENT_AT_OID ) );
+
+        oids.put( "dc", dcOidNormalizer );
+        oids.put( "domaincomponent", dcOidNormalizer );
+        oids.put( "0.9.2342.19200300.100.1.25", dcOidNormalizer );
+
+        // OU normalizer
+        OidNormalizer ouOidNormalizer = new OidNormalizer( "ou", new DeepTrimToLowerNormalizer(
+            SchemaConstants.OU_AT_OID ) );
+
+        oids.put( "ou", ouOidNormalizer );
+        oids.put( "organizationalUnitName", ouOidNormalizer );
+        oids.put( "2.5.4.11", ouOidNormalizer );
+
+        // ObjectClass normalizer
+        OidNormalizer objectClassOidNormalizer = new OidNormalizer( "objectClass", new DeepTrimToLowerNormalizer(
+            SchemaConstants.OBJECT_CLASS_AT_OID ) );
+
+        oids.put( "objectclass", objectClassOidNormalizer );
+        oids.put( "2.5.4.0", objectClassOidNormalizer );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with no controls. The search filter
+     * is : (&(|(objectclass=top)(ou=contacts))(!(objectclass=ttt)))
+     */
+    @Test
+    public void testDecodeSearchRequestGlobalNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x90 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81,
+                ( byte ) 0x8D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x87, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly  BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x0E, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x02,
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (& (...
+        ExprNode node = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) node;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+
+        // (& (| (...
+        assertEquals( 2, andNodes.size() );
+        OrNode orFilter = ( OrNode ) andNodes.get( 0 );
+        assertNotNull( orFilter );
+
+        // (& (| (obectclass=top) (...
+        List<ExprNode> orNodes = orFilter.getChildren();
+        assertEquals( 2, orNodes.size() );
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) orNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "objectclass", equalityNode.getAttribute() );
+        assertEquals( "top", equalityNode.getValue().getString() );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (...
+        equalityNode = ( EqualityNode<?> ) orNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "ou", equalityNode.getAttribute() );
+        assertEquals( "contacts", equalityNode.getValue().getString() );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (! ...
+        NotNode notNode = ( NotNode ) andNodes.get( 1 );
+        assertNotNull( notNode );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (! (objectclass=ttt) ) )
+        equalityNode = ( EqualityNode<?> ) notNode.getFirstChild();
+        assertNotNull( equalityNode );
+
+        assertEquals( "objectclass", equalityNode.getAttribute() );
+        assertEquals( "ttt", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x90, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x81 ), decodedPdu.substring( 0, 0x81 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with no controls. Test the various
+     * types of filter : >=, <=, ~= The search filter is :
+     * (&(|(objectclass~=top)(ou<=contacts))(!(objectclass>=ttt)))
+     */
+    @Test
+    public void testDecodeSearchRequestCompareFiltersNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x90 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81,
+                ( byte ) 0x8D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, //     messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x87, //     CHOICE { ...,
+                //         searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, //     baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, //     scope ENUMERATED {
+                //         baseObject   (0),
+                //         singleLevel  (1),
+                //         wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, //     derefAliases ENUMERATED {
+                //         neverDerefAliases (0),
+                //         derefInSearching (1),
+                //         derefFindingBaseObj (2),
+                //         derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, //     sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, //     timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, //     typesOnly BOOLEAN, (TRUE)
+                //     filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                //      and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, //      or [1] SET of Filter,
+                ( byte ) 0xA8,
+                0x12, //      approxMatch [8]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x0B, // attributeDesc AttributeDescription (LDAPString),
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x04,
+                0x03, // attributeDesc AttributeDescription (LDAPString),
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA6,
+                0x0E, // lessOrEqual [3] Assertion,
+                0x04,
+                0x02, // Assertion ::= SEQUENCE {
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x08, // assertionValue AssertionValue (OCTET STRING) }
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA5,
+                0x12, // greaterOrEqual [5] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x0B, // attributeDesc AttributeDescription (LDAPString),
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x04,
+                0x03,
+                't',
+                't',
+                't', // assertionValue AssertionValue (OCTET STRING) }
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (& (...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+
+        // (& (| (...
+        assertEquals( 2, andNodes.size() );
+        OrNode orFilter = ( OrNode ) andNodes.get( 0 );
+        assertNotNull( orFilter );
+
+        // (& (| (objectclass~=top) (...
+        List<ExprNode> orNodes = orFilter.getChildren();
+        assertEquals( 2, orNodes.size() );
+        ApproximateNode<?> approxNode = ( ApproximateNode<?> ) orNodes.get( 0 );
+        assertNotNull( approxNode );
+
+        assertEquals( "objectclass", approxNode.getAttribute() );
+        assertEquals( "top", approxNode.getValue().getString() );
+
+        // (& (| (objectclass~=top) (ou<=contacts) ) (...
+        LessEqNode<?> lessOrEqualNode = ( LessEqNode<?> ) orNodes.get( 1 );
+        assertNotNull( lessOrEqualNode );
+
+        assertEquals( "ou", lessOrEqualNode.getAttribute() );
+        assertEquals( "contacts", lessOrEqualNode.getValue().getString() );
+
+        // (& (| (objectclass~=top) (ou<=contacts) ) (! ...
+        NotNode notNode = ( NotNode ) andNodes.get( 1 );
+        assertNotNull( notNode );
+
+        // (& (| (objectclass~=top) (ou<=contacts) ) (! (objectclass>=ttt) ) )
+        GreaterEqNode<?> greaterOrEqual = ( GreaterEqNode<?> ) notNode.getFirstChild();
+        assertNotNull( greaterOrEqual );
+
+        assertEquals( "objectclass", greaterOrEqual.getAttribute() );
+        assertEquals( "ttt", greaterOrEqual.getValue().getString() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x0090, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x81 ), decodedPdu.substring( 0, 0x81 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with no controls. Test the present
+     * filter : =* The search filter is :
+     * (&(|(objectclass=*)(ou=*))(!(objectclass>=ttt)))
+     */
+    @Test
+    public void testDecodeSearchRequestPresentNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x7B );
+        stream.put( new byte[]
+            { 0x30,
+                0x79, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x74, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x29, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x11, // or [1] SET of Filter,
+                ( byte ) 0x87,
+                0x0B, // present [7] AttributeDescription,
+                // AttributeDescription ::= LDAPString
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0x87,
+                0x02,
+                'o',
+                'u', // present [7]
+                // AttributeDescription,
+                // AttributeDescription ::= LDAPString
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA5,
+                0x12, // greaterOrEqual [5]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (& (...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+
+        // (& (| (...
+        assertEquals( 2, andNodes.size() );
+        OrNode orFilter = ( OrNode ) andNodes.get( 0 );
+        assertNotNull( orFilter );
+
+        // (& (| (objectclass=*) (...
+        List<ExprNode> orNodes = orFilter.getChildren();
+        assertEquals( 2, orNodes.size() );
+
+        PresenceNode presenceNode = ( PresenceNode ) orNodes.get( 0 );
+        assertNotNull( presenceNode );
+
+        assertEquals( "objectclass", presenceNode.getAttribute() );
+
+        // (& (| (objectclass=*) (ou=*) ) (...
+        presenceNode = ( PresenceNode ) orNodes.get( 1 );
+        assertNotNull( presenceNode );
+
+        assertEquals( "ou", presenceNode.getAttribute() );
+
+        // (& (| (objectclass=*) (ou=*) ) (! ...
+        NotNode notNode = ( NotNode ) andNodes.get( 1 );
+        assertNotNull( notNode );
+
+        // (& (| (objectclass=*) (ou=*) ) (! (objectclass>=ttt) ) )
+        GreaterEqNode<?> greaterOrEqual = ( GreaterEqNode<?> ) notNode.getFirstChild();
+        assertNotNull( greaterOrEqual );
+
+        assertEquals( "objectclass", greaterOrEqual.getAttribute() );
+        assertEquals( "ttt", greaterOrEqual.getValue().getString() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x7B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x6C ), decodedPdu.substring( 0, 0x6C ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with no attributes. The search
+     * filter is : (objectclass=*)
+     */
+    @Test
+    public void testDecodeSearchRequestNoAttributes()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x40 );
+        stream.put( new byte[]
+            { 0x30,
+                0x37, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x63,
+                0x32, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x12, // baseObject LDAPDN,
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x0A,
+                0x01,
+                0x00, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (infinite)
+                0x02,
+                0x01,
+                0x00,
+                // timeLimit INTEGER (0 .. maxInt), (infinite)
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0x00, // typesOnly
+                // BOOLEAN,
+                // (FALSE)
+                // filter Filter,
+                // Filter ::= CHOICE {
+                ( byte ) 0x87,
+                0x0B, // present [7] AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'C',
+                'l',
+                'a',
+                's',
+                's',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x00,
+                0x00, // Some trailing 00, useless.
+                0x00,
+                0x00,
+                0x00,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 3, searchRequest.getMessageId() );
+        assertEquals( "ou=users,ou=system", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.OBJECT, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        // (objectClass = *)
+        ExprNode filter = searchRequest.getFilter();
+
+        PresenceNode presenceNode = ( PresenceNode ) filter;
+        assertNotNull( presenceNode );
+        assertEquals( "objectClass", presenceNode.getAttribute() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x39, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu.substring( 0, decodedPdu.length() - 35 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty attribute. The search
+     * filter is : (objectclass=*)
+     */
+    @Test
+    public void testDecodeSearchRequestOneEmptyAttribute()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3F );
+        stream.put( new byte[]
+            { 0x30,
+                0x3D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x63,
+                0x38, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x12, // baseObject LDAPDN,
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x0A,
+                0x01,
+                0x00, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (infinite)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (infinite)
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                0x00, // typesOnly
+                // BOOLEAN,
+                // (FALSE)
+                // filter Filter,
+                // Filter ::= CHOICE {
+                ( byte ) 0x87,
+                0x0B, // present [7] AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'C',
+                'l',
+                'a',
+                's',
+                's',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x06, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x02, // Request for sn
+                's',
+                'n',
+                0x04,
+                0x00 // Empty attribute
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 3, searchRequest.getMessageId() );
+        assertEquals( "ou=users,ou=system", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.OBJECT, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        // (objectClass = *)
+        ExprNode filter = searchRequest.getFilter();
+
+        PresenceNode presenceNode = ( PresenceNode ) filter;
+        assertNotNull( presenceNode );
+        assertEquals( "objectClass", presenceNode.getAttribute() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 1, attributes.size() );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a star and an attribute. The search
+     * filter is : (objectclass=*)
+     */
+    @Test
+    public void testDecodeSearchRequestWithStarAndAttr()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x40 );
+        stream.put( new byte[]
+            { 0x30,
+                0x3E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x03, // messageID MessageID
+                0x63,
+                0x39, // CHOICE { ..., searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x12, // baseObject LDAPDN,
+                'o',
+                'u',
+                '=',
+                'u',
+                's',
+                'e',
+                'r',
+                's',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                0x0A,
+                0x01,
+                0x00, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (infinite)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (infinite)
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                0x00, // typesOnly
+                // BOOLEAN,
+                // (FALSE)
+                // filter Filter,
+                // Filter ::= CHOICE {
+                ( byte ) 0x87,
+                0x0B, // present [7] AttributeDescription,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'C',
+                'l',
+                'a',
+                's',
+                's',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x07, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x02, // Request for sn
+                's',
+                'n',
+                0x04,
+                0x01,
+                '*' // * attribute
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 3, searchRequest.getMessageId() );
+        assertEquals( "ou=users,ou=system", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.OBJECT, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        // (objectClass = *)
+        ExprNode filter = searchRequest.getFilter();
+
+        PresenceNode presenceNode = ( PresenceNode ) filter;
+        assertNotNull( presenceNode );
+        assertEquals( "objectClass", presenceNode.getAttribute() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 2, attributes.size() );
+        Set<String> expectedAttrs = new HashSet<String>();
+        expectedAttrs.add( "sn" );
+        expectedAttrs.add( "*" );
+
+        for ( String attribute : attributes )
+        {
+            assertTrue( expectedAttrs.contains( attribute ) );
+            expectedAttrs.remove( attribute );
+        }
+
+        assertEquals( 0, expectedAttrs.size() );
+    }
+
+
+    /**
+     * Tests an search request decode with a simple equality match filter.
+     */
+    @Test
+    public void testDecodeSearchRequestOrFilters()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x96 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81, ( byte ) 0x93, 0x02, 0x01,
+                0x21,
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x8D, // "dc=example,dc=com"
+                0x04,
+                0x11,
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x02,
+                0x02,
+                0x01,
+                0x02,
+                0x02,
+                0x01,
+                0x03,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA1,
+                0x52, // ( |
+                ( byte ) 0xA3,
+                0x10, // ( uid=akarasulu )
+                0x04,
+                0x03,
+                'u',
+                'i',
+                'd',
+                0x04,
+                0x09,
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ( byte ) 0xA3,
+                0x09, // ( cn=aok )
+                0x04,
+                0x02,
+                'c',
+                'n',
+                0x04,
+                0x03,
+                'a',
+                'o',
+                'k',
+                ( byte ) 0xA3,
+                0x15, // ( ou=Human Resources )
+                0x04,
+                0x02,
+                'o',
+                'u',
+                0x04,
+                0x0F,
+                'H',
+                'u',
+                'm',
+                'a',
+                'n',
+                ' ',
+                'R',
+                'e',
+                's',
+                'o',
+                'u',
+                'r',
+                'c',
+                'e',
+                's',
+                ( byte ) 0xA3,
+                0x10,
+                0x04,
+                0x01,
+                'l', // (l=Santa Clara )
+                0x04,
+                0x0B,
+                'S',
+                'a',
+                'n',
+                't',
+                'a',
+                ' ',
+                'C',
+                'l',
+                'a',
+                'r',
+                'a',
+                ( byte ) 0xA3,
+                0x0A, // ( cn=abok ))
+                0x04,
+                0x02,
+                'c',
+                'n',
+                0x04,
+                0x04,
+                'a',
+                'b',
+                'o',
+                'k',
+                0x30,
+                0x15, // Attributes
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // attr0
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // attr1
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // attr2
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 33, searchRequest.getMessageId() );
+        assertEquals( "dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.OBJECT, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_FINDING_BASE_OBJ, searchRequest.getDerefAliases() );
+        assertEquals( 2, searchRequest.getSizeLimit() );
+        assertEquals( 3, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (objectclass=t*)
+        OrNode orNode = ( OrNode ) searchRequest.getFilter();
+        assertNotNull( orNode );
+        assertEquals( 5, orNode.getChildren().size() );
+
+        // uid=akarasulu
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) orNode.getChildren().get( 0 );
+
+        assertEquals( "uid", equalityNode.getAttribute() );
+        assertEquals( "akarasulu", equalityNode.getValue().getString() );
+
+        // cn=aok
+        equalityNode = ( EqualityNode<?> ) orNode.getChildren().get( 1 );
+
+        assertEquals( "cn", equalityNode.getAttribute() );
+        assertEquals( "aok", equalityNode.getValue().getString() );
+
+        // ou = Human Resources
+        equalityNode = ( EqualityNode<?> ) orNode.getChildren().get( 2 );
+
+        assertEquals( "ou", equalityNode.getAttribute() );
+        assertEquals( "Human Resources", equalityNode.getValue().getString() );
+
+        // l=Santa Clara
+        equalityNode = ( EqualityNode<?> ) orNode.getChildren().get( 3 );
+
+        assertEquals( "l", equalityNode.getAttribute() );
+        assertEquals( "Santa Clara", equalityNode.getValue().getString() );
+
+        // cn=abok
+        equalityNode = ( EqualityNode<?> ) orNode.getChildren().get( 4 );
+
+        assertEquals( "cn", equalityNode.getAttribute() );
+        assertEquals( "abok", equalityNode.getValue().getString() );
+
+        // The attributes
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x0096, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x87 ), decodedPdu.substring( 0, 0x87 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with controls.
+     */
+    @Test
+    public void testDecodeSearchRequestWithControls()
+    {
+        byte[] asn1BERJava5 = new byte[]
+            { 0x30, 0x7f,
+                0x02, 0x01, 0x04, // messageID
+                0x63,
+                0x33,
+                0x04,
+                0x13, // baseObject
+                'd',
+                'c',
+                '=',
+                'm',
+                'y',
+                '-',
+                'd',
+                'o',
+                'm',
+                'a',
+                'i',
+                'n',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0a,
+                0x01,
+                0x02, // scope: subtree
+                0x0a,
+                0x01,
+                0x03, // derefAliases: derefAlways
+                0x02,
+                0x01,
+                0x00, // sizeLimit: 0
+                0x02,
+                0x01,
+                0x00, // timeLimit: 0
+                0x01,
+                0x01,
+                0x00, // typesOnly: false
+                ( byte ) 0x87,
+                0x0b, // Present filter: (objectClass=*)
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'C',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x00, // Attributes = '*'
+                ( byte ) 0xa0,
+                0x45, // controls
+                0x30,
+                0x28,
+                0x04,
+                0x16, // control
+                '1',
+                '.',
+                '2',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '1',
+                '3',
+                '5',
+                '5',
+                '6',
+                '.',
+                '1',
+                '.',
+                '4',
+                '.',
+                '3',
+                '1',
+                '9',
+                0x01,
+                0x01,
+                ( byte ) 0xff, // criticality: false
+                0x04,
+                0x0b,
+                0x30,
+                0x09,
+                0x02,
+                0x01,
+                0x02,
+                0x04,
+                0x04,
+                0x47,
+                0x00,
+                0x00,
+                0x00, // value: pageSize=2
+                0x30,
+                0x19,
+                0x04,
+                0x17, // control
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2',
+        };
+
+        byte[] asn1BERJava6 = new byte[]
+            { 0x30, 0x7f,
+                0x02, 0x01, 0x04, // messageID
+                0x63,
+                0x33,
+                0x04,
+                0x13, // baseObject
+                'd',
+                'c',
+                '=',
+                'm',
+                'y',
+                '-',
+                'd',
+                'o',
+                'm',
+                'a',
+                'i',
+                'n',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0a,
+                0x01,
+                0x02, // scope: subtree
+                0x0a,
+                0x01,
+                0x03, // derefAliases: derefAlways
+                0x02,
+                0x01,
+                0x00, // sizeLimit: 0
+                0x02,
+                0x01,
+                0x00, // timeLimit: 0
+                0x01,
+                0x01,
+                0x00, // typesOnly: false
+                ( byte ) 0x87,
+                0x0b, // Present filter: (objectClass=*)
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'C',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x00, // Attributes = '*'
+                ( byte ) 0xa0,
+                0x45, // controls
+                0x30,
+                0x19,
+                0x04,
+                0x17, // control
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2',
+                0x30,
+                0x28,
+                0x04,
+                0x16, // control
+                '1',
+                '.',
+                '2',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '1',
+                '3',
+                '5',
+                '5',
+                '6',
+                '.',
+                '1',
+                '.',
+                '4',
+                '.',
+                '3',
+                '1',
+                '9',
+                0x01,
+                0x01,
+                ( byte ) 0xff, // criticality: false
+                0x04,
+                0x0b,
+                0x30,
+                0x09,
+                0x02,
+                0x01,
+                0x02,
+                0x04,
+                0x04,
+                0x47,
+                0x00,
+                0x00,
+                0x00, // value: pageSize=2
+            };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        // For Java6
+        ByteBuffer streamJava6 = ByteBuffer.allocate( asn1BERJava6.length );
+        streamJava6.put( asn1BERJava6 );
+        String decodedPduJava6 = Strings.dumpBytes( streamJava6.array() );
+        streamJava6.flip();
+
+        // For Java5
+        ByteBuffer streamJava5 = ByteBuffer.allocate( asn1BERJava5.length );
+        streamJava5.put( asn1BERJava5 );
+        String decodedPduJava5 = Strings.dumpBytes( streamJava5.array() );
+
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( streamJava6, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 4, searchRequest.getMessageId() );
+        assertEquals( 2, searchRequest.getControls().size() );
+
+        // this is a constant in Java 5 API
+        String pagedResultsControlOID = "1.2.840.113556.1.4.319";
+        Control pagedResultsControl = searchRequest.getControl( pagedResultsControlOID );
+        assertEquals( pagedResultsControlOID, pagedResultsControl.getOid() );
+        assertTrue( pagedResultsControl.isCritical() );
+
+        // this is a constant in Java 5 API
+        String manageReferralControlOID = "2.16.840.1.113730.3.4.2";
+        Control manageReferralControl = searchRequest.getControl( manageReferralControlOID );
+        assertEquals( manageReferralControlOID, manageReferralControl.getOid() );
+
+        assertEquals( "dc=my-domain,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.SUBTREE, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof PresenceNode );
+        assertEquals( "objectClass", ( ( PresenceNode ) filter ).getAttribute() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x81, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertTrue( decodedPduJava5.equals( encodedPdu ) || decodedPduJava6.equals( encodedPdu ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with no controls but with oid
+     * attributes. The search filter is :
+     * (&(|(objectclass=top)(2.5.4.11=contacts))(!(organizationalUnitName=ttt)))
+     */
+    @Test
+    public void testDecodeSearchRequestGlobalNoControlsOidAndAlias()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0xA1 );
+        stream.put( new byte[]
+            {
+                0x30,
+                ( byte ) 0x81,
+                ( byte ) 0x9E, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x98, // CHOICE { ...,
+                // searchRequest
+                // SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope
+                // ENUMERATED
+                // {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8,
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly
+                // BOOLEAN,
+                // (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x4D, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x2A, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x14, // equalityMatch
+                // [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x08,
+                '2',
+                '.',
+                '5',
+                '.',
+                '4',
+                '.',
+                '1',
+                '1', // attributeDesc
+                // AttributeDescription
+                // (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x1F, // not
+                // [2]
+                // Filter,
+                ( byte ) 0xA3,
+                0x1D, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x16,
+                'o',
+                'r',
+                'g',
+                'a',
+                'n',
+                'i',
+                'z',
+                'a',
+                't',
+                'i',
+                'o',
+                'n',
+                'a',
+                'l',
+                'U',
+                'n',
+                'i',
+                't',
+                'N',
+                'a',
+                'm',
+                'e',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription
+                // ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::=
+            // LDAPString
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (& (...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+
+        // (& (| (...
+        assertEquals( 2, andNodes.size() );
+        OrNode orFilter = ( OrNode ) andNodes.get( 0 );
+        assertNotNull( orFilter );
+
+        // (& (| (obectclass=top) (...
+        List<ExprNode> orNodes = orFilter.getChildren();
+        assertEquals( 2, orNodes.size() );
+
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) orNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "objectclass", equalityNode.getAttribute() );
+        assertEquals( "top", equalityNode.getValue().getString() );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (...
+        equalityNode = ( EqualityNode<?> ) orNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "2.5.4.11", equalityNode.getAttribute() );
+        assertEquals( "contacts", equalityNode.getValue().getString() );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (! ...
+        NotNode notNode = ( NotNode ) andNodes.get( 1 );
+        assertNotNull( notNode );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (! (objectclass=ttt) ) )
+        equalityNode = ( EqualityNode<?> ) notNode.getFirstChild();
+        assertNotNull( equalityNode );
+
+        assertEquals( "organizationalUnitName", equalityNode.getAttribute() );
+        assertEquals( "ttt", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // We won't check the encoding, as it has changed because of
+        // attributes transformations
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with SubEntry control.
+     */
+    @Test
+    public void testDecodeSearchRequestSubEntryControl()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x5D, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x33,
+                0x04,
+                0x13, // baseObject: dc=my-domain,dc=com
+                'd',
+                'c',
+                '=',
+                'm',
+                'y',
+                '-',
+                'd',
+                'o',
+                'm',
+                'a',
+                'i',
+                'n',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0a,
+                0x01,
+                0x02, // scope: subtree
+                0x0a,
+                0x01,
+                0x03, // derefAliases: derefAlways
+                0x02,
+                0x01,
+                0x00, // sizeLimit: 0
+                0x02,
+                0x01,
+                0x00, // timeLimit: 0
+                0x01,
+                0x01,
+                0x00, // typesOnly: false
+                ( byte ) 0x87,
+                0x0b, // filter: (objectClass=*)
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'C',
+                'l',
+                'a',
+                's',
+                's',
+                0x30,
+                0x00,
+                ( byte ) 0xa0,
+                0x23, // controls
+                0x30,
+                0x21,
+                0x04,
+                0x17,
+                '1',
+                '.',
+                '3',
+                '.',
+                '6',
+                '.',
+                '1',
+                '.',
+                '4',
+                '.',
+                '1',
+                '.',
+                '4',
+                '2',
+                '0',
+                '3',
+                '.',
+                '1',
+                '.',
+                '1',
+                '0',
+                '.',
+                '1', // SubEntry OID
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // criticality: true
+                0x04,
+                0x03,
+                0x01,
+                0x01,
+                ( byte ) 0xFF // SubEntry visibility
+        };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 4, searchRequest.getMessageId() );
+        assertEquals( 1, searchRequest.getControls().size() );
+
+        // SubEntry Control
+        String subEntryControlOID = "1.3.6.1.4.1.4203.1.10.1";
+        Control subEntryControl = searchRequest.getControl( subEntryControlOID );
+        assertEquals( subEntryControlOID, subEntryControl.getOid() );
+        assertTrue( subEntryControl.isCritical() );
+        assertTrue( subEntryControl instanceof SubentriesDecorator );
+        assertTrue( ( ( SubentriesDecorator ) subEntryControl ).getDecorated().isVisible() );
+
+        assertEquals( "dc=my-domain,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.SUBTREE, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        ExprNode filter = searchRequest.getFilter();
+
+        assertTrue( filter instanceof PresenceNode );
+        assertEquals( "objectClass", ( ( PresenceNode ) filter ).getAttribute() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x5F, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+            assertEquals( decodedPdu, encodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    // Defensive tests
+    /**
+     * Test the decoding of a SearchRequest with an empty body
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyBody()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x05, 0x02, 0x01, 0x04, // messageID
+                0x63,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty baseDN and nothing more
+     */
+    @Test
+    public void testDecodeSearchRequestBaseDnOnly()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x07, 0x02, 0x01, 0x04, // messageID
+                0x63,
+                0x02,
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with no controls. The search filter
+     * is : (&(|(objectclass=top)(ou=contacts))(!(objectclass=ttt)))
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyBaseDnNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x6F );
+        stream.put( new byte[]
+            { 0x30, 0x6D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x68, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x00, // baseObject LDAPDN,
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly  BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x0E, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x02,
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 1000, searchRequest.getSizeLimit() );
+        assertEquals( 1000, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (& (...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+
+        // (& (| (...
+        assertEquals( 2, andNodes.size() );
+        OrNode orFilter = ( OrNode ) andNodes.get( 0 );
+        assertNotNull( orFilter );
+
+        // (& (| (obectclass=top) (...
+        List<ExprNode> orNodes = orFilter.getChildren();
+        assertEquals( 2, orNodes.size() );
+
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) orNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "objectclass", equalityNode.getAttribute() );
+        assertEquals( "top", equalityNode.getValue().getString() );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (...
+        equalityNode = ( EqualityNode<?> ) orNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "ou", equalityNode.getAttribute() );
+        assertEquals( "contacts", equalityNode.getValue().getString() );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (! ...
+        NotNode notNode = ( NotNode ) andNodes.get( 1 );
+        assertNotNull( notNode );
+
+        // (& (| (objectclass=top) (ou=contacts) ) (! (objectclass=ttt) ) )
+        equalityNode = ( EqualityNode<?> ) notNode.getFirstChild();
+        assertNotNull( equalityNode );
+
+        assertEquals( "objectclass", equalityNode.getAttribute() );
+        assertEquals( "ttt", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        for ( String attribute : attributes )
+        {
+            assertNotNull( attribute );
+        }
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x6F, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x6F ), decodedPdu.substring( 0, 0x6F ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a bad objectBase
+     */
+    @Test
+    public void testDecodeSearchRequestGlobalBadObjectBase()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x90 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81,
+                ( byte ) 0x8D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x87, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                ':',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly  BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x0E, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x02,
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( de instanceof ResponseCarryingException );
+            Message response = ( ( ResponseCarryingException ) de ).getResponse();
+            assertTrue( response instanceof SearchResultDoneImpl );
+            assertEquals( ResultCodeEnum.INVALID_DN_SYNTAX, ( ( SearchResultDoneImpl ) response ).getLdapResult()
+                .getResultCode() );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty scope
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyScope()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x28, 0x02, 0x01,
+                0x04, // messageID
+                0x63,
+                0x23,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a bad scope
+     */
+    @Test
+    public void testDecodeSearchRequestGlobalBadScope()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x90 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81,
+                ( byte ) 0x8D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x87, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                ':',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x03, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly  BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x0E, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x02,
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty derefAlias
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyDerefAlias()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x2B, 0x02, 0x01,
+                0x04, // messageID
+                0x63,
+                0x26,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a bad derefAlias
+     */
+    @Test
+    public void testDecodeSearchRequestGlobalBadDerefAlias()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x90 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81,
+                ( byte ) 0x8D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x87, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                ':',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x04, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly  BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x0E, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x02,
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty size limit
+     */
+    @Test
+    public void testDecodeSearchRequestEmptySizeLimit()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x2E, 0x02, 0x01,
+                0x04, // messageID
+                0x63,
+                0x29,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a bad sizeLimit
+     */
+    @Test
+    public void testDecodeSearchRequestGlobalBadSizeLimit()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x8F );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81,
+                ( byte ) 0x8C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x86, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                ':',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x01,
+                ( byte ) 0xFF, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly  BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x0E, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x02,
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty time limit
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyTimeLimit()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x31, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x2C,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a bad timeLimit
+     */
+    @Test
+    public void testDecodeSearchRequestGlobalBadTimeLimit()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x8F );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x81,
+                ( byte ) 0x8C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                ( byte ) 0x81,
+                ( byte ) 0x86, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                ':',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                // baseObject (0),
+                // singleLevel (1),
+                // wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                // neverDerefAliases (0),
+                // derefInSearching (1),
+                // derefFindingBaseObj (2),
+                // derefAlways (3) },
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8, // sizeLimit INTEGER (0 .. maxInt), (1000)
+                0x02,
+                0x01,
+                ( byte ) 0xFF, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF, // typesOnly  BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x3C, // Filter ::= CHOICE {
+                // and [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x24, // or [1] SET of Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3]
+                // Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                ( byte ) 0xA3,
+                0x0E, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x02,
+                'o',
+                'u', // attributeDesc AttributeDescription (LDAPString),
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x08,
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ( byte ) 0xA2,
+                0x14, // not [2] Filter,
+                ( byte ) 0xA3,
+                0x12, // equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                // attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // assertionValue AssertionValue (OCTET STRING) }
+                0x04,
+                0x03,
+                't',
+                't',
+                't',
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x15, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '0', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '1', // AttributeDescription ::= LDAPString
+                0x04,
+                0x05,
+                'a',
+                't',
+                't',
+                'r',
+                '2' // AttributeDescription ::= LDAPString
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyTypeOnly()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x34, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x2F,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x37, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x32,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA0,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty Present filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyPresentFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x37, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x32,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0x87,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty equalityMatch filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyEqualityMatchFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x37, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x32,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA3,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty greaterOrEqual filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyGreaterOrEqualFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x37, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x32,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA5,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty lessOrEqual filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyLessOrEqualFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x37, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x32,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA6,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an approxMatch filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyApproxMatchFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x37, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x32,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA8,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a greaterOrEqual filter and an
+     * empty attributeDesc
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyGreaterOrEqualEmptyAttrDesc()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x39, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x34,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x00,
+                0x0A,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA5,
+                0x02,
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a greaterOrEqual filter and an
+     * empty attributeValue, and an empty attribute List
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyGreaterOrEqualEmptyAttrValue()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x41,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3C,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA5,
+                0x08,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x04,
+                0x00,
+                0x30,
+                0x00 // AttributeDescriptionList ::= SEQUENCE
+            // OF AttributeDescription
+        };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 4, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // >=
+        GreaterEqNode<?> greaterOrEqual = ( GreaterEqNode<?> ) searchRequest.getFilter();
+
+        assertNotNull( greaterOrEqual );
+
+        assertEquals( "test", greaterOrEqual.getAttribute() );
+        assertEquals( "", greaterOrEqual.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x43, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a greaterOrEqual filter and an
+     * empty attributeValue, and an '*' attribute List
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyGreaterOrEqualEmptyAttrValueStar()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x44,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3F,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA5,
+                0x08,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x04,
+                0x00,
+                0x30,
+                0x03, // AttributeDescriptionList ::= SEQUENCE
+                // OF AttributeDescription
+                0x04,
+                0x01,
+                '*' };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 4, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // >=
+        GreaterEqNode<?> greaterOrEqual = ( GreaterEqNode<?> ) searchRequest.getFilter();
+
+        assertNotNull( greaterOrEqual );
+
+        assertEquals( "test", greaterOrEqual.getAttribute() );
+        assertEquals( "", greaterOrEqual.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 1, attributes.size() );
+        assertEquals( "*", attributes.get( 0 ) );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x46, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a greaterOrEqual filter and an
+     * empty attributeValue, and an empty attribute List
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyGreaterOrEqualEmptyAttrValueEmpty()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x43,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x3E,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA5,
+                0x08,
+                0x04,
+                0x04,
+                't',
+                'e',
+                's',
+                't',
+                0x04,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE
+                // OF AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 4, searchRequest.getMessageId() );
+        assertEquals( "uid=akarasulu,dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // >=
+        GreaterEqNode<?> greaterOrEqual = ( GreaterEqNode<?> ) searchRequest.getFilter();
+
+        assertNotNull( greaterOrEqual );
+
+        assertEquals( "test", greaterOrEqual.getAttribute() );
+        assertEquals( "", greaterOrEqual.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+
+        assertEquals( 0, attributes.size() );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty And filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyAndFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3B, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x36,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA0,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty Or filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyOrFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3B, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x36,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA1,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with an empty Not filter
+     */
+    @Test
+    public void testDecodeSearchRequestEmptyNotFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3B, 0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x36,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA2,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList
+                // ::=
+                // SEQUENCE
+                // OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a Not filter and an empty And
+     * filter
+     */
+    @Test
+    public void testDecodeSearchRequestNotFilterEmptyAndFilter()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x3D,
+                0x02,
+                0x01,
+                0x04, // messageID
+                0x63,
+                0x38,
+                0x04,
+                0x1F, // baseObject LDAPDN,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'k',
+                'a',
+                'r',
+                'a',
+                's',
+                'u',
+                'l',
+                'u',
+                ',',
+                'd',
+                'c',
+                '=',
+                'e',
+                'x',
+                'a',
+                'm',
+                'p',
+                'l',
+                'e',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                0x0A,
+                0x01,
+                0x01,
+                0x0A,
+                0x01,
+                0x03,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x01,
+                0x01,
+                ( byte ) 0xFF,
+                ( byte ) 0xA2,
+                0x02,
+                ( byte ) 0xA0,
+                0x00,
+                0x30,
+                0x02, // AttributeDescriptionList ::= SEQUENCE OF
+                // AttributeDescription
+                0x04,
+                0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a greaterOrEqual filter and an
+     * empty attributeValue, and an '*' attribute List
+     */
+    @Test
+    public void testDecodeSearchRequestDIRSERVER_651()
+    {
+        byte[] asn1BER = new byte[]
+            { 0x30, 0x60, 0x02, 0x01, 0x02, 0x63, 0x5b, 0x04, 0x0a, 'd', 'c', '=', 'p', 'g', 'p', 'k', 'e', 'y', 's',
+                0x0a, 01, 02, 0x0a, 01, 00, 0x02, 01, 00, 0x02, 01, 00, 0x01, 01, 00, ( byte ) 0xa0, 0x3c,
+                ( byte ) 0xa4, 0x28, 0x04, 0x09, 'p', 'g', 'p', 'u', 's', 'e', 'r', 'i', 'd', 0x30, 0x1b,
+                ( byte ) 0x80, 0x19, 'v', 'g', 'j', 'o', 'k', 'j', 'e', 'v', '@', 'n', 'e', 't', 'c', 'e', 't', 'e',
+                'r', 'a', '.', 'c', 'o', 'm', '.', 'm', 'k', ( byte ) 0xa3, 0x10, 0x04, 0x0b, 'p', 'g', 'p', 'd', 'i',
+                's', 'a', 'b', 'l', 'e', 'd', 0x04, 0x01, '0', 0x30, 0x00 };
+
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
+        stream.put( asn1BER );
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        // Decode a SearchRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 2, searchRequest.getMessageId() );
+        assertEquals( "dc=pgpkeys", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.SUBTREE, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.NEVER_DEREF_ALIASES, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        // And
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        SubstringNode substringNode = ( SubstringNode ) andNodes.get( 0 );
+        assertNotNull( substringNode );
+
+        assertEquals( "pgpuserid", substringNode.getAttribute() );
+        assertEquals( "vgjokjev@netcetera.com.mk", substringNode.getInitial() );
+        assertEquals( 0, substringNode.getAny().size() );
+        assertEquals( null, substringNode.getFinal() );
+
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "pgpdisabled", equalityNode.getAttribute() );
+        assertEquals( "0", equalityNode.getValue().getString() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x62, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (a=b)
+     */
+    @Test
+    public void testDecodeSearchRequestEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x25 );
+        stream.put( new byte[]
+            { 0x30, 0x23, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x1E, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA3,
+                0x06, // Filter ::= CHOICE {
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (a=b)
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) searchRequest.getFilter();
+
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x25, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x25 ), decodedPdu.substring( 0, 0x25 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(a=b))
+     */
+    @Test
+    public void testDecodeSearchRequestAndEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x27 );
+        stream.put( new byte[]
+            { 0x30, 0x25, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x20, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x08, // Filter ::= CHOICE {
+                ( byte ) 0xA3,
+                0x06,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 1, andNodes.size() );
+
+        // (&(a=b))
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x27, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x27 ), decodedPdu.substring( 0, 0x27 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(a=b)(c=d))
+     */
+    @Test
+    public void testDecodeSearchRequestAndEqEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2F );
+        stream.put( new byte[]
+            { 0x30, 0x2D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x28, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x10, // Filter ::= CHOICE {
+                ( byte ) 0xA3,
+                0x06,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA3,
+                0x06,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'c', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'd', //      assertionValue AssertionValue (OCTET STRING) }
+                // attributes AttributeDescriptionList }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(a=b)...
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        // (&(a=b)(c=d))
+        equalityNode = ( EqualityNode<?> ) andNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "c", equalityNode.getAttribute() );
+        assertEquals( "d", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x2F, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x2F ), decodedPdu.substring( 0, 0x2F ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(&(a=b))
+     */
+    @Test
+    public void testDecodeSearchRequestAndAndEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x29 );
+        stream.put( new byte[]
+            { 0x30, 0x27, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x22, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x0A, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA0,
+                0x08, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 1, andNodes.size() );
+
+        // (&(&(..
+        AndNode andNode2 = ( AndNode ) andNodes.get( 0 );
+        assertNotNull( andNode2 );
+
+        List<ExprNode> andNodes2 = andNode2.getChildren();
+        assertEquals( 1, andNodes2.size() );
+
+        // (&(&(a=b)))
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x29, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x29 ), decodedPdu.substring( 0, 0x29 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(&(a=b)(c=d))
+     */
+    @Test
+    public void testDecodeSearchRequestAndAndEqEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x31 );
+        stream.put( new byte[]
+            { 0x30, 0x2F, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x2A, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x12, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA0,
+                0x10, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA3,
+                0x06,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'c', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'd', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 1, andNodes.size() );
+
+        // (&(&(..
+        AndNode andNode2 = ( AndNode ) andNodes.get( 0 );
+        assertNotNull( andNode2 );
+
+        List<ExprNode> andNodes2 = andNode2.getChildren();
+        assertEquals( 2, andNodes2.size() );
+
+        // (&(&(a=b)...
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        // (&(&(a=b)(c=d)
+        equalityNode = ( EqualityNode<?> ) andNodes2.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "c", equalityNode.getAttribute() );
+        assertEquals( "d", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x31, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x31 ), decodedPdu.substring( 0, 0x31 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(&(a=b))(c=d))
+     */
+    @Test
+    public void testDecodeSearchRequestAnd_AndEq_Eq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x31 );
+        stream.put( new byte[]
+            { 0x30, 0x2F, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x2A, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x12, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA0,
+                0x08, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA3,
+                0x06, //      equalityMatch [3] Assertion,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'c', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'd', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(&(..
+        AndNode andNode2 = ( AndNode ) andNodes.get( 0 );
+        assertNotNull( andNode2 );
+
+        List<ExprNode> andNodes2 = andNode2.getChildren();
+        assertEquals( 1, andNodes2.size() );
+
+        // (&(&(a=b))...
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        // (&(&(a=b))(c=d))
+        equalityNode = ( EqualityNode<?> ) andNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "c", equalityNode.getAttribute() );
+        assertEquals( "d", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x31, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x31 ), decodedPdu.substring( 0, 0x31 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(&(a=b)(c=d))(e=f))
+     */
+    @Test
+    public void testDecodeSearchRequestAnd_AndEqEq_Eq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x39 );
+        stream.put( new byte[]
+            { 0x30, 0x37, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x32, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x1A, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA0,
+                0x10, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'c', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'd', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA3,
+                0x06, //      equalityMatch [3] Assertion,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'e', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'f', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(&(..
+        AndNode andNode2 = ( AndNode ) andNodes.get( 0 );
+        assertNotNull( andNode2 );
+
+        List<ExprNode> andNodes2 = andNode2.getChildren();
+        assertEquals( 2, andNodes2.size() );
+
+        // (&(&(a=b)...
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        // (&(&(a=b)(c=d)...
+        equalityNode = ( EqualityNode<?> ) andNodes2.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "c", equalityNode.getAttribute() );
+        assertEquals( "d", equalityNode.getValue().getString() );
+
+        // (&(&(a=b)(c=d))(e=f))
+        equalityNode = ( EqualityNode<?> ) andNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "e", equalityNode.getAttribute() );
+        assertEquals( "f", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x39, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x39 ), decodedPdu.substring( 0, 0x39 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(a=b)(|(a=b)(c=d)))
+     */
+    @Test
+    public void testDecodeSearchRequestAndEq_OrEqEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x39 );
+        stream.put( new byte[]
+            { 0x30, 0x37, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x32, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x1A, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06, //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA1,
+                0x10, // Filter ::= CHOICE { or             [1] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'c', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'd', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'e', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'f', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00, // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+            } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode exprNode = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) exprNode;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(a=b)..
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        // (&(a=b)(|(...
+        OrNode orNode = ( OrNode ) andNodes.get( 1 );
+        assertNotNull( orNode );
+
+        List<ExprNode> orNodes = orNode.getChildren();
+        assertEquals( 2, orNodes.size() );
+
+        // (&(a=b)(|(c=d)...
+        equalityNode = ( EqualityNode<?> ) orNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "c", equalityNode.getAttribute() );
+        assertEquals( "d", equalityNode.getValue().getString() );
+
+        // (&(a=b)(|(c=d)(e=f)))
+        equalityNode = ( EqualityNode<?> ) orNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "e", equalityNode.getAttribute() );
+        assertEquals( "f", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x39, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x39 ), decodedPdu.substring( 0, 0x39 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(&(a=b))(&(c=d)))
+     */
+    @Test
+    public void testDecodeSearchRequestAnd_AndEq_AndEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x33 );
+        stream.put( new byte[]
+            { 0x30, 0x31, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x2C, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x14, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA0,
+                0x08, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA0,
+                0x08, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'c', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'd', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00 // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(&(..
+        AndNode andNode2 = ( AndNode ) andNodes.get( 0 );
+        assertNotNull( andNode2 );
+
+        List<ExprNode> andNodes2 = andNode2.getChildren();
+        assertEquals( 1, andNodes2.size() );
+
+        // (&(&(a=b)...
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        // (&(&(a=b))(&...
+        andNode2 = ( AndNode ) andNodes.get( 1 );
+        assertNotNull( andNode2 );
+
+        andNodes2 = andNode2.getChildren();
+        assertEquals( 1, andNodes2.size() );
+
+        // (&(&(a=b))(&(c=d)))
+        equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "c", equalityNode.getAttribute() );
+        assertEquals( "d", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x33, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x33 ), decodedPdu.substring( 0, 0x33 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(&(a=b)(c=d))(&(e=f)))
+     */
+    @Test
+    public void testDecodeSearchRequestAnd_AndEqEq_AndEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3B );
+        stream.put( new byte[]
+            { 0x30, 0x39, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x34, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x1C, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA0,
+                0x10, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'a', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'b', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'c', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'd', //      assertionValue AssertionValue (OCTET STRING) }
+                ( byte ) 0xA0,
+                0x08, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA3,
+                0x06,//      equalityMatch [3] Assertion,
+                //      equalityMatch [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'e', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'f', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00 // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(&(..
+        AndNode andNode2 = ( AndNode ) andNodes.get( 0 );
+        assertNotNull( andNode2 );
+
+        List<ExprNode> andNodes2 = andNode2.getChildren();
+        assertEquals( 2, andNodes2.size() );
+
+        // (&(&(a=b)...
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "a", equalityNode.getAttribute() );
+        assertEquals( "b", equalityNode.getValue().getString() );
+
+        // (&(&(a=b)(c=d))...
+        equalityNode = ( EqualityNode<?> ) andNodes2.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "c", equalityNode.getAttribute() );
+        assertEquals( "d", equalityNode.getValue().getString() );
+
+        // (&(&(a=b)(c=d))(&...
+        andNode2 = ( AndNode ) andNodes.get( 1 );
+        assertNotNull( andNode2 );
+
+        andNodes2 = andNode2.getChildren();
+        assertEquals( 1, andNodes2.size() );
+
+        // (&(&(a=b)(c=d))(&(e=f)))
+        equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "e", equalityNode.getAttribute() );
+        assertEquals( "f", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x3B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x3B ), decodedPdu.substring( 0, 0x3B ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * (&(|(abcdef=*)(ghijkl=*))(!(e>=f)))
+     */
+    @Test
+    public void testDecodeSearchRequestAnd_OrPrPr_NotGEq()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3B );
+        stream.put( new byte[]
+            { 0x30, 0x39, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x63,
+                0x34, // CHOICE { ...,
+                // searchRequest SearchRequest, ...
+                // SearchRequest ::= APPLICATION[3] SEQUENCE {
+                0x04,
+                0x03, // baseObject LDAPDN,
+                'a',
+                '=',
+                'b',
+                0x0A,
+                0x01,
+                0x01, // scope ENUMERATED {
+                //      baseObject (0),
+                //      singleLevel (1),
+                //      wholeSubtree (2) },
+                0x0A,
+                0x01,
+                0x03, // derefAliases ENUMERATED {
+                //      neverDerefAliases (0),
+                //      derefInSearching (1),
+                //      derefFindingBaseObj (2),
+                //      derefAlways (3) },
+                0x02,
+                0x01,
+                0x00, // sizeLimit INTEGER (0 .. maxInt), (0)
+                0x02,
+                0x01,
+                0x00, // timeLimit INTEGER (0 .. maxInt), (1000)
+                0x01,
+                0x01,
+                ( byte ) 0xFF,// typesOnly BOOLEAN, (TRUE)
+                // filter Filter,
+                ( byte ) 0xA0,
+                0x1C, // Filter ::= CHOICE { and             [0] SET OF Filter,
+                ( byte ) 0xA1,
+                0x10, // Filter ::= CHOICE { or             [0] SET OF Filter,
+                ( byte ) 0x87,
+                0x06,// present [7] AttributeDescription,
+                'a',
+                'b',
+                'c', // AttributeDescription ::= LDAPString
+                'd',
+                'e',
+                'f',
+                ( byte ) 0x87,
+                0x06,// present [7] AttributeDescription,
+                'g',
+                'h',
+                'i', // AttributeDescription ::= LDAPString
+                'j',
+                'k',
+                'l',
+                ( byte ) 0xA2,
+                0x08, // Filter ::= CHOICE { not             Filter,
+                ( byte ) 0xA5,
+                0x06,//      greaterOrEqual [3] Assertion,
+                // Assertion ::= SEQUENCE {
+                0x04,
+                0x01,
+                'e', //      attributeDesc AttributeDescription (LDAPString),
+                0x04,
+                0x01,
+                'f', //      assertionValue AssertionValue (OCTET STRING) }
+                0x30,
+                0x00 // AttributeDescriptionList ::= SEQUENCE OF AttributeDescription
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "a=b", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(|(..
+        OrNode orFilter = ( OrNode ) andNodes.get( 0 );
+        assertNotNull( orFilter );
+
+        List<ExprNode> orNodes = orFilter.getChildren();
+        assertEquals( 2, orNodes.size() );
+
+        // (&(&(abcdef=*)...
+        PresenceNode presenceNode = ( PresenceNode ) orNodes.get( 0 );
+        assertNotNull( presenceNode );
+
+        assertEquals( "abcdef", presenceNode.getAttribute() );
+
+        // (&(&(abcdef=*)(ghijkl=*))...
+        presenceNode = ( PresenceNode ) orNodes.get( 1 );
+        assertNotNull( presenceNode );
+
+        assertEquals( "ghijkl", presenceNode.getAttribute() );
+
+        // (&(&(abcdef=*)(ghijkl=*))(&...
+        NotNode notNode = ( NotNode ) andNodes.get( 1 );
+        assertNotNull( notNode );
+
+        // (&(&(abcdef=*)(ghijkl=*))(&(e>=f)))
+        GreaterEqNode<?> greaterEqNode = ( GreaterEqNode<?> ) notNode.getFirstChild();
+        assertNotNull( greaterEqNode );
+
+        assertEquals( "e", greaterEqNode.getAttribute() );
+        assertEquals( "f", greaterEqNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+
+        // Check the encoding
+        // We won't check the whole PDU, as it may differs because
+        // attributes may have been reordered
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchRequest );
+
+            // Check the length
+            assertEquals( 0x3B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.substring( 0, 0x3B ), decodedPdu.substring( 0, 0x3B ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest
+     * for rootDSE
+     */
+    @Test
+    public void testDecodeSearchRequestRootDse()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x33 );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x84, 0x00, 0x00, 0x00, 0x2D, 0x02, 0x01, 0x01, 0x63, ( byte ) 0x84, 0x00, 0x00, 0x00,
+                0x24, 0x04, 0x00, 0x0A, 0x01, 0x00, 0x0A, 0x01, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x01, 0x01,
+                0x00, ( byte ) 0x87, 0x0B, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x30,
+                ( byte ) 0x84, 0x00, 0x00, 0x00, 0x00 } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchRequest.getMessageId() );
+        assertEquals( "", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.OBJECT, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.NEVER_DEREF_ALIASES, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        ExprNode filter = searchRequest.getFilter();
+
+        PresenceNode presenceNode = ( PresenceNode ) filter;
+        assertNotNull( presenceNode );
+        assertEquals( "objectClass", presenceNode.getAttribute() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with special length (long form)
+     * for rootDSE
+     */
+    @Test
+    public void testDecodeSearchRequestDIRSERVER_810()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x6B );
+        stream.put( new byte[]
+            { 0x30, ( byte ) 0x84, 0x00, 0x00, 0x00, 0x65, 0x02, 0x01, 0x03, 0x63, ( byte ) 0x84, 0x00, 0x00, 0x00,
+                0x5c, 0x04, 0x12, 0x6f, 0x75, 0x3d, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2c, 0x6f, 0x75, 0x3d, 0x73, 0x79,
+                0x73,
+                0x74,
+                0x65,
+                0x6d, // 'ou=users,ou=system'
+                0x0a,
+                0x01,
+                0x01,
+                0x0a,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x1e,
+                0x01,
+                0x01,
+                ( byte ) 0xff,
+                ( byte ) 0xa0,
+                ( byte ) 0x84,
+                0x00,
+                0x00,
+                0x00,
+                0x2d,
+                ( byte ) 0xa3,
+                ( byte ) 0x84,
+                0x00,
+                0x00,
+                0x00,
+                0x0e,
+                0x04,
+                0x03,
+                0x75,
+                0x69,
+                0x64,
+                0x04,
+                0x07,
+                0x62,
+                0x75,
+                0x73,
+                0x74,
+                0x65,
+                0x72,
+                0x20, // 'buster ' (with a space at the end)
+                ( byte ) 0xa3,
+                ( byte ) 0x84,
+                0x00,
+                0x00,
+                0x00,
+                0x13,
+                0x04,
+                0x0b,
+                0x73,
+                0x62,
+                0x41,
+                0x74,
+                0x74,
+                0x72,
+                0x69,
+                0x62,
+                0x75,
+                0x74,
+                0x65, // sbAttribute
+                0x04,
+                0x04,
+                0x42,
+                0x75,
+                0x79,
+                0x20, // 'Buy ' (with a space at the end)
+                0x30,
+                ( byte ) 0x84,
+                0x00,
+                0x00,
+                0x00,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 3, searchRequest.getMessageId() );
+        assertEquals( "ou=users,ou=system", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.ONELEVEL, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.NEVER_DEREF_ALIASES, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 30, searchRequest.getTimeLimit() );
+        assertEquals( true, searchRequest.getTypesOnly() );
+
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(uid=buster)...
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "uid", equalityNode.getAttribute() );
+        assertEquals( "buster ", equalityNode.getValue().getString() );
+
+        // (&(uid=buster)(sbAttribute=Buy))
+        equalityNode = ( EqualityNode<?> ) andNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "sbAttribute", equalityNode.getAttribute() );
+        assertEquals( "Buy ", equalityNode.getValue().getString() );
+
+        List<String> attributes = searchRequest.getAttributes();
+        assertEquals( 0, attributes.size() );
+    }
+
+
+    /**
+     * Test the decoding of a SearchRequest with a complex filter :
+     * (&(objectClass=person)(|(cn=Tori*)(sn=Jagger)))
+     */
+    @Test
+    public void testDecodeSearchRequestComplexFilterWithControl()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x77 );
+        stream.put( new byte[]
+            { 0x30, 0x75, // LdapMessage
+                0x02,
+                0x01,
+                0x06, // message Id = 6
+                0x63,
+                0x53, // SearchRequest
+                0x04,
+                0x09, // BaseDN 'ou=system'
+                0x6F,
+                0x75,
+                0x3D,
+                0x73,
+                0x79,
+                0x73,
+                0x74,
+                0x65,
+                0x6D,
+                0x0A,
+                0x01,
+                0x02, // scope = SUBTREE
+                0x0A,
+                0x01,
+                0x03, // derefAlias = 3
+                0x02,
+                0x01,
+                0x00, // sizeLimit = none
+                0x02,
+                0x01,
+                0x00, // timeLimit = none
+                0x01,
+                0x01,
+                0x00, // types only = false
+                ( byte ) 0xA0,
+                0x35, // AND
+                ( byte ) 0xA3,
+                0x15, // equals
+                0x04,
+                0x0B, // 'objectclass'
+                0x6F,
+                0x62,
+                0x6A,
+                0x65,
+                0x63,
+                0x74,
+                0x43,
+                0x6C,
+                0x61,
+                0x73,
+                0x73,
+                0x04,
+                0x06, // 'person' 
+                0x70,
+                0x65,
+                0x72,
+                0x73,
+                0x6F,
+                0x6E,
+                ( byte ) 0xA1,
+                0x1C, // OR
+                ( byte ) 0xA4,
+                0x0C, // substrings : 'cn=Tori*'
+                0x04,
+                0x02, // 'cn'
+                0x63,
+                0x6E,
+                0x30,
+                0x06, // initial = 'Tori'
+                ( byte ) 0x80,
+                0x04,
+                0x54,
+                0x6F,
+                0x72,
+                0x69,
+                ( byte ) 0xA3,
+                0x0C, // equals
+                0x04,
+                0x02, // 'sn'
+                0x73,
+                0x6E,
+                0x04,
+                0x06, // 'Jagger'
+                0x4A,
+                0x61,
+                0x67,
+                0x67,
+                0x65,
+                0x72,
+                0x30,
+                0x00, // Control
+                ( byte ) 0xA0,
+                0x1B,
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2'
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 6, searchRequest.getMessageId() );
+        assertEquals( "ou=system", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.SUBTREE, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.DEREF_ALWAYS, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        // (&(...
+        ExprNode filter = searchRequest.getFilter();
+
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(objectClass=person)..
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "objectClass", equalityNode.getAttribute() );
+        assertEquals( "person", equalityNode.getValue().getString() );
+
+        // (&(a=b)(|
+        OrNode orNode = ( OrNode ) andNodes.get( 1 );
+        assertNotNull( orNode );
+
+        List<ExprNode> orNodes = orNode.getChildren();
+        assertEquals( 2, orNodes.size() );
+
+        // (&(a=b)(|(cn=Tori*
+        SubstringNode substringNode = ( SubstringNode ) orNodes.get( 0 );
+        assertNotNull( substringNode );
+
+        assertEquals( "cn", substringNode.getAttribute() );
+        assertEquals( "Tori", substringNode.getInitial() );
+        assertEquals( 0, substringNode.getAny().size() );
+        assertEquals( null, substringNode.getFinal() );
+
+        // (&(a=b)(|(cn=Tori*)(sn=Jagger)))
+        equalityNode = ( EqualityNode<?> ) orNodes.get( 1 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "sn", equalityNode.getAttribute() );
+        assertEquals( "Jagger", equalityNode.getValue().getString() );
+    }
+
+
+    @Test
+    public void decodeComplexFilter()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x77 );
+        stream.put( new byte[]
+            {
+                0x30, 0x53,
+                0x02, 0x01, 0x02,
+                0x63, 0x4E,
+                0x04, 0x11,
+                'd', 'c', '=', 'e', 'x', 'a', 'm', 'p', 'l', 'e', ',', 'd', 'c', '=', 'c', 'o', 'm',
+                0x0A, 0x01, 0x02,
+                0x0A, 0x01, 0x00,
+                0x02, 0x01, 0x00,
+                0x02, 0x01, 0x00,
+                0x01, 0x01, 0x00,
+                ( byte ) 0xA0, 0x28,
+                ( byte ) 0xA1, 0x1F,
+                ( byte ) 0xA0, 0x1D,
+                ( byte ) 0xA3, 0x1B,
+                0x04, 0x0B,
+                'o', 'b', 'j', 'e', 'c', 't', 'c', 'l', 'a', 's', 's',
+                0x04, 0x0C,
+                'g', 'r', 'o', 'u', 'p', 'o', 'f', 'n', 'a', 'm', 'e', 's',
+                ( byte ) 0x87, 0x05,
+                'o', 'w', 'n', 'e', 'r',
+                0x30, 0x00
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchRequestDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchRequestDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        assertEquals( TLVStateEnum.PDU_DECODED, ldapMessageContainer.getState() );
+
+        SearchRequest searchRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 2, searchRequest.getMessageId() );
+        assertEquals( "dc=example,dc=com", searchRequest.getBase().toString() );
+        assertEquals( SearchScope.SUBTREE, searchRequest.getScope() );
+        assertEquals( AliasDerefMode.NEVER_DEREF_ALIASES, searchRequest.getDerefAliases() );
+        assertEquals( 0, searchRequest.getSizeLimit() );
+        assertEquals( 0, searchRequest.getTimeLimit() );
+        assertEquals( false, searchRequest.getTypesOnly() );
+
+        ExprNode filter = searchRequest.getFilter();
+
+        // (&(...
+        AndNode andNode = ( AndNode ) filter;
+        assertNotNull( andNode );
+
+        List<ExprNode> andNodes = andNode.getChildren();
+        assertEquals( 2, andNodes.size() );
+
+        // (&(|(...
+        filter = searchRequest.getFilter();
+
+        OrNode orNode = ( OrNode ) andNodes.get( 0 );
+        assertNotNull( orNode );
+
+        List<ExprNode> orNodes = orNode.getChildren();
+        assertEquals( 1, orNodes.size() );
+
+        // (&(|(&...
+        AndNode andNode2 = ( AndNode ) orNodes.get( 0 );
+        assertNotNull( andNode2 );
+
+        List<ExprNode> andNodes2 = andNode2.getChildren();
+        assertEquals( 1, andNodes2.size() );
+
+        // (&(|(&(objectClass=groupOfNames)
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) andNodes2.get( 0 );
+        assertNotNull( equalityNode );
+
+        assertEquals( "objectclass", equalityNode.getAttribute() );
+        assertEquals( "groupofnames", equalityNode.getValue().getString() );
+
+        // (&(|(&(objectClass=groupOfNames)))(owner=*))
+        PresenceNode presenceNode = ( PresenceNode ) andNodes.get( 1 );
+        assertNotNull( presenceNode );
+
+        assertEquals( "owner", presenceNode.getAttribute() );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultDoneTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultDoneTest.java
new file mode 100644
index 0000000..a6da968
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultDoneTest.java
@@ -0,0 +1,366 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultDoneDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the SearchResultDone codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResultDoneTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a SearchResultDone
+     */
+    @Test
+    public void testDecodeSearchResultDoneSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            { 0x30, 0x0C, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x65,
+                0x07, // CHOICE { ..., searchResDone SearchResultDone, ...
+                // SearchResultDone ::= [APPLICATION 5] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a SearchResultDone Container
+        LdapMessageContainer<SearchResultDoneDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultDoneDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultDone.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, searchResultDone.getLdapResult().getResultCode() );
+        assertEquals( "", searchResultDone.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", searchResultDone.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultDone );
+
+            // Check the length
+            assertEquals( 0x0E, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultDone with controls
+     */
+    @Test
+    public void testDecodeSearchResultDoneSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2B );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x29, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x65,
+                0x07, // CHOICE { ..., searchResDone SearchResultDone, ...
+                // SearchResultDone ::= [APPLICATION 5] LDAPResult
+                0x0A,
+                0x01,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00, // errorMessage LDAPString,
+                // referral [3] Referral OPTIONAL }
+                // }
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32
+
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultDoneDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultDoneDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultDone.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, searchResultDone.getLdapResult().getResultCode() );
+        assertEquals( "", searchResultDone.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", searchResultDone.getLdapResult().getDiagnosticMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = searchResultDone.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultDone );
+
+            // Check the length
+            assertEquals( 0x2B, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultDone with no LdapResult
+     */
+    @Test
+    public void testDecodeSearchResultDoneEmptyResult()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x65,
+                0x00 // CHOICE { ..., searchResDone SearchResultDone, ...
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchResultDoneDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultDoneDecorator>( codec );
+
+        // Decode a SearchResultDone message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultDone with a result code of length 2 bytes
+     */
+    @Test
+    public void testDecodeSearchResultDoneEsyncRefresh()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0F );
+
+        stream.put( new byte[]
+            { 0x30, 0x0D, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x65,
+                0x08, // CHOICE { ..., searchResDone SearchResultDone, ...
+                // SearchResultDone ::= [APPLICATION 5] LDAPResult
+                0x0A,
+                0x02,
+                0x10,
+                0x00, // LDAPResult ::= SEQUENCE {
+                // resultCode ENUMERATED {
+                // success (0), ...
+                // },
+                0x04,
+                0x00, // matchedDN LDAPDN,
+                0x04,
+                0x00 // errorMessage LDAPString,
+            // referral [3] Referral OPTIONAL }
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a SearchResultDone Container
+        LdapMessageContainer<SearchResultDoneDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultDoneDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultDone searchResultDone = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultDone.getMessageId() );
+        assertEquals( ResultCodeEnum.E_SYNC_REFRESH_REQUIRED, searchResultDone.getLdapResult().getResultCode() );
+        assertEquals( "", searchResultDone.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", searchResultDone.getLdapResult().getDiagnosticMessage() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultDone );
+
+            // Check the length
+            assertEquals( 0x0F, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultEntryTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultEntryTest.java
new file mode 100644
index 0000000..b6d35be
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultEntryTest.java
@@ -0,0 +1,1999 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import javax.naming.NamingException;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the SearchResultEntry codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResultEntryTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a SearchResultEntry
+     */
+    @Test
+    public void testDecodeSearchResultEntrySuccess() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x50 );
+
+        stream.put( new byte[]
+            {
+
+                0x30,
+                0x4e, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x49, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x2a,
+                0x30,
+                0x28,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // vals SET OF AttributeValue }
+                0x31,
+                0x19,
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x12,
+                'o',
+                'r',
+                'g',
+                'a',
+                'n',
+                'i',
+                'z',
+                'a',
+                't',
+                'i',
+                'o',
+                'n',
+                'a',
+                'l',
+                'U',
+                'n',
+                'i',
+                't' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        for ( int i = 0; i < entry.size(); i++ )
+        {
+            Attribute attribute = entry.get( "objectclass" );
+
+            assertEquals( Strings.toLowerCase( "objectClass" ), Strings.toLowerCase( attribute.getUpId() ) );
+
+            assertTrue( attribute.contains( "top" ) );
+            assertTrue( attribute.contains( "organizationalUnit" ) );
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x50, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry
+     */
+    @Test
+    public void testDecodeSearchResultEntry2AttrsSuccess() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x7b );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x79, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x74, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x55,
+                0x30,
+                0x28,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // vals SET OF AttributeValue }
+                0x31,
+                0x19,
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x12,
+                'o',
+                'r',
+                'g',
+                'a',
+                'n',
+                'i',
+                'z',
+                'a',
+                't',
+                'i',
+                'o',
+                'n',
+                'a',
+                'l',
+                'U',
+                'n',
+                'i',
+                't',
+                0x30,
+                0x29,
+                // type AttributeDescription,
+                0x04,
+                0x0c,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                '2',
+                // vals SET OF AttributeValue }
+                0x31,
+                0x19,
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x12,
+                'o',
+                'r',
+                'g',
+                'a',
+                'n',
+                'i',
+                'z',
+                'a',
+                't',
+                'i',
+                'o',
+                'n',
+                'a',
+                'l',
+                'U',
+                'n',
+                'i',
+                't' } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 2, entry.size() );
+
+        String[] expectedAttributes = new String[]
+            { "objectClass", "objectClass2" };
+
+        for ( int i = 0; i < expectedAttributes.length; i++ )
+        {
+            Attribute attribute = entry.get( expectedAttributes[i] );
+
+            assertEquals(
+                Strings.toLowerCase( expectedAttributes[i] ),
+                Strings.toLowerCase( attribute.getUpId() ) );
+
+            assertTrue( attribute.contains( "top" ) );
+            assertTrue( attribute.contains( "organizationalUnit" ) );
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x7B, bb.limit() );
+
+            // We can't compare the encodings, the order of the attributes has
+            // changed
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with more bytes to be decoded at
+     * the end
+     */
+    @Test
+    public void testDecodeSearchResultEntrySuccessWithFollowingMessage() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x66 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x5F, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x02, // messageID MessageID
+                0x64,
+                0x5A, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x13,
+                'u',
+                'i',
+                'd',
+                '=',
+                'a',
+                'd',
+                'm',
+                'i',
+                'n',
+                ',',
+                'o',
+                'u',
+                '=',
+                's',
+                'y',
+                's',
+                't',
+                'e',
+                'm',
+                // attributes PartialAttributeList }
+                0x30,
+                0x43, // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x41,
+                // type AttributeDescription,
+                0x04,
+                0x0B,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x31,
+                0x32, // vals
+                // SET
+                // OF
+                // AttributeValue
+                // }
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x0D,
+                'i',
+                'n',
+                'e',
+                't',
+                'O',
+                'r',
+                'g',
+                'P',
+                'e',
+                'r',
+                's',
+                'o',
+                'n',
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x14,
+                'o',
+                'r',
+                'g',
+                'a',
+                'n',
+                'i',
+                'z',
+                'a',
+                't',
+                'i',
+                'o',
+                'n',
+                'a',
+                'l',
+                'P',
+                'e',
+                'r',
+                's',
+                'o',
+                'n',
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x06,
+                'p',
+                'e',
+                'r',
+                's',
+                'o',
+                'n',
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x03,
+                't',
+                'o',
+                'p',
+                0x30,
+                0x45, // Start of the next
+                // message
+                0x02,
+                0x01,
+                0x02 // messageID MessageID ...
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 2, searchResultEntry.getMessageId() );
+        assertEquals( "uid=admin,ou=system", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        for ( int i = 0; i < entry.size(); i++ )
+        {
+            Attribute attribute = entry.get( "objectclass" );
+
+            assertEquals( Strings.toLowerCase( "objectClass" ), Strings.toLowerCase( attribute.getUpId() ) );
+
+            assertTrue( attribute.contains( "top" ) );
+            assertTrue( attribute.contains( "person" ) );
+            assertTrue( attribute.contains( "organizationalPerson" ) );
+            assertTrue( attribute.contains( "inetOrgPerson" ) );
+        }
+
+        // Check that the next bytes is the first of the next PDU
+        assertEquals( 0x30, stream.get( stream.position() ) );
+        assertEquals( 0x45, stream.get( stream.position() + 1 ) );
+        assertEquals( 0x02, stream.get( stream.position() + 2 ) );
+        assertEquals( 0x01, stream.get( stream.position() + 3 ) );
+        assertEquals( 0x02, stream.get( stream.position() + 4 ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x61, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            // We have to supress the last 5 chars from the decodedPDU, as they
+            // belongs to the next message.
+            assertEquals( encodedPdu, decodedPdu.substring( 0, 0x61 * 5 ) );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    // Defensive tests
+
+    /**
+     * Test the decoding of an empty SearchResultEntry
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmpty()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            {
+
+                0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x00 // CHOICE { ..., searchResEntry SearchResultEntry,
+            // ...
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of an SearchResultEntry with an empty object name
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyObjectName()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+
+        stream.put( new byte[]
+            { 0x30, 0x07, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x02, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x00
+
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of an SearchResultEntry with an object name alone
+     */
+    @Test
+    public void testDecodeSearchResultEntryObjectNameAlone()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x24 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x22, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x1D, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1B,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+
+        } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of an SearchResultEntry with an empty attributes
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyAttributes()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x26 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x24, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x1F, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1B,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 0, entry.size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x26, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of an SearchResultEntry with an empty attributes list
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyAttributeList()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x28 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x26, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x21, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1B,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x02,
+                0x30,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of an SearchResultEntry with an empty attributes list
+     * with controls
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyAttributeListWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x45 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x43, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x21, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1B,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x02,
+                0x30,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with an empty type
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyType()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x2A );
+
+        stream.put( new byte[]
+            {
+
+                0x30,
+                0x28, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x23, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x04,
+                0x30,
+                0x02,
+                // type AttributeDescription,
+                0x04,
+                0x00 } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with a type alone
+     */
+    @Test
+    public void testDecodeSearchResultEntryTypeAlone()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x35 );
+
+        stream.put( new byte[]
+            {
+
+                0x30,
+                0x33, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x2E, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x0F,
+                0x30,
+                0x0D,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's' } );
+
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with an empty vals
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyVals() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x37 );
+
+        stream.put( new byte[]
+            {
+
+                0x30,
+                0x35, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x30, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x11,
+                0x30,
+                0x0F,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x31,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        for ( int i = 0; i < entry.size(); i++ )
+        {
+            Attribute attribute = entry.get( "objectclass" );
+
+            assertEquals( Strings.toLowerCase( "objectClass" ), Strings.toLowerCase( attribute.getUpId() ) );
+            assertEquals( 0, attribute.size() );
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x37, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with two empty vals
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyVals2() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x48 );
+
+        stream.put( new byte[]
+            {
+
+                0x30,
+                0x46, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x41, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x22,
+                0x30,
+                0x0F,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x31,
+                0x00,
+                0x30,
+                0x0F,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                'z',
+                'z',
+                0x31,
+                0x00 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 2, entry.size() );
+
+        Attribute attribute = entry.get( "objectclass" );
+        assertEquals( Strings.toLowerCase( "objectClass" ), Strings.toLowerCase( attribute.getUpId() ) );
+        assertEquals( 0, attribute.size() );
+
+        attribute = entry.get( "objectclazz" );
+        assertEquals( Strings.toLowerCase( "objectClazz" ), Strings.toLowerCase( attribute.getUpId() ) );
+        assertEquals( 0, attribute.size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x48, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu.length(), decodedPdu.length() );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with an empty vals with controls
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyValsWithControls() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x54 );
+
+        stream.put( new byte[]
+            {
+
+                0x30,
+                0x52, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x30, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x11,
+                0x30,
+                0x0F,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                0x31,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A
+                // control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        for ( int i = 0; i < entry.size(); i++ )
+        {
+            Attribute attribute = entry.get( "objectclass" );
+
+            assertEquals( Strings.toLowerCase( "objectClass" ), Strings.toLowerCase( attribute.getUpId() ) );
+
+            assertEquals( 0, attribute.size() );
+        }
+
+        // Check the Control
+        Map<String, Control> controls = searchResultEntry.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x54, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with an empty attribute value
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyAttributeValue() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x39 );
+
+        stream.put( new byte[]
+            { 0x30,
+                0x37, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x32, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x13,
+                0x30,
+                0x11,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // vals SET OF AttributeValue }
+                0x31,
+                0x02,
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x00, } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        for ( int i = 0; i < entry.size(); i++ )
+        {
+            Attribute attribute = entry.get( "objectclass" );
+
+            assertEquals( Strings.toLowerCase( "objectClass" ), Strings.toLowerCase( attribute.getUpId() ) );
+
+            assertTrue( attribute.contains( "" ) );
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x39, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultEntry with an empty attribute value
+     * with controls
+     */
+    @Test
+    public void testDecodeSearchResultEntryEmptyAttributeValueWithControls() throws NamingException
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x56 );
+
+        stream.put( new byte[]
+            {
+                0x30,
+                0x54, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x64,
+                0x32, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                // SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
+                // objectName LDAPDN,
+                0x04,
+                0x1b,
+                'o',
+                'u',
+                '=',
+                'c',
+                'o',
+                'n',
+                't',
+                'a',
+                'c',
+                't',
+                's',
+                ',',
+                'd',
+                'c',
+                '=',
+                'i',
+                'k',
+                't',
+                'e',
+                'k',
+                ',',
+                'd',
+                'c',
+                '=',
+                'c',
+                'o',
+                'm',
+                // attributes PartialAttributeList }
+                // PartialAttributeList ::= SEQUENCE OF SEQUENCE {
+                0x30,
+                0x13,
+                0x30,
+                0x11,
+                // type AttributeDescription,
+                0x04,
+                0x0b,
+                'o',
+                'b',
+                'j',
+                'e',
+                'c',
+                't',
+                'c',
+                'l',
+                'a',
+                's',
+                's',
+                // vals SET OF AttributeValue }
+                0x31,
+                0x02,
+                // AttributeValue ::= OCTET STRING
+                0x04,
+                0x00,
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultEntryDecorator> ldapMessageContainer =
+            new LdapMessageContainer<SearchResultEntryDecorator>( codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultEntry searchResultEntry = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultEntry.getMessageId() );
+        assertEquals( "ou=contacts,dc=iktek,dc=com", searchResultEntry.getObjectName().toString() );
+
+        Entry entry = searchResultEntry.getEntry();
+
+        assertEquals( 1, entry.size() );
+
+        for ( int i = 0; i < entry.size(); i++ )
+        {
+            Attribute attribute = entry.get( "objectclass" );
+
+            assertEquals( Strings.toLowerCase( "objectClass" ), Strings.toLowerCase( attribute.getUpId() ) );
+
+            assertTrue( attribute.contains( "" ) );
+        }
+
+        // Check the Control
+        Map<String, Control> controls = searchResultEntry.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultEntry );
+
+            // Check the length
+            assertEquals( 0x56, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultReferenceTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultReferenceTest.java
new file mode 100644
index 0000000..e28f77e
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/search/SearchResultReferenceTest.java
@@ -0,0 +1,484 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.search;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.SearchResultReferenceDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.SearchResultReference;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the SearchResultReference codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResultReferenceTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a SearchResultReference
+     */
+    @Test
+    public void testDecodeSearchResultReferenceSuccess()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3d8 );
+
+        String[] ldapUrls = new String[]
+            { "ldap:///", "ldap://directory.apache.org:80/", "ldap://d-a.org:80/", "ldap://1.2.3.4/",
+                "ldap://1.2.3.4:80/", "ldap://1.1.1.100000.a/", "ldap://directory.apache.org:389/dc=example,dc=org/",
+                "ldap://directory.apache.org:389/dc=example", "ldap://directory.apache.org:389/dc=example%202,dc=org",
+                "ldap://directory.apache.org:389/dc=example,dc=org?ou",
+                "ldap://directory.apache.org:389/dc=example,dc=org?ou,objectclass,dc",
+                "ldap://directory.apache.org:389/dc=example,dc=org?ou,dc,ou",
+                "ldap:///o=University%20of%20Michigan,c=US",
+                "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US",
+                "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress",
+                "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)",
+                "ldap://ldap.itd.umich.edu/c=GB?objectClass?one", "ldap://ldap.question.com/o=Question%3f,c=US?mail",
+                "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)",
+                "ldap:///??sub??bindname=cn=Manager%2co=Foo", "ldap:///??sub??!bindname=cn=Manager%2co=Foo" };
+
+        stream.put( new byte[]
+            {
+
+                0x30, ( byte ) 0x82, 0x03, ( byte ) 0xd4, // LDAPMessage
+                // ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x73,
+                ( byte ) 0x82,
+                0x03,
+                ( byte ) 0xcd, // CHOICE { ...,
+            // searchResEntry
+            // SearchResultEntry,
+            // ...
+            // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+        } );
+
+        for ( int i = 0; i < ldapUrls.length; i++ )
+        {
+            stream.put( ( byte ) 0x04 );
+            stream.put( ( byte ) ldapUrls[i].getBytes().length );
+
+            byte[] bytes = Strings.getBytesUtf8( ldapUrls[i] );
+
+            for ( int j = 0; j < bytes.length; j++ )
+            {
+                stream.put( bytes[j] );
+            }
+        }
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultReferenceDecorator> ldapMessageContainer = new LdapMessageContainer<SearchResultReferenceDecorator>(
+            codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultReference.getMessageId() );
+
+        Set<String> ldapUrlsSet = new HashSet<String>();
+
+        for ( int i = 0; i < ldapUrls.length; i++ )
+        {
+            ldapUrlsSet.add( Strings.utf8ToString( ldapUrls[i].getBytes() ) );
+        }
+
+        Referral referral = searchResultReference.getReferral();
+
+        assertNotNull( referral );
+
+        for ( String ldapUrl : referral.getLdapUrls() )
+        {
+            if ( ldapUrlsSet.contains( ldapUrl ) )
+            {
+                ldapUrlsSet.remove( ldapUrl );
+            }
+            else
+            {
+                fail( ldapUrl.toString() + " is not present" );
+            }
+        }
+
+        assertTrue( ldapUrlsSet.size() == 0 );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultReference );
+
+            // Check the length
+            assertEquals( 0x3D8, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultReference with controls
+     */
+    @Test
+    public void testDecodeSearchResultReferenceSuccessWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x3F5 );
+
+        String[] ldapUrls = new String[]
+            { "ldap:///", "ldap://directory.apache.org:80/", "ldap://d-a.org:80/", "ldap://1.2.3.4/",
+                "ldap://1.2.3.4:80/", "ldap://1.1.1.100000.a/", "ldap://directory.apache.org:389/dc=example,dc=org/",
+                "ldap://directory.apache.org:389/dc=example", "ldap://directory.apache.org:389/dc=example%202,dc=org",
+                "ldap://directory.apache.org:389/dc=example,dc=org?ou",
+                "ldap://directory.apache.org:389/dc=example,dc=org?ou,objectclass,dc",
+                "ldap://directory.apache.org:389/dc=example,dc=org?ou,dc,ou",
+                "ldap:///o=University%20of%20Michigan,c=US",
+                "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US",
+                "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress",
+                "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)",
+                "ldap://ldap.itd.umich.edu/c=GB?objectClass?one", "ldap://ldap.question.com/o=Question%3f,c=US?mail",
+                "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)",
+                "ldap:///??sub??bindname=cn=Manager%2co=Foo", "ldap:///??sub??!bindname=cn=Manager%2co=Foo" };
+
+        stream.put( new byte[]
+            {
+
+                0x30, ( byte ) 0x82, 0x03, ( byte ) 0xF1, // LDAPMessage
+                // ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x73,
+                ( byte ) 0x82,
+                0x03,
+                ( byte ) 0xcd, // CHOICE { ...,
+            // searchResEntry
+            // SearchResultEntry,
+            // ...
+            // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+        } );
+
+        for ( int i = 0; i < ldapUrls.length; i++ )
+        {
+            stream.put( ( byte ) 0x04 );
+            stream.put( ( byte ) ldapUrls[i].getBytes().length );
+
+            byte[] bytes = ldapUrls[i].getBytes();
+
+            for ( int j = 0; j < bytes.length; j++ )
+            {
+                stream.put( bytes[j] );
+            }
+        }
+
+        byte[] controlBytes = new byte[]
+            { ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                0x32,
+                0x2E,
+                0x31,
+                0x36,
+                0x2E,
+                0x38,
+                0x34,
+                0x30,
+                0x2E,
+                0x31,
+                0x2E,
+                0x31,
+                0x31,
+                0x33,
+                0x37,
+                0x33,
+                0x30,
+                0x2E,
+                0x33,
+                0x2E,
+                0x34,
+                0x2E,
+                0x32 };
+
+        for ( int i = 0; i < controlBytes.length; i++ )
+        {
+            stream.put( controlBytes[i] );
+        }
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultReferenceDecorator> ldapMessageContainer = new LdapMessageContainer<SearchResultReferenceDecorator>(
+            codec );
+
+        try
+        {
+            ldapMessageContainer.clean();
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        stream.flip();
+
+        SearchResultReference searchResultReference = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultReference.getMessageId() );
+
+        Set<String> ldapUrlsSet = new HashSet<String>();
+
+        for ( int i = 0; i < ldapUrls.length; i++ )
+        {
+            ldapUrlsSet.add( Strings.utf8ToString( ldapUrls[i].getBytes() ) );
+        }
+
+        Referral referral = searchResultReference.getReferral();
+
+        assertNotNull( referral );
+
+        for ( String ldapUrl : referral.getLdapUrls() )
+        {
+            if ( ldapUrlsSet.contains( ldapUrl ) )
+            {
+                ldapUrlsSet.remove( ldapUrl );
+            }
+            else
+            {
+                fail( ldapUrl.toString() + " is not present" );
+            }
+        }
+
+        assertTrue( ldapUrlsSet.size() == 0 );
+
+        // Check the Control
+        Map<String, Control> controls = searchResultReference.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultReference );
+
+            // Check the length
+            assertEquals( 0x3F5, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultReference with no reference
+     */
+    @Test
+    public void testDecodeSearchResultReferenceNoReference()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+
+        stream.put( new byte[]
+            {
+
+                0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x73,
+                0x00 // CHOICE { ..., searchResEntry SearchResultEntry,
+            // ...
+            // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<SearchResultReferenceDecorator> ldapMessageContainer = new LdapMessageContainer<SearchResultReferenceDecorator>(
+            codec );
+
+        // Decode a SearchResultReference message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a SearchResultReference with one reference
+     */
+    @Test
+    public void testDecodeSearchResultReferenceOneReference()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x11 );
+
+        stream.put( new byte[]
+            {
+
+                0x30, 0x0F, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x73,
+                0x0A, // CHOICE { ..., searchResEntry SearchResultEntry,
+                // ...
+                0x04,
+                0x08,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                '/' // SearchResultReference
+            // ::=
+            // [APPLICATION
+            // 19]
+            // SEQUENCE
+            // OF
+            // LDAPURL
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<SearchResultReferenceDecorator> ldapMessageContainer = new LdapMessageContainer<SearchResultReferenceDecorator>(
+            codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        SearchResultReference searchResultReference = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, searchResultReference.getMessageId() );
+
+        Referral referral = searchResultReference.getReferral();
+
+        assertNotNull( referral );
+
+        for ( String ldapUrl : referral.getLdapUrls() )
+        {
+            assertEquals( "ldap:///", ldapUrl );
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( searchResultReference );
+
+            // Check the length
+            assertEquals( 0x11, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/unbind/UnBindRequestTest.java b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/unbind/UnBindRequestTest.java
new file mode 100644
index 0000000..3c36e67
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/java/org/apache/directory/api/ldap/codec/unbind/UnBindRequestTest.java
@@ -0,0 +1,262 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.unbind;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.api.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.UnbindRequest;
+import org.apache.directory.api.ldap.model.message.UnbindRequestImpl;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UnBindRequestTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a UnBindRequest with no controls
+     */
+    @Test
+    public void testDecodeUnBindRequestNoControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x07 );
+        stream.put( new byte[]
+            { 0x30, 0x05, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x42,
+                0x00, // CHOICE { ..., unbindRequest UnbindRequest,...
+            // UnbindRequest ::= [APPLICATION 2] NULL
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<UnbindRequestDecorator> ldapMessageContainer = new LdapMessageContainer<UnbindRequestDecorator>(
+            codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        UnbindRequest unbindRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, unbindRequest.getMessageId() );
+
+        // Check the encoding
+        UnbindRequest internalUnbindRequest = new UnbindRequestImpl();
+        internalUnbindRequest.setMessageId( unbindRequest.getMessageId() );
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalUnbindRequest );
+
+            // Check the length
+            assertEquals( 0x07, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a UnBindRequest with controls
+     */
+    @Test
+    public void testDecodeUnBindRequestWithControls()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x24 );
+        stream.put( new byte[]
+            { 0x30,
+                0x22, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x42,
+                0x00, // CHOICE { ..., unbindRequest UnbindRequest,...
+                // UnbindRequest ::= [APPLICATION 2] NULL
+                ( byte ) 0xA0,
+                0x1B, // A control
+                0x30,
+                0x19,
+                0x04,
+                0x17,
+                '2',
+                '.',
+                '1',
+                '6',
+                '.',
+                '8',
+                '4',
+                '0',
+                '.',
+                '1',
+                '.',
+                '1',
+                '1',
+                '3',
+                '7',
+                '3',
+                '0',
+                '.',
+                '3',
+                '.',
+                '4',
+                '.',
+                '2' } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a BindRequest Container
+        LdapMessageContainer<UnbindRequestDecorator> ldapMessageContainer = new LdapMessageContainer<UnbindRequestDecorator>(
+            codec );
+
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        UnbindRequest unbindRequest = ldapMessageContainer.getMessage();
+
+        assertEquals( 1, unbindRequest.getMessageId() );
+
+        // Check the Control
+        Map<String, Control> controls = unbindRequest.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = ( org.apache.directory.api.ldap.codec.api.CodecControl<Control> ) controls
+            .get( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "2.16.840.1.113730.3.4.2", control.getOid() );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) control.getValue() ) );
+
+        // Check the encoding
+        UnbindRequest internalUnbindRequest = new UnbindRequestImpl();
+        internalUnbindRequest.setMessageId( unbindRequest.getMessageId() );
+        internalUnbindRequest.addControl( control );
+
+        try
+        {
+            ByteBuffer bb = encoder.encodeMessage( internalUnbindRequest );
+
+            // Check the length
+            assertEquals( 0x24, bb.limit() );
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a UnBindRequest with a not null body
+     */
+    @Test
+    public void testDecodeUnBindRequestNotNull()
+    {
+        Asn1Decoder ldapDecoder = new Asn1Decoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+        stream.put( new byte[]
+            { 0x30, 0x07, // LDAPMessage ::=SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // messageID MessageID
+                0x42,
+                0x02, // CHOICE { ..., unbindRequest UnbindRequest,...
+                0x04,
+                0x00 // UnbindRequest ::= [APPLICATION 2] NULL
+
+        } );
+
+        stream.flip();
+
+        // Allocate a LdapMessage Container
+        LdapMessageContainer<UnbindRequestDecorator> ldapMessageContainer = new LdapMessageContainer<UnbindRequestDecorator>(
+            codec );
+
+        // Decode a UnbindRequest message
+        try
+        {
+            ldapDecoder.decode( stream, ldapMessageContainer );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/codec/core/src/test/resources/log4j.properties b/trunk/ldap/codec/core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/codec/core/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/codec/pom.xml b/trunk/ldap/codec/pom.xml
new file mode 100644
index 0000000..52b77cd
--- /dev/null
+++ b/trunk/ldap/codec/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-codec-parent</artifactId>
+  <name>Apache Directory LDAP API Codec Parent</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>core</module>
+    <module>standalone</module>
+  </modules>
+
+</project>
diff --git a/trunk/ldap/codec/src/site/site.xml b/trunk/ldap/codec/src/site/site.xml
new file mode 100644
index 0000000..b6ec180
--- /dev/null
+++ b/trunk/ldap/codec/src/site/site.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="modules" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/codec/standalone/pom.xml b/trunk/ldap/codec/standalone/pom.xml
new file mode 100644
index 0000000..625fa52
--- /dev/null
+++ b/trunk/ldap/codec/standalone/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-codec-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-codec-standalone</artifactId>
+  <name>Apache Directory LDAP API Codec Standalone</name>
+  <packaging>jar</packaging>
+  <description>
+    This module was created to fix issue DIRSHARED-91 where the embedded Felix
+    instance inside the default LdapCodecService implementation was making it 
+    very problematic to deploy the ldap-codec inside an RCP (OSGi) environment
+    and hence Apache Directory Studio could not use it.
+
+    This module is most likely temporary and will disappear once we are fully
+    OSGi enabled. This module is a plain old jar, not a bundle to avoid 
+    accidental reuse as an OSGi module because it contains the version of the
+    LdapCodecService that embeds Felix to make controls and extended ops 
+    pluggable in the codec.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-net-mina</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>org.apache.mina</groupId>
+      <artifactId>mina-core</artifactId>
+    </dependency>
+  </dependencies>
+  
+</project>
diff --git a/trunk/ldap/codec/standalone/src/checkstyle/suppressions.xml b/trunk/ldap/codec/standalone/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..74a4604
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/checkstyle/suppressions.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+</suppressions>
diff --git a/trunk/ldap/codec/standalone/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/codec/standalone/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/codec/standalone/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/codec/standalone/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/codec/standalone/src/main/java/org/apache/directory/api/ldap/codec/standalone/CodecFactoryUtil.java b/trunk/ldap/codec/standalone/src/main/java/org/apache/directory/api/ldap/codec/standalone/CodecFactoryUtil.java
new file mode 100644
index 0000000..e1c27a6
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/main/java/org/apache/directory/api/ldap/codec/standalone/CodecFactoryUtil.java
@@ -0,0 +1,201 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with apiService work for additional information
+ *   regarding copyright ownership.  The ASF licenses apiService file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use apiService 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.directory.api.ldap.codec.standalone;
+
+
+import java.util.Map;
+
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory;
+import org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
+import org.apache.directory.api.ldap.codec.controls.proxiedauthz.ProxiedAuthzFactory;
+import org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory;
+import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
+import org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
+import org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory;
+import org.apache.directory.api.ldap.codec.controls.sort.SortRequestFactory;
+import org.apache.directory.api.ldap.codec.controls.sort.SortResponseFactory;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSync;
+import org.apache.directory.api.ldap.extras.controls.ad_impl.AdDirSyncFactory;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncDoneValueFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncInfoValueFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncRequestValueFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncStateValueFactory;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewRequest;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResponse;
+import org.apache.directory.api.ldap.extras.controls.vlv_impl.VirtualListViewRequestFactory;
+import org.apache.directory.api.ldap.extras.controls.vlv_impl.VirtualListViewResponseFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration.CertGenerationFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown.GracefulShutdownFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.startTls.StartTlsFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI.WhoAmIFactory;
+import org.apache.directory.api.ldap.model.message.controls.Cascade;
+import org.apache.directory.api.ldap.model.message.controls.EntryChange;
+import org.apache.directory.api.ldap.model.message.controls.ManageDsaIT;
+import org.apache.directory.api.ldap.model.message.controls.PagedResults;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+import org.apache.directory.api.ldap.model.message.controls.ProxiedAuthz;
+import org.apache.directory.api.ldap.model.message.controls.SortRequest;
+import org.apache.directory.api.ldap.model.message.controls.SortResponse;
+import org.apache.directory.api.ldap.model.message.controls.Subentries;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A utility class for adding Codec and extended operation factories.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class CodecFactoryUtil
+{
+    private static final Logger LOG = LoggerFactory.getLogger( CodecFactoryUtil.class );
+
+
+    private CodecFactoryUtil()
+    {
+    }
+
+
+    /**
+     * Loads the Controls implement out of the box in the codec.
+     */
+    public static void loadStockControls( Map<String, ControlFactory<?>> controlFactories, LdapApiService apiService )
+    {
+        ControlFactory<Cascade> cascadeFactory = new CascadeFactory( apiService );
+        controlFactories.put( cascadeFactory.getOid(), cascadeFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", cascadeFactory.getOid() );
+
+        ControlFactory<EntryChange> entryChangeFactory = new EntryChangeFactory( apiService );
+        controlFactories.put( entryChangeFactory.getOid(), entryChangeFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", entryChangeFactory.getOid() );
+
+        ControlFactory<ManageDsaIT> manageDsaITFactory = new ManageDsaITFactory( apiService );
+        controlFactories.put( manageDsaITFactory.getOid(), manageDsaITFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", manageDsaITFactory.getOid() );
+
+        ControlFactory<ProxiedAuthz> proxiedAuthzFactory = new ProxiedAuthzFactory( apiService );
+        controlFactories.put( proxiedAuthzFactory.getOid(), proxiedAuthzFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", proxiedAuthzFactory.getOid() );
+
+        ControlFactory<PagedResults> pagedResultsFactory = new PagedResultsFactory( apiService );
+        controlFactories.put( pagedResultsFactory.getOid(), pagedResultsFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", pagedResultsFactory.getOid() );
+
+        ControlFactory<PersistentSearch> persistentSearchFactory = new PersistentSearchFactory( apiService );
+        controlFactories.put( persistentSearchFactory.getOid(), persistentSearchFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", persistentSearchFactory.getOid() );
+
+        ControlFactory<Subentries> subentriesFactory = new SubentriesFactory( apiService );
+        controlFactories.put( subentriesFactory.getOid(), subentriesFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", subentriesFactory.getOid() );
+
+        ControlFactory<PasswordPolicy> passwordPolicyFactory = new PasswordPolicyFactory( apiService );
+        controlFactories.put( passwordPolicyFactory.getOid(), passwordPolicyFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", passwordPolicyFactory.getOid() );
+
+        ControlFactory<VirtualListViewRequest> virtualListViewRequestFactory = new VirtualListViewRequestFactory(
+            apiService );
+        controlFactories.put( virtualListViewRequestFactory.getOid(), virtualListViewRequestFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", virtualListViewRequestFactory.getOid() );
+
+        ControlFactory<VirtualListViewResponse> virtualListViewResponseFactory = new VirtualListViewResponseFactory(
+            apiService );
+        controlFactories.put( virtualListViewResponseFactory.getOid(), virtualListViewResponseFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", virtualListViewResponseFactory.getOid() );
+
+        ControlFactory<SyncDoneValue> syncDoneValueFactory = new SyncDoneValueFactory( apiService );
+        controlFactories.put( syncDoneValueFactory.getOid(), syncDoneValueFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", syncDoneValueFactory.getOid() );
+
+        ControlFactory<SyncInfoValue> syncInfoValueFactory = new SyncInfoValueFactory( apiService );
+        controlFactories.put( syncInfoValueFactory.getOid(), syncInfoValueFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", syncInfoValueFactory.getOid() );
+
+        ControlFactory<SyncRequestValue> syncRequestValueFactory = new SyncRequestValueFactory( apiService );
+        controlFactories.put( syncRequestValueFactory.getOid(), syncRequestValueFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", syncRequestValueFactory.getOid() );
+
+        ControlFactory<SyncStateValue> syncStateValueFactory = new SyncStateValueFactory( apiService );
+        controlFactories.put( syncStateValueFactory.getOid(), syncStateValueFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", syncStateValueFactory.getOid() );
+
+        ControlFactory<SortRequest> sortRequestFactory = new SortRequestFactory( apiService );
+        controlFactories.put( sortRequestFactory.getOid(), sortRequestFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", sortRequestFactory.getOid() );
+
+        ControlFactory<SortResponse> sortResponseFactory = new SortResponseFactory( apiService );
+        controlFactories.put( sortResponseFactory.getOid(), sortResponseFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", sortResponseFactory.getOid() );
+
+        ControlFactory<AdDirSync> adDirSyncFactory = new AdDirSyncFactory( apiService );
+        controlFactories.put( adDirSyncFactory.getOid(), adDirSyncFactory );
+        LOG.info( "Registered pre-bundled control factory: {}", adDirSyncFactory.getOid() );
+    }
+
+
+    public static void loadStockExtendedOperations(
+        Map<String, ExtendedOperationFactory> extendendOperationsFactories, LdapApiService apiService )
+    {
+        CancelFactory cancelFactory = new CancelFactory( apiService );
+        extendendOperationsFactories.put( cancelFactory.getOid(), cancelFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", cancelFactory.getOid() );
+
+        CertGenerationFactory certGenerationFactory = new CertGenerationFactory( apiService );
+        extendendOperationsFactories.put( certGenerationFactory.getOid(), certGenerationFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", certGenerationFactory.getOid() );
+
+        GracefulShutdownFactory gracefulShutdownFactory = new GracefulShutdownFactory( apiService );
+        extendendOperationsFactories.put( gracefulShutdownFactory.getOid(), gracefulShutdownFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", gracefulShutdownFactory.getOid() );
+
+        StoredProcedureFactory storedProcedureFactory = new StoredProcedureFactory( apiService );
+        extendendOperationsFactories.put( storedProcedureFactory.getOid(), storedProcedureFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", storedProcedureFactory.getOid() );
+
+        GracefulDisconnectFactory gracefulDisconnectFactory = new GracefulDisconnectFactory( apiService );
+        extendendOperationsFactories.put( gracefulDisconnectFactory.getOid(), gracefulDisconnectFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", gracefulDisconnectFactory.getOid() );
+
+        PasswordModifyFactory passwordModifyFactory = new PasswordModifyFactory( apiService );
+        extendendOperationsFactories.put( passwordModifyFactory.getOid(), passwordModifyFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", passwordModifyFactory.getOid() );
+
+        WhoAmIFactory whoAmIFactory = new WhoAmIFactory( apiService );
+        extendendOperationsFactories.put( whoAmIFactory.getOid(), whoAmIFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", whoAmIFactory.getOid() );
+
+        StartTlsFactory startTlsFactory = new StartTlsFactory( apiService );
+        extendendOperationsFactories.put( startTlsFactory.getOid(), startTlsFactory );
+        LOG.info( "Registered pre-bundled extended operation factory: {}", startTlsFactory.getOid() );
+    }
+}
diff --git a/trunk/ldap/codec/standalone/src/main/java/org/apache/directory/api/ldap/codec/standalone/StandaloneLdapApiService.java b/trunk/ldap/codec/standalone/src/main/java/org/apache/directory/api/ldap/codec/standalone/StandaloneLdapApiService.java
new file mode 100644
index 0000000..23d40f8
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/main/java/org/apache/directory/api/ldap/codec/standalone/StandaloneLdapApiService.java
@@ -0,0 +1,346 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.standalone;
+
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.osgi.DefaultLdapCodecService;
+import org.apache.directory.api.util.Strings;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The default {@link org.apache.directory.api.ldap.codec.api.LdapApiService} implementation.
+ * It loads the Controls and ExtendedOperations as defined in the following system parameters :
+ * <li>Controls :
+ * <ul>
+ * <li>apacheds.controls</li> ok
+ * <li>default.controls</li>
+ * </ul>
+ * </li>
+ * <li>ExtendedOperations
+ * <ul>
+ * <li>apacheds.extendedOperations</li> ok
+ * <li>default.extendedOperation.responses</li>
+ * <li>extra.extendedOperations</ul>
+ * </ul>
+ * </li>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class StandaloneLdapApiService extends DefaultLdapCodecService
+{
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StandaloneLdapApiService.class );
+
+    /** The list of controls to load at startup */
+    public static final String CONTROLS_LIST = "apacheds.controls";
+
+    /** The list of extended operations to load at startup */
+    public static final String EXTENDED_OPERATIONS_LIST = "apacheds.extendedOperations";
+
+    /** The (old) list of default controls to load at startup */
+    private static final String OLD_DEFAULT_CONTROLS_LIST = "default.controls";
+
+    /** The (old) list of extra extended operations to load at startup */
+    private static final String OLD_EXTRA_EXTENDED_OPERATION_LIST = "extra.extendedOperations";
+
+
+    /**
+     * Creates a new instance of StandaloneLdapCodecService. Optionally checks for
+     * system property {@link #PLUGIN_DIRECTORY_PROPERTY}. 
+     * <br /><br />
+     * The following pom configuration is intended for use by unit test running 
+     * tools like Maven's surefire:
+     * <pre>
+     *   &lt;properties&gt;
+     *     &lt;codec.plugin.directory&gt;${project.build.directory}/pluginDirectory&lt;/codec.plugin.directory&gt;
+     *   &lt;/properties&gt;
+     * 
+     *   &lt;build&gt;
+     *     &lt;plugins&gt;
+     *       &lt;plugin&gt;
+     *         &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
+     *         &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
+     *         &lt;configuration&gt;
+     *           &lt;systemPropertyVariables&gt;
+     *             &lt;workingDirectory&gt;${basedir}/target&lt;/workingDirectory&gt;
+     *             &lt;felix.cache.rootdir&gt;
+     *               ${project.build.directory}
+     *             &lt;/felix.cache.rootdir&gt;
+     *             &lt;felix.cache.locking&gt;
+     *               true
+     *             &lt;/felix.cache.locking&gt;
+     *             &lt;org.osgi.framework.storage.clean&gt;
+     *               onFirstInit
+     *             &lt;/org.osgi.framework.storage.clean&gt;
+     *             &lt;org.osgi.framework.storage&gt;
+     *               osgi-cache
+     *             &lt;/org.osgi.framework.storage&gt;
+     *             &lt;codec.plugin.directory&gt;
+     *               ${codec.plugin.directory}
+     *             &lt;/codec.plugin.directory&gt;
+     *           &lt;/systemPropertyVariables&gt;
+     *         &lt;/configuration&gt;
+     *       &lt;/plugin&gt;
+     *       
+     *       &lt;plugin&gt;
+     *         &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
+     *         &lt;artifactId&gt;maven-dependency-plugin&lt;/artifactId&gt;
+     *         &lt;executions&gt;
+     *           &lt;execution&gt;
+     *             &lt;id&gt;copy&lt;/id&gt;
+     *             &lt;phase&gt;compile&lt;/phase&gt;
+     *             &lt;goals&gt;
+     *               &lt;goal&gt;copy&lt;/goal&gt;
+     *             &lt;/goals&gt;
+     *             &lt;configuration&gt;
+     *               &lt;artifactItems&gt;
+     *                 &lt;artifactItem&gt;
+     *                   &lt;groupId&gt;${project.groupId}&lt;/groupId&gt;
+     *                   &lt;artifactId&gt;api-ldap-extras-codec&lt;/artifactId&gt;
+     *                   &lt;version&gt;${project.version}&lt;/version&gt;
+     *                   &lt;outputDirectory&gt;${codec.plugin.directory}&lt;/outputDirectory&gt;
+     *                 &lt;/artifactItem&gt;
+     *               &lt;/artifactItems&gt;
+     *             &lt;/configuration&gt;
+     *           &lt;/execution&gt;
+     *         &lt;/executions&gt;
+     *       &lt;/plugin&gt;
+     *     &lt;/plugins&gt;
+     *   &lt;/build&gt;
+     * </pre>
+     */
+    public StandaloneLdapApiService() throws Exception
+    {
+        this( getControlsFromSystemProperties(), getExtendedOperationsFromSystemProperties() );
+    }
+
+
+    public StandaloneLdapApiService( List<String> controls, List<String> extendedOperations ) throws Exception
+    {
+        CodecFactoryUtil.loadStockControls( getControlFactories(), this );
+
+        CodecFactoryUtil.loadStockExtendedOperations( getExtendedOperationsFactories(), this );
+
+        // Load the controls
+        loadControls( controls );
+
+        // Load the extended operations
+        loadExtendedOperations( extendedOperations );
+
+        if ( getProtocolCodecFactory() == null )
+        {
+            try
+            {
+                @SuppressWarnings("unchecked")
+                Class<? extends ProtocolCodecFactory> clazz = ( Class<? extends ProtocolCodecFactory> )
+                    Class.forName( DEFAULT_PROTOCOL_CODEC_FACTORY );
+                Constructor<? extends ProtocolCodecFactory> constructor =
+                    clazz.getConstructor( LdapApiService.class );
+                if ( constructor != null )
+                {
+                    setProtocolCodecFactory( constructor.newInstance( this ) );
+                }
+                else
+                {
+                    setProtocolCodecFactory( clazz.newInstance() );
+                }
+            }
+            catch ( Exception cause )
+            {
+                throw new RuntimeException( "Failed to load default codec factory.", cause );
+            }
+        }
+    }
+
+
+    /**
+     * Parses the system properties to obtain the controls list.
+     * 
+     * @throws Exception
+     */
+    private static List<String> getControlsFromSystemProperties() throws Exception
+    {
+        List<String> controlsList = new ArrayList<String>();
+
+        // Loading controls list from command line properties if it exists
+        String controlsString = System.getProperty( CONTROLS_LIST );
+
+        if ( !Strings.isEmpty( controlsString ) )
+        {
+            for ( String control : controlsString.split( "," ) )
+            {
+                controlsList.add( control );
+            }
+        }
+        else
+        {
+            // Loading old default controls list from command line properties if it exists
+            String oldDefaultControlsString = System.getProperty( OLD_DEFAULT_CONTROLS_LIST );
+
+            if ( !Strings.isEmpty( oldDefaultControlsString ) )
+            {
+                for ( String control : oldDefaultControlsString.split( "," ) )
+                {
+                    controlsList.add( control );
+                }
+            }
+        }
+
+        return controlsList;
+    }
+
+
+    /**
+     * Parses the system properties to obtain the extended operations.
+     * Such extended operations are stored in the <b>apacheds.extendedOperations</b>
+     * and <b>default.extendedOperation.requests</b> system properties.
+     */
+    private static List<String> getExtendedOperationsFromSystemProperties() throws Exception
+    {
+        List<String> extendedOperationsList = new ArrayList<String>();
+
+        // Loading extended operations from command line properties if it exists
+        String defaultExtendedOperationsList = System.getProperty( EXTENDED_OPERATIONS_LIST );
+
+        if ( !Strings.isEmpty( defaultExtendedOperationsList ) )
+        {
+            for ( String extendedOperation : defaultExtendedOperationsList.split( "," ) )
+            {
+                extendedOperationsList.add( extendedOperation );
+            }
+        }
+        else
+        {
+            // Loading old extra extended operations list from command line properties if it exists
+            String oldDefaultControlsString = System.getProperty( OLD_EXTRA_EXTENDED_OPERATION_LIST );
+
+            if ( !Strings.isEmpty( oldDefaultControlsString ) )
+            {
+                for ( String extendedOperation : oldDefaultControlsString.split( "," ) )
+                {
+                    extendedOperationsList.add( extendedOperation );
+                }
+            }
+        }
+
+        return extendedOperationsList;
+    }
+
+
+    /**
+     * Loads a list of controls from their FQCN.
+     */
+    private void loadControls( List<String> controlsList ) throws Exception
+    {
+        // Adding all controls
+        if ( controlsList.size() > 0 )
+        {
+            for ( String controlFQCN : controlsList )
+            {
+                loadControl( controlFQCN );
+            }
+        }
+    }
+
+
+    /**
+     * Loads a control from its FQCN.
+     */
+    private void loadControl( String controlFQCN ) throws Exception
+    {
+        if ( getControlFactories().containsKey( controlFQCN ) )
+        {
+            LOG.debug( "Factory for control {} was already loaded", controlFQCN );
+            return;
+        }
+
+        Class<?>[] types = new Class<?>[]
+            { LdapApiService.class };
+        // note, trimming whitespace doesnt hurt as it is a class name and
+        // helps DI containers that use xml config as xml ignores whitespace
+        @SuppressWarnings("unchecked")
+        Class<? extends ControlFactory<?>> clazz = ( Class<? extends ControlFactory<?>> ) Class
+            .forName( controlFQCN.trim() );
+        Constructor<?> constructor = clazz.getConstructor( types );
+
+        ControlFactory<?> factory = ( ControlFactory<?> ) constructor.newInstance( new Object[]
+            { this } );
+        getControlFactories().put( factory.getOid(), factory );
+
+        LOG.info( "Registered control factory: {}", factory.getOid() );
+    }
+
+
+    /**
+     * Loads a list of extended operation from their FQCN
+     */
+    private void loadExtendedOperations( List<String> extendedOperationsList ) throws Exception
+    {
+        // Adding all extended operations
+        if ( extendedOperationsList.size() > 0 )
+        {
+            for ( String extendedOperationFQCN : extendedOperationsList )
+            {
+                loadExtendedOperation( extendedOperationFQCN );
+            }
+        }
+    }
+
+
+    /**
+     * Loads an of extended operations from its FQCN
+     */
+    private void loadExtendedOperation( String extendedOperationFQCN ) throws Exception
+    {
+        if ( getExtendedOperationsFactories().containsKey( extendedOperationFQCN ) )
+        {
+            LOG.debug( "Factory for extended operation {} was already loaded", extendedOperationFQCN );
+            return;
+        }
+
+        Class<?>[] types = new Class<?>[]
+            { LdapApiService.class };
+
+        // note, trimming whitespace doesn't hurt as it is a class name and
+        // helps DI containers that use xml config as xml ignores whitespace
+        @SuppressWarnings("unchecked")
+        Class<? extends ExtendedOperationFactory> clazz = ( Class<? extends ExtendedOperationFactory> ) Class
+            .forName( extendedOperationFQCN.trim() );
+        Constructor<?> constructor = clazz.getConstructor( types );
+
+        ExtendedOperationFactory factory = ( ExtendedOperationFactory ) constructor
+            .newInstance( new Object[]
+                { this } );
+        getExtendedOperationsFactories().put( factory.getOid(), factory );
+
+        LOG.info( "Registered pre-bundled extended operation factory: {}", factory.getOid() );
+    }
+}
diff --git a/trunk/ldap/codec/standalone/src/site/site.xml b/trunk/ldap/codec/standalone/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/codec/standalone/src/test/java/org/apache/directory/api/ldap/codec/standalone/AbstractCodecServiceTest.java b/trunk/ldap/codec/standalone/src/test/java/org/apache/directory/api/ldap/codec/standalone/AbstractCodecServiceTest.java
new file mode 100644
index 0000000..d9d0866
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/test/java/org/apache/directory/api/ldap/codec/standalone/AbstractCodecServiceTest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.standalone;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.api.LdapEncoder;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+
+/**
+ * Initialize the Codec service
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractCodecServiceTest
+{
+    /** The codec service */
+    protected static LdapApiService codec;
+
+    /** The encoder instance */
+    protected static LdapEncoder encoder;
+
+
+    /**
+     * Initialize the codec service
+     */
+    @BeforeClass
+    public static void setupLdapApiService() throws Exception
+    {
+        // Load the extension points
+        System.setProperty( StandaloneLdapApiService.CONTROLS_LIST,
+            "org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory," +
+                "org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory," +
+                "org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory," +
+                "org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory," +
+                "org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory," +
+                "org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory," +
+                "org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyFactory," +
+                "org.apache.directory.api.ldap.extras.controls.ppolicy_impl.VirtualListViewRequestFactory," +
+                "org.apache.directory.api.ldap.extras.controls.ppolicy_impl.VirtualListViewResponseFactory," +
+                "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncDoneValueFactory," +
+                "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncInfoValueFactory," +
+                "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncRequestValueFactory," +
+                "org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncStateValueFactory," +
+                "org.apache.directory.api.ldap.extras.controls.ad_impl.AdDirSyncFactory" );
+
+        System.setProperty( StandaloneLdapApiService.EXTENDED_OPERATIONS_LIST,
+            "org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelFactory," +
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration.CertGenerationFactory," +
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown.GracefulShutdownFactory," +
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureFactory," +
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyFactory," +
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectFactory" +
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI.WhoAmIFactory," +
+                "org.apache.directory.api.ldap.extras.extended.ads_impl.startTls.StartTlsFactory" );
+
+        codec = LdapApiServiceFactory.getSingleton();
+        encoder = new LdapEncoder( codec );
+    }
+
+
+    /**
+     * Shutdown the codec service
+     */
+    @AfterClass
+    public static void tearDownLdapCodecService()
+    {
+        codec = null;
+        encoder = null;
+    }
+}
diff --git a/trunk/ldap/codec/standalone/src/test/resources/log4j.properties b/trunk/ldap/codec/standalone/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/codec/standalone/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/extras/aci/pom.xml b/trunk/ldap/extras/aci/pom.xml
new file mode 100644
index 0000000..1029eab
--- /dev/null
+++ b/trunk/ldap/extras/aci/pom.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-extras-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-extras-aci</artifactId>
+  <name>Apache Directory LDAP API Extras ACI</name>
+  <packaging>bundle</packaging>
+  <description>Extra LDAP API for Access Control Items</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+
+  <!-- The original antlr artifact is needed by the antlr-maven-plugin which 
+    checks for its existence within the classpath. Use scope provided to avoid 
+    propagation to dependent projects. Choosen artifact is a valid OSGi bundle 
+    repackaged by ServiceMix team, kudos to them. -->
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.antlr</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>antlr-maven-plugin</artifactId>
+        <configuration>
+          <grammars>*.g</grammars>
+        </configuration>
+        <executions>
+           <execution>
+              <goals>
+                 <goal>generate</goal>
+              </goals>
+           </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.extras.aci</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.aci;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.aci.protectedItem;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              antlr;version=${antlr.version},
+              antlr.collections.impl;version=${antlr.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.model.constants;version=${project.version},
+              org.apache.directory.api.ldap.model.entry;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.filter;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.schema;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.normalizers;version=${project.version},
+              org.apache.directory.api.ldap.model.subtree;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion}
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/extras/aci/src/checkstyle/suppressions.xml b/trunk/ldap/extras/aci/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..2f315a0
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/checkstyle/suppressions.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <!-- UnixCrypt is from external, no formatting is applied -->
+    <suppress files="org.apache.directory.api.util.UnixCrypt" checks="[A-Za-z0-9]" />
+    
+    <!-- hashcode() is final in super class -->
+    <suppress files="org.apache.directory.api.ldap.model.schema.SyntaxChecker" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.Normalizer" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LoadableSchemaObject" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LdapComparator" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.DITStructureRule" checks="EqualsHashCode" />
+    
+    <!-- No Javadoc for schema constants required -->
+    <suppress files="org.apache.directory.api.ldap.model.constants.SchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.MetaSchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.PasswordPolicySchemaConstants" checks="JavadocVariable" />
+
+    <!-- Classes in org.apache.directory.api.asn1.der are forked from Bouncy Castle -->
+    <suppress files="org.apache.directory.api.asn1.der" checks="[A-Za-z0-9]" />
+
+    <!-- Exclude Antlr generated sources -->
+    <suppress files="[\\/]generated-sources[\\/]" checks="[a-zA-Z0-9]*"/>
+</suppressions>
diff --git a/trunk/ldap/extras/aci/src/main/antlr/ACIItem.g b/trunk/ldap/extras/aci/src/main/antlr/ACIItem.g
new file mode 100644
index 0000000..eeba915
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/antlr/ACIItem.g
@@ -0,0 +1,1580 @@
+header
+{
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Enumeration;
+
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.LeafNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.apache.directory.api.ldap.model.schema.normalizers.NameComponentNormalizer;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecificationModifier;
+import org.apache.directory.api.util.ComponentsMonitor;
+import org.apache.directory.api.util.MandatoryAndOptionalComponentsMonitor;
+import org.apache.directory.api.util.MandatoryComponentsMonitor;
+import org.apache.directory.api.ldap.model.name.DnUtils;
+import org.apache.directory.api.util.NoDuplicateKeysMap;
+import org.apache.directory.api.util.OptionalComponentsMonitor;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.aci.protectedItem.AllAttributeValuesItem;
+import org.apache.directory.api.ldap.aci.protectedItem.AttributeTypeItem;
+import org.apache.directory.api.ldap.aci.protectedItem.AttributeValueItem;
+import org.apache.directory.api.ldap.aci.protectedItem.SelfValueItem;
+import org.apache.directory.api.ldap.aci.protectedItem.ClassesItem;
+import org.apache.directory.api.ldap.aci.protectedItem.EntryItem;
+import org.apache.directory.api.ldap.aci.protectedItem.RangeOfValuesItem;
+import org.apache.directory.api.ldap.aci.protectedItem.MaxImmSubItem;
+import org.apache.directory.api.ldap.aci.protectedItem.MaxValueCountElem;
+import org.apache.directory.api.ldap.aci.protectedItem.MaxValueCountItem;
+import org.apache.directory.api.ldap.aci.protectedItem.RestrictedByElem;
+import org.apache.directory.api.ldap.aci.protectedItem.RestrictedByItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The antlr generated ACIItem parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrACIItemParser extends Parser;
+
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 1; // ;-)
+    defaultErrorHandler = false;
+}
+
+
+// ----------------------------------------------------------------------------
+// imaginary tokens
+// ----------------------------------------------------------------------------
+
+tokens
+{
+    ATTRIBUTE_VALUE_CANDIDATE;
+    RANGE_OF_VALUES_CANDIDATE;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser initialization
+// ----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrACIItemParser.class );
+    
+    NameComponentNormalizer normalizer;
+    
+    // nonshared global data needed to avoid extensive pass/return stuff
+    // these are only used by three first order components
+    private String identificationTag;
+    private AuthenticationLevel authenticationLevel;
+    private Integer aciPrecedence = null;
+    
+    private boolean isItemFirstACIItem;
+    
+    // shared global data needed to avoid extensive pass/return stuff
+    private Set<ProtectedItem> protectedItems;
+    private Map<String, ProtectedItem> protectedItemsMap;
+    private Set<UserClass> userClasses;
+    private Map<String, UserClass> userClassesMap;
+    private Set<ItemPermission> itemPermissions;
+    private Integer precedence = null;
+    private Set<GrantAndDenial> grantsAndDenials;
+    private Set<UserPermission> userPermissions;
+    
+    /** The SchemaManager */
+    private SchemaManager schemaManager;
+    
+    private Set<Dn> chopBeforeExclusions;
+    private Set<Dn> chopAfterExclusions;
+    private SubtreeSpecificationModifier ssModifier = null;
+    
+    private ComponentsMonitor mainACIItemComponentsMonitor;
+    private ComponentsMonitor itemPermissionComponentsMonitor;
+    private ComponentsMonitor userPermissionComponentsMonitor;
+    private ComponentsMonitor subtreeSpecificationComponentsMonitor;
+    
+    
+    /**
+     * Creates a (normalizing) subordinate DnParser for parsing Names.
+     * This method MUST be called for each instance while we cannot do
+     * constructor overloading for this class.
+     *
+     * @return the DnParser to be used for parsing Names
+     */
+    public void init( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+
+    /**
+     * Sets the NameComponentNormalizer for this parser's dnParser.
+     */
+    public void setNormalizer(NameComponentNormalizer normalizer)
+    {
+        this.normalizer = normalizer;
+    }
+
+    private int token2Integer( Token token ) throws RecognitionException
+    {
+        int i = 0;
+        
+        try
+        {
+            i = Integer.parseInt( token.getText());
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new RecognitionException( "Value of INTEGER token " +
+                                            token.getText() +
+                                            " cannot be converted to an Integer" );
+        }
+        
+        return i;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// parser productions
+// ----------------------------------------------------------------------------
+
+wrapperEntryPoint returns [ ACIItem aciItem ]
+{
+    log.debug( "entered wrapperEntryPoint()" );
+    aciItem = null;
+}
+    :
+    ( SP )* aciItem = theACIItem ( SP )* EOF
+    ;
+
+theACIItem returns [ ACIItem aciItem ]
+{
+    log.debug( "entered theACIItem()" );
+    aciItem = null;
+    mainACIItemComponentsMonitor = new MandatoryComponentsMonitor( 
+            new String [] { "identificationTag", "precedence", "authenticationLevel", "itemOrUserFirst" } );
+}
+    :
+    OPEN_CURLY
+        ( SP )* mainACIItemComponent ( SP )*
+            ( SEP ( SP )* mainACIItemComponent ( SP )* )*
+    CLOSE_CURLY
+    {
+        if ( !mainACIItemComponentsMonitor.finalStateValid() )
+        {
+            throw new RecognitionException( "Missing mandatory ACIItem components: " 
+                    + mainACIItemComponentsMonitor.getRemainingComponents() );
+        }
+        
+        if ( isItemFirstACIItem )
+        {
+            aciItem = new ItemFirstACIItem(
+                    identificationTag,
+                    aciPrecedence,
+                    authenticationLevel,
+                    protectedItems,
+                    itemPermissions );
+        }
+        else
+        {
+            aciItem = new UserFirstACIItem(
+                    identificationTag,
+                    aciPrecedence,
+                    authenticationLevel,
+                    userClasses,
+                    userPermissions );
+        }
+    }
+    ;
+    
+mainACIItemComponent
+{
+    log.debug( "entered mainACIItemComponent()" );
+}
+    :
+    aci_identificationTag
+    {
+        mainACIItemComponentsMonitor.useComponent( "identificationTag" );
+    }
+    | aci_precedence
+    {
+        mainACIItemComponentsMonitor.useComponent( "precedence" );
+    }
+    | aci_authenticationLevel
+    {
+        mainACIItemComponentsMonitor.useComponent( "authenticationLevel" );
+    }
+    | aci_itemOrUserFirst
+    {
+        mainACIItemComponentsMonitor.useComponent( "itemOrUserFirst" );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( e.getMessage() );
+    }
+    
+aci_identificationTag
+{
+    log.debug( "entered aci_identificationTag()" );
+}
+    :
+    ID_identificationTag ( SP )+ token:SAFEUTF8STRING
+    {
+        identificationTag = token.getText();
+    }
+    ;
+
+aci_precedence
+{
+    log.debug( "entered aci_precedence()" );
+}
+    :
+    precedence
+    {
+        aciPrecedence = Integer.valueOf( precedence );
+        precedence = null;
+    }
+    ;
+
+precedence
+{
+    log.debug( "entered precedence()" );
+}
+    :
+    ID_precedence ( SP )+ token:INTEGER
+    {
+        precedence = Integer.valueOf( token2Integer( token ) );
+        
+        if ( ( precedence < 0 ) || ( precedence > 255 ) )
+        {
+            throw new RecognitionException( "Expecting INTEGER token having an Integer value between 0 and 255, found " + precedence );
+        }
+    }
+    ;
+
+aci_authenticationLevel
+{
+    log.debug( "entered aci_authenticationLevel()" );
+}
+    :
+    ID_authenticationLevel ( SP )+ authenticationLevel
+    ;
+
+authenticationLevel
+{
+    log.debug( "entered authenticationLevel()" );
+}
+    :
+    ID_none
+    {
+        authenticationLevel = AuthenticationLevel.NONE;
+    }
+    |
+    ID_simple
+    {
+        authenticationLevel = AuthenticationLevel.SIMPLE;
+    }
+    |
+    ID_strong
+    {
+        authenticationLevel = AuthenticationLevel.STRONG;
+    }
+    ;
+
+aci_itemOrUserFirst
+{
+    log.debug( "entered aci_itemOrUserFirst()" );
+}
+    :
+    ID_itemOrUserFirst ( SP )+ itemOrUserFirst
+    ;
+
+itemOrUserFirst
+{
+    log.debug( "entered itemOrUserFirst()" );
+}
+    :
+    itemFirst | userFirst
+    ;
+
+itemFirst
+{
+    log.debug( "entered itemFirst()" );
+}
+    :
+    ID_itemFirst ( SP )* COLON ( SP )*
+        OPEN_CURLY ( SP )*
+          protectedItems ( SP )* SEP ( SP )* itemPermissions
+        ( SP )* CLOSE_CURLY
+    {
+        isItemFirstACIItem = true;
+    }
+    ;
+
+userFirst
+{
+    log.debug( "entered userFirst()" );
+}
+    :
+    ID_userFirst ( SP )* COLON ( SP )*
+        OPEN_CURLY ( SP )*
+              userClasses ( SP )* SEP ( SP )* userPermissions
+        ( SP )* CLOSE_CURLY
+    {
+        isItemFirstACIItem = false;
+    }
+    ;
+
+protectedItems
+{
+    log.debug( "entered protectedItems()" );
+    protectedItemsMap = new NoDuplicateKeysMap();
+}
+    :
+    ID_protectedItems ( SP )*
+        OPEN_CURLY ( SP )*
+            (
+                protectedItem ( SP )*
+                    ( SEP ( SP )* protectedItem ( SP )* )*
+            )?
+        CLOSE_CURLY
+    {
+        protectedItems = new HashSet<ProtectedItem>( protectedItemsMap.values() );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( "Protected Items cannot be duplicated. " + e.getMessage() );
+    }
+
+protectedItem
+{
+    log.debug( "entered protectedItem()" );
+}
+    :
+    entry
+    | allUserAttributeTypes
+    | attributeType
+    | allAttributeValues 
+    | allUserAttributeTypesAndValues
+    | attributeValue
+    | selfValue
+    | rangeOfValues
+    | maxValueCount
+    | maxImmSub
+    | restrictedBy
+    | classes
+    ;
+
+entry
+{
+    log.debug( "entered entry()" );  
+}
+    :
+    ID_entry
+    {
+        protectedItemsMap.put( "entry", ProtectedItem.ENTRY );
+    }
+    ;
+
+allUserAttributeTypes
+{
+    log.debug( "entered allUserAttributeTypes()" );
+}
+    :
+    ID_allUserAttributeTypes
+    {
+        protectedItemsMap.put( "allUserAttributeTypes", ProtectedItem.ALL_USER_ATTRIBUTE_TYPES );
+    }
+    ;
+
+attributeType
+{
+    log.debug( "entered attributeType()" );
+    Set<AttributeType> attributeTypeSet = null;
+}
+    :
+    ID_attributeType ( SP )+ attributeTypeSet=attributeTypeSet
+    {
+        protectedItemsMap.put( "attributeType", new AttributeTypeItem(attributeTypeSet ) );
+    }
+    ;
+
+allAttributeValues
+{
+    log.debug( "entered allAttributeValues()" );
+    Set<AttributeType> attributeTypeSet = null;
+}
+    :
+    ID_allAttributeValues ( SP )+ attributeTypeSet=attributeTypeSet
+    {
+        protectedItemsMap.put( "allAttributeValues", new AllAttributeValuesItem( attributeTypeSet ) );
+    }
+    ;
+
+allUserAttributeTypesAndValues
+{
+    log.debug( "entered allUserAttributeTypesAndValues()" );
+}
+    :
+    ID_allUserAttributeTypesAndValues
+    {
+        protectedItemsMap.put( "allUserAttributeTypesAndValues", ProtectedItem.ALL_USER_ATTRIBUTE_TYPES_AND_VALUES );
+    }
+    ;
+
+attributeValue
+{
+    log.debug( "entered attributeValue()" );
+    String attributeTypeAndValue = null;
+    String attributeType = null;
+    String attributeValue = null;
+    Set<Attribute> attributeSet = new HashSet<Attribute>();
+}
+    :
+    token:ATTRIBUTE_VALUE_CANDIDATE // ate the identifier for subordinate dn parser workaround
+    {
+        // A Dn can be considered as a set of attributeTypeAndValues
+        // So, parse the set as a Dn and extract each attributeTypeAndValue
+        Dn attributeTypeAndValueSetAsDn = new Dn( token.getText() );
+        
+        if ( schemaManager != null )
+        {        
+          attributeTypeAndValueSetAsDn.apply( schemaManager );
+        }
+        
+        for ( Rdn rdn : attributeTypeAndValueSetAsDn )
+        {
+            attributeTypeAndValue = rdn.getNormName();
+            attributeType = DnUtils.getRdnAttributeType( attributeTypeAndValue );
+            attributeValue = DnUtils.getRdnValue( attributeTypeAndValue );
+            
+            attributeSet.add( new DefaultAttribute( attributeType, attributeValue ) );
+            log.debug( "An attributeTypeAndValue from the set: " + attributeType + "=" +  attributeValue);
+        }
+        
+        protectedItemsMap.put( "attributeValue", new AttributeValueItem( attributeSet ) );
+    }
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "dnParser failed for " + token.getText() + " , " + e.getMessage() );
+    }
+
+selfValue
+{
+    log.debug( "entered selfValue()" );
+    Set<AttributeType> attributeTypeSet = null;
+}
+    :
+    ID_selfValue ( SP )+ attributeTypeSet=attributeTypeSet
+    {
+        protectedItemsMap.put( "sefValue", new SelfValueItem( attributeTypeSet ) );
+    }
+    ;
+
+rangeOfValues
+{
+    log.debug( "entered rangeOfValues()" );
+}
+    :
+    token:RANGE_OF_VALUES_CANDIDATE
+    {
+        protectedItemsMap.put( "rangeOfValues",
+                new RangeOfValuesItem(
+                        FilterParser.parse( token.getText() ) ) );
+        log.debug( "filterParser parsed " + token.getText() );
+    }
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "filterParser failed. " + e.getMessage() );
+    }   
+
+maxValueCount
+{
+    log.debug( "entered maxValueCount()" );
+    MaxValueCountElem maxValueCount = null;
+    Set<MaxValueCountElem> maxValueCountSet = new HashSet<MaxValueCountElem>();
+}
+    :
+    ID_maxValueCount ( SP )+
+    OPEN_CURLY ( SP )*
+        maxValueCount=aMaxValueCount ( SP )*
+        {
+            maxValueCountSet.add( maxValueCount );
+        }
+            ( SEP ( SP )* maxValueCount=aMaxValueCount ( SP )*
+            {
+                maxValueCountSet.add( maxValueCount );
+            }
+            )*
+    CLOSE_CURLY
+    {
+        protectedItemsMap.put( "maxValueCount", new MaxValueCountItem( maxValueCountSet ) );
+    }
+    ;
+
+aMaxValueCount returns [ MaxValueCountElem maxValueCount ]
+{
+    log.debug( "entered aMaxValueCount()" );
+    maxValueCount = null;
+    String oid = null;
+    Token token = null;
+    AttributeType attributeType = null;
+}
+    :
+    OPEN_CURLY ( SP )*
+        (
+          ID_type ( SP )+ oid=oid ( SP )* SEP ( SP )*
+          ID_maxCount ( SP )+ token1:INTEGER
+          { token = token1; }
+        | // relaxing
+          ID_maxCount ( SP )+ token2:INTEGER ( SP )* SEP ( SP )*
+          ID_type ( SP )+ oid=oid
+          { token = token2; }
+        )
+    ( SP )* CLOSE_CURLY
+    {
+        try
+        {
+            if ( schemaManager != null )
+            {
+                attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
+            }
+            else
+            {
+                attributeType = new AttributeType( oid );
+            }
+
+            maxValueCount = new MaxValueCountElem( attributeType, token2Integer( token ) );
+        }
+        catch ( LdapException le )
+        {
+              // The oid does not exist
+              // TODO : deal with such an exception
+        }
+    }
+    ;
+
+maxImmSub
+{
+    log.debug( "entered maxImmSub()" );
+}
+    :
+    ID_maxImmSub ( SP )+ token:INTEGER
+    {
+        
+        protectedItemsMap.put( "maxImmSub",
+                new MaxImmSubItem(
+                        token2Integer( token ) ) );
+    }
+    ;
+
+restrictedBy
+{
+    log.debug( "entered restrictedBy()" );
+    RestrictedByElem restrictedValue = null;
+    Set<RestrictedByElem> restrictedBy = new HashSet<RestrictedByElem>();
+}
+    :
+    ID_restrictedBy ( SP )+
+        OPEN_CURLY ( SP )*
+            restrictedValue=restrictedValue ( SP )*
+            {
+                restrictedBy.add( restrictedValue );
+            }
+                    ( SEP ( SP )* restrictedValue=restrictedValue ( SP )*
+                    {
+                        restrictedBy.add( restrictedValue );
+                    }
+                    )*
+        CLOSE_CURLY
+    {
+        protectedItemsMap.put( "restrictedBy", new RestrictedByItem( restrictedBy ) );
+    }
+    ;
+
+restrictedValue returns [ RestrictedByElem restrictedValue ]
+{
+    log.debug( "entered restrictedValue()" );
+    String typeOid = null;
+    String valuesInOid = null;
+    restrictedValue = null;
+    AttributeType attributeType = null;
+    AttributeType valueInAttributeType = null;
+}
+    :
+    OPEN_CURLY ( SP )*
+        (
+          ID_type ( SP )+ typeOid=oid ( SP )* SEP ( SP )*
+          ID_valuesIn ( SP )+ valuesInOid=oid
+        | // relaxing
+          ID_valuesIn ( SP )+ valuesInOid=oid ( SP )* SEP ( SP )*
+          ID_type ( SP )+ typeOid=oid
+        )
+    ( SP )* CLOSE_CURLY
+    {
+        try
+        {
+            if ( schemaManager != null )
+            {
+                attributeType = schemaManager.lookupAttributeTypeRegistry( typeOid );
+                valueInAttributeType = schemaManager.lookupAttributeTypeRegistry( valuesInOid );
+            }
+            else
+            {
+                attributeType = new AttributeType( typeOid );
+                valueInAttributeType = new AttributeType( valuesInOid );
+            }
+            
+            restrictedValue = new RestrictedByElem( attributeType, valueInAttributeType );
+        }
+        catch ( LdapException le )
+        {
+              // The oid does not exist
+              // TODO : deal with such an exception
+        }
+    }
+    ;
+
+attributeTypeSet returns [ Set<AttributeType> attributeTypeSet ]
+{
+    log.debug( "entered attributeTypeSet()" );
+    String oid = null;
+    attributeTypeSet = new HashSet<AttributeType>();
+    AttributeType attributeType = null;
+}
+    :
+    OPEN_CURLY ( SP )*
+        oid=oid ( SP )*
+        {
+            try
+            {
+                if ( schemaManager != null )
+                {
+                    attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
+                }
+                else
+                {
+                    attributeType = new AttributeType( oid );
+                }
+                
+                attributeTypeSet.add( attributeType );
+            }
+            catch ( LdapException le )
+            {
+                // The oid does not exist
+                // TODO : deal with such an exception
+            }
+        }
+            ( SEP ( SP )* oid=oid ( SP )*
+            {
+                try
+                {
+                    if ( schemaManager != null )
+                    {
+                        attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
+                    }
+                    else
+                    {
+                        attributeType = new AttributeType( oid );
+                    }
+
+                    attributeTypeSet.add( attributeType );
+                }
+                catch ( LdapException le )
+                {
+                    // The oid does not exist
+                    // TODO : deal with such an exception
+                }
+            }
+            )*
+    CLOSE_CURLY
+    ;
+
+classes
+{
+    log.debug( "entered classes()" );
+    ExprNode classes = null;
+}
+    :
+    ID_classes ( SP )+ classes=refinement
+    {
+        protectedItemsMap.put( "classes", new ClassesItem( classes ) );
+    }
+    ;
+
+itemPermissions
+{
+    log.debug( "entered itemPermissions()" );
+    itemPermissions = new HashSet<ItemPermission>();
+    ItemPermission itemPermission = null;
+}
+    :
+    ID_itemPermissions ( SP )+
+        OPEN_CURLY ( SP )*
+            ( itemPermission=itemPermission ( SP )*
+              {
+                  itemPermissions.add( itemPermission );
+              }
+                ( SEP ( SP )* itemPermission=itemPermission ( SP )*
+                  {
+                      itemPermissions.add( itemPermission );
+                  }
+                )*
+            )?
+        CLOSE_CURLY
+    ;
+
+itemPermission returns [ ItemPermission itemPermission ]
+{
+    log.debug( "entered itemPermission()" );
+    itemPermission = null;
+    itemPermissionComponentsMonitor = new MandatoryAndOptionalComponentsMonitor( 
+            new String [] { "userClasses", "grantsAndDenials" }, new String [] { "precedence" } );
+}
+    :
+    OPEN_CURLY ( SP )*
+        anyItemPermission ( SP )*
+            ( SEP ( SP )* anyItemPermission ( SP )* )*
+    CLOSE_CURLY
+    {
+        if ( !itemPermissionComponentsMonitor.finalStateValid() )
+        {
+            throw new RecognitionException( "Missing mandatory itemPermission components: " 
+                    + itemPermissionComponentsMonitor.getRemainingComponents() );
+        }
+        
+        itemPermission = new ItemPermission( precedence, grantsAndDenials, userClasses );
+        precedence = null;
+    }
+    ;
+
+anyItemPermission
+    :
+    precedence
+    {
+        itemPermissionComponentsMonitor.useComponent( "precedence" );
+    }
+    | userClasses
+    {
+        itemPermissionComponentsMonitor.useComponent( "userClasses" );
+    }
+    | grantsAndDenials
+    {
+        itemPermissionComponentsMonitor.useComponent( "grantsAndDenials" );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( e.getMessage() );
+    }
+
+grantsAndDenials
+{
+    log.debug( "entered grantsAndDenials()" );
+    grantsAndDenials = new HashSet<GrantAndDenial>();
+    GrantAndDenial grantAndDenial = null;
+}
+    :
+    ID_grantsAndDenials ( SP )+
+    OPEN_CURLY ( SP )*
+        ( grantAndDenial = grantAndDenial ( SP )*
+          {
+              if ( !grantsAndDenials.add( grantAndDenial ))
+              {
+                  throw new RecognitionException( "Duplicated GrantAndDenial bit: " + grantAndDenial );
+              }
+          }
+            ( SEP ( SP )* grantAndDenial = grantAndDenial ( SP )*
+              {
+                  if ( !grantsAndDenials.add( grantAndDenial ))
+                  {
+                      throw new RecognitionException( "Duplicated GrantAndDenial bit: " + grantAndDenial );
+                  }
+              }
+            )*
+        )?
+    CLOSE_CURLY
+    ;
+
+grantAndDenial returns [ GrantAndDenial l_grantAndDenial ]
+{
+    log.debug( "entered grantAndDenialsBit()" );
+    l_grantAndDenial = null;
+}
+    :
+    ID_grantAdd { l_grantAndDenial = GrantAndDenial.GRANT_ADD; }
+    | ID_denyAdd { l_grantAndDenial = GrantAndDenial.DENY_ADD; }
+    | ID_grantDiscloseOnError { l_grantAndDenial = GrantAndDenial.GRANT_DISCLOSE_ON_ERROR; }
+    | ID_denyDiscloseOnError { l_grantAndDenial = GrantAndDenial.DENY_DISCLOSE_ON_ERROR; }
+    | ID_grantRead { l_grantAndDenial = GrantAndDenial.GRANT_READ; }
+    | ID_denyRead { l_grantAndDenial = GrantAndDenial.DENY_READ; }
+    | ID_grantRemove { l_grantAndDenial = GrantAndDenial.GRANT_REMOVE; }
+    | ID_denyRemove { l_grantAndDenial = GrantAndDenial.DENY_REMOVE; }
+    //-- permissions that may be used only in conjunction
+    //-- with the entry component
+    | ID_grantBrowse { l_grantAndDenial = GrantAndDenial.GRANT_BROWSE; }
+    | ID_denyBrowse { l_grantAndDenial = GrantAndDenial.DENY_BROWSE; }
+    | ID_grantExport { l_grantAndDenial = GrantAndDenial.GRANT_EXPORT; }
+    | ID_denyExport { l_grantAndDenial = GrantAndDenial.DENY_EXPORT; }
+    | ID_grantImport { l_grantAndDenial = GrantAndDenial.GRANT_IMPORT; }
+    | ID_denyImport { l_grantAndDenial = GrantAndDenial.DENY_IMPORT; }
+    | ID_grantModify { l_grantAndDenial = GrantAndDenial.GRANT_MODIFY; }
+    | ID_denyModify { l_grantAndDenial = GrantAndDenial.DENY_MODIFY; }
+    | ID_grantRename { l_grantAndDenial = GrantAndDenial.GRANT_RENAME; }
+    | ID_denyRename { l_grantAndDenial = GrantAndDenial.DENY_RENAME; }
+    | ID_grantReturnDN { l_grantAndDenial = GrantAndDenial.GRANT_RETURN_DN; }
+    | ID_denyReturnDN { l_grantAndDenial = GrantAndDenial.DENY_RETURN_DN; }
+    //-- permissions that may be used in conjunction
+    //-- with any component, except entry, of ProtectedItems
+    | ID_grantCompare { l_grantAndDenial = GrantAndDenial.GRANT_COMPARE; }
+    | ID_denyCompare { l_grantAndDenial = GrantAndDenial.DENY_COMPARE; }
+    | ID_grantFilterMatch { l_grantAndDenial = GrantAndDenial.GRANT_FILTER_MATCH; }
+    | ID_denyFilterMatch { l_grantAndDenial = GrantAndDenial.DENY_FILTER_MATCH; }
+    | ID_grantInvoke { l_grantAndDenial = GrantAndDenial.GRANT_INVOKE; }
+    | ID_denyInvoke { l_grantAndDenial = GrantAndDenial.DENY_INVOKE; }
+    ;
+
+userClasses
+{
+    log.debug( "entered userClasses()" );
+    userClassesMap = new NoDuplicateKeysMap();
+}
+    :
+    ID_userClasses ( SP )+
+    OPEN_CURLY ( SP )*
+        (
+            userClass ( SP )*
+                ( SEP ( SP )* userClass ( SP )* )*
+        )?
+    CLOSE_CURLY
+    {
+        userClasses  = new HashSet<UserClass>( userClassesMap.values() );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( "User Classes cannot be duplicated. " + e.getMessage() );
+    }
+
+userClass
+{
+    log.debug( "entered userClasses()" );
+}
+    :
+    allUsers
+    | thisEntry
+    | parentOfEntry
+    | name
+    | userGroup
+    | subtree
+    ;
+
+allUsers
+{
+    log.debug( "entered allUsers()" );
+}
+    :
+    ID_allUsers
+    {
+        userClassesMap.put( "allUsers", UserClass.ALL_USERS );
+    }
+    ;
+
+thisEntry
+{
+    log.debug( "entered thisEntry()" );
+}
+    :
+    ID_thisEntry
+    {
+        userClassesMap.put( "thisEntry", UserClass.THIS_ENTRY );
+    }
+    ;
+
+parentOfEntry
+{
+    log.debug( "entered parentOfEntry()" );
+}
+    :
+    ID_parentOfEntry
+    {
+        userClassesMap.put( "parentOfEntry", UserClass.PARENT_OF_ENTRY );
+    }
+    ;
+
+name
+{
+    log.debug( "entered name()" );
+    Set<Dn> names = new HashSet<Dn>();
+    Dn distinguishedName = null;
+}
+    :
+    ID_name ( SP )+ 
+        OPEN_CURLY ( SP )*
+            distinguishedName=distinguishedName ( SP )*
+            {
+                names.add( distinguishedName );
+            }
+                ( SEP ( SP )* distinguishedName=distinguishedName ( SP )*
+                {
+                    names.add( distinguishedName );
+                } )*
+        CLOSE_CURLY
+    {
+        userClassesMap.put( "name", new UserClass.Name( names ) );
+    }
+    ;
+
+userGroup
+{
+    log.debug( "entered userGroup()" );
+    Set<Dn> userGroup = new HashSet<Dn>();
+    Dn distinguishedName = null;
+}
+    :
+    ID_userGroup ( SP )+ 
+        OPEN_CURLY ( SP )*
+            distinguishedName=distinguishedName ( SP )*
+            {
+                userGroup.add( distinguishedName );
+            }
+                ( SEP ( SP )* distinguishedName=distinguishedName ( SP )*
+                {
+                    userGroup.add( distinguishedName );
+                } )*
+        CLOSE_CURLY
+    {
+        userClassesMap.put( "userGroup", new UserClass.UserGroup( userGroup ) );
+    }
+    ;
+
+subtree
+{
+    log.debug( "entered subtree()" );
+    Set<SubtreeSpecification> subtrees = new HashSet<SubtreeSpecification>();
+    SubtreeSpecification subtreeSpecification = null;    
+}
+    :
+    ID_subtree ( SP )+
+        OPEN_CURLY ( SP )*
+            subtreeSpecification=subtreeSpecification ( SP )*
+            {
+                subtrees.add( subtreeSpecification );
+            }
+                ( SEP ( SP )* subtreeSpecification=subtreeSpecification ( SP )*
+                {
+                    subtrees.add( subtreeSpecification );
+                } )*
+        CLOSE_CURLY
+    {
+        userClassesMap.put( "subtree", new UserClass.Subtree( subtrees ) );
+    }
+    ;
+
+userPermissions
+{
+    log.debug( "entered userPermissions()" );
+    userPermissions = new HashSet<UserPermission>();
+    UserPermission userPermission = null;
+}
+    :
+    ID_userPermissions ( SP )+
+        OPEN_CURLY ( SP )*
+            ( userPermission=userPermission ( SP )*
+              {
+                  userPermissions.add( userPermission );
+              }
+                ( SEP ( SP )* userPermission=userPermission ( SP )*
+                  {
+                      userPermissions.add( userPermission );
+                  }
+                )*
+            )?
+        CLOSE_CURLY
+    ;
+
+userPermission returns [ UserPermission userPermission ]
+{
+    log.debug( "entered userPermission()" );
+    userPermission = null;
+    userPermissionComponentsMonitor = new MandatoryAndOptionalComponentsMonitor( 
+             new String [] { "protectedItems", "grantsAndDenials" }, new String [] { "precedence" } );
+}
+     :
+     OPEN_CURLY ( SP )*
+         anyUserPermission ( SP )*
+             ( SEP ( SP )* anyUserPermission ( SP )* )*
+     CLOSE_CURLY
+     {
+         if ( !userPermissionComponentsMonitor.finalStateValid() )
+         {
+             throw new RecognitionException( "Missing mandatory userPermission components: " 
+                     + userPermissionComponentsMonitor.getRemainingComponents() );
+         }
+         
+         userPermission = new UserPermission( precedence, grantsAndDenials, protectedItems );
+         precedence = null;
+     }
+     ;
+
+anyUserPermission
+    :
+    precedence
+    {
+        userPermissionComponentsMonitor.useComponent( "precedence" );
+    }
+    | protectedItems
+    {
+        userPermissionComponentsMonitor.useComponent( "protectedItems" );
+    }
+    | grantsAndDenials
+    {
+        userPermissionComponentsMonitor.useComponent( "grantsAndDenials" );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( e.getMessage() );
+    }
+
+subtreeSpecification returns [SubtreeSpecification ss]
+{
+    log.debug( "entered subtreeSpecification()" );
+    // clear out ss, ssModifier, chopBeforeExclusions and chopAfterExclusions
+    // in case something is left from the last parse
+    ss = null;
+    ssModifier = new SubtreeSpecificationModifier();
+    chopBeforeExclusions = new HashSet<Dn>();
+    chopAfterExclusions = new HashSet<Dn>();
+    subtreeSpecificationComponentsMonitor = new OptionalComponentsMonitor( 
+            new String [] { "base", "specificExclusions", "minimum", "maximum" } );
+}
+    :
+    OPEN_CURLY ( SP )*
+        ( subtreeSpecificationComponent ( SP )*
+            ( SEP ( SP )* subtreeSpecificationComponent ( SP )* )* )?
+    CLOSE_CURLY
+    {
+        ss = ssModifier.getSubtreeSpecification();
+    }
+    ;
+
+subtreeSpecificationComponent
+{
+    log.debug( "entered subtreeSpecification()" );
+}
+    :
+    ss_base
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "base" );
+    }
+    | ss_specificExclusions
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "specificExclusions" );
+    }
+    | ss_minimum
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "minimum" );
+    }
+    | ss_maximum
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "maximum" );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( e.getMessage() );
+    }
+
+ss_base
+{
+    log.debug( "entered ss_base()" );
+    Dn base = null;
+}
+    :
+    ID_base ( SP )+ base=distinguishedName
+    {
+        ssModifier.setBase( base );
+    }
+    ;
+
+ss_specificExclusions
+{
+    log.debug( "entered ss_specificExclusions()" );
+}
+    :
+    ID_specificExclusions ( SP )+ specificExclusions
+    {
+        ssModifier.setChopBeforeExclusions( chopBeforeExclusions );
+        ssModifier.setChopAfterExclusions( chopAfterExclusions );
+    }
+    ;
+
+specificExclusions
+{
+    log.debug( "entered specificExclusions()" );
+}
+    :
+    OPEN_CURLY ( SP )*
+        ( specificExclusion ( SP )*
+            ( SEP ( SP )* specificExclusion ( SP )* )*
+        )?
+    CLOSE_CURLY
+    ;
+
+specificExclusion
+{
+    log.debug( "entered specificExclusion()" );
+}
+    :
+    chopBefore | chopAfter
+    ;
+
+chopBefore
+{
+    log.debug( "entered chopBefore()" );
+    Dn chopBeforeExclusion = null;
+}
+    :
+    ID_chopBefore ( SP )* COLON ( SP )* chopBeforeExclusion=distinguishedName
+    {
+        chopBeforeExclusions.add( chopBeforeExclusion );
+    }
+    ;
+
+chopAfter
+{
+    log.debug( "entered chopAfter()" );
+    Dn chopAfterExclusion = null;
+}
+    :
+    ID_chopAfter ( SP )* COLON ( SP )* chopAfterExclusion=distinguishedName
+    {
+        chopAfterExclusions.add( chopAfterExclusion );
+    }
+    ;
+
+ss_minimum
+{
+    log.debug( "entered ss_minimum()" );
+    int minimum = 0;
+}
+    :
+    ID_minimum ( SP )+ minimum=baseDistance
+    {
+        ssModifier.setMinBaseDistance( minimum );
+    }
+    ;
+
+ss_maximum
+{
+    log.debug( "entered ss_maximum()" );
+    int maximum = 0;
+}
+    :
+    ID_maximum ( SP )+ maximum=baseDistance
+    {
+        ssModifier.setMaxBaseDistance( maximum );
+    }
+    ;
+
+distinguishedName returns [ Dn name ]
+{
+    log.debug( "entered distinguishedName()" );
+    name = null;
+}
+    :
+    token:SAFEUTF8STRING
+    {
+        name = new Dn( token.getText() );
+        if ( schemaManager != null )
+        {
+            name.apply( schemaManager );
+        }
+        log.debug( "recognized a DistinguishedName: " + token.getText() );
+    }
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "dnParser failed for " + token.getText() + " " + e.getMessage() );
+    }
+
+baseDistance returns [ int distance ]
+{
+    log.debug( "entered baseDistance()" );
+    distance = 0;
+}
+    :
+    token:INTEGER
+    {
+        distance = token2Integer( token );
+    }
+    ;
+
+oid returns [ String result ]
+{
+    log.debug( "entered oid()" );
+    result = null;
+    Token token = null;
+}
+    :
+    { token = LT( 1 ); } // an interesting trick goes here ;-)
+    ( DESCR | NUMERICOID )
+    {
+        result = token.getText();
+        log.debug( "recognized an oid: " + result );
+    }
+    ;
+
+refinement returns [ ExprNode node ]
+{
+    log.debug( "entered refinement()" );
+    node = null;
+}
+    :
+    node=item | node=and | node=or | node=not
+    ;
+
+item returns [ LeafNode node ]
+{
+    log.debug( "entered item()" );
+    node = null;
+    String oid = null;
+}
+    :
+    ID_item ( SP )* COLON ( SP )* oid=oid
+    {
+        node = new EqualityNode( SchemaConstants.OBJECT_CLASS_AT , new StringValue( oid ) );
+    }
+    ;
+
+and returns [ BranchNode node ]
+{
+    log.debug( "entered and()" );
+    node = null;
+    List<ExprNode> children = null; 
+}
+    :
+    ID_and ( SP )* COLON ( SP )* children=refinements
+    {
+        node = new AndNode( children );
+    }
+    ;
+
+or returns [ BranchNode node ]
+{
+    log.debug( "entered or()" );
+    node = null;
+    List<ExprNode> children = null; 
+}
+    :
+    ID_or ( SP )* COLON ( SP )* children=refinements
+    {
+        node = new OrNode( children );
+    }
+    ;
+
+not returns [ BranchNode node ]
+{
+    log.debug( "entered not()" );
+    node = null;
+    List<ExprNode> children = null;
+}
+    :
+    ID_not ( SP )* COLON ( SP )* children=refinements
+    {
+        node = new NotNode( children );
+    }
+    ;
+
+refinements returns [ List<ExprNode> children ]
+{
+    log.debug( "entered refinements()" );
+    children = null;
+    ExprNode child = null;
+    List<ExprNode> tempChildren = new ArrayList<ExprNode>();
+}
+    :
+    OPEN_CURLY ( SP )*
+    (
+        child=refinement ( SP )*
+        {
+            tempChildren.add( child );
+        }
+        ( SEP ( SP )* child=refinement ( SP )*
+        {
+            tempChildren.add( child );
+        } )*
+    )? CLOSE_CURLY
+    {
+        children = tempChildren;
+    }
+    ;
+
+    
+//  ----------------------------------------------------------------------------
+//  lexer class definition
+//  ----------------------------------------------------------------------------
+
+/**
+  * The parser's primary lexer.
+  *
+  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+  */
+class AntlrACIItemLexer extends Lexer;
+
+
+//  ----------------------------------------------------------------------------
+//  lexer options
+//  ----------------------------------------------------------------------------
+
+options
+{
+    k = 2;
+    charVocabulary = '\3'..'\377';
+}
+
+
+//----------------------------------------------------------------------------
+// tokens
+//----------------------------------------------------------------------------
+
+tokens
+{
+    ID_identificationTag = "identificationTag";
+    ID_precedence = "precedence";
+    ID_FALSE = "FALSE";
+    ID_TRUE = "TRUE";
+    ID_none = "none";
+    ID_simple = "simple";
+    ID_strong = "strong";
+    ID_level = "level";
+    ID_basicLevels = "basicLevels";
+    ID_localQualifier = "localQualifier";
+    ID_signed = "signed";
+    ID_authenticationLevel = "authenticationLevel";
+    ID_itemOrUserFirst = "itemOrUserFirst";
+    ID_itemFirst = "itemFirst";
+    ID_userFirst = "userFirst";
+    ID_protectedItems = "protectedItems";
+    ID_classes = "classes";
+    ID_entry = "entry";
+    ID_allUserAttributeTypes = "allUserAttributeTypes";
+    ID_attributeType = "attributeType";
+    ID_allAttributeValues = "allAttributeValues";
+    ID_allUserAttributeTypesAndValues = "allUserAttributeTypesAndValues";
+    ID_selfValue = "selfValue";
+    ID_item = "item";
+    ID_and = "and";
+    ID_or = "or";
+    ID_not = "not";
+    ID_rangeOfValues = "rangeOfValues";
+    ID_maxValueCount = "maxValueCount";
+    ID_type = "type";
+    ID_maxCount = "maxCount";
+    ID_maxImmSub = "maxImmSub";
+    ID_restrictedBy = "restrictedBy";
+    ID_valuesIn = "valuesIn";
+    ID_userClasses = "userClasses";
+    ID_base = "base";
+    ID_specificExclusions = "specificExclusions";
+    ID_chopBefore = "chopBefore";
+    ID_chopAfter = "chopAfter";
+    ID_minimum = "minimum";
+    ID_maximum = "maximum";
+    ID_specificationFilter = "specificationFilter";
+    ID_grantsAndDenials = "grantsAndDenials";
+    ID_itemPermissions = "itemPermissions";
+    ID_userPermissions = "userPermissions";
+    ID_allUsers = "allUsers";
+    ID_thisEntry = "thisEntry";
+    ID_parentOfEntry = "parentOfEntry";
+    ID_subtree = "subtree";
+    ID_name = "name";
+    ID_userGroup = "userGroup";
+
+    ID_grantAdd = "grantAdd"; // (0),
+    ID_denyAdd = "denyAdd";  // (1),
+    ID_grantDiscloseOnError = "grantDiscloseOnError";  // (2),
+    ID_denyDiscloseOnError = "denyDiscloseOnError";  // (3),
+    ID_grantRead = "grantRead";  // (4),
+    ID_denyRead = "denyRead";  // (5),
+    ID_grantRemove = "grantRemove";  // (6),
+    ID_denyRemove = "denyRemove";  // (7),
+    //-- permissions that may be used only in conjunction
+    //-- with the entry component
+    ID_grantBrowse = "grantBrowse";  // (8),
+    ID_denyBrowse = "denyBrowse";  // (9),
+    ID_grantExport = "grantExport";  // (10),
+    ID_denyExport = "denyExport";  // (11),
+    ID_grantImport = "grantImport";  // (12),
+    ID_denyImport = "denyImport";  // (13),
+    ID_grantModify = "grantModify";  // (14),
+    ID_denyModify = "denyModify";  // (15),
+    ID_grantRename = "grantRename";  // (16),
+    ID_denyRename = "denyRename";  // (17),
+    ID_grantReturnDN = "grantReturnDN";  // (18),
+    ID_denyReturnDN = "denyReturnDN";  // (19),
+    //-- permissions that may be used in conjunction
+    //-- with any component, except entry, of ProtectedItems
+    ID_grantCompare = "grantCompare";  // (20),
+    ID_denyCompare = "denyCompare";  // (21),
+    ID_grantFilterMatch = "grantFilterMatch";  // (22),
+    ID_denyFilterMatch = "denyFilterMatch";  // (23),
+    ID_grantInvoke = "grantInvoke";  // (24),
+    ID_denyInvoke = "denyInvoke";  // (25)
+}
+
+
+// ----------------------------------------------------------------------------
+//  lexer initialization
+// ----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrACIItemLexer.class );
+}
+
+
+// ----------------------------------------------------------------------------
+// attribute description lexer rules from models
+// ----------------------------------------------------------------------------
+
+//  This is all messed up - could not figure out how to get antlr to represent
+//  the safe UTF-8 character set from RFC 3642 for production SafeUTF8Character
+
+protected SAFEUTF8CHAR :
+    '\u0001'..'\u0021' |
+    '\u0023'..'\u007F' |
+    '\u00c0'..'\u00d6' |
+    '\u00d8'..'\u00f6' |
+    '\u00f8'..'\u00ff' |
+    '\u0100'..'\u1fff' |
+    '\u3040'..'\u318f' |
+    '\u3300'..'\u337f' |
+    '\u3400'..'\u3d2d' |
+    '\u4e00'..'\u9fff' |
+    '\uf900'..'\ufaff' ;
+
+OPEN_CURLY : '{' ;
+
+CLOSE_CURLY : '}' ;
+
+SEP : ',' ;
+
+SP : ' ' | '\t' | '\n' { newline(); } | '\r' ;
+
+COLON : ':' ;
+
+protected DIGIT : '0' | LDIGIT ;
+
+protected LDIGIT : '1'..'9' ;
+
+protected ALPHA : 'A'..'Z' | 'a'..'z' ;
+
+protected INTEGER : DIGIT | ( LDIGIT ( DIGIT )+ ) ;
+
+protected HYPHEN : '-' ;
+
+protected NUMERICOID : INTEGER ( DOT INTEGER )+ ;
+
+protected DOT : '.' ;
+
+INTEGER_OR_NUMERICOID
+    :
+    ( INTEGER DOT ) => NUMERICOID
+    {
+        $setType( NUMERICOID );
+    }
+    |
+    INTEGER
+    {
+        $setType( INTEGER );
+    }
+    ;
+
+SAFEUTF8STRING : '"'! ( SAFEUTF8CHAR )* '"'! ;
+
+DESCR // THIS RULE ALSO STANDS FOR AN IDENTIFIER
+    :
+    ( "attributeValue" ( SP! )+ '{' ) =>
+      "attributeValue"! ( SP! )+ '{'! ( options { greedy = false; } : . )* '}'!
+      { $setType( ATTRIBUTE_VALUE_CANDIDATE ); }
+    | ( "rangeOfValues" ( SP! )+ '(' ) =>
+      "rangeOfValues"! ( SP! )+ FILTER
+      { $setType( RANGE_OF_VALUES_CANDIDATE ); }
+    | ALPHA ( ALPHA | DIGIT | HYPHEN )*
+    ;
+
+protected FILTER : '(' ( ( '&' (SP)* (FILTER)+ ) | ( '|' (SP)* (FILTER)+ ) | ( '!' (SP)* FILTER ) | FILTER_VALUE ) ')' (SP)* ;
+
+protected FILTER_VALUE : (options{greedy=true;}: ~( ')' | '(' | '&' | '|' | '!' ) ( ~(')') )* ) ;
+
diff --git a/trunk/ldap/extras/aci/src/main/antlr/ACIItemChecker.g b/trunk/ldap/extras/aci/src/main/antlr/ACIItemChecker.g
new file mode 100644
index 0000000..085755b
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/antlr/ACIItemChecker.g
@@ -0,0 +1,780 @@
+header
+{
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+
+package org.apache.directory.api.ldap.aci;
+
+
+import org.apache.directory.api.ldap.model.schema.normalizers.NameComponentNormalizer;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The antlr generated ACIItem checker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrACIItemChecker extends Parser;
+
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 1; // ;-)
+    defaultErrorHandler = false;
+}
+
+
+// ----------------------------------------------------------------------------
+// imaginary tokens
+// ----------------------------------------------------------------------------
+
+tokens
+{
+    ATTRIBUTE_VALUE_CANDIDATE;
+    RANGE_OF_VALUES_CANDIDATE;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser initialization
+// ----------------------------------------------------------------------------
+
+{
+    NameComponentNormalizer normalizer;
+    
+    /**
+     * Creates a (normalizing) subordinate DnParser for parsing Names.
+     * This method MUST be called for each instance while we cannot do
+     * constructor overloading for this class.
+     *
+     * @return the DnParser to be used for parsing Names
+     */
+    public void init()
+    {
+    }
+
+    /**
+     * Sets the NameComponentNormalizer for this parser's dnParser.
+     */
+    public void setNormalizer(NameComponentNormalizer normalizer)
+    {
+        this.normalizer = normalizer;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// parser productions
+// ----------------------------------------------------------------------------
+
+wrapperEntryPoint
+    :
+    ( SP )* theACIItem ( SP )* EOF
+    ;
+
+theACIItem
+    :
+    OPEN_CURLY
+        ( SP )* mainACIItemComponent ( SP )*
+            ( SEP ( SP )* mainACIItemComponent ( SP )* )*
+    CLOSE_CURLY
+    ;
+    
+mainACIItemComponent
+    :
+    aci_identificationTag
+    | aci_precedence
+    | aci_authenticationLevel
+    | aci_itemOrUserFirst
+    ;
+    
+aci_identificationTag
+    :
+    ID_identificationTag ( SP )+ SAFEUTF8STRING
+    ;
+
+aci_precedence
+    :
+    precedence
+    ;
+
+precedence
+    :
+    ID_precedence ( SP )+ INTEGER
+    ;
+
+aci_authenticationLevel
+    :
+    ID_authenticationLevel ( SP )+ authenticationLevel
+    ;
+
+authenticationLevel
+    :
+    ID_none
+    |
+    ID_simple
+    |
+    ID_strong
+    ;
+
+aci_itemOrUserFirst
+    :
+    ID_itemOrUserFirst ( SP )+ itemOrUserFirst
+    ;
+
+itemOrUserFirst
+    :
+    itemFirst | userFirst
+    ;
+
+itemFirst
+    :
+    ID_itemFirst ( SP )* COLON ( SP )*
+        OPEN_CURLY ( SP )*
+            ( 
+              protectedItems ( SP )*
+                SEP ( SP )* itemPermissions
+            | // relaxing
+              itemPermissions ( SP )*
+                SEP ( SP )* protectedItems
+            )
+        ( SP )* CLOSE_CURLY
+    ;
+
+userFirst
+    :
+    ID_userFirst ( SP )* COLON ( SP )*
+        OPEN_CURLY ( SP )*
+            (
+              userClasses ( SP )*
+                SEP ( SP )* userPermissions
+            | // relaxing
+              userPermissions ( SP )*
+                SEP ( SP )* userClasses
+            )
+        ( SP )* CLOSE_CURLY
+    ;
+
+protectedItems
+    :
+    ID_protectedItems ( SP )*
+        OPEN_CURLY ( SP )*
+            (
+                protectedItem ( SP )*
+                    ( SEP ( SP )* protectedItem ( SP )* )*
+            )?
+        CLOSE_CURLY
+    ;
+
+protectedItem
+    :
+    entry
+    | allUserAttributeTypes
+    | attributeType
+    | allAttributeValues 
+    | allUserAttributeTypesAndValues
+    | attributeValue
+    | selfValue
+    | rangeOfValues
+    | maxValueCount
+    | maxImmSub
+    | restrictedBy
+    | classes
+    ;
+
+entry
+    :
+    ID_entry
+    ;
+
+allUserAttributeTypes
+    :
+    ID_allUserAttributeTypes
+    ;
+
+attributeType
+    :
+    ID_attributeType ( SP )+ attributeTypeSet
+    ;
+
+allAttributeValues
+    :
+    ID_allAttributeValues ( SP )+ attributeTypeSet
+    ;
+
+allUserAttributeTypesAndValues
+    :
+    ID_allUserAttributeTypesAndValues
+    ;
+
+attributeValue
+    :
+    ATTRIBUTE_VALUE_CANDIDATE // ate the identifier for subordinate dn parser workaround
+    ;
+
+selfValue
+    :
+    ID_selfValue ( SP )+ attributeTypeSet
+    ;
+
+rangeOfValues
+    :
+    RANGE_OF_VALUES_CANDIDATE
+    ;
+
+maxValueCount
+    :
+    ID_maxValueCount ( SP )+
+    OPEN_CURLY ( SP )*
+        aMaxValueCount ( SP )*
+            ( SEP ( SP )* aMaxValueCount ( SP )*
+            )*
+    CLOSE_CURLY
+    ;
+
+aMaxValueCount
+    :
+    OPEN_CURLY ( SP )*
+        (
+          ID_type ( SP )+ oid ( SP )* SEP ( SP )*
+          ID_maxCount ( SP )+ INTEGER
+        | // relaxing
+          ID_maxCount ( SP )+ INTEGER ( SP )* SEP ( SP )*
+          ID_type ( SP )+ oid
+        )
+    ( SP )* CLOSE_CURLY
+    ;
+
+maxImmSub
+    :
+    ID_maxImmSub ( SP )+ INTEGER
+    ;
+
+restrictedBy
+    :
+    ID_restrictedBy ( SP )+
+        OPEN_CURLY ( SP )*
+            restrictedValue ( SP )*
+                    ( SEP ( SP )* restrictedValue ( SP )*
+                    )*
+        CLOSE_CURLY
+    ;
+
+restrictedValue
+    :
+    OPEN_CURLY ( SP )*
+        (
+          ID_type ( SP )+ oid ( SP )* SEP ( SP )*
+          ID_valuesIn ( SP )+ oid
+        | // relaxing
+          ID_valuesIn ( SP )+ oid ( SP )* SEP ( SP )*
+          ID_type ( SP )+ oid
+        )
+    ( SP )* CLOSE_CURLY
+    ;
+
+attributeTypeSet 
+    :
+    OPEN_CURLY ( SP )*
+        oid ( SP )*
+            ( SEP ( SP )* oid ( SP )*
+            )*
+    CLOSE_CURLY
+    ;
+
+classes
+    :
+    ID_classes ( SP )+ refinement
+    ;
+
+itemPermissions
+    :
+    ID_itemPermissions ( SP )+
+        OPEN_CURLY ( SP )*
+            ( itemPermission ( SP )*
+                ( SEP ( SP )* itemPermission ( SP )*
+                )*
+            )?
+        CLOSE_CURLY
+    ;
+
+itemPermission
+    :
+    OPEN_CURLY ( SP )*
+        anyItemPermission ( SP )*
+            ( SEP ( SP )* anyItemPermission ( SP )* )*
+    CLOSE_CURLY
+    ;
+
+anyItemPermission
+    :
+    precedence
+    | userClasses
+    | grantsAndDenials
+    ;
+
+grantsAndDenials
+    :
+    ID_grantsAndDenials ( SP )+
+    OPEN_CURLY ( SP )*
+        ( grantAndDenial ( SP )*
+            ( SEP ( SP )* grantAndDenial ( SP )*
+            )*
+        )?
+    CLOSE_CURLY
+    ;
+
+grantAndDenial
+    :
+    ID_grantAdd 
+    | ID_denyAdd
+    | ID_grantDiscloseOnError
+    | ID_denyDiscloseOnError 
+    | ID_grantRead
+    | ID_denyRead
+    | ID_grantRemove
+    | ID_denyRemove 
+    //-- permissions that may be used only in conjunction
+    //-- with the entry component
+    | ID_grantBrowse
+    | ID_denyBrowse
+    | ID_grantExport
+    | ID_denyExport
+    | ID_grantImport
+    | ID_denyImport
+    | ID_grantModify
+    | ID_denyModify
+    | ID_grantRename
+    | ID_denyRename
+    | ID_grantReturnDN
+    | ID_denyReturnDN
+    //-- permissions that may be used in conjunction
+    //-- with any component, except entry, of ProtectedItems
+    | ID_grantCompare
+    | ID_denyCompare
+    | ID_grantFilterMatch
+    | ID_denyFilterMatch
+    | ID_grantInvoke
+    | ID_denyInvoke
+    ;
+
+userClasses
+    :
+    ID_userClasses ( SP )+
+    OPEN_CURLY ( SP )*
+        (
+            userClass ( SP )*
+                ( SEP ( SP )* userClass ( SP )* )*
+        )?
+    CLOSE_CURLY
+    ;
+
+userClass
+    :
+    allUsers
+    | thisEntry
+    | parentOfEntry
+    | name
+    | userGroup
+    | subtree
+    ;
+
+allUsers
+    :
+    ID_allUsers
+    ;
+
+thisEntry
+    :
+    ID_thisEntry
+    ;
+
+parentOfEntry
+    :
+    ID_parentOfEntry
+    ;
+
+name
+    :
+    ID_name ( SP )+ 
+        OPEN_CURLY ( SP )*
+            distinguishedName ( SP )*
+                ( SEP ( SP )* distinguishedName ( SP )*
+            )*
+        CLOSE_CURLY
+    ;
+
+userGroup
+    :
+    ID_userGroup ( SP )+ 
+        OPEN_CURLY ( SP )*
+            distinguishedName ( SP )*
+                ( SEP ( SP )* distinguishedName ( SP )* )*
+        CLOSE_CURLY
+    ;
+
+subtree
+    :
+    ID_subtree ( SP )+
+        OPEN_CURLY ( SP )*
+            subtreeSpecification ( SP )*
+                ( SEP ( SP )* subtreeSpecification ( SP )* )*
+        CLOSE_CURLY
+    ;
+
+userPermissions
+    :
+    ID_userPermissions ( SP )+
+        OPEN_CURLY ( SP )*
+            ( userPermission ( SP )*
+                ( SEP ( SP )* userPermission ( SP )* )*
+            )?
+        CLOSE_CURLY
+    ;
+
+userPermission
+     :
+     OPEN_CURLY ( SP )*
+         anyUserPermission ( SP )*
+             ( SEP ( SP )* anyUserPermission ( SP )* )*
+     CLOSE_CURLY
+     ;
+
+anyUserPermission
+    :
+    precedence
+    | protectedItems
+    | grantsAndDenials
+    ;
+
+subtreeSpecification
+    :
+    OPEN_CURLY ( SP )*
+        ( subtreeSpecificationComponent ( SP )*
+            ( SEP ( SP )* subtreeSpecificationComponent ( SP )* )* )?
+    CLOSE_CURLY
+    ;
+
+subtreeSpecificationComponent
+    :
+    ss_base
+    | ss_specificExclusions
+    | ss_minimum
+    | ss_maximum
+    ;
+
+ss_base
+    :
+    ID_base ( SP )+ distinguishedName
+    ;
+
+ss_specificExclusions
+    :
+    ID_specificExclusions ( SP )+ specificExclusions
+    ;
+
+specificExclusions
+    :
+    OPEN_CURLY ( SP )*
+        ( specificExclusion ( SP )*
+            ( SEP ( SP )* specificExclusion ( SP )* )*
+        )?
+    CLOSE_CURLY
+    ;
+
+specificExclusion
+    :
+    chopBefore | chopAfter
+    ;
+
+chopBefore
+    :
+    ID_chopBefore ( SP )* COLON ( SP )* distinguishedName
+    ;
+
+chopAfter
+    :
+    ID_chopAfter ( SP )* COLON ( SP )* distinguishedName
+    ;
+
+ss_minimum
+    :
+    ID_minimum ( SP )+ baseDistance
+    ;
+
+ss_maximum
+    :
+    ID_maximum ( SP )+ baseDistance
+    ;
+
+distinguishedName
+    :
+    SAFEUTF8STRING
+    ;
+
+baseDistance
+    :
+    INTEGER
+    ;
+
+oid
+    :
+    ( DESCR | NUMERICOID )
+    ;
+
+refinement
+    :
+    item | and | or | not
+    ;
+
+item
+    :
+    ID_item ( SP )* COLON ( SP )* oid
+    ;
+
+and
+    :
+    ID_and ( SP )* COLON ( SP )* refinements
+    ;
+
+or
+    :
+    ID_or ( SP )* COLON ( SP )* refinements
+    ;
+
+not
+    :
+    ID_not ( SP )* COLON ( SP )* refinements
+    ;
+
+refinements
+    :
+    OPEN_CURLY ( SP )*
+    (
+        refinement ( SP )*
+        ( SEP ( SP )* refinement ( SP )* )*
+    )? CLOSE_CURLY
+    ;
+
+    
+//  ----------------------------------------------------------------------------
+//  lexer class definition
+//  ----------------------------------------------------------------------------
+
+/**
+  * The parser's primary lexer.
+  *
+  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+   */
+class AntlrACIItemCheckerLexer extends Lexer;
+
+
+//  ----------------------------------------------------------------------------
+//  lexer options
+//  ----------------------------------------------------------------------------
+
+options
+{
+    k = 2;
+    charVocabulary = '\3'..'\377';
+}
+
+
+//----------------------------------------------------------------------------
+// tokens
+//----------------------------------------------------------------------------
+
+tokens
+{
+    ID_identificationTag = "identificationTag";
+    ID_precedence = "precedence";
+    ID_FALSE = "FALSE";
+    ID_TRUE = "TRUE";
+    ID_none = "none";
+    ID_simple = "simple";
+    ID_strong = "strong";
+    ID_level = "level";
+    ID_basicLevels = "basicLevels";
+    ID_localQualifier = "localQualifier";
+    ID_signed = "signed";
+    ID_authenticationLevel = "authenticationLevel";
+    ID_itemOrUserFirst = "itemOrUserFirst";
+    ID_itemFirst = "itemFirst";
+    ID_userFirst = "userFirst";
+    ID_protectedItems = "protectedItems";
+    ID_classes = "classes";
+    ID_entry = "entry";
+    ID_allUserAttributeTypes = "allUserAttributeTypes";
+    ID_attributeType = "attributeType";
+    ID_allAttributeValues = "allAttributeValues";
+    ID_allUserAttributeTypesAndValues = "allUserAttributeTypesAndValues";
+    ID_selfValue = "selfValue";
+    ID_item = "item";
+    ID_and = "and";
+    ID_or = "or";
+    ID_not = "not";
+    ID_rangeOfValues = "rangeOfValues";
+    ID_maxValueCount = "maxValueCount";
+    ID_type = "type";
+    ID_maxCount = "maxCount";
+    ID_maxImmSub = "maxImmSub";
+    ID_restrictedBy = "restrictedBy";
+    ID_valuesIn = "valuesIn";
+    ID_userClasses = "userClasses";
+    ID_base = "base";
+    ID_specificExclusions = "specificExclusions";
+    ID_chopBefore = "chopBefore";
+    ID_chopAfter = "chopAfter";
+    ID_minimum = "minimum";
+    ID_maximum = "maximum";
+    ID_specificationFilter = "specificationFilter";
+    ID_grantsAndDenials = "grantsAndDenials";
+    ID_itemPermissions = "itemPermissions";
+    ID_userPermissions = "userPermissions";
+    ID_allUsers = "allUsers";
+    ID_thisEntry = "thisEntry";
+    ID_parentOfEntry = "parentOfEntry";
+    ID_subtree = "subtree";
+    ID_name = "name";
+    ID_userGroup = "userGroup";
+
+    ID_grantAdd = "grantAdd"; // (0),
+    ID_denyAdd = "denyAdd";  // (1),
+    ID_grantDiscloseOnError = "grantDiscloseOnError";  // (2),
+    ID_denyDiscloseOnError = "denyDiscloseOnError";  // (3),
+    ID_grantRead = "grantRead";  // (4),
+    ID_denyRead = "denyRead";  // (5),
+    ID_grantRemove = "grantRemove";  // (6),
+    ID_denyRemove = "denyRemove";  // (7),
+    //-- permissions that may be used only in conjunction
+    //-- with the entry component
+    ID_grantBrowse = "grantBrowse";  // (8),
+    ID_denyBrowse = "denyBrowse";  // (9),
+    ID_grantExport = "grantExport";  // (10),
+    ID_denyExport = "denyExport";  // (11),
+    ID_grantImport = "grantImport";  // (12),
+    ID_denyImport = "denyImport";  // (13),
+    ID_grantModify = "grantModify";  // (14),
+    ID_denyModify = "denyModify";  // (15),
+    ID_grantRename = "grantRename";  // (16),
+    ID_denyRename = "denyRename";  // (17),
+    ID_grantReturnDN = "grantReturnDN";  // (18),
+    ID_denyReturnDN = "denyReturnDN";  // (19),
+    //-- permissions that may be used in conjunction
+    //-- with any component, except entry, of ProtectedItems
+    ID_grantCompare = "grantCompare";  // (20),
+    ID_denyCompare = "denyCompare";  // (21),
+    ID_grantFilterMatch = "grantFilterMatch";  // (22),
+    ID_denyFilterMatch = "denyFilterMatch";  // (23),
+    ID_grantInvoke = "grantInvoke";  // (24),
+    ID_denyInvoke = "denyInvoke";  // (25)
+}
+
+
+// ----------------------------------------------------------------------------
+//  lexer initialization
+// ----------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------
+// attribute description lexer rules from models
+// ----------------------------------------------------------------------------
+
+//  This is all messed up - could not figure out how to get antlr to represent
+//  the safe UTF-8 character set from RFC 3642 for production SafeUTF8Character
+
+protected SAFEUTF8CHAR :
+    '\u0001'..'\u0021' |
+    '\u0023'..'\u007F' |
+    '\u00c0'..'\u00d6' |
+    '\u00d8'..'\u00f6' |
+    '\u00f8'..'\u00ff' |
+    '\u0100'..'\u1fff' |
+    '\u3040'..'\u318f' |
+    '\u3300'..'\u337f' |
+    '\u3400'..'\u3d2d' |
+    '\u4e00'..'\u9fff' |
+    '\uf900'..'\ufaff' ;
+
+OPEN_CURLY : '{' ;
+
+CLOSE_CURLY : '}' ;
+
+SEP : ',' ;
+
+SP : ' ' | '\t' | '\n' { newline(); } | '\r' ;
+
+COLON : ':' ;
+
+protected DIGIT : '0' | LDIGIT ;
+
+protected LDIGIT : '1'..'9' ;
+
+protected ALPHA : 'A'..'Z' | 'a'..'z' ;
+
+protected INTEGER : DIGIT | ( LDIGIT ( DIGIT )+ ) ;
+
+protected HYPHEN : '-' ;
+
+protected NUMERICOID : INTEGER ( DOT INTEGER )+ ;
+
+protected DOT : '.' ;
+
+INTEGER_OR_NUMERICOID
+    :
+    ( INTEGER DOT ) => NUMERICOID
+    {
+        $setType( NUMERICOID );
+    }
+    |
+    INTEGER
+    {
+        $setType( INTEGER );
+    }
+    ;
+
+SAFEUTF8STRING : '"'! ( SAFEUTF8CHAR )* '"'! ;
+
+DESCR // THIS RULE ALSO STANDS FOR AN IDENTIFIER
+    :
+    ( "attributeValue" ( SP! )+ '{' ) =>
+      "attributeValue"! ( SP! )+ '{'! ( options { greedy = false; } : . )* '}'!
+      { $setType( ATTRIBUTE_VALUE_CANDIDATE ); }
+    | ( "rangeOfValues" ( SP! )+ '(' ) =>
+      "rangeOfValues"! ( SP! )+ FILTER
+      { $setType( RANGE_OF_VALUES_CANDIDATE ); }
+    | ALPHA ( ALPHA | DIGIT | HYPHEN )*
+    ;
+
+protected FILTER : '(' ( ( '&' (SP)* (FILTER)+ ) | ( '|' (SP)* (FILTER)+ ) | ( '!' (SP)* FILTER ) | FILTER_VALUE ) ')' (SP)* ;
+
+protected FILTER_VALUE : (options{greedy=true;}: ~( ')' | '(' | '&' | '|' | '!' ) ( ~(')') )* ) ;
+
+    
\ No newline at end of file
diff --git a/trunk/ldap/extras/aci/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/extras/aci/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/extras/aci/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/extras/aci/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItem.java
new file mode 100644
index 0000000..7fe0104
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItem.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
+
+
+/**
+ * An abstract class that provides common properties and operations for
+ * {@link ItemFirstACIItem} and {@link UserFirstACIItem} as specified X.501
+ * specification.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class ACIItem
+{
+    /** The ACIItemComponet identifier */
+    private String identificationTag;
+
+    /** The precedence : a number in [0 - 255] */
+    private int precedence = 0;
+
+    /** The authentication level. One of 'none', 'simple' and 'strong' */
+    private AuthenticationLevel authenticationLevel;
+
+
+    /**
+     * Creates a new instance
+     * 
+     * @param identificationTag the id string of this item
+     * @param precedence the precedence of this item
+     * @param authenticationLevel the level of authentication required to this item
+     */
+    protected ACIItem( String identificationTag, int precedence, AuthenticationLevel authenticationLevel )
+    {
+        if ( identificationTag == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04001_NULL_IDENTIFICATION_TAG ) );
+        }
+
+        if ( ( precedence < 0 ) || ( precedence > 255 ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04002_BAD_PRECENDENCE, precedence ) );
+        }
+
+        if ( authenticationLevel == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04003_NULL_AUTHENTICATION_LEVEL ) );
+        }
+
+        this.identificationTag = identificationTag;
+        this.precedence = precedence;
+        this.authenticationLevel = authenticationLevel;
+    }
+
+
+    /**
+     * Gets the id string of this item.
+     *
+     * @return the identification tag
+     */
+    public String getIdentificationTag()
+    {
+        return identificationTag;
+    }
+
+
+    /**
+     * Gets the precedence of this item.
+     *
+     * @return the precedence
+     */
+    public int getPrecedence()
+    {
+        return precedence;
+    }
+
+
+    /**
+     * Gets the level of authentication required to this item.
+     *
+     * @return the authentication level
+     */
+    public AuthenticationLevel getAuthenticationLevel()
+    {
+        return authenticationLevel;
+    }
+
+
+    /**
+     * Converts this item into a collection of {@link ACITuple}s.
+     *
+     * @return the converted collection of {@link ACITuple}
+     */
+    public abstract Collection<ACITuple> toTuples();
+
+
+    /**
+     * Converts a collection of {@link GrantAndDenial}s into a collection of {@link MicroOperation}s.
+     *
+     * @param grantsAndDenials the grants and denials
+     * @return the collection of {@link MicroOperation}s
+     */
+    protected static Collection<MicroOperation> toMicroOperations( Collection<GrantAndDenial> grantsAndDenials )
+    {
+        Set<MicroOperation> microOps = new HashSet<MicroOperation>();
+
+        for ( GrantAndDenial grantAndDenial : grantsAndDenials )
+        {
+            microOps.add( grantAndDenial.getMicroOperation() );
+        }
+
+        return microOps;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        // identificationTag
+        buf.append( "identificationTag \"" );
+        buf.append( getIdentificationTag() );
+
+        // precedence
+        buf.append( "\", precedence " );
+        buf.append( getPrecedence() );
+
+        // authenticationLevel
+        buf.append( ", authenticationLevel " );
+        buf.append( getAuthenticationLevel().getName() );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemChecker.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemChecker.java
new file mode 100644
index 0000000..d82eee3
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemChecker.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import java.io.StringReader;
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper around the antlr generated parser for an ACIItem as
+ * defined by X.501. This class enables the reuse of the antlr parser/lexer pair
+ * without having to recreate them every time.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ACIItemChecker
+{
+    /** the antlr generated parser being wrapped */
+    private ReusableAntlrACIItemParser checker;
+
+    /** the antlr generated lexer being wrapped */
+    private ReusableAntlrACIItemLexer lexer;
+
+
+    /**
+     * Creates a ACIItem parser.
+     *
+     * @param schemaManager the schema manager
+     */
+    public ACIItemChecker( SchemaManager schemaManager )
+    {
+        this.lexer = new ReusableAntlrACIItemLexer( new StringReader( "" ) );
+        this.checker = new ReusableAntlrACIItemParser( lexer );
+        this.checker.init( schemaManager );
+    }
+
+
+    /**
+     * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+     * pair with it. param spec the specification to be parsed
+     */
+    private synchronized void reset( String spec )
+    {
+        StringReader in = new StringReader( spec );
+        this.lexer.prepareNextInput( in );
+        this.checker.resetState();
+    }
+
+
+    /**
+     * Parses an ACIItem without exhausting the parser.
+     * 
+     * @param spec
+     *            the specification to be parsed
+     * @throws ParseException
+     *             if there are any recognition errors (bad syntax)
+     */
+    public synchronized void parse( String spec ) throws ParseException
+    {
+        if ( spec == null || spec.trim().equals( "" ) )
+        {
+            return;
+        }
+
+        // reset and initialize the parser / lexer pair
+        reset( spec );
+
+        try
+        {
+            this.checker.wrapperEntryPoint();
+        }
+        catch ( TokenStreamException e )
+        {
+            throw new ParseException( I18n
+                .err( I18n.ERR_04004_PARSER_FAILURE_ACI_ITEM, spec, e.getLocalizedMessage() ), 0 );
+        }
+        catch ( RecognitionException e )
+        {
+            throw new ParseException( I18n
+                .err( I18n.ERR_04004_PARSER_FAILURE_ACI_ITEM, spec, e.getLocalizedMessage() ), e.getColumn() );
+        }
+    }
+
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemParser.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemParser.java
new file mode 100644
index 0000000..d20f803
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemParser.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import java.io.StringReader;
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.normalizers.NameComponentNormalizer;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper around the antlr generated parser for an ACIItem as
+ * defined by X.501. This class enables the reuse of the antlr parser/lexer pair
+ * without having to recreate them every time.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ACIItemParser
+{
+    /** the antlr generated parser being wrapped */
+    private ReusableAntlrACIItemParser parser;
+
+    /** the antlr generated lexer being wrapped */
+    private ReusableAntlrACIItemLexer lexer;
+
+    /** The is normalizing flag. */
+    private final boolean isNormalizing;
+
+
+    /**
+     * Creates a ACIItem parser.
+     *
+     * @param schemaManager the schema manager
+     */
+    public ACIItemParser( SchemaManager schemaManager )
+    {
+        this.lexer = new ReusableAntlrACIItemLexer( new StringReader( "" ) );
+        this.parser = new ReusableAntlrACIItemParser( lexer );
+
+        // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.parser.init( schemaManager );
+
+        this.isNormalizing = false;
+    }
+
+
+    /**
+     * Creates a normalizing ACIItem parser.
+     *
+     * @param normalizer the normalizer
+     * @param schemaManager the schema manager
+     */
+    public ACIItemParser( NameComponentNormalizer normalizer, SchemaManager schemaManager )
+    {
+        this.lexer = new ReusableAntlrACIItemLexer( new StringReader( "" ) );
+        this.parser = new ReusableAntlrACIItemParser( lexer );
+
+        this.parser.setNormalizer( normalizer );
+        this.isNormalizing = true;
+
+        // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.parser.init( schemaManager );
+    }
+
+
+    /**
+     * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+     * pair with it. param spec the specification to be parsed
+     */
+    private synchronized void reset( String spec )
+    {
+        StringReader in = new StringReader( spec );
+        this.lexer.prepareNextInput( in );
+        this.parser.resetState();
+    }
+
+
+    /**
+     * Parses an ACIItem without exhausting the parser.
+     * 
+     * @param spec
+     *            the specification to be parsed
+     * @return the specification bean
+     * @throws ParseException
+     *             if there are any recognition errors (bad syntax)
+     */
+    public synchronized ACIItem parse( String spec ) throws ParseException
+    {
+        ACIItem aCIItem = null;
+
+        if ( spec == null || spec.trim().equals( "" ) )
+        {
+            return null;
+        }
+
+        // reset and initialize the parser / lexer pair
+        reset( spec );
+
+        try
+        {
+            aCIItem = this.parser.wrapperEntryPoint();
+        }
+        catch ( TokenStreamException e )
+        {
+            throw new ParseException( I18n
+                .err( I18n.ERR_04004_PARSER_FAILURE_ACI_ITEM, spec, e.getLocalizedMessage() ), 0 );
+        }
+        catch ( RecognitionException e )
+        {
+            throw new ParseException(
+                I18n
+                    .err( I18n.ERR_04004_PARSER_FAILURE_ACI_ITEM, spec, e.getLocalizedMessage(), e.getLine(),
+                        e.getColumn() ), e.getColumn() );
+        }
+
+        return aCIItem;
+    }
+
+
+    /**
+     * Tests to see if this parser is normalizing.
+     * 
+     * @return true if it normalizes false otherwise
+     */
+    public boolean isNormizing()
+    {
+        return this.isNormalizing;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemSyntaxChecker.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemSyntaxChecker.java
new file mode 100644
index 0000000..8a1187c
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACIItemSyntaxChecker.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid ACIItem.
+ * 
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class ACIItemSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ACIItemSyntaxChecker.class );
+
+    /** An instance of ACI Item Checker */
+    private ACIItemChecker aciItemChecker;
+
+
+    /**
+     * Creates a new instance of ACIItemSyntaxChecker
+     */
+    public ACIItemSyntaxChecker()
+    {
+        super( SchemaConstants.ACI_ITEM_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        try
+        {
+            synchronized ( aciItemChecker )
+            {
+                aciItemChecker.parse( strValue );
+            }
+
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        aciItemChecker = new ACIItemChecker( schemaManager );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACITuple.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACITuple.java
new file mode 100644
index 0000000..dfd2251
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ACITuple.java
@@ -0,0 +1,173 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
+
+
+/**
+ * A flatten entity which is converted from an {@link ACIItem}. The tuples are
+ * accepted by ACDF (Access Control Decision Function, 18.8, X.501)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ACITuple
+{
+    /** The collection of {@link UserClass}es this tuple relates to **/
+    private final Collection<UserClass> userClasses;
+
+    /** The level of authentication required */
+    private final AuthenticationLevel authenticationLevel;
+
+    /** The collection of {@link ProtectedItem}s this tuple relates */
+    private final Collection<ProtectedItem> protectedItems;
+
+    /** The set of {@link MicroOperation}s this tuple relates */
+    private final Set<MicroOperation> microOperations;
+
+    /** Tells if this tuple grant some access */
+    private final boolean grant;
+
+    /** The precedence for this tuple */
+    private final Integer precedence;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param userClasses the collection of {@link UserClass}es this tuple relates to
+     * @param authenticationLevel the level of authentication required
+     * @param protectedItems the collection of {@link ProtectedItem}s this tuple relates
+     * @param microOperations the collection of {@link MicroOperation}s this tuple relates
+     * @param grant <tt>true</tt> if and only if this tuple grants an access
+     * @param precedence the precedence of this tuple (<tt>0</tt>-<tt>255</tt>)
+     */
+    public ACITuple(
+        Collection<UserClass> userClasses,
+        AuthenticationLevel authenticationLevel,
+        Collection<ProtectedItem> protectedItems,
+        Collection<MicroOperation> microOperations,
+        boolean grant,
+        Integer precedence )
+    {
+        if ( authenticationLevel == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04003_NULL_AUTHENTICATION_LEVEL ) );
+        }
+
+        if ( precedence < 0 || precedence > 255 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04002_BAD_PRECENDENCE, precedence ) );
+        }
+
+        this.userClasses = Collections.unmodifiableCollection( new ArrayList<UserClass>( userClasses ) );
+        this.authenticationLevel = authenticationLevel;
+        this.protectedItems = Collections.unmodifiableCollection( new ArrayList<ProtectedItem>( protectedItems ) );
+        this.microOperations = Collections.unmodifiableSet( new HashSet<MicroOperation>( microOperations ) );
+        this.grant = grant;
+        this.precedence = precedence;
+    }
+
+
+    /**
+     * Gets the collection of {@link UserClass}es this tuple relates to.
+     *
+     * @return the collection of {@link UserClass}es
+     */
+    public Collection<UserClass> getUserClasses()
+    {
+        return userClasses;
+    }
+
+
+    /**
+     * Gets the level of authentication required.
+     *
+     * @return the authentication level
+     */
+    public AuthenticationLevel getAuthenticationLevel()
+    {
+        return authenticationLevel;
+    }
+
+
+    /**
+     * Gets the collection of {@link ProtectedItem}s this tuple relates.
+     *
+     * @return the collection of {@link ProtectedItem}s
+     */
+    public Collection<ProtectedItem> getProtectedItems()
+    {
+        return protectedItems;
+    }
+
+
+    /**
+     * Gets the collection of {@link MicroOperation}s this tuple relates.
+     *
+     * @return the collection of {@link MicroOperation}s
+     */
+    public Collection<MicroOperation> getMicroOperations()
+    {
+        return microOperations;
+    }
+
+
+    /**
+     * Gets <tt>true</tt> if and only if this tuple grants an access.
+     *
+     * @return <tt>true</tt> if and only if this tuple grants an access
+     */
+    public boolean isGrant()
+    {
+        return grant;
+    }
+
+
+    /**
+     * Gets the precedence of this tuple (<tt>0</tt>-<tt>255</tt>).
+     *
+     * @return the precedence
+     */
+    public Integer getPrecedence()
+    {
+        return precedence;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "ACITuple: userClasses=" + userClasses + ", " + "authenticationLevel=" + authenticationLevel + ", "
+            + "protectedItems=" + protectedItems + ", " + ( grant ? "grants=" : "denials=" ) + microOperations + ", "
+            + "precedence=" + precedence;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/GrantAndDenial.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/GrantAndDenial.java
new file mode 100644
index 0000000..0209712
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/GrantAndDenial.java
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+/**
+ * An enumeration that represents grants or denials of {@link MicroOperation}s.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum GrantAndDenial
+{
+    // Permissions that may be used in conjunction with any component of
+    // <tt>ProtectedItem</tt>s.
+    /** Grant for {@link MicroOperation#ADD} */
+    GRANT_ADD(MicroOperation.ADD, 0, true),
+
+    /** Denial for {@link MicroOperation#ADD} */
+    DENY_ADD(MicroOperation.ADD, 1, false),
+
+    /** Grant for {@link MicroOperation#DISCLOSE_ON_ERROR} */
+    GRANT_DISCLOSE_ON_ERROR(MicroOperation.DISCLOSE_ON_ERROR, 2, true),
+
+    /** Denial for {@link MicroOperation#DISCLOSE_ON_ERROR} */
+    DENY_DISCLOSE_ON_ERROR(MicroOperation.DISCLOSE_ON_ERROR, 3, false),
+
+    /** Grant for {@link MicroOperation#READ} */
+    GRANT_READ(MicroOperation.READ, 4, true),
+
+    /** Denial for {@link MicroOperation#READ} */
+    DENY_READ(MicroOperation.READ, 5, false),
+
+    /** Grant for {@link MicroOperation#REMOVE} */
+    GRANT_REMOVE(MicroOperation.REMOVE, 6, true),
+
+    /** Denial for {@link MicroOperation#REMOVE} */
+    DENY_REMOVE(MicroOperation.REMOVE, 7, false),
+
+    // Permissions that may be used only in conjunction with the entry
+    // component.
+    /** Grant for {@link MicroOperation#BROWSE} */
+    GRANT_BROWSE(MicroOperation.BROWSE, 8, true),
+
+    /** Denial for {@link MicroOperation#BROWSE} */
+    DENY_BROWSE(MicroOperation.BROWSE, 9, false),
+
+    /** Grant for {@link MicroOperation#EXPORT} */
+    GRANT_EXPORT(MicroOperation.EXPORT, 10, true),
+
+    /** Denial for {@link MicroOperation#EXPORT} */
+    DENY_EXPORT(MicroOperation.EXPORT, 11, false),
+
+    /** Grant for {@link MicroOperation#IMPORT} */
+    GRANT_IMPORT(MicroOperation.IMPORT, 12, true),
+
+    /** Denial for {@link MicroOperation#IMPORT} */
+    DENY_IMPORT(MicroOperation.IMPORT, 13, false),
+
+    /** Grant for {@link MicroOperation#MODIFY} */
+    GRANT_MODIFY(MicroOperation.MODIFY, 14, true),
+
+    /** Denial for {@link MicroOperation#MODIFY} */
+    DENY_MODIFY(MicroOperation.MODIFY, 15, false),
+
+    /** Grant for {@link MicroOperation#RENAME} */
+    GRANT_RENAME(MicroOperation.RENAME, 16, true),
+
+    /** Denial for {@link MicroOperation#RENAME} */
+    DENY_RENAME(MicroOperation.RENAME, 17, false),
+
+    /** Grant for {@link MicroOperation#RETURN_DN} */
+    GRANT_RETURN_DN(MicroOperation.RETURN_DN, 18, true),
+
+    /** Denial for {@link MicroOperation#RETURN_DN} */
+    DENY_RETURN_DN(MicroOperation.RETURN_DN, 19, false),
+
+    // Permissions that may be used in conjunction with any component,
+    // except entry, of <tt>ProtectedItem</tt>s.
+    /** Grant for {@link MicroOperation#COMPARE} */
+    GRANT_COMPARE(MicroOperation.COMPARE, 20, true),
+
+    /** Deny for {@link MicroOperation#COMPARE} */
+    DENY_COMPARE(MicroOperation.COMPARE, 21, false),
+
+    /** Grant for {@link MicroOperation#FILTER_MATCH} */
+    GRANT_FILTER_MATCH(MicroOperation.FILTER_MATCH, 22, true),
+
+    /** Denial for {@link MicroOperation#FILTER_MATCH} */
+    DENY_FILTER_MATCH(MicroOperation.FILTER_MATCH, 23, false),
+
+    /** Grant for {@link MicroOperation#INVOKE} */
+    GRANT_INVOKE(MicroOperation.INVOKE, 24, true),
+
+    /** Denial for {@link MicroOperation#INVOKE} */
+    DENY_INVOKE(MicroOperation.INVOKE, 25, false);
+
+    /** The micro operation. */
+    private final MicroOperation microOperation;
+
+    /** The code number. */
+    private final int code;
+
+    /** The name. */
+    private final String name;
+
+    /** The grant flag. */
+    private final boolean grant;
+
+
+    private GrantAndDenial( MicroOperation microOperation, int code, boolean grant )
+    {
+        this.microOperation = microOperation;
+        this.code = code;
+        this.name = ( grant ? "grant" : "deny" ) + microOperation.getName();
+        this.grant = grant;
+    }
+
+
+    /**
+     * Gets the {@link MicroOperation} related with this grant or denial.
+     *
+     * @return the micro operation
+     */
+    public MicroOperation getMicroOperation()
+    {
+        return microOperation;
+    }
+
+
+    /**
+     * Gets the code number of this grant or denial.
+     *
+     * @return the code number
+     */
+    public int getCode()
+    {
+        return code;
+    }
+
+
+    /**
+     * Gets the name of this grant or denial.
+     *
+     * @return the name
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * Returns <tt>true</tt> if and only if this is grant.
+     *
+     * @return <tt>true</tt> if and only if this is grant
+     */
+    public boolean isGrant()
+    {
+        return grant;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return name;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ItemFirstACIItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ItemFirstACIItem.java
new file mode 100644
index 0000000..bfbf6a4
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ItemFirstACIItem.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
+
+
+/**
+ * An {@link ACIItem} which specifies {@link ProtectedItem}s first and then
+ * {@link UserClass}es each {@link ProtectedItem} will have. (18.4.2.4. X.501)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ItemFirstACIItem extends ACIItem
+{
+    /** The list of protected items ( userClasses or userPermissions ) */
+    private final Collection<ProtectedItem> protectedItems;
+
+    /** The associated permissions */
+    private final Collection<ItemPermission> itemPermissions;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param identificationTag the id string of this item
+     * @param precedence the precedence of this item
+     * @param authenticationLevel the level of authentication required to this item
+     * @param protectedItems the collection of {@link ProtectedItem}s this item protects
+     * @param itemPermissions the collection of {@link ItemPermission}s each <tt>protectedItems</tt> will have
+     */
+    public ItemFirstACIItem( String identificationTag, int precedence, AuthenticationLevel authenticationLevel,
+        Collection<ProtectedItem> protectedItems, Collection<ItemPermission> itemPermissions )
+    {
+        super( identificationTag, precedence, authenticationLevel );
+
+        this.protectedItems = Collections.unmodifiableCollection( new ArrayList<ProtectedItem>( protectedItems ) );
+        this.itemPermissions = Collections.unmodifiableCollection( new ArrayList<ItemPermission>( itemPermissions ) );
+    }
+
+
+    /**
+     * Gets the collection of {@link ProtectedItem}s.
+     *
+     * @return the collection of {@link ProtectedItem}s
+     */
+    public Collection<ProtectedItem> getProtectedItems()
+    {
+        return protectedItems;
+    }
+
+
+    /**
+     * Gets the collection of {@link ItemPermission}s.
+     *
+     * @return the collection of {@link ItemPermission}s
+     */
+    public Collection<ItemPermission> getItemPermissions()
+    {
+        return itemPermissions;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "{" );
+        buf.append( super.toString() );
+
+        // itemOrUserFirst
+        buf.append( ", itemOrUserFirst itemFirst: { " );
+
+        // protectedItems
+        buf.append( "protectedItems { " );
+
+        boolean isFirst = true;
+
+        for ( ProtectedItem item : protectedItems )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( item.toString() );
+        }
+
+        // itemPermissions
+        buf.append( " }, itemPermissions { " );
+
+        isFirst = true;
+
+        for ( ItemPermission permission : itemPermissions )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( permission.toString() );
+        }
+
+        buf.append( " } } }" );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Transform this protected Item and permissions to a set of Tuples
+     * 
+     * @return The list of created Tuples
+     */
+    public Collection<ACITuple> toTuples()
+    {
+        Collection<ACITuple> tuples = new ArrayList<ACITuple>();
+
+        for ( ItemPermission itemPermission : itemPermissions )
+        {
+            Set<GrantAndDenial> grants = itemPermission.getGrants();
+            Set<GrantAndDenial> denials = itemPermission.getDenials();
+            int precedence = itemPermission.getPrecedence() != null
+                ? itemPermission.getPrecedence()
+                : this.getPrecedence();
+
+            if ( grants.size() > 0 )
+            {
+                tuples.add( new ACITuple( itemPermission.getUserClasses(), getAuthenticationLevel(), protectedItems,
+                    toMicroOperations( grants ), true, precedence ) );
+            }
+
+            if ( denials.size() > 0 )
+            {
+                tuples.add( new ACITuple( itemPermission.getUserClasses(), getAuthenticationLevel(), protectedItems,
+                    toMicroOperations( denials ), false, precedence ) );
+            }
+        }
+
+        return tuples;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ItemPermission.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ItemPermission.java
new file mode 100644
index 0000000..f8d46e5
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ItemPermission.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+
+/**
+ * Represents permissions to be applied to all {@link ProtectedItem}s in
+ * {@link ItemFirstACIItem}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ItemPermission extends Permission
+{
+    /** The user classes. */
+    private final Collection<UserClass> userClasses;
+
+
+    /**
+     * Creates a new instance
+     * 
+     * @param precedence
+     *            the precedence of this permission (<tt>-1</tt> to use the
+     *            default)
+     * @param grantsAndDenials
+     *            the collection of {@link GrantAndDenial}s
+     * @param userClasses
+     *            the collection of {@link UserClass}es
+     */
+    public ItemPermission( Integer precedence, Collection<GrantAndDenial> grantsAndDenials,
+        Collection<UserClass> userClasses )
+    {
+        super( precedence, grantsAndDenials );
+
+        this.userClasses = Collections.unmodifiableCollection( new ArrayList<UserClass>( userClasses ) );
+    }
+
+
+    /**
+     * Gets the collection of {@link UserClass}es.
+     *
+     * @return the collection of {@link UserClass}es
+     */
+    public Collection<UserClass> getUserClasses()
+    {
+        return userClasses;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buffer = new StringBuilder();
+
+        buffer.append( "{ " );
+
+        if ( getPrecedence() != null )
+        {
+            buffer.append( "precedence " );
+            buffer.append( getPrecedence() );
+            buffer.append( ", " );
+        }
+
+        buffer.append( "userClasses { " );
+
+        boolean isFirst = true;
+
+        for ( UserClass userClass : userClasses )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buffer.append( ", " );
+            }
+
+            buffer.append( userClass.toString() );
+        }
+
+        buffer.append( " }, grantsAndDenials { " );
+
+        isFirst = true;
+
+        for ( GrantAndDenial grantAndDenial : getGrantsAndDenials() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buffer.append( ", " );
+            }
+
+            buffer.append( grantAndDenial.toString() );
+        }
+
+        buffer.append( " } }" );
+
+        return buffer.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/MicroOperation.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/MicroOperation.java
new file mode 100644
index 0000000..1663957
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/MicroOperation.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+/**
+ * An enumeration that represents all micro-operations that makes up LDAP
+ * operations.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum MicroOperation
+{
+    // Permissions that may be used in conjunction with any component of <tt>ProtectedItem</tt>s.
+    /** The Add permission, may be used in conjunction with any component of {@link ProtectedItem}s. */
+    ADD("Add"),
+
+    /** The DiscloseOnError permission, may be used in conjunction with any component of {@link ProtectedItem}s. */
+    DISCLOSE_ON_ERROR("DiscloseOnError"),
+
+    /** The Read permission, may be used in conjunction with any component of {@link ProtectedItem}s. */
+    READ("Read"),
+
+    /** The Remove permission, may be used in conjunction with any component of {@link ProtectedItem}s. */
+    REMOVE("Remove"),
+
+    // Permissions that may be used only in conjunction with the entry component.
+    /** The Browse permission, may be used only in conjunction with the entry component. */
+    BROWSE("Browse"),
+
+    /** The Export permission, may be used only in conjunction with the entry component. */
+    EXPORT("Export"),
+
+    /** The Import permission, may be used only in conjunction with the entry component. */
+    IMPORT("Import"),
+
+    /** The Modify permission, may be used only in conjunction with the entry component. */
+    MODIFY("Modify"),
+
+    /** The Rename permission, may be used only in conjunction with the entry component. */
+    RENAME("Rename"),
+
+    /** The ReturnDN permission, may be used only in conjunction with the entry component. */
+    RETURN_DN("ReturnDN"),
+
+    // Permissions that may be used in conjunction with any component, except entry, of <tt>ProtectedItem</tt>s.
+    /** The Compare permission, may be used in conjunction with any component, except entry. */
+    COMPARE("Compare"),
+
+    /** The FilterMatch permission, may be used in conjunction with any component, except entry. */
+    FILTER_MATCH("FilterMatch"),
+
+    /** The Invoke permission, may be used in conjunction with any component, except entry. */
+    INVOKE("Invoke");
+
+    /** The name. */
+    private final String name;
+
+
+    private MicroOperation( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Gets the name of this micro-operation.
+     *
+     * @return the name
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return name;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/Permission.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/Permission.java
new file mode 100644
index 0000000..1cb3903
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/Permission.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+
+/**
+ * An abstract base class for {@link ItemPermission} and {@link UserPermission}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class Permission
+{
+    /** The precedence. */
+    private final Integer precedence;
+
+    /** The grants and denials. */
+    private final Set<GrantAndDenial> grantsAndDenials;
+
+    /** The grants. */
+    private final Set<GrantAndDenial> grants;
+
+    /** The denials. */
+    private final Set<GrantAndDenial> denials;
+
+
+    /**
+     * Creates a new instance
+     * 
+     * @param precedence
+     *            the precedence of this permission (<tt>-1</tt> to use the
+     *            default)
+     * @param grantsAndDenials
+     *            the set of {@link GrantAndDenial}s
+     */
+    protected Permission( Integer precedence, Collection<GrantAndDenial> grantsAndDenials )
+    {
+        this.precedence = precedence;
+
+        Set<GrantAndDenial> tmpGrantsAndDenials = new HashSet<GrantAndDenial>();
+        Set<GrantAndDenial> tmpGrants = new HashSet<GrantAndDenial>();
+        Set<GrantAndDenial> tmpDenials = new HashSet<GrantAndDenial>();
+
+        for ( GrantAndDenial gad : grantsAndDenials )
+        {
+            if ( gad.isGrant() )
+            {
+                tmpGrants.add( gad );
+            }
+            else
+            {
+                tmpDenials.add( gad );
+            }
+
+            tmpGrantsAndDenials.add( gad );
+        }
+
+        this.grants = Collections.unmodifiableSet( tmpGrants );
+        this.denials = Collections.unmodifiableSet( tmpDenials );
+        this.grantsAndDenials = Collections.unmodifiableSet( tmpGrantsAndDenials );
+    }
+
+
+    /**
+     * Gets the precedence of this permission.
+     *
+     * @return the precedence
+     */
+    public Integer getPrecedence()
+    {
+        return precedence;
+    }
+
+
+    /**
+     * Gets the set of {@link GrantAndDenial}s.
+     *
+     * @return the grants and denials
+     */
+    public Set<GrantAndDenial> getGrantsAndDenials()
+    {
+        return grantsAndDenials;
+    }
+
+
+    /**
+     * Gets the set of grants only.
+     *
+     * @return the grants
+     */
+    public Set<GrantAndDenial> getGrants()
+    {
+        return grants;
+    }
+
+
+    /**
+     * Gets the set of denials only.
+     *
+     * @return the denials
+     */
+    public Set<GrantAndDenial> getDenials()
+    {
+        return denials;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ProtectedItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ProtectedItem.java
new file mode 100644
index 0000000..65e330f
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ProtectedItem.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import org.apache.directory.api.ldap.aci.protectedItem.AllUserAttributeTypesAndValuesItem;
+import org.apache.directory.api.ldap.aci.protectedItem.AllUserAttributeTypesItem;
+import org.apache.directory.api.ldap.aci.protectedItem.EntryItem;
+
+
+/**
+ * Defines the items to which the access controls apply.  It's one of the
+ * following elements :
+ * <ul>
+ * <li>AllAttributeValuesItem</li>
+ * <li>AllUserAttributeTypesAndValuesItem</li>
+ * <li>AllUserAttributeTypesItem</li>
+ * <li>AttributeTypeItem</li>
+ * <li>AttributeValueItem</li>
+ * <li>ClassesItem</li>
+ * <li>EntryItem</li>
+ * <li>MaxImmSubItem</li>
+ * <li>MaxValueCountItem</li>
+ * <li>RangeOfValuesItem</li>
+ * <li>RestrictedByItem</li>
+ * <li>SelfValueItem</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class ProtectedItem
+{
+    /**
+     * The entry contents as a whole. In case of a family member, it also means
+     * the entry content of each subordinate family member within the same
+     * compound attribute. It does not necessarily include the information in
+     * these entries. This element shall be ignored if the classes element is
+     * present, since this latter element selects protected entries (and
+     * subordinate family members) on the basis of their object class.
+     */
+    public static final EntryItem ENTRY = new EntryItem();
+
+    /**
+     * All user attribute type information associated with the entry, but not
+     * values associated with those attributes.
+     */
+    public static final AllUserAttributeTypesItem ALL_USER_ATTRIBUTE_TYPES = new AllUserAttributeTypesItem();
+
+    /**
+     * All user attribute information associated with the entry, including all
+     * values of all user attributes.
+     */
+    public static final AllUserAttributeTypesAndValuesItem ALL_USER_ATTRIBUTE_TYPES_AND_VALUES = new AllUserAttributeTypesAndValuesItem();
+
+
+    /**
+     * Creates a new instance.
+     */
+    protected ProtectedItem()
+    {
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemChecker.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemChecker.java
new file mode 100644
index 0000000..cbbec61
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemChecker.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr parser without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrACIItemChecker extends AntlrACIItemChecker
+{
+    /**
+     * Creates a ReusableAntlrACIItemChecker instance.
+     */
+    public ReusableAntlrACIItemChecker( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+
+        this.getInputState().reset();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemCheckerLexer.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemCheckerLexer.java
new file mode 100644
index 0000000..2509e08
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemCheckerLexer.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import java.io.Reader;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+
+
+/**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr lexer without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrACIItemCheckerLexer extends AntlrACIItemCheckerLexer
+{
+
+    /** The saved case sensitive flag. */
+    private boolean savedCaseSensitive;
+
+    /** The saved case sensitive literals flag. */
+    private boolean savedCaseSensitiveLiterals;
+
+
+    /**
+     * Creates a ReusableAntlrACIItemCheckerLexer instance.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public ReusableAntlrACIItemCheckerLexer( Reader in )
+    {
+        super( in );
+        savedCaseSensitive = getCaseSensitive();
+        savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+    }
+
+
+    /**
+     * Resets the state of an antlr lexer and initializes it with new input.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public void prepareNextInput( Reader in )
+    {
+        CharBuffer buf = new CharBuffer( in );
+        LexerSharedInputState state = new LexerSharedInputState( buf );
+        this.setInputState( state );
+
+        this.setCaseSensitive( savedCaseSensitive );
+
+        // no set method for this protected field.
+        this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemLexer.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemLexer.java
new file mode 100644
index 0000000..77a0b49
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemLexer.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import java.io.Reader;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+
+
+/**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr lexer without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrACIItemLexer extends AntlrACIItemLexer
+{
+
+    /** The saved case sensitive flag. */
+    private boolean savedCaseSensitive;
+
+    /** The saved case sensitive literals flag. */
+    private boolean savedCaseSensitiveLiterals;
+
+
+    /**
+     * Creates a ReusableAntlrSubtreeSpecificationLexer instance.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public ReusableAntlrACIItemLexer( Reader in )
+    {
+        super( in );
+        savedCaseSensitive = getCaseSensitive();
+        savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+    }
+
+
+    /**
+     * Resets the state of an antlr lexer and initializes it with new input.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public void prepareNextInput( Reader in )
+    {
+        CharBuffer buf = new CharBuffer( in );
+        LexerSharedInputState state = new LexerSharedInputState( buf );
+        this.setInputState( state );
+
+        this.setCaseSensitive( savedCaseSensitive );
+
+        // no set method for this protected field.
+        this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemParser.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemParser.java
new file mode 100644
index 0000000..9dccaf0
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/ReusableAntlrACIItemParser.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.aci;
+
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr parser without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrACIItemParser extends AntlrACIItemParser
+{
+    /**
+     * Creates a ReusableAntlrSubtreeSpecificationParser instance.
+     */
+    public ReusableAntlrACIItemParser( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+
+        this.getInputState().reset();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserClass.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserClass.java
new file mode 100644
index 0000000..21514c4
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserClass.java
@@ -0,0 +1,409 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification;
+
+
+/**
+ * Defines a set of zero or more users the permissions apply to.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class UserClass
+{
+    /**
+     * Every directory user (with possible requirements for
+     * authenticationLevel).
+     */
+    public static final AllUsers ALL_USERS = new AllUsers();
+
+    /**
+     * The user with the same distinguished name as the entry being accessed, or
+     * if the entry is a member of a family, then additionally the user with the
+     * distinguished name of the ancestor.
+     */
+    public static final ThisEntry THIS_ENTRY = new ThisEntry();
+
+    /**
+     * The user as parent (ancestor) of accessed entry.
+     */
+    public static final ParentOfEntry PARENT_OF_ENTRY = new ParentOfEntry();
+
+
+    /**
+     * Creates a new instance.
+     */
+    protected UserClass()
+    {
+    }
+    
+
+    /**
+     * Every directory user (with possible requirements for
+     * authenticationLevel).
+     */
+    public static final class AllUsers extends UserClass
+    {
+        /**
+         * Creates a new instance of AllUsers.
+         */
+        private AllUsers()
+        {
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString()
+        {
+            return "allUsers";
+        }
+    }
+    
+
+    /**
+     * The user with the same distinguished name as the entry being accessed, or
+     * if the entry is a member of a family, then additionally the user with the
+     * distinguished name of the ancestor.
+     */
+    public static final class ThisEntry extends UserClass
+    {
+        /**
+         * Creates a new instance of ThisEntry.
+         */
+        private ThisEntry()
+        {
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString()
+        {
+            return "thisEntry";
+        }
+    }
+    
+
+    /**
+     * The user as parent (ancestor) of accessed entry.
+     */
+    public static final class ParentOfEntry extends UserClass
+    {
+        /**
+         * Creates a new instance of ParentOfEntry.
+         */
+        private ParentOfEntry()
+        {
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString()
+        {
+            return "parentOfEntry";
+        }
+    }
+    
+
+    /**
+     * A base class for all user classes which has a set of DNs.
+     */
+    private abstract static class NamedUserClass extends UserClass
+    {
+        /** The names. */
+        protected final Set<Dn> names;
+
+
+        /**
+         * Creates a new instance.
+         * 
+         * @param names a set of names
+         */
+        protected NamedUserClass( Set<Dn> names )
+        {
+            if ( names == null )
+            {
+                this.names = Collections.unmodifiableSet( new HashSet<Dn>() );
+            }
+            else
+            {
+                this.names = Collections.unmodifiableSet( new HashSet<Dn>( names ) );
+            }
+        }
+
+
+        /**
+         * Returns the set of all names.
+         * 
+         * @return The set of all names
+         */
+        public Set<Dn> getNames()
+        {
+            return names;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean equals( Object o )
+        {
+            if ( this == o )
+            {
+                return true;
+            }
+
+            if ( o == null )
+            {
+                return false;
+            }
+
+            if ( getClass().isAssignableFrom( o.getClass() ) )
+            {
+                Name that = ( Name ) o;
+                
+                return names.equals( that.names );
+            }
+
+            return false;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int hashCode()
+        {
+            int result = 37;
+
+            for ( Dn dn : this.names )
+            {
+                result = result * 17 + dn.hashCode();
+            }
+
+            return result;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        public String toString()
+        {
+            StringBuilder buffer = new StringBuilder();
+
+            boolean isFirst = true;
+            buffer.append( "{ " );
+
+            for ( Dn name : names )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    buffer.append( ", " );
+                }
+
+                buffer.append( '"' );
+                buffer.append( name.toString() );
+                buffer.append( '"' );
+            }
+
+            buffer.append( " }" );
+
+            return buffer.toString();
+        }
+    }
+    
+
+    /**
+     * The user with the specified distinguished name.
+     */
+    public static class Name extends NamedUserClass
+    {
+        /**
+         * Creates a new instance.
+         * 
+         * @param usernames the set of user DNs.
+         */
+        public Name( Set<Dn> usernames )
+        {
+            super( usernames );
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString()
+        {
+            return "name " + super.toString();
+        }
+    }
+    
+
+    /**
+     * The set of users who are members of the groupOfUniqueNames entry,
+     * identified by the specified distinguished name. Members of a group of
+     * unique names are treated as individual object names, and not as the names
+     * of other groups of unique names.
+     */
+    public static class UserGroup extends NamedUserClass
+    {
+        /**
+         * Creates a new instance.
+         * 
+         * @param groupNames the set of group DNs.
+         */
+        public UserGroup( Set<Dn> groupNames )
+        {
+            super( groupNames );
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString()
+        {
+            return "userGroup " + super.toString();
+        }
+    }
+    
+
+    /**
+     * The set of users whose distinguished names fall within the definition of
+     * the (unrefined) subtree.
+     */
+    public static class Subtree extends UserClass
+    {
+        /** The subtree specifications. */
+        protected final Set<SubtreeSpecification> subtreeSpecifications;
+
+
+        /**
+         * Creates a new instance.
+         * 
+         * @param subtreeSpecs the collection of unrefined {@link SubtreeSpecification}s.
+         */
+        public Subtree( Set<SubtreeSpecification> subtreeSpecs )
+        {
+            subtreeSpecifications = Collections.unmodifiableSet( subtreeSpecs );
+        }
+
+
+        /**
+         * Returns the collection of unrefined {@link SubtreeSpecification}s.
+         *
+         * @return the subtree specifications
+         */
+        public Set<SubtreeSpecification> getSubtreeSpecifications()
+        {
+            return subtreeSpecifications;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int hashCode()
+        {
+            int hash = 37;
+            hash = hash * 17 + subtreeSpecifications.hashCode();
+
+            return hash;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean equals( Object o )
+        {
+            if ( this == o )
+            {
+                return true;
+            }
+
+            if ( o instanceof Subtree )
+            {
+                Subtree that = ( Subtree ) o;
+                
+                return subtreeSpecifications.equals( that.subtreeSpecifications );
+            }
+
+            return false;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public String toString()
+        {
+            StringBuilder buffer = new StringBuilder();
+
+            boolean isFirst = true;
+            buffer.append( "subtree { " );
+
+            for ( SubtreeSpecification ss : subtreeSpecifications )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    buffer.append( ", " );
+                }
+
+                ss.toString( buffer );
+            }
+
+            buffer.append( " }" );
+
+            return buffer.toString();
+        }
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserFirstACIItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserFirstACIItem.java
new file mode 100644
index 0000000..040757a
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserFirstACIItem.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
+
+
+/**
+ * An {@link ACIItem} which specifies {@link UserClass}es first and then
+ * {@link ProtectedItem}s each {@link UserClass} will have. (18.4.2.4. X.501)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UserFirstACIItem extends ACIItem
+{
+    /** The user classes. */
+    private final Collection<UserClass> userClasses;
+
+    /** The user permissions. */
+    private final Collection<UserPermission> userPermissions;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param identificationTag
+     *            the id string of this item
+     * @param precedence
+     *            the precedence of this item
+     * @param authenticationLevel
+     *            the level of authentication required to this item
+     * @param userClasses
+     *            the collection of {@link UserClass}es this item protects
+     * @param userPermissions
+     *            the collection of {@link UserPermission}s each
+     *            <tt>protectedItems</tt> will have
+     */
+    public UserFirstACIItem( String identificationTag, int precedence, AuthenticationLevel authenticationLevel,
+        Collection<UserClass> userClasses, Collection<UserPermission> userPermissions )
+    {
+        super( identificationTag, precedence, authenticationLevel );
+
+        this.userClasses = Collections.unmodifiableCollection( new ArrayList<UserClass>( userClasses ) );
+        this.userPermissions = Collections.unmodifiableCollection( new ArrayList<UserPermission>( userPermissions ) );
+    }
+
+
+    /**
+     * Gets the collection of {@link UserClass}es.
+     *
+     * @return the collection of {@link UserClass}es
+     */
+    public Collection<UserClass> getUserClasses()
+    {
+        return userClasses;
+    }
+
+
+    /**
+     * Gets the collection of {@link UserPermission}s.
+     *
+     * @return the collection of {@link UserPermission}s
+     */
+    public Collection<UserPermission> getUserPermission()
+    {
+        return userPermissions;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        // identificationTag
+        buf.append( "{ identificationTag \"" );
+        buf.append( getIdentificationTag() );
+        buf.append( "\", " );
+
+        // precedence
+        buf.append( "precedence " );
+        buf.append( getPrecedence() );
+        buf.append( ", " );
+
+        // authenticationLevel
+        buf.append( "authenticationLevel " );
+        buf.append( getAuthenticationLevel().getName() );
+        buf.append( ", " );
+
+        // itemOrUserFirst
+        buf.append( "itemOrUserFirst userFirst: { " );
+
+        // protectedItems
+        buf.append( "userClasses { " );
+
+        boolean isFirst = true;
+
+        for ( UserClass userClass : userClasses )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( userClass.toString() );
+        }
+
+        buf.append( " }, " );
+
+        // itemPermissions
+        buf.append( "userPermissions { " );
+
+        isFirst = true;
+
+        for ( UserPermission permission : userPermissions )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( permission.toString() );
+        }
+
+        buf.append( " } } }" );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<ACITuple> toTuples()
+    {
+        Collection<ACITuple> tuples = new ArrayList<ACITuple>();
+
+        for ( UserPermission userPermission : userPermissions )
+        {
+            Set<GrantAndDenial> grants = userPermission.getGrants();
+            Set<GrantAndDenial> denials = userPermission.getDenials();
+            int precedence = userPermission.getPrecedence() != null
+                ? userPermission.getPrecedence()
+                : this.getPrecedence();
+
+            if ( grants.size() > 0 )
+            {
+                tuples.add( new ACITuple( getUserClasses(), getAuthenticationLevel(), userPermission
+                    .getProtectedItems(), toMicroOperations( grants ), true, precedence ) );
+            }
+            if ( denials.size() > 0 )
+            {
+                tuples.add( new ACITuple( getUserClasses(), getAuthenticationLevel(), userPermission
+                    .getProtectedItems(), toMicroOperations( denials ), false, precedence ) );
+            }
+        }
+        return tuples;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserPermission.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserPermission.java
new file mode 100644
index 0000000..9eedfb5
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/UserPermission.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import java.util.Collection;
+import java.util.Collections;
+
+
+/**
+ * Represents permissions to be applied to all {@link UserClass}es in
+ * {@link UserFirstACIItem}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UserPermission extends Permission
+{
+    /** The protected items. */
+    private final Collection<ProtectedItem> protectedItems;
+
+
+    /**
+     * Creates a new instance
+     * 
+     * @param precedence
+     *            the precedence of this permission (<tt>-1</tt> to use the
+     *            default)
+     * @param grantsAndDenials
+     *            the set of {@link GrantAndDenial}s
+     * @param protectedItems
+     *            the collection of {@link ProtectedItem}s
+     */
+    public UserPermission( Integer precedence, Collection<GrantAndDenial> grantsAndDenials,
+        Collection<ProtectedItem> protectedItems )
+    {
+        super( precedence, grantsAndDenials );
+
+        this.protectedItems = Collections.unmodifiableCollection( protectedItems );
+    }
+
+
+    /**
+     * Gets the collection of {@link ProtectedItem}s.
+     *
+     * @return the collection of {@link ProtectedItem}s
+     */
+    public Collection<ProtectedItem> getProtectedItems()
+    {
+        return protectedItems;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "{ " );
+
+        if ( getPrecedence() != null )
+        {
+            buf.append( "precedence " );
+            buf.append( getPrecedence() );
+            buf.append( ", " );
+        }
+
+        buf.append( "protectedItems { " );
+
+        boolean isFirst = true;
+
+        for ( ProtectedItem item : protectedItems )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( item.toString() );
+        }
+
+        buf.append( " }, grantsAndDenials { " );
+
+        isFirst = true;
+
+        for ( GrantAndDenial grantAndDenial : getGrantsAndDenials() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( grantAndDenial.toString() );
+        }
+
+        buf.append( " } }" );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AbstractAttributeTypeProtectedItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AbstractAttributeTypeProtectedItem.java
new file mode 100644
index 0000000..edcd323
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AbstractAttributeTypeProtectedItem.java
@@ -0,0 +1,129 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * A base class for all items which protects attribute types (or its values)
+ */
+public abstract class AbstractAttributeTypeProtectedItem extends ProtectedItem
+{
+    /** The attribute types. */
+    protected final Set<AttributeType> attributeTypes;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param attributeTypes the collection of attribute IDs
+     */
+    protected AbstractAttributeTypeProtectedItem( Set<AttributeType> attributeTypes )
+    {
+        this.attributeTypes = Collections.unmodifiableSet( attributeTypes );
+    }
+
+
+    /**
+     * Gets an iterator of all attribute types.
+     *
+     * @return the iterator of all attribute types
+     */
+    public Iterator<AttributeType> iterator()
+    {
+        return attributeTypes.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + attributeTypes.hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( getClass().isAssignableFrom( o.getClass() ) )
+        {
+            AbstractAttributeTypeProtectedItem that = ( AbstractAttributeTypeProtectedItem ) o;
+            return this.attributeTypes.equals( that.attributeTypes );
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "{ " );
+        boolean isFirst = true;
+
+        for ( AttributeType attributeType : attributeTypes )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( attributeType.getName() );
+        }
+
+        buf.append( " }" );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllAttributeValuesItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllAttributeValuesItem.java
new file mode 100644
index 0000000..fe48b78
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllAttributeValuesItem.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * All attribute value information pertaining to specific attributes.
+ */
+public class AllAttributeValuesItem extends AbstractAttributeTypeProtectedItem
+{
+    /**
+     * Creates a new instance.
+     * 
+     * @param attributeTypes the collection of attribute IDs.
+     */
+    public AllAttributeValuesItem( Set<AttributeType> attributeTypes )
+    {
+        super( attributeTypes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "allAttributeValues " + super.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllUserAttributeTypesAndValuesItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllUserAttributeTypesAndValuesItem.java
new file mode 100644
index 0000000..1e074f4
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllUserAttributeTypesAndValuesItem.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+
+
+/**
+ * All user attribute information associated with the entry, including all
+ * values of all user attributes.
+ */
+public class AllUserAttributeTypesAndValuesItem extends ProtectedItem
+{
+    /**
+     * Creates a new instance of AllUserAttributeTypesAndValuesItem.
+     */
+    public AllUserAttributeTypesAndValuesItem()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "allUserAttributeTypesAndValues";
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllUserAttributeTypesItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllUserAttributeTypesItem.java
new file mode 100644
index 0000000..94d9be2
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AllUserAttributeTypesItem.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+
+
+/**
+ * All user attribute type information associated with the entry, but not
+ * values associated with those attributes.
+ */
+public class AllUserAttributeTypesItem extends ProtectedItem
+{
+    /**
+     * Creates a new instance of AllUserAttributeTypesItem.
+     */
+    public AllUserAttributeTypesItem()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "allUserAttributeTypes";
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeTypeItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeTypeItem.java
new file mode 100644
index 0000000..e83f491
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeTypeItem.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * Attribute type information pertaining to specific attributes but not
+ * values associated with the type.
+ */
+public class AttributeTypeItem extends AbstractAttributeTypeProtectedItem
+{
+    /**
+     * Creates a new instance.
+     * 
+     * @param attributeTypes the collection of attribute IDs.
+     */
+    public AttributeTypeItem( Set<AttributeType> attributeTypes )
+    {
+        super( attributeTypes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "attributeType " + super.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeValueItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeValueItem.java
new file mode 100644
index 0000000..dd3a918
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeValueItem.java
@@ -0,0 +1,132 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+
+
+/**
+ * A specific value of specific attributes.
+ */
+public class AttributeValueItem extends ProtectedItem
+{
+    /** The protected Attributes */
+    private final Set<Attribute> attributes;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param attributes the collection of {@link Attribute}s.
+     */
+    public AttributeValueItem( Set<Attribute> attributes )
+    {
+        this.attributes = Collections.unmodifiableSet( attributes );
+    }
+
+
+    /**
+     * Returns an iterator of all {@link org.apache.directory.api.ldap.model.entry.Attribute}s.
+     *
+     * @return the iterator
+     */
+    public Iterator<Attribute> iterator()
+    {
+        return attributes.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + attributes.hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( o instanceof AttributeValueItem )
+        {
+            AttributeValueItem that = ( AttributeValueItem ) o;
+
+            return this.attributes.equals( that.attributes );
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "attributeValue {" );
+
+        boolean isFirst = true;
+
+        for ( Attribute attribute : attributes )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( attribute.getId() );
+            buf.append( '=' );
+            buf.append( attribute.get() );
+        }
+
+        buf.append( " }" );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/ClassesItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/ClassesItem.java
new file mode 100644
index 0000000..4829642
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/ClassesItem.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+
+
+/**
+ * The contents of entries (possibly a family member) which are restricted
+ * to those that have object class values that satisfy the predicate defined
+ * by Refinement (see 12.3.5), together (in the case of an ancestor or other
+ * family member) with the entry contents as a whole of each subordinate
+ * family member entry; it does not necessarily include the information in
+ * these entries.
+ */
+public class ClassesItem extends ProtectedItem
+{
+    /** The classes refinement. */
+    private final ExprNode classes;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param classes refinement
+     */
+    public ClassesItem( ExprNode classes )
+    {
+        this.classes = classes;
+    }
+
+
+    /**
+     * Gets the classes refinement.
+     *
+     * @return the classes refinement
+     */
+    public ExprNode getClasses()
+    {
+        return classes;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + getClass().getName().hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o instanceof ClassesItem )
+        {
+            ClassesItem that = ( ClassesItem ) o;
+            return this.classes.equals( that.classes );
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "classes " );
+        classes.printRefinementToBuffer( buf );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/EntryItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/EntryItem.java
new file mode 100644
index 0000000..a0b3294
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/EntryItem.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+
+
+/**
+ * The entry contents as a whole. In case of a family member, it also means
+ * the entry content of each subordinate family member within the same
+ * compound attribute. It does not necessarily include the information in
+ * these entries. This element shall be ignored if the classes element is
+ * present, since this latter element selects protected entries (and
+ * subordinate family members) on the basis of their object class.
+ */
+public class EntryItem extends ProtectedItem
+{
+    /**
+     * Creates a new instance of EntryItem.
+     */
+    public EntryItem()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "entry";
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxImmSubItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxImmSubItem.java
new file mode 100644
index 0000000..183c83f
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxImmSubItem.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+
+
+/**
+ * Restricts the maximum number of immediate subordinates of the superior
+ * entry to an entry being added or imported. It is examined if the
+ * protected item is an entry, the permission sought is add or import, and
+ * the immediate superior entry is in the same DSA as the entry being added
+ * or imported. Immediate subordinates of the superior entry are counted
+ * without regard to context or access control as though the entry addition
+ * or importing were successful. If the number of subordinates exceeds
+ * maxImmSub, the ACI item is treated as not granting add or import access.
+ */
+public class MaxImmSubItem extends ProtectedItem
+{
+    /** The maximum number of allowed subordinates */
+    private final int value;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param value The maximum number of immediate subordinates
+     */
+    public MaxImmSubItem( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * Gets the maximum number of immediate subordinates.
+     *
+     * @return the maximum number of immediate subordinates
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + value;
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o instanceof MaxImmSubItem )
+        {
+            MaxImmSubItem that = ( MaxImmSubItem ) o;
+            return this.value == that.value;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "maxImmSub " + value;
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountElem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountElem.java
new file mode 100644
index 0000000..85c9ada
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountElem.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * An element of {@link MaxValueCount}.
+ */
+public class MaxValueCountElem
+{
+    /** The targeted AttributeType */
+    private AttributeType attributeType;
+
+    /** The maximum number of accepted values for this attributeType */
+    private int maxCount;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param attributeType the attribute ID to limit the maximum count
+     * @param maxCount the maximum count of the attribute allowed
+     */
+
+    public MaxValueCountElem( AttributeType attributeType, int maxCount )
+    {
+        this.attributeType = attributeType;
+        this.maxCount = maxCount;
+    }
+
+
+    /**
+     * Gets the attribute to limit the maximum count.
+     *
+     * @return the attribute type
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    /**
+     * Gets the maximum count of the attribute allowed.
+     *
+     * @return the maximum count of the attribute allowed
+     */
+    public int getMaxCount()
+    {
+        return maxCount;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + maxCount;
+        hash = hash * 17 + attributeType.hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o instanceof MaxValueCountElem )
+        {
+            MaxValueCountElem that = ( MaxValueCountElem ) o;
+            if ( this.maxCount == that.maxCount )
+            {
+                if ( this.attributeType == null )
+                {
+                    return that.attributeType == null;
+                }
+                else
+                {
+                    return this.attributeType.equals( that.attributeType );
+                }
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "{ type " + attributeType.getName() + ", maxCount " + maxCount + " }";
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountItem.java
new file mode 100644
index 0000000..79b04ea
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountItem.java
@@ -0,0 +1,135 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+
+
+/**
+ * Restricts the maximum number of attribute values allowed for a specified
+ * attribute type. It is examined if the protected item is an attribute
+ * value of the specified type and the permission sought is add. Values of
+ * that attribute in the entry are counted without regard to context or
+ * access control and as though the operation which adds the values were
+ * successful. If the number of values in the attribute exceeds maxCount,
+ * the ACI item is treated as not granting add access.
+ */
+public class MaxValueCountItem extends ProtectedItem
+{
+    /** The set of elements to protect */
+    private final Set<MaxValueCountElem> items;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param items the collection of {@link MaxValueCountElem}s.
+     */
+    public MaxValueCountItem( Set<MaxValueCountElem> items )
+    {
+        this.items = Collections.unmodifiableSet( items );
+    }
+
+
+    /**
+     * Gets an iterator of all {@link MaxValueCountElem}s.
+     *
+     * @return an iterator of all {@link MaxValueCountElem}s
+     */
+    public Iterator<MaxValueCountElem> iterator()
+    {
+        return items.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + items.hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( o instanceof MaxValueCountItem )
+        {
+            MaxValueCountItem that = ( MaxValueCountItem ) o;
+            return this.items.equals( that.items );
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "maxValueCount {" );
+
+        boolean isFirst = true;
+
+        for ( MaxValueCountElem item : items )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( item.toString() );
+        }
+
+        buf.append( "}" );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RangeOfValuesItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RangeOfValuesItem.java
new file mode 100644
index 0000000..de1a0a3
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RangeOfValuesItem.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+
+
+/**
+ * Any attribute value which matches the specified filter, i.e. for which
+ * the specified filter evaluated on that attribute value would return TRUE.
+ */
+public class RangeOfValuesItem extends ProtectedItem
+{
+
+    /** The filter. */
+    private final ExprNode filter;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param filter the expression
+     */
+    public RangeOfValuesItem( ExprNode filter )
+    {
+        if ( filter == null )
+        {
+            throw new IllegalArgumentException( "filter" );
+        }
+
+        this.filter = filter;
+    }
+
+
+    /**
+     * Gets the filter.
+     * 
+     * TODO: rename to getFilter()
+     *
+     * @return the filter
+     */
+    public ExprNode getRefinement()
+    {
+        return filter;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + filter.hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o instanceof RangeOfValuesItem )
+        {
+            RangeOfValuesItem that = ( RangeOfValuesItem ) o;
+            return this.filter.equals( that.filter );
+        }
+
+        return false;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "rangeOfValues " );
+        buf.append( filter.toString() );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByElem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByElem.java
new file mode 100644
index 0000000..d76a962
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByElem.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * An element of {@link RestrictedByItem}.
+ */
+public class RestrictedByElem
+{
+    /** The AttributeType on which the restriction is applied */
+    private AttributeType attributeType;
+
+    /** The list of allowed AttributeType values */
+    private AttributeType valuesIn;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param attributeType the attribute type to restrict
+     * @param valuesIn the attribute type only whose values are allowed in <tt>attributeType</tt>.
+     */
+    public RestrictedByElem( AttributeType attributeType, AttributeType valuesIn )
+    {
+        this.attributeType = attributeType;
+        this.valuesIn = valuesIn;
+    }
+
+
+    /**
+     * Gets the attribute type to restrict.
+     *
+     * @return the attribute type
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    /**
+     * Gets the attribute type only whose values are allowed in
+     * <tt>attributeType</tt>.
+     *
+     * @return the list of allowed AttributeType values
+     */
+    public AttributeType getValuesIn()
+    {
+        return valuesIn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + attributeType.hashCode();
+        hash = hash * 17 + valuesIn.hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o instanceof RestrictedByElem )
+        {
+            RestrictedByElem that = ( RestrictedByElem ) o;
+            if ( this.attributeType == null )
+            {
+                if ( that.attributeType == null )
+                {
+                    if ( this.valuesIn == null )
+                    {
+                        return that.valuesIn == null;
+                    }
+                    else
+                    {
+                        return this.valuesIn.equals( that.valuesIn );
+                    }
+                }
+                return false;
+            }
+            else
+            {
+                if ( this.attributeType.equals( that.attributeType ) )
+                {
+                    if ( this.valuesIn == null )
+                    {
+                        return that.valuesIn == null;
+                    }
+                    else
+                    {
+                        return this.valuesIn.equals( that.valuesIn );
+                    }
+                }
+                return false;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "{ type " + attributeType.getName() + ", valuesIn " + valuesIn.getName() + " }";
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByItem.java
new file mode 100644
index 0000000..e037208
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByItem.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.aci.ProtectedItem;
+
+
+/**
+ * Restricts values added to the attribute type to being values that are
+ * already present in the same entry as values of the attribute valuesIn. It
+ * is examined if the protected item is an attribute value of the specified
+ * type and the permission sought is add. Values of the valuesIn attribute
+ * are checked without regard to context or access control and as though the
+ * operation which adds the values were successful. If the value to be added
+ * is not present in valuesIn the ACI item is treated as not granting add
+ * access.
+ */
+public class RestrictedByItem extends ProtectedItem
+{
+    /** The set of restricted elements */
+    private final Set<RestrictedByElem> items;
+
+
+    /**
+     * Creates a new instance.
+     * 
+     * @param items the collection of {@link RestrictedByElem}s.
+     */
+    public RestrictedByItem( Set<RestrictedByElem> items )
+    {
+        this.items = Collections.unmodifiableSet( items );
+    }
+
+
+    /**
+     * Gets an iterator of all {@link RestrictedByElem}s.
+     *
+     * @return the iterator of all {@link RestrictedByElem}s
+     */
+    public Iterator<RestrictedByElem> iterator()
+    {
+        return items.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + items.hashCode();
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( o instanceof RestrictedByItem )
+        {
+            RestrictedByItem that = ( RestrictedByItem ) o;
+            return this.items.equals( that.items );
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "restrictedBy {" );
+
+        boolean isFirst = true;
+
+        for ( RestrictedByElem item : items )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            buf.append( item.toString() );
+        }
+
+        buf.append( '}' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/SelfValueItem.java b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/SelfValueItem.java
new file mode 100644
index 0000000..ad0cef2
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/main/java/org/apache/directory/api/ldap/aci/protectedItem/SelfValueItem.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * The attribute value assertion corresponding to the current requestor. The
+ * protected item selfValue applies only when the access controls are to be
+ * applied with respect to a specific authenticated user. It can only apply
+ * in the specific case where the attribute specified is of Dn and the
+ * attribute value within the specified attribute matches the Dn of the
+ * originator of the operation.
+ */
+public class SelfValueItem extends AbstractAttributeTypeProtectedItem
+{
+    /**
+     * Creates a new instance.
+     * 
+     * @param attributeTypes the collection of attribute IDs.
+     */
+    public SelfValueItem( Set<AttributeType> attributeTypes )
+    {
+        super( attributeTypes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "selfValue " + super.toString();
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/site/site.xml b/trunk/ldap/extras/aci/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AllAttributeValuesTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AllAttributeValuesTest.java
new file mode 100644
index 0000000..c23f833
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AllAttributeValuesTest.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.AllAttributeValuesItem;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.AllAttributeValues.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_AllAttributeValuesTest
+{
+    AllAttributeValuesItem allAttributeValuesA;
+    AllAttributeValuesItem allAttributeValuesACopy;
+    AllAttributeValuesItem allAttributeValuesB;
+    AllAttributeValuesItem allAttributeValuesC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        Set<AttributeType> colA = new HashSet<AttributeType>();
+        colA.add( new AttributeType( "aa" ) );
+        colA.add( new AttributeType( "bb" ) );
+        colA.add( new AttributeType( "cc" ) );
+        Set<AttributeType> colB = new HashSet<AttributeType>();
+        colB.add( new AttributeType( "aa" ) );
+        colB.add( new AttributeType( "bb" ) );
+        colB.add( new AttributeType( "cc" ) );
+        Set<AttributeType> colC = new HashSet<AttributeType>();
+        colC.add( new AttributeType( "bb" ) );
+        colC.add( new AttributeType( "cc" ) );
+        colC.add( new AttributeType( "dd" ) );
+
+        allAttributeValuesA = new AllAttributeValuesItem( colA );
+        allAttributeValuesACopy = new AllAttributeValuesItem( colA );
+        allAttributeValuesB = new AllAttributeValuesItem( colB );
+        allAttributeValuesC = new AllAttributeValuesItem( colC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( allAttributeValuesA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( allAttributeValuesA, allAttributeValuesA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( allAttributeValuesA.hashCode(), allAttributeValuesA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( allAttributeValuesA, allAttributeValuesACopy );
+        assertEquals( allAttributeValuesACopy, allAttributeValuesA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( allAttributeValuesA.hashCode(), allAttributeValuesACopy.hashCode() );
+        assertEquals( allAttributeValuesACopy.hashCode(), allAttributeValuesA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( allAttributeValuesA, allAttributeValuesACopy );
+        assertEquals( allAttributeValuesACopy, allAttributeValuesB );
+        assertEquals( allAttributeValuesA, allAttributeValuesB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( allAttributeValuesA.hashCode(), allAttributeValuesACopy.hashCode() );
+        assertEquals( allAttributeValuesACopy.hashCode(), allAttributeValuesB.hashCode() );
+        assertEquals( allAttributeValuesA.hashCode(), allAttributeValuesB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( allAttributeValuesA.equals( allAttributeValuesC ) );
+        assertFalse( allAttributeValuesC.equals( allAttributeValuesA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AttributeTypeTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AttributeTypeTest.java
new file mode 100644
index 0000000..164e009
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AttributeTypeTest.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.AttributeTypeItem;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.AttributeType.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_AttributeTypeTest
+{
+    AttributeTypeItem attributeTypeA;
+    AttributeTypeItem attributeTypeACopy;
+    AttributeTypeItem attributeTypeB;
+    AttributeTypeItem attributeTypeC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        Set<AttributeType> colA = new HashSet<AttributeType>();
+        colA.add( new AttributeType( "aa" ) );
+        colA.add( new AttributeType( "bb" ) );
+        colA.add( new AttributeType( "cc" ) );
+        Set<AttributeType> colB = new HashSet<AttributeType>();
+        colB.add( new AttributeType( "aa" ) );
+        colB.add( new AttributeType( "bb" ) );
+        colB.add( new AttributeType( "cc" ) );
+        Set<AttributeType> colC = new HashSet<AttributeType>();
+        colC.add( new AttributeType( "bb" ) );
+        colC.add( new AttributeType( "cc" ) );
+        colC.add( new AttributeType( "dd" ) );
+
+        attributeTypeA = new AttributeTypeItem( colA );
+        attributeTypeACopy = new AttributeTypeItem( colA );
+        attributeTypeB = new AttributeTypeItem( colB );
+        attributeTypeC = new AttributeTypeItem( colC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( attributeTypeA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( attributeTypeA, attributeTypeA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( attributeTypeA.hashCode(), attributeTypeA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( attributeTypeA, attributeTypeACopy );
+        assertEquals( attributeTypeACopy, attributeTypeA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( attributeTypeA.hashCode(), attributeTypeACopy.hashCode() );
+        assertEquals( attributeTypeACopy.hashCode(), attributeTypeA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( attributeTypeA, attributeTypeACopy );
+        assertEquals( attributeTypeACopy, attributeTypeB );
+        assertEquals( attributeTypeA, attributeTypeB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( attributeTypeA.hashCode(), attributeTypeACopy.hashCode() );
+        assertEquals( attributeTypeACopy.hashCode(), attributeTypeB.hashCode() );
+        assertEquals( attributeTypeA.hashCode(), attributeTypeB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( attributeTypeA.equals( attributeTypeC ) );
+        assertFalse( attributeTypeC.equals( attributeTypeA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AttributeValueTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AttributeValueTest.java
new file mode 100644
index 0000000..7895367
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_AttributeValueTest.java
@@ -0,0 +1,152 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.AttributeValueItem;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.AttributeValue.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_AttributeValueTest
+{
+    AttributeValueItem attributeValueA;
+    AttributeValueItem attributeValueACopy;
+    AttributeValueItem attributeValueB;
+    AttributeValueItem attributeValueC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+
+        Attribute attrA = new DefaultAttribute( "aa" );
+        attrA.add( "aa" );
+        Attribute attrB = new DefaultAttribute( "bb" );
+        attrB.add( "bb" );
+        Attribute attrC = new DefaultAttribute( "cc" );
+        attrC.add( "cc" );
+        Attribute attrD = new DefaultAttribute( "dd" );
+        attrD.add( "dd" );
+
+        Set<Attribute> colA = new HashSet<Attribute>();
+        colA.add( attrA );
+        colA.add( attrB );
+        colA.add( attrC );
+        Set<Attribute> colB = new HashSet<Attribute>();
+        colB.add( attrA );
+        colB.add( attrB );
+        colB.add( attrC );
+        Set<Attribute> colC = new HashSet<Attribute>();
+        colC.add( attrB );
+        colC.add( attrC );
+        colC.add( attrD );
+
+        attributeValueA = new AttributeValueItem( colA );
+        attributeValueACopy = new AttributeValueItem( colA );
+        attributeValueB = new AttributeValueItem( colB );
+        attributeValueC = new AttributeValueItem( colC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( attributeValueA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( attributeValueA, attributeValueA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( attributeValueA.hashCode(), attributeValueA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( attributeValueA, attributeValueACopy );
+        assertEquals( attributeValueACopy, attributeValueA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( attributeValueA.hashCode(), attributeValueACopy.hashCode() );
+        assertEquals( attributeValueACopy.hashCode(), attributeValueA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( attributeValueA, attributeValueACopy );
+        assertEquals( attributeValueACopy, attributeValueB );
+        assertEquals( attributeValueA, attributeValueB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( attributeValueA.hashCode(), attributeValueACopy.hashCode() );
+        assertEquals( attributeValueACopy.hashCode(), attributeValueB.hashCode() );
+        assertEquals( attributeValueA.hashCode(), attributeValueB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( attributeValueA.equals( attributeValueC ) );
+        assertFalse( attributeValueC.equals( attributeValueA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_ClassesTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_ClassesTest.java
new file mode 100644
index 0000000..8cb921e
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_ClassesTest.java
@@ -0,0 +1,129 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.ClassesItem;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.Classes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_ClassesTest
+{
+    ClassesItem classesA;
+    ClassesItem classesACopy;
+    ClassesItem classesB;
+    ClassesItem classesC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        ExprNode filterA = FilterParser.parse( "(&(cn=test)(sn=test))" );
+        ExprNode filterB = FilterParser.parse( "(&(cn=test)(sn=test))" );
+        ExprNode filterC = FilterParser.parse( "(&(cn=sample)(sn=sample))" );
+        classesA = new ClassesItem( filterA );
+        classesACopy = new ClassesItem( filterA );
+        classesB = new ClassesItem( filterB );
+        classesC = new ClassesItem( filterC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( classesA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( classesA, classesA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( classesA.hashCode(), classesA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( classesA, classesACopy );
+        assertEquals( classesACopy, classesA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( classesA.hashCode(), classesACopy.hashCode() );
+        assertEquals( classesACopy.hashCode(), classesA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( classesA, classesACopy );
+        assertEquals( classesACopy, classesB );
+        assertEquals( classesA, classesB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( classesA.hashCode(), classesACopy.hashCode() );
+        assertEquals( classesACopy.hashCode(), classesB.hashCode() );
+        assertEquals( classesA.hashCode(), classesB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( classesA.equals( classesC ) );
+        assertFalse( classesC.equals( classesA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_MaxImmSubTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_MaxImmSubTest.java
new file mode 100644
index 0000000..79f3314
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_MaxImmSubTest.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.MaxImmSubItem;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.MaxImmSub.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_MaxImmSubTest
+{
+    MaxImmSubItem maxValueCountA;
+    MaxImmSubItem maxValueCountACopy;
+    MaxImmSubItem maxValueCountB;
+    MaxImmSubItem maxValueCountC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        MaxImmSubItem misA = new MaxImmSubItem( 1 );
+        MaxImmSubItem misB = new MaxImmSubItem( 1 );
+        MaxImmSubItem misC = new MaxImmSubItem( 2 );
+
+        maxValueCountA = misA;
+        maxValueCountACopy = misA;
+        maxValueCountB = misB;
+        maxValueCountC = misC;
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( maxValueCountA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( maxValueCountA, maxValueCountA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( maxValueCountA.hashCode(), maxValueCountA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( maxValueCountA, maxValueCountACopy );
+        assertEquals( maxValueCountACopy, maxValueCountA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( maxValueCountA.hashCode(), maxValueCountACopy.hashCode() );
+        assertEquals( maxValueCountACopy.hashCode(), maxValueCountA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( maxValueCountA, maxValueCountACopy );
+        assertEquals( maxValueCountACopy, maxValueCountB );
+        assertEquals( maxValueCountA, maxValueCountB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( maxValueCountA.hashCode(), maxValueCountACopy.hashCode() );
+        assertEquals( maxValueCountACopy.hashCode(), maxValueCountB.hashCode() );
+        assertEquals( maxValueCountA.hashCode(), maxValueCountB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( maxValueCountA.equals( maxValueCountC ) );
+        assertFalse( maxValueCountC.equals( maxValueCountA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_MaxValueCountTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_MaxValueCountTest.java
new file mode 100644
index 0000000..37fe2a7
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_MaxValueCountTest.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.MaxValueCountElem;
+import org.apache.directory.api.ldap.aci.protectedItem.MaxValueCountItem;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.MaxValueCount.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_MaxValueCountTest
+{
+    MaxValueCountItem maxValueCountA;
+    MaxValueCountItem maxValueCountACopy;
+    MaxValueCountItem maxValueCountB;
+    MaxValueCountItem maxValueCountC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+
+        MaxValueCountElem mvciA = new MaxValueCountElem( new AttributeType( "aa" ), 1 );
+        MaxValueCountElem mvciB = new MaxValueCountElem( new AttributeType( "bb" ), 2 );
+        MaxValueCountElem mvciC = new MaxValueCountElem( new AttributeType( "cc" ), 3 );
+        MaxValueCountElem mvciD = new MaxValueCountElem( new AttributeType( "dd" ), 4 );
+
+        Set<MaxValueCountElem> colA = new HashSet<MaxValueCountElem>();
+        colA.add( mvciA );
+        colA.add( mvciB );
+        colA.add( mvciC );
+        Set<MaxValueCountElem> colB = new HashSet<MaxValueCountElem>();
+        colB.add( mvciA );
+        colB.add( mvciB );
+        colB.add( mvciC );
+        Set<MaxValueCountElem> colC = new HashSet<MaxValueCountElem>();
+        colC.add( mvciB );
+        colC.add( mvciC );
+        colC.add( mvciD );
+
+        maxValueCountA = new MaxValueCountItem( colA );
+        maxValueCountACopy = new MaxValueCountItem( colA );
+        maxValueCountB = new MaxValueCountItem( colB );
+        maxValueCountC = new MaxValueCountItem( colC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( maxValueCountA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( maxValueCountA, maxValueCountA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( maxValueCountA.hashCode(), maxValueCountA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( maxValueCountA, maxValueCountACopy );
+        assertEquals( maxValueCountACopy, maxValueCountA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( maxValueCountA.hashCode(), maxValueCountACopy.hashCode() );
+        assertEquals( maxValueCountACopy.hashCode(), maxValueCountA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( maxValueCountA, maxValueCountACopy );
+        assertEquals( maxValueCountACopy, maxValueCountB );
+        assertEquals( maxValueCountA, maxValueCountB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( maxValueCountA.hashCode(), maxValueCountACopy.hashCode() );
+        assertEquals( maxValueCountACopy.hashCode(), maxValueCountB.hashCode() );
+        assertEquals( maxValueCountA.hashCode(), maxValueCountB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( maxValueCountA.equals( maxValueCountC ) );
+        assertFalse( maxValueCountC.equals( maxValueCountA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_RangeOfValuesTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_RangeOfValuesTest.java
new file mode 100644
index 0000000..2c4e50c
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_RangeOfValuesTest.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.RangeOfValuesItem;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.RangeOfValues.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_RangeOfValuesTest
+{
+    RangeOfValuesItem rangeOfValuesA;
+    RangeOfValuesItem rangeOfValuesACopy;
+    RangeOfValuesItem rangeOfValuesB;
+    RangeOfValuesItem rangeOfValuesC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+
+        ExprNode filterA = FilterParser.parse( "(&(cn=test)(sn=test))" );
+        ExprNode filterB = FilterParser.parse( "(&(cn=test)(sn=test))" );
+        ExprNode filterC = FilterParser.parse( "(&(cn=sample)(sn=sample))" );
+
+        rangeOfValuesA = new RangeOfValuesItem( filterA );
+        rangeOfValuesACopy = new RangeOfValuesItem( filterA );
+        rangeOfValuesB = new RangeOfValuesItem( filterB );
+        rangeOfValuesC = new RangeOfValuesItem( filterC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( rangeOfValuesA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( rangeOfValuesA, rangeOfValuesA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( rangeOfValuesA.hashCode(), rangeOfValuesA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( rangeOfValuesA, rangeOfValuesACopy );
+        assertEquals( rangeOfValuesACopy, rangeOfValuesA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( rangeOfValuesA.hashCode(), rangeOfValuesACopy.hashCode() );
+        assertEquals( rangeOfValuesACopy.hashCode(), rangeOfValuesA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( rangeOfValuesA, rangeOfValuesACopy );
+        assertEquals( rangeOfValuesACopy, rangeOfValuesB );
+        assertEquals( rangeOfValuesA, rangeOfValuesB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( rangeOfValuesA.hashCode(), rangeOfValuesACopy.hashCode() );
+        assertEquals( rangeOfValuesACopy.hashCode(), rangeOfValuesB.hashCode() );
+        assertEquals( rangeOfValuesA.hashCode(), rangeOfValuesB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( rangeOfValuesA.equals( rangeOfValuesC ) );
+        assertFalse( rangeOfValuesC.equals( rangeOfValuesA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_RestrictedByTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_RestrictedByTest.java
new file mode 100644
index 0000000..22e6d3c
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_RestrictedByTest.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.RestrictedByElem;
+import org.apache.directory.api.ldap.aci.protectedItem.RestrictedByItem;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.RestrictedBy.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_RestrictedByTest
+{
+    RestrictedByItem restrictedByA;
+    RestrictedByItem restrictedByACopy;
+    RestrictedByItem restrictedByB;
+    RestrictedByItem restrictedByC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        RestrictedByElem rbiA = new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "aa" ) );
+        RestrictedByElem rbiB = new RestrictedByElem( new AttributeType( "bb" ), new AttributeType( "bb" ) );
+        RestrictedByElem rbiC = new RestrictedByElem( new AttributeType( "cc" ), new AttributeType( "cc" ) );
+        RestrictedByElem rbiD = new RestrictedByElem( new AttributeType( "dd" ), new AttributeType( "dd" ) );
+
+        Set<RestrictedByElem> colA = new HashSet<RestrictedByElem>();
+        colA.add( rbiA );
+        colA.add( rbiB );
+        colA.add( rbiC );
+        Set<RestrictedByElem> colB = new HashSet<RestrictedByElem>();
+        colB.add( rbiA );
+        colB.add( rbiB );
+        colB.add( rbiC );
+        Set<RestrictedByElem> colC = new HashSet<RestrictedByElem>();
+        colC.add( rbiB );
+        colC.add( rbiC );
+        colC.add( rbiD );
+
+        restrictedByA = new RestrictedByItem( colA );
+        restrictedByACopy = new RestrictedByItem( colA );
+        restrictedByB = new RestrictedByItem( colB );
+        restrictedByC = new RestrictedByItem( colC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( restrictedByA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( restrictedByA, restrictedByA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( restrictedByA.hashCode(), restrictedByA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( restrictedByA, restrictedByACopy );
+        assertEquals( restrictedByACopy, restrictedByA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( restrictedByA.hashCode(), restrictedByACopy.hashCode() );
+        assertEquals( restrictedByACopy.hashCode(), restrictedByA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( restrictedByA, restrictedByACopy );
+        assertEquals( restrictedByACopy, restrictedByB );
+        assertEquals( restrictedByA, restrictedByB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( restrictedByA.hashCode(), restrictedByACopy.hashCode() );
+        assertEquals( restrictedByACopy.hashCode(), restrictedByB.hashCode() );
+        assertEquals( restrictedByA.hashCode(), restrictedByB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( restrictedByA.equals( restrictedByC ) );
+        assertFalse( restrictedByC.equals( restrictedByA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_SelfValueTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_SelfValueTest.java
new file mode 100644
index 0000000..a0219e5
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/ProtectedItem_SelfValueTest.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.SelfValueItem;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ProtectedItem.SelfValue.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtectedItem_SelfValueTest
+{
+    SelfValueItem selfValueA;
+    SelfValueItem selfValueACopy;
+    SelfValueItem selfValueB;
+    SelfValueItem selfValueC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        Set<AttributeType> colA = new HashSet<AttributeType>();
+        colA.add( new AttributeType( "aa" ) );
+        colA.add( new AttributeType( "bb" ) );
+        colA.add( new AttributeType( "cc" ) );
+        Set<AttributeType> colB = new HashSet<AttributeType>();
+        colB.add( new AttributeType( "aa" ) );
+        colB.add( new AttributeType( "bb" ) );
+        colB.add( new AttributeType( "cc" ) );
+        Set<AttributeType> colC = new HashSet<AttributeType>();
+        colC.add( new AttributeType( "bb" ) );
+        colC.add( new AttributeType( "cc" ) );
+        colC.add( new AttributeType( "dd" ) );
+
+        selfValueA = new SelfValueItem( colA );
+        selfValueACopy = new SelfValueItem( colA );
+        selfValueB = new SelfValueItem( colB );
+        selfValueC = new SelfValueItem( colC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( selfValueA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( selfValueA, selfValueA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( selfValueA.hashCode(), selfValueA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( selfValueA, selfValueACopy );
+        assertEquals( selfValueACopy, selfValueA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( selfValueA.hashCode(), selfValueACopy.hashCode() );
+        assertEquals( selfValueACopy.hashCode(), selfValueA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( selfValueA, selfValueACopy );
+        assertEquals( selfValueACopy, selfValueB );
+        assertEquals( selfValueA, selfValueB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( selfValueA.hashCode(), selfValueACopy.hashCode() );
+        assertEquals( selfValueACopy.hashCode(), selfValueB.hashCode() );
+        assertEquals( selfValueA.hashCode(), selfValueB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( selfValueA.equals( selfValueC ) );
+        assertFalse( selfValueC.equals( selfValueA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/UserClass_NameTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/UserClass_NameTest.java
new file mode 100644
index 0000000..8f0d2be
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/UserClass_NameTest.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.UserClass.Name;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class UserClass.Name.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UserClass_NameTest
+{
+    private Name nameA;
+    private Name nameACopy;
+    private Name nameB;
+    private Name nameC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws LdapInvalidDnException
+    {
+        Set<Dn> dnSetA = new HashSet<Dn>();
+        dnSetA.add( new Dn( "a=aa" ) );
+        dnSetA.add( new Dn( "b=bb" ) );
+
+        Set<Dn> dnSetB = new HashSet<Dn>();
+        dnSetB.add( new Dn( "b=bb" ) );
+        dnSetB.add( new Dn( "a=aa" ) );
+
+        Set<Dn> dnSetC = new HashSet<Dn>();
+        dnSetC.add( new Dn( "a=aa" ) );
+        dnSetC.add( new Dn( "b=bb" ) );
+
+        Set<Dn> dnSetD = new HashSet<Dn>();
+        dnSetD.add( new Dn( "b=bb" ) );
+        dnSetD.add( new Dn( "c=cc" ) );
+
+        nameA = new Name( dnSetA );
+        nameACopy = new Name( dnSetB );
+        nameB = new Name( dnSetC );
+        nameC = new Name( dnSetD );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( nameA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( nameA, nameA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( nameA.hashCode(), nameA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( nameA, nameACopy );
+        assertEquals( nameACopy, nameA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( nameA.hashCode(), nameACopy.hashCode() );
+        assertEquals( nameACopy.hashCode(), nameA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( nameA, nameACopy );
+        assertEquals( nameACopy, nameB );
+        assertEquals( nameA, nameB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( nameA.hashCode(), nameACopy.hashCode() );
+        assertEquals( nameACopy.hashCode(), nameB.hashCode() );
+        assertEquals( nameA.hashCode(), nameB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( nameA.equals( nameC ) );
+        assertFalse( nameC.equals( nameA ) );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/UserClass_SubtreeTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/UserClass_SubtreeTest.java
new file mode 100644
index 0000000..160672f
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/UserClass_SubtreeTest.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.UserClass.Subtree;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.subtree.BaseSubtreeSpecification;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class UserClass.Subtree.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UserClass_SubtreeTest
+{
+    Subtree subtreeA;
+    Subtree subtreeACopy;
+    Subtree subtreeB;
+    Subtree subtreeC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        SubtreeSpecification subtreeSpecA = new BaseSubtreeSpecification();
+        SubtreeSpecification subtreeSpecB = new BaseSubtreeSpecification();
+        SubtreeSpecification subtreeSpecC = new BaseSubtreeSpecification();
+        SubtreeSpecification subtreeSpecD = new BaseSubtreeSpecification( new Dn( "cn=dummy" ) );
+
+        Set<SubtreeSpecification> colA = new HashSet<SubtreeSpecification>();
+        colA.add( subtreeSpecA );
+        colA.add( subtreeSpecB );
+        colA.add( subtreeSpecC );
+        Set<SubtreeSpecification> colB = new HashSet<SubtreeSpecification>();
+        colB.add( subtreeSpecA );
+        colB.add( subtreeSpecB );
+        colB.add( subtreeSpecC );
+        Set<SubtreeSpecification> colC = new HashSet<SubtreeSpecification>();
+        colC.add( subtreeSpecB );
+        colC.add( subtreeSpecC );
+        colC.add( subtreeSpecD );
+
+        subtreeA = new Subtree( colA );
+        subtreeACopy = new Subtree( colA );
+        subtreeB = new Subtree( colB );
+        subtreeC = new Subtree( colC );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( subtreeA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( subtreeA, subtreeA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( subtreeA.hashCode(), subtreeA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( subtreeA, subtreeACopy );
+        assertEquals( subtreeACopy, subtreeA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( subtreeA.hashCode(), subtreeACopy.hashCode() );
+        assertEquals( subtreeACopy.hashCode(), subtreeA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( subtreeA, subtreeACopy );
+        assertEquals( subtreeACopy, subtreeB );
+        assertEquals( subtreeA, subtreeB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( subtreeA.hashCode(), subtreeACopy.hashCode() );
+        assertEquals( subtreeACopy.hashCode(), subtreeB.hashCode() );
+        assertEquals( subtreeA.hashCode(), subtreeB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( subtreeA.equals( subtreeC ) );
+        assertFalse( subtreeC.equals( subtreeA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeValueItemTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeValueItemTest.java
new file mode 100644
index 0000000..5206e7e
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/AttributeValueItemTest.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.AttributeValueItem;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.filter.UndefinedNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class AttributeValueItem.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeValueItemTest
+{
+    AttributeValueItem attributeValueItemA;
+    AttributeValueItem attributeValueItemACopy;
+    AttributeValueItem attributeValueItemB;
+    AttributeValueItem attributeValueItemC;
+    AttributeValueItem attributeValueItemD;
+    Set<Attribute> attributeA;
+    Set<Attribute> attributeB;
+    Set<Attribute> attributeC;
+    Set<Attribute> attributeD;
+
+
+    /**
+     * Initialize maxValueCountItem instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        attributeA = new HashSet<Attribute>();
+        attributeA.add( new DefaultAttribute( "aa", "aa" ) );
+        attributeA.add( new DefaultAttribute( "aa", "bb" ) );
+        attributeA.add( new DefaultAttribute( "aa", "cc" ) );
+        // Sets aren't ordered, so adding order must not matter
+        attributeB = new HashSet<Attribute>();
+        attributeB.add( new DefaultAttribute( "aa", "bb" ) );
+        attributeB.add( new DefaultAttribute( "aa", "cc" ) );
+        attributeB.add( new DefaultAttribute( "aa", "aa" ) );
+        attributeC = new HashSet<Attribute>();
+        attributeC.add( new DefaultAttribute( "aa", "aa" ) );
+        attributeC.add( new DefaultAttribute( "bb", "bb" ) );
+        attributeC.add( new DefaultAttribute( "aa", "cc" ) );
+        attributeD = new HashSet<Attribute>();
+        attributeD.add( new DefaultAttribute( "aa", "aa" ) );
+        attributeD.add( new DefaultAttribute( "aa", "bb" ) );
+        attributeD.add( new DefaultAttribute( "aa", "dd" ) );
+        attributeValueItemA = new AttributeValueItem( attributeA );
+        attributeValueItemACopy = new AttributeValueItem( attributeA );
+        attributeValueItemB = new AttributeValueItem( attributeB );
+        attributeValueItemC = new AttributeValueItem( attributeC );
+        attributeValueItemD = new AttributeValueItem( attributeD );
+    }
+
+
+    @Test
+    public void testEqualsNotInstanceOf() throws Exception
+    {
+        assertFalse( attributeValueItemA.equals( UndefinedNode.UNDEFINED_NODE ) );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( attributeValueItemA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( attributeValueItemA, attributeValueItemA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( attributeValueItemA.hashCode(), attributeValueItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( attributeValueItemA, attributeValueItemACopy );
+        assertEquals( attributeValueItemACopy, attributeValueItemA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( attributeValueItemA.hashCode(), attributeValueItemACopy.hashCode() );
+        assertEquals( attributeValueItemACopy.hashCode(), attributeValueItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( attributeValueItemA, attributeValueItemACopy );
+        assertEquals( attributeValueItemACopy, attributeValueItemB );
+        assertEquals( attributeValueItemA, attributeValueItemB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( attributeValueItemA.hashCode(), attributeValueItemACopy.hashCode() );
+        assertEquals( attributeValueItemACopy.hashCode(), attributeValueItemB.hashCode() );
+        assertEquals( attributeValueItemA.hashCode(), attributeValueItemB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( attributeValueItemA.equals( attributeValueItemC ) );
+        assertFalse( attributeValueItemC.equals( attributeValueItemA ) );
+        assertFalse( attributeValueItemA.equals( attributeValueItemD ) );
+        assertFalse( attributeValueItemD.equals( attributeValueItemA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/ClassesItemTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/ClassesItemTest.java
new file mode 100644
index 0000000..fe9afa5
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/ClassesItemTest.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.ClassesItem;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.apache.directory.api.ldap.model.filter.UndefinedNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class ClassesItem.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ClassesItemTest
+{
+    ClassesItem classesItemA;
+    ClassesItem classesItemACopy;
+    ClassesItem classesItemB;
+    ClassesItem classesItemC;
+
+
+    /**
+     * Initialize classesItem instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        classesItemA = new ClassesItem( new SubstringNode( "aa" ) );
+        classesItemACopy = new ClassesItem( new SubstringNode( "aa" ) );
+        classesItemB = new ClassesItem( new SubstringNode( "aa" ) );
+        classesItemC = new ClassesItem( new SubstringNode( "cc" ) );
+    }
+
+
+    @Test
+    public void testEqualsNotInstanceOf() throws Exception
+    {
+        assertFalse( classesItemA.equals( UndefinedNode.UNDEFINED_NODE ) );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( classesItemA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( classesItemA, classesItemA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( classesItemA.hashCode(), classesItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( classesItemA, classesItemACopy );
+        assertEquals( classesItemACopy, classesItemA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( classesItemA.hashCode(), classesItemACopy.hashCode() );
+        assertEquals( classesItemACopy.hashCode(), classesItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( classesItemA, classesItemACopy );
+        assertEquals( classesItemACopy, classesItemB );
+        assertEquals( classesItemA, classesItemB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( classesItemA.hashCode(), classesItemACopy.hashCode() );
+        assertEquals( classesItemACopy.hashCode(), classesItemB.hashCode() );
+        assertEquals( classesItemA.hashCode(), classesItemB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( classesItemA.equals( classesItemC ) );
+        assertFalse( classesItemC.equals( classesItemA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/MaxImmSubItemTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/MaxImmSubItemTest.java
new file mode 100644
index 0000000..8c358d6
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/MaxImmSubItemTest.java
@@ -0,0 +1,132 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.MaxImmSubItem;
+import org.apache.directory.api.ldap.model.filter.UndefinedNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class MaxImmSubItem.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MaxImmSubItemTest
+{
+    MaxImmSubItem maxImmSubItemA;
+    MaxImmSubItem maxImmSubItemACopy;
+    MaxImmSubItem maxImmSubItemB;
+    MaxImmSubItem maxImmSubItemC;
+
+
+    /**
+     * Initialize maxImmSubItem instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        maxImmSubItemA = new MaxImmSubItem( 1 );
+        maxImmSubItemACopy = new MaxImmSubItem( 1 );
+        maxImmSubItemB = new MaxImmSubItem( 1 );
+        maxImmSubItemC = new MaxImmSubItem( 2 );
+    }
+
+
+    @Test
+    public void testEqualsNotInstanceOf() throws Exception
+    {
+        assertFalse( maxImmSubItemA.equals( UndefinedNode.UNDEFINED_NODE ) );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( maxImmSubItemA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( maxImmSubItemA, maxImmSubItemA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( maxImmSubItemA.hashCode(), maxImmSubItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( maxImmSubItemA, maxImmSubItemACopy );
+        assertEquals( maxImmSubItemACopy, maxImmSubItemA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( maxImmSubItemA.hashCode(), maxImmSubItemACopy.hashCode() );
+        assertEquals( maxImmSubItemACopy.hashCode(), maxImmSubItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( maxImmSubItemA, maxImmSubItemACopy );
+        assertEquals( maxImmSubItemACopy, maxImmSubItemB );
+        assertEquals( maxImmSubItemA, maxImmSubItemB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( maxImmSubItemA.hashCode(), maxImmSubItemACopy.hashCode() );
+        assertEquals( maxImmSubItemACopy.hashCode(), maxImmSubItemB.hashCode() );
+        assertEquals( maxImmSubItemA.hashCode(), maxImmSubItemB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( maxImmSubItemA.equals( maxImmSubItemC ) );
+        assertFalse( maxImmSubItemC.equals( maxImmSubItemA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountItemTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountItemTest.java
new file mode 100644
index 0000000..0b6beb4
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/MaxValueCountItemTest.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.MaxValueCountElem;
+import org.apache.directory.api.ldap.aci.protectedItem.MaxValueCountItem;
+import org.apache.directory.api.ldap.model.filter.UndefinedNode;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class MaxValueCountItem.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MaxValueCountItemTest
+{
+    MaxValueCountItem maxValueCountItemA;
+    MaxValueCountItem maxValueCountItemACopy;
+    MaxValueCountItem maxValueCountItemB;
+    MaxValueCountItem maxValueCountItemC;
+    MaxValueCountItem maxValueCountItemD;
+    Set<MaxValueCountElem> itemsA;
+    Set<MaxValueCountElem> itemsB;
+    Set<MaxValueCountElem> itemsC;
+    Set<MaxValueCountElem> itemsD;
+
+
+    /**
+     * Initialize maxValueCountItem instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        itemsA = new HashSet<MaxValueCountElem>();
+        itemsA.add( new MaxValueCountElem( new AttributeType( "aa" ), 1 ) );
+        itemsA.add( new MaxValueCountElem( new AttributeType( "aa" ), 2 ) );
+        itemsA.add( new MaxValueCountElem( new AttributeType( "aa" ), 3 ) );
+        // Sets aren't ordered, so adding order must not matter
+        itemsB = new HashSet<MaxValueCountElem>();
+        itemsB.add( new MaxValueCountElem( new AttributeType( "aa" ), 2 ) );
+        itemsB.add( new MaxValueCountElem( new AttributeType( "aa" ), 3 ) );
+        itemsB.add( new MaxValueCountElem( new AttributeType( "aa" ), 1 ) );
+        itemsC = new HashSet<MaxValueCountElem>();
+        itemsC.add( new MaxValueCountElem( new AttributeType( "aa" ), 1 ) );
+        itemsC.add( new MaxValueCountElem( new AttributeType( "bb" ), 2 ) );
+        itemsC.add( new MaxValueCountElem( new AttributeType( "aa" ), 3 ) );
+        itemsD = new HashSet<MaxValueCountElem>();
+        itemsD.add( new MaxValueCountElem( new AttributeType( "aa" ), 1 ) );
+        itemsD.add( new MaxValueCountElem( new AttributeType( "aa" ), 2 ) );
+        itemsD.add( new MaxValueCountElem( new AttributeType( "aa" ), 4 ) );
+        maxValueCountItemA = new MaxValueCountItem( itemsA );
+        maxValueCountItemACopy = new MaxValueCountItem( itemsA );
+        maxValueCountItemB = new MaxValueCountItem( itemsB );
+        maxValueCountItemC = new MaxValueCountItem( itemsC );
+        maxValueCountItemD = new MaxValueCountItem( itemsD );
+    }
+
+
+    @Test
+    public void testEqualsNotInstanceOf() throws Exception
+    {
+        assertFalse( maxValueCountItemA.equals( UndefinedNode.UNDEFINED_NODE ) );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( maxValueCountItemA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( maxValueCountItemA, maxValueCountItemA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( maxValueCountItemA.hashCode(), maxValueCountItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( maxValueCountItemA, maxValueCountItemACopy );
+        assertEquals( maxValueCountItemACopy, maxValueCountItemA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( maxValueCountItemA.hashCode(), maxValueCountItemACopy.hashCode() );
+        assertEquals( maxValueCountItemACopy.hashCode(), maxValueCountItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( maxValueCountItemA, maxValueCountItemACopy );
+        assertEquals( maxValueCountItemACopy, maxValueCountItemB );
+        assertEquals( maxValueCountItemA, maxValueCountItemB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( maxValueCountItemA.hashCode(), maxValueCountItemACopy.hashCode() );
+        assertEquals( maxValueCountItemACopy.hashCode(), maxValueCountItemB.hashCode() );
+        assertEquals( maxValueCountItemA.hashCode(), maxValueCountItemB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( maxValueCountItemA.equals( maxValueCountItemC ) );
+        assertFalse( maxValueCountItemC.equals( maxValueCountItemA ) );
+        assertFalse( maxValueCountItemA.equals( maxValueCountItemD ) );
+        assertFalse( maxValueCountItemD.equals( maxValueCountItemA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByItemTest.java b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByItemTest.java
new file mode 100644
index 0000000..c2460dc
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/java/org/apache/directory/api/ldap/aci/protectedItem/RestrictedByItemTest.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.aci.protectedItem;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.aci.protectedItem.RestrictedByElem;
+import org.apache.directory.api.ldap.aci.protectedItem.RestrictedByItem;
+import org.apache.directory.api.ldap.model.filter.UndefinedNode;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class RestrictedByItem.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class RestrictedByItemTest
+{
+    RestrictedByItem restrictedByItemA;
+    RestrictedByItem restrictedByItemACopy;
+    RestrictedByItem restrictedByItemB;
+    RestrictedByItem restrictedByItemC;
+    RestrictedByItem restrictedByItemD;
+    Set<RestrictedByElem> elemsA;
+    Set<RestrictedByElem> elemsB;
+    Set<RestrictedByElem> elemsC;
+    Set<RestrictedByElem> elemsD;
+
+
+    /**
+     * Initialize maxValueCountItem instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        elemsA = new HashSet<RestrictedByElem>();
+        elemsA.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "aa" ) ) );
+        elemsA.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "bb" ) ) );
+        elemsA.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "cc" ) ) );
+        // Sets aren't ordered, so adding order must not matter
+        elemsB = new HashSet<RestrictedByElem>();
+        elemsB.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "bb" ) ) );
+        elemsB.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "cc" ) ) );
+        elemsB.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "aa" ) ) );
+        elemsC = new HashSet<RestrictedByElem>();
+        elemsC.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "aa" ) ) );
+        elemsC.add( new RestrictedByElem( new AttributeType( "bb" ), new AttributeType( "bb" ) ) );
+        elemsC.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "cc" ) ) );
+        elemsD = new HashSet<RestrictedByElem>();
+        elemsD.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "aa" ) ) );
+        elemsD.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "bb" ) ) );
+        elemsD.add( new RestrictedByElem( new AttributeType( "aa" ), new AttributeType( "dd" ) ) );
+        restrictedByItemA = new RestrictedByItem( elemsA );
+        restrictedByItemACopy = new RestrictedByItem( elemsA );
+        restrictedByItemB = new RestrictedByItem( elemsB );
+        restrictedByItemC = new RestrictedByItem( elemsC );
+        restrictedByItemD = new RestrictedByItem( elemsD );
+    }
+
+
+    @Test
+    public void testEqualsNotInstanceOf() throws Exception
+    {
+        assertFalse( restrictedByItemA.equals( UndefinedNode.UNDEFINED_NODE ) );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( restrictedByItemA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( restrictedByItemA, restrictedByItemA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( restrictedByItemA.hashCode(), restrictedByItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( restrictedByItemA, restrictedByItemACopy );
+        assertEquals( restrictedByItemACopy, restrictedByItemA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( restrictedByItemA.hashCode(), restrictedByItemACopy.hashCode() );
+        assertEquals( restrictedByItemACopy.hashCode(), restrictedByItemA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( restrictedByItemA, restrictedByItemACopy );
+        assertEquals( restrictedByItemACopy, restrictedByItemB );
+        assertEquals( restrictedByItemA, restrictedByItemB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( restrictedByItemA.hashCode(), restrictedByItemACopy.hashCode() );
+        assertEquals( restrictedByItemACopy.hashCode(), restrictedByItemB.hashCode() );
+        assertEquals( restrictedByItemA.hashCode(), restrictedByItemB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( restrictedByItemA.equals( restrictedByItemC ) );
+        assertFalse( restrictedByItemC.equals( restrictedByItemA ) );
+        assertFalse( restrictedByItemA.equals( restrictedByItemD ) );
+        assertFalse( restrictedByItemD.equals( restrictedByItemA ) );
+    }
+}
diff --git a/trunk/ldap/extras/aci/src/test/resources/log4j.properties b/trunk/ldap/extras/aci/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/extras/aci/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/extras/codec-api/pom.xml b/trunk/ldap/extras/codec-api/pom.xml
new file mode 100644
index 0000000..d1a6fc6
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/pom.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-extras-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-extras-codec-api</artifactId>
+  <name>Apache Directory LDAP API Extras Codec API</name>
+  <packaging>bundle</packaging>
+  <description>
+    Extra LDAP controls and extended operation interfaces and POJOs for the
+    Codec extensions used by clients and servers.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>findbugs</groupId>
+      <artifactId>annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.extras.codec.api</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.extras.controls;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.ad;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.ppolicy;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.vlv;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.syncrepl.syncState;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.cancel;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.certGeneration;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.gracefulDisconnect;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.gracefulShutdown;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.pwdModify;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.startTls;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.storedProcedure;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.whoAmI;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1.ber.tlv;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.message.controls;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.apache.directory.api.util.exception;version=${project.version}
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/extras/codec-api/src/checkstyle/suppressions.xml b/trunk/ldap/extras/codec-api/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..61c9f03
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/checkstyle/suppressions.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <!-- Contol inferfaces that don't declare any new method -->
+    <suppress files="org.apache.directory.api.ldap.extras.extended" checks="InterfaceIsType" />
+</suppressions>
diff --git a/trunk/ldap/extras/codec-api/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/extras/codec-api/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/extras/codec-api/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/extras/codec-api/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/SyncModifyDnType.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/SyncModifyDnType.java
new file mode 100644
index 0000000..5df18a4
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/SyncModifyDnType.java
@@ -0,0 +1,79 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls;
+
+
+/**
+ * The type of MODDN modification. One of MOVE, RENAME or MOVE_AND_RENAME
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SyncModifyDnType
+{
+    MOVE(0),
+    RENAME(1),
+    MOVE_AND_RENAME(2);
+
+    /** Internal value for each tag */
+    private int value;
+
+
+    /**
+     * Creates the value
+     */
+    private SyncModifyDnType( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Get the instance from it's interger value
+     * @param value The value we are looking for 
+     * @return The associated value
+     */
+    public static SyncModifyDnType getModifyDnType( int value )
+    {
+        switch ( value )
+        {
+            case 0:
+                return MOVE;
+
+            case 1:
+                return RENAME;
+
+            case 2:
+                return MOVE_AND_RENAME;
+
+            default:
+                throw new IllegalArgumentException( "unknown modify dn operantion type " + value );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/SynchronizationModeEnum.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/SynchronizationModeEnum.java
new file mode 100644
index 0000000..1353e3c
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/SynchronizationModeEnum.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls;
+
+
+/**
+ * This class describes the four possible synchronization mode, out of
+ * which only two are presently valid :
+ * 
+ * <pre>
+ * syncRequestValue ::= SEQUENCE {
+ *     mode ENUMERATED {
+ *         -- 0 unused
+ *         refreshOnly       (1),
+ *         -- 2 reserved
+ *         refreshAndPersist (3)
+ * ...
+ * </pre>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc4533.html">RFC 4533</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ */
+public enum SynchronizationModeEnum
+{
+    UNUSED(0),
+    REFRESH_ONLY(1),
+    RESERVED(2),
+    REFRESH_AND_PERSIST(3);
+
+    /** The internal value */
+    private int value;
+
+
+    /**
+     * Private constructor so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param value the integer value of the enumeration.
+     */
+    private SynchronizationModeEnum( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Get the {@link SynchronizationModeEnum} instance from an integer value.
+     * 
+     * @param value The value we want the enum element from
+     * @return The enum element associated with this integer
+     */
+    public static SynchronizationModeEnum getSyncMode( int value )
+    {
+        if ( value == REFRESH_AND_PERSIST.getValue() )
+        {
+            return REFRESH_AND_PERSIST;
+        }
+        else if ( value == REFRESH_ONLY.getValue() )
+        {
+            return REFRESH_ONLY;
+        }
+        else if ( value == UNUSED.getValue() )
+        {
+            return UNUSED;
+        }
+        else
+        {
+            return RESERVED;
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSync.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSync.java
new file mode 100644
index 0000000..0819c71
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSync.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ad;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * The DirSync control, as described in http://tools.ietf.org/html/draft-armijo-ldap-dirsync-00.
+ * We use the same control for both the SearchRequest and the SearchResultDone. Here is the
+ * ASN/1 description of the SearchRequest control :
+ * 
+ * <pre>
+ * Repl    Control ::= SEQUENCE {
+ *     controlType             1.2.840.113556.1.4.841
+ *     controlValue            replControlValue
+ *     criticality             TRUE
+ * }
+ * 
+ * the control value can be one of the two structures :
+ * 
+ * Client side :
+ * realReplControlValue ::= SEQUENCE {
+ *     parentsFirst            integer
+ *     maxReturnLength         integer
+ *     cookie                  OCTET STRING
+ * }
+ * 
+ * or
+ * 
+ * server side :
+ * realReplControlValue ::= SEQUENCE {
+ *     flag                  integer
+ *     maxReturnLength       integer
+ *     cookie                OCTET STRING
+ * }
+ * </pre> 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ */
+public interface AdDirSync extends Control
+{
+    /** This control OID */
+    String OID = "1.2.840.113556.1.4.841";
+
+
+    /**
+     * @return 1 if the parents are guaranteed to be returned before the children.
+     */
+    int getParentFirst();
+
+
+    /**
+     * @param parentFirst The parentFirst flag. A value of 1 will tell the server to return the parents first.
+     */
+    void setParentFirst( int parentFirst );
+
+
+    /**
+     * @return The maximum length of attributes to be returned
+     */
+    int getMaxReturnLength();
+
+
+    /**
+     * @param maxReturnLength The maximum length of attributes to be returned
+     */
+    void setMaxReturnLength( int maxReturnLength );
+
+
+    /**
+     * @return The cookie used while processing the successive DirSync operations
+     */
+    byte[] getCookie();
+
+
+    /**
+     * @param cookie The cookie to send to the server. It's the value found in the response control. Should be null
+     * for the first control.
+     */
+    void setCookie( byte[] cookie );
+
+
+    /**
+     * @return The flag returned by the server. One of :
+     * <ul>
+     * <li>LDAP_DIRSYNC_OBJECT_SECURITY (0x0001)</li>
+     * <li>LDAP_DIRSYNC_ANCESTORS_FIRST_ORDER (0x0800)</li>
+     * <li>LDAP_DIRSYNC_PUBLIC_DATA_ONLY (0x2000)(</li>
+     * <li>LDAP_DIRSYNC_INCREMENTAL_VALUES (0x7FFFFFFF)</li>
+     * </ul>
+     */
+    AdDirSyncFlag getFlag();
+
+
+    /**
+     * @param flag The flag. 
+     */
+    void setFlag( AdDirSyncFlag flag );
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncFlag.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncFlag.java
new file mode 100644
index 0000000..b25ac9c
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncFlag.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ad;
+
+/**
+ * The flags used in the AdDirSync response.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum AdDirSyncFlag
+{
+    DEFAULT (0x0000),
+    LDAP_DIRSYNC_OBJECT_SECURITY (0x0001),
+    LDAP_DIRSYNC_ANCESTORS_FIRST_ORDER (0x0800),
+    LDAP_DIRSYNC_PUBLIC_DATA_ONLY (0x2000),
+    LDAP_DIRSYNC_INCREMENTAL_VALUES (0x7FFFFFFF);
+
+    /** The interned value */
+    private int value;
+    
+    /** A private constructor that associates a value to each flag */
+    private AdDirSyncFlag( int value )
+    {
+        this.value = value;
+    }
+    
+    
+    /**
+     * @return The associated value of a given flag
+     */
+    public int getValue()
+    {
+        return value;
+    }
+    
+    
+    /**
+     * Get back the flag associated with a given value
+     * @param value The integer value
+     * @return The associated flag
+     */
+    public static AdDirSyncFlag getFlag( int value )
+    {
+        switch ( value )
+        {
+            case 0x0000 : return DEFAULT;
+            case 0x0001 : return LDAP_DIRSYNC_OBJECT_SECURITY;
+            case 0x0800 : return LDAP_DIRSYNC_ANCESTORS_FIRST_ORDER;
+            case 0x2000 : return LDAP_DIRSYNC_PUBLIC_DATA_ONLY;
+            case 0x7FFFFFFF : return LDAP_DIRSYNC_INCREMENTAL_VALUES;
+            default : return null;
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncImpl.java
new file mode 100644
index 0000000..23f651a
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncImpl.java
@@ -0,0 +1,202 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.ad;
+
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.directory.api.util.Strings;
+
+/**
+ * The class implemnting the AdDirsSync interface
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AdDirSyncImpl extends AbstractControl implements AdDirSync
+{
+    /** A flag used to tell the server to return the parent before the children */
+    int parentFirst = 1;
+    
+    /** A flag used to indicate that there are more data to return */
+    AdDirSyncFlag flag = AdDirSyncFlag.DEFAULT;
+
+    /** The maximum number of attributes to return */
+    int maxReturnLength = 0;
+    
+    /** The DirSync cookie */
+    private byte[] cookie;
+
+    /**
+     * Creates an instance of the DirSync control
+     */
+    public AdDirSyncImpl()
+    {
+        super( OID, Boolean.TRUE );
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public int getParentFirst()
+    {
+        return parentFirst;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void setParentFirst( int parentFirst )
+    {
+        this.parentFirst = parentFirst;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AdDirSyncFlag getFlag()
+    {
+        return flag;
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setFlag( AdDirSyncFlag flag )
+    {
+        this.flag = flag;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getMaxReturnLength()
+    {
+        return maxReturnLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMaxReturnLength( int maxReturnLength )
+    {
+        this.maxReturnLength = maxReturnLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        if ( cookie != null )
+        {
+            this.cookie = new byte[cookie.length];
+            System.arraycopy( cookie, 0, this.cookie, 0, cookie.length );
+        }
+        else
+        {
+            this.cookie = Strings.EMPTY_BYTES;
+        }
+    }
+    
+    
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + parentFirst;
+        h = h * 17 + maxReturnLength;
+
+        if ( cookie != null )
+        {
+            for ( byte b : cookie )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof AdDirSync ) )
+        {
+            return false;
+        }
+
+        AdDirSync otherControl = ( AdDirSync ) o;
+
+        return ( maxReturnLength == otherControl.getMaxReturnLength() )
+            && ( parentFirst == otherControl.getParentFirst() )
+            && ( Arrays.equals( cookie, otherControl.getCookie() ) )
+            && ( isCritical() == otherControl.isCritical() );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    DirSync control :\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        parentFirst : '" ).append( getParentFirst() ).append( "'\n" );
+        sb.append( "        maxReturnLength : '" ).append( getMaxReturnLength() ).append( "'\n" );
+        sb.append( "        cookie            : '" ).append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicy.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicy.java
new file mode 100644
index 0000000..a68ca4f
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicy.java
@@ -0,0 +1,82 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * The password policy {@link Control} interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface PasswordPolicy extends Control
+{
+    /** the password policy request control */
+    String OID = "1.3.6.1.4.1.42.2.27.8.5.1";
+
+
+    /**
+     * Checks whether this Control is the password policy request or the response
+     * by carrying with it an IPasswordPolicyResponse object. If it is a request, 
+     * then no response component will be associated with the control: getResponse()
+     * will return null.
+     *
+     * @return true if this Control carries a response, false if it is a request
+     */
+    boolean hasResponse();
+
+
+    /**
+     * Sets the response. If null hasResponse() will return null and this will be
+     * handled as a password policy request control rather than a response control.
+     *
+     * @param response a valid response object, or null to make this a request
+     */
+    void setResponse( PasswordPolicyResponse response );
+
+
+    /**
+     * If true sets the response to a default newly initialized response object. 
+     * If this was previously a request, it automatically becomes a response. If it 
+     * was not a request with an already existing response object then that response
+     * is replace with a new one and the old is returned. If false then any response
+     * object set will be cleared to null. 
+     * 
+     * Effectively this will cause hasResponse() to return whatever you plug into it.
+     *
+     * @param hasResponse true to create default response, false to clear it
+     * @return the old response object, if one did not exist null is returned
+     */
+    PasswordPolicyResponse setResponse( boolean hasResponse );
+
+
+    /**
+     * Get's the response component of this control if this control carries a 
+     * response. If {@link #hasResponse()} returns true, this will return a non-null
+     * policy response object. 
+     *
+     * @return a non-null policy response or null, if {@link #hasResponse()} 
+     * returns false
+     */
+    PasswordPolicyResponse getResponse();
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyErrorEnum.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyErrorEnum.java
new file mode 100644
index 0000000..86d7fff
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyErrorEnum.java
@@ -0,0 +1,94 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.ppolicy;
+
+
+/**
+ *  constants representing PasswordPolicyErrorS as stated in the <a href="http://tools.ietf.org/html/draft-behera-ldap-password-policy-10">draft</a>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum PasswordPolicyErrorEnum
+{
+    PASSWORD_EXPIRED(0),
+    ACCOUNT_LOCKED(1),
+    CHANGE_AFTER_RESET(2),
+    PASSWORD_MOD_NOT_ALLOWED(3),
+    MUST_SUPPLY_OLD_PASSWORD(
+        4),
+    INSUFFICIENT_PASSWORD_QUALITY(5),
+    PASSWORD_TOO_SHORT(6),
+    PASSWORD_TOO_YOUNG(7),
+    PASSWORD_IN_HISTORY(8);
+
+    private int value;
+
+
+    private PasswordPolicyErrorEnum( int value )
+    {
+        this.value = value;
+    }
+
+
+    public static PasswordPolicyErrorEnum get( int val )
+    {
+        switch ( val )
+        {
+            case 0:
+                return PASSWORD_EXPIRED;
+
+            case 1:
+                return ACCOUNT_LOCKED;
+
+            case 2:
+                return CHANGE_AFTER_RESET;
+
+            case 3:
+                return PASSWORD_MOD_NOT_ALLOWED;
+
+            case 4:
+                return MUST_SUPPLY_OLD_PASSWORD;
+
+            case 5:
+                return INSUFFICIENT_PASSWORD_QUALITY;
+
+            case 6:
+                return PASSWORD_TOO_SHORT;
+
+            case 7:
+                return PASSWORD_TOO_YOUNG;
+
+            case 8:
+                return PASSWORD_IN_HISTORY;
+
+            default:
+
+                throw new IllegalArgumentException( "unknown password policy error value " + val );
+        }
+    }
+
+
+    public int getValue()
+    {
+        return value;
+    }
+
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyImpl.java
new file mode 100644
index 0000000..b151d92
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyImpl.java
@@ -0,0 +1,149 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy;
+
+
+/**
+ * A simple {@link PasswordPolicy} {@link Control} implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class PasswordPolicyImpl implements PasswordPolicy
+{
+    /** The criticality of this {@link Control} */
+    private boolean criticality;
+
+    /** The password policy response component if this is a response control */
+    private PasswordPolicyResponse response;
+
+
+    /**
+     * Creates a new instance of a PasswordPolicy request Control without any
+     * response data associated with it.
+     */
+    public PasswordPolicyImpl()
+    {
+        response = null;
+    }
+
+
+    /**
+     * Creates a new instance of a PasswordPolicy request Control without any
+     * response data associated with it.
+     */
+    public PasswordPolicyImpl( boolean hasResponse )
+    {
+        if ( hasResponse )
+        {
+            response = new PasswordPolicyResponseImpl();
+        }
+        else
+        {
+            response = null;
+        }
+    }
+
+
+    /**
+     * Creates a new instance of PasswordPolicy response Control with response 
+     * information packaged into the control.
+     */
+    public PasswordPolicyImpl( PasswordPolicyResponse response )
+    {
+        this.response = response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return PasswordPolicy.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isCritical()
+    {
+        return criticality;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCritical( boolean isCritical )
+    {
+        this.criticality = isCritical;
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public void setResponse( PasswordPolicyResponse response )
+    {
+        this.response = response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasResponse()
+    {
+        return response != null;
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public PasswordPolicyResponse setResponse( boolean hasResponse )
+    {
+        PasswordPolicyResponse old = this.response;
+
+        if ( hasResponse )
+        {
+            this.response = new PasswordPolicyResponseImpl();
+        }
+        else
+        {
+            this.response = null;
+        }
+
+        return old;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordPolicyResponse getResponse()
+    {
+        return response;
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyResponse.java
new file mode 100644
index 0000000..1dfd441
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyResponse.java
@@ -0,0 +1,81 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy;
+
+
+/**
+ * The PasswordPolicy response. It contains information about the error if we
+ * had one when injecting a bad password into the server.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface PasswordPolicyResponse
+{
+    /**
+     * Returns the time before expiration.  Will return -1 if this warning 
+     * was not present in the response.
+     * 
+     * @return The time before expiration of the password, or -1 if not set
+     */
+    int getTimeBeforeExpiration();
+
+
+    /**
+     * Set a date of expiration for the password.
+     * 
+     * @param timeBeforeExpiration The time before the password will expire
+     */
+    void setTimeBeforeExpiration( int timeBeforeExpiration );
+
+
+    /**
+     * Returns the number of possible attempts on the password before it's 
+     * locked.  Will return -1 if this warning was not present in the 
+     * response.
+     * 
+     * @return The number of possible attempts on the password before it's locked
+     */
+    int getGraceAuthNRemaining();
+
+
+    /**
+     * Sets the number of remaining wrong authentication for this password.
+     * 
+     * @param graceAuthNRemaining The number of remaining attempts
+     */
+    void setGraceAuthNRemaining( int graceAuthNRemaining );
+
+
+    /**
+     * Returns the password policy error.
+     * 
+     * @return The PasswordPolicyErrorEnum representing the error
+     */
+    PasswordPolicyErrorEnum getPasswordPolicyError();
+
+
+    /**
+     * Sets the PasswordPolicy error.
+     * 
+     * @param ppolicyError The PasswordPolicyErrorEnum representing the error
+     */
+    void setPasswordPolicyError( PasswordPolicyErrorEnum ppolicyError );
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyResponseImpl.java
new file mode 100644
index 0000000..7ba6ef5
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyResponseImpl.java
@@ -0,0 +1,101 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy;
+
+
+/**
+ * A PasswordPolicyResponse.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class PasswordPolicyResponseImpl implements PasswordPolicyResponse
+{
+    /** time before expiration of the password */
+    private int timeBeforeExpiration = -1;
+
+    /** number of remaining grace authentications */
+    private int graceAuthNRemaining = -1;
+
+    /** number representing the password policy error */
+    private PasswordPolicyErrorEnum ppolicyError;
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeBeforeExpiration()
+    {
+        return timeBeforeExpiration;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTimeBeforeExpiration( int timeBeforeExpiration )
+    {
+        this.timeBeforeExpiration = timeBeforeExpiration;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getGraceAuthNRemaining()
+    {
+        return graceAuthNRemaining;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setGraceAuthNRemaining( int graceAuthNRemaining )
+    {
+        this.graceAuthNRemaining = graceAuthNRemaining;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordPolicyErrorEnum getPasswordPolicyError()
+    {
+        return ppolicyError;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setPasswordPolicyError( PasswordPolicyErrorEnum ppolicyError )
+    {
+        this.ppolicyError = ppolicyError;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return "PasswordPolicyResponseImpl [timeBeforeExpiration=" + timeBeforeExpiration + ", graceAuthNRemaining="
+            + graceAuthNRemaining + ", ppolicyError=" + ppolicyError + "]";
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncDone/SyncDoneValue.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncDone/SyncDoneValue.java
new file mode 100644
index 0000000..497b077
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncDone/SyncDoneValue.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A syncDoneValue object as described in rfc4533 :
+ *
+ * <pre>
+ * 2.4.  Sync Done Control
+ *
+ *    The Sync Done Control is an LDAP Control [RFC4511] where the
+ *    controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.3 and the
+ *    controlValue contains a BER-encoded syncDoneValue.  The criticality
+ *    is FALSE (and hence absent).
+ *
+ *       syncDoneValue ::= SEQUENCE {
+ *           cookie          syncCookie OPTIONAL,
+ *           refreshDeletes  BOOLEAN DEFAULT FALSE
+ *       }
+ *
+ *    The Sync Done Control is only applicable to the SearchResultDone
+ *    Message.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SyncDoneValue extends Control
+{
+    /** This control OID */
+    String OID = "1.3.6.1.4.1.4203.1.9.1.3";
+
+
+    /**
+     * @return the cookie
+     */
+    byte[] getCookie();
+
+
+    /**
+     * @param cookie cookie to be set
+     */
+    void setCookie( byte[] cookie );
+
+
+    /**
+     * @return true, if refreshDeletes flag is set, false otherwise
+     */
+    boolean isRefreshDeletes();
+
+
+    /**
+     * @param refreshDeletes set the refreshDeletes flag
+     */
+    void setRefreshDeletes( boolean refreshDeletes );
+
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncDone/SyncDoneValueImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncDone/SyncDoneValueImpl.java
new file mode 100644
index 0000000..3ae65b8
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncDone/SyncDoneValueImpl.java
@@ -0,0 +1,164 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A simple {@link SyncDoneValue} implementation to store control properties.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncDoneValueImpl extends AbstractControl implements SyncDoneValue
+{
+    /** The Sync cookie */
+    private byte[] cookie;
+
+    /** the refreshDeletes flag */
+    private boolean refreshDeletes;
+
+
+    /**
+     * Creates a new instance of SyncDoneValueImpl.
+     */
+    public SyncDoneValueImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     *
+     * Creates a new instance of SyncDoneValueImpl.
+     *
+     * @param isCritical The critical flag
+     */
+    public SyncDoneValueImpl( boolean isCritical )
+    {
+        super( OID, isCritical );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        this.cookie = cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRefreshDeletes()
+    {
+        return refreshDeletes;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRefreshDeletes( boolean refreshDeletes )
+    {
+        this.refreshDeletes = refreshDeletes;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + ( refreshDeletes ? 1 : 0 );
+
+        if ( cookie != null )
+        {
+            for ( byte b : cookie )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof SyncDoneValue ) )
+        {
+            return false;
+        }
+
+        SyncDoneValue otherControl = ( SyncDoneValue ) o;
+
+        return ( refreshDeletes == otherControl.isRefreshDeletes() )
+            && ( Arrays.equals( cookie, otherControl.getCookie() ) )
+            && ( isCritical() == otherControl.isCritical() );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    SyncDoneValue control :\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        cookie            : '" ).append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+        sb.append( "        refreshDeletes : '" ).append( isRefreshDeletes() ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncInfoValue.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncInfoValue.java
new file mode 100644
index 0000000..8b6e19c
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncInfoValue.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A syncInfoValue object, as defined in RFC 4533 ;
+ * <pre>
+ * 2.5.  Sync Info Message
+ *
+ *    The Sync Info Message is an LDAP Intermediate Response Message
+ *    [RFC4511] where responseName is the object identifier
+ *    1.3.6.1.4.1.4203.1.9.1.4 and responseValue contains a BER-encoded
+ *    syncInfoValue.  The criticality is FALSE (and hence absent).
+ *
+ *       syncInfoValue ::= CHOICE {
+ *           newcookie      [0] syncCookie,
+ *           refreshDelete  [1] SEQUENCE {
+ *               cookie         syncCookie OPTIONAL,
+ *               refreshDone    BOOLEAN DEFAULT TRUE
+ *           },
+ *           refreshPresent [2] SEQUENCE {
+ *               cookie         syncCookie OPTIONAL,
+ *               refreshDone    BOOLEAN DEFAULT TRUE
+ *           },
+ *           syncIdSet      [3] SEQUENCE {
+ *               cookie         syncCookie OPTIONAL,
+ *               refreshDeletes BOOLEAN DEFAULT FALSE,
+ *               syncUUIDs      SET OF syncUUID
+ *           }
+ *       }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SyncInfoValue extends Control
+{
+    /** This control OID */
+    String OID = "1.3.6.1.4.1.4203.1.9.1.4";
+
+
+    /**
+     * Get the control type.
+     *
+     * @return the type : one of newCookie, refreshDelete, refreshPresent or syncIdSet
+     */
+    SynchronizationInfoEnum getType();
+
+
+    /**
+     * @param syncMode the syncMode to set
+     */
+    void setType( SynchronizationInfoEnum type );
+
+
+    /**
+     * @return the cookie
+     */
+    byte[] getCookie();
+
+
+    /**
+     * @param cookie the cookie to set
+     */
+    void setCookie( byte[] cookie );
+
+
+    /**
+     * @return the refreshDone
+     */
+    boolean isRefreshDone();
+
+
+    /**
+     * @param refreshDone the refreshDone to set
+     */
+    void setRefreshDone( boolean refreshDone );
+
+
+    /**
+     * @return the refreshDeletes
+     */
+    boolean isRefreshDeletes();
+
+
+    /**
+     * @param refreshDeletes the refreshDeletes to set
+     */
+    void setRefreshDeletes( boolean refreshDeletes );
+
+
+    /**
+     * @return the syncUUIDs
+     */
+    List<byte[]> getSyncUUIDs();
+
+
+    /**
+     * @param syncUUIDs the syncUUIDs to set
+     */
+    void setSyncUUIDs( List<byte[]> syncUUIDs );
+
+
+    /**
+     * @param syncUUIDs the syncUUIDs to set
+     */
+    void addSyncUUID( byte[] syncUUID );
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncInfoValueImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncInfoValueImpl.java
new file mode 100644
index 0000000..b928f95
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncInfoValueImpl.java
@@ -0,0 +1,369 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A simple {@link SyncInfoValue} implementation to store control properties.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncInfoValueImpl extends AbstractControl implements SyncInfoValue
+{
+    /** The kind of syncInfoValue we are dealing with */
+    private SynchronizationInfoEnum type;
+
+    /** The cookie */
+    private byte[] cookie;
+
+    /** The refreshDone flag if we are dealing with refreshXXX syncInfo. Default to true */
+    private boolean refreshDone = true;
+
+    /** The refreshDeletes flag if we are dealing with syncIdSet syncInfo. Defaults to false */
+    private boolean refreshDeletes = false;
+
+    /** The list of UUIDs if we are dealing with syncIdSet syncInfo */
+    private List<byte[]> syncUUIDs;
+
+
+    /**
+     * Creates a new instance of SyncInfoValueImpl.
+     */
+    public SyncInfoValueImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     *
+     * Creates a new instance of SyncInfoValueImpl.
+     *
+     * @param isCritical The critical flag
+     */
+    public SyncInfoValueImpl( boolean isCritical )
+    {
+        super( OID, isCritical );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SynchronizationInfoEnum getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setType( SynchronizationInfoEnum type )
+    {
+        this.type = type;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        this.cookie = cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRefreshDone()
+    {
+        return refreshDone;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRefreshDone( boolean refreshDone )
+    {
+        this.refreshDone = refreshDone;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRefreshDeletes()
+    {
+        return refreshDeletes;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRefreshDeletes( boolean refreshDeletes )
+    {
+        this.refreshDeletes = refreshDeletes;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<byte[]> getSyncUUIDs()
+    {
+        return syncUUIDs;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSyncUUIDs( List<byte[]> syncUUIDs )
+    {
+        this.syncUUIDs = syncUUIDs;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addSyncUUID( byte[] syncUUID )
+    {
+        if ( syncUUIDs == null )
+        {
+            syncUUIDs = new ArrayList<byte[]>();
+        }
+
+        syncUUIDs.add( syncUUID );
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + type.getValue();
+        h = h * 17 + ( refreshDone ? 1 : 0 );
+        h = h * 17 + ( refreshDeletes ? 1 : 0 );
+
+        if ( cookie != null )
+        {
+            for ( byte b : cookie )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        if ( syncUUIDs != null )
+        {
+            for ( byte[] bytes : syncUUIDs )
+            {
+                if ( bytes != null )
+                {
+                    for ( byte b : bytes )
+                    {
+                        h = h * 17 + b;
+                    }
+                }
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof SyncInfoValue ) )
+        {
+            return false;
+        }
+
+        SyncInfoValue otherControl = ( SyncInfoValue ) o;
+
+        if ( syncUUIDs != null )
+        {
+            if ( otherControl.getSyncUUIDs() == null )
+            {
+                return false;
+            }
+
+            // @TODO : this is extremely heavy... We have to find a better way to
+            // compare the lists of suncUuids, but atm, it's enough.
+            for ( byte[] syncUuid : syncUUIDs )
+            {
+                boolean found = false;
+
+                for ( byte[] otherSyncUuid : otherControl.getSyncUUIDs() )
+                {
+                    if ( Arrays.equals( syncUuid, otherSyncUuid ) )
+                    {
+                        found = true;
+                        break;
+                    }
+                }
+
+                if ( !found )
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            if ( otherControl.getSyncUUIDs() != null )
+            {
+                return false;
+            }
+        }
+
+        return ( refreshDeletes == otherControl.isRefreshDeletes() )
+            && ( refreshDone == otherControl.isRefreshDone() )
+            && ( type == otherControl.getType() )
+            && ( Arrays.equals( cookie, otherControl.getCookie() ) ) 
+            && ( isCritical() == otherControl.isCritical() );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    SyncInfoValue control :\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+
+        switch ( getType() )
+        {
+            case NEW_COOKIE:
+                sb.append( "        newCookie : '" ).
+                    append( Strings.utf8ToString( getCookie() ) ).append( "'\n" );
+                break;
+
+            case REFRESH_DELETE:
+                sb.append( "        refreshDelete : \n" );
+
+                if ( getCookie() != null )
+                {
+                    sb.append( "            cookie : '" ).
+                        append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+                }
+
+                sb.append( "            refreshDone : " ).append( isRefreshDone() ).append( '\n' );
+                break;
+
+            case REFRESH_PRESENT:
+                sb.append( "        refreshPresent : \n" );
+
+                if ( getCookie() != null )
+                {
+                    sb.append( "            cookie : '" ).
+                        append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+                }
+
+                sb.append( "            refreshDone : " ).append( isRefreshDone() ).append( '\n' );
+                break;
+
+            case SYNC_ID_SET:
+                sb.append( "        syncIdSet : \n" );
+
+                if ( getCookie() != null )
+                {
+                    sb.append( "            cookie : '" ).
+                        append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+                }
+
+                sb.append( "            refreshDeletes : " ).append( isRefreshDeletes() ).append( '\n' );
+                sb.append( "            syncUUIDS : " );
+
+                if ( getSyncUUIDs().size() != 0 )
+                {
+                    boolean isFirst = true;
+
+                    for ( byte[] syncUUID : getSyncUUIDs() )
+                    {
+                        if ( isFirst )
+                        {
+                            isFirst = false;
+                        }
+                        else
+                        {
+                            sb.append( ", " );
+                        }
+
+                        sb.append( Arrays.toString( syncUUID ) );
+                    }
+
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    sb.append( "empty\n" );
+                }
+
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected SynchronizationInfo: " + getType() );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncRequestValue.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncRequestValue.java
new file mode 100644
index 0000000..14bf20e
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncRequestValue.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue;
+
+
+import org.apache.directory.api.ldap.extras.controls.SynchronizationModeEnum;
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A syncRequestValue object, as defined in RFC 4533
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SyncRequestValue extends Control
+{
+    /** This control OID */
+    String OID = "1.3.6.1.4.1.4203.1.9.1.1";
+
+
+    /**
+     * @return the mode
+     */
+    SynchronizationModeEnum getMode();
+
+
+    /**
+     * @param syncMode the syncMode to set
+     */
+    void setMode( SynchronizationModeEnum mode );
+
+
+    /**
+     * @return the cookie
+     */
+    byte[] getCookie();
+
+
+    /**
+     * @param cookie the cookie to set
+     */
+    void setCookie( byte[] cookie );
+
+
+    /**
+     * @return the reloadHint
+     */
+    boolean isReloadHint();
+
+
+    /**
+     * @param reloadHint the reloadHint to set
+     */
+    void setReloadHint( boolean reloadHint );
+
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncRequestValueImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncRequestValueImpl.java
new file mode 100644
index 0000000..1b3a0f0
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SyncRequestValueImpl.java
@@ -0,0 +1,211 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.extras.controls.SynchronizationModeEnum;
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A syncRequestValue object, as defined in RFC 4533 :
+ * <pre>
+ * 2.2.  Sync Request Control
+ *
+ *    The Sync Request Control is an LDAP Control [RFC4511] where the
+ *    controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.1 and the
+ *    controlValue, an OCTET STRING, contains a BER-encoded
+ *    syncRequestValue.  The criticality field is either TRUE or FALSE.
+ *
+ *       syncRequestValue ::= SEQUENCE {
+ *           mode ENUMERATED {
+ *               -- 0 unused
+ *               refreshOnly       (1),
+ *               -- 2 reserved
+ *               refreshAndPersist (3)
+ *           },
+ *           cookie     syncCookie OPTIONAL,
+ *           reloadHint BOOLEAN DEFAULT FALSE
+ *       }
+ *
+ *    The Sync Request Control is only applicable to the SearchRequest
+ *    Message.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncRequestValueImpl extends AbstractControl implements SyncRequestValue
+{
+    /** The synchronization type */
+    private SynchronizationModeEnum mode;
+
+    /** The Sync cookie */
+    private byte[] cookie;
+
+    /** The reloadHint flag */
+    private boolean isReloadHint;
+
+
+    /**
+     * Creates a new instance of SyncRequestValueImpl.
+     */
+    public SyncRequestValueImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     *
+     * Creates a new instance of SyncRequestValueImpl.
+     *
+     * @param isCritical The critical flag
+     */
+    public SyncRequestValueImpl( boolean isCritical )
+    {
+        super( OID, isCritical );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return this.cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        this.cookie = cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SynchronizationModeEnum getMode()
+    {
+        return mode;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMode( SynchronizationModeEnum mode )
+    {
+        this.mode = mode;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isReloadHint()
+    {
+        return isReloadHint;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReloadHint( boolean reloadHint )
+    {
+        this.isReloadHint = reloadHint;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + ( isReloadHint ? 1 : 0 );
+        h = h * 17 + mode.getValue();
+
+        if ( cookie != null )
+        {
+            for ( byte b : cookie )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof SyncRequestValue ) )
+        {
+            return false;
+        }
+
+        SyncRequestValue otherControl = ( SyncRequestValue ) o;
+
+        return ( mode == otherControl.getMode() )
+            && ( isReloadHint == otherControl.isReloadHint() )
+            && ( Arrays.equals( cookie, otherControl.getCookie() ) );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    SyncRequestValue control :\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        mode              : '" ).append( getMode() ).append( "'\n" );
+        sb.append( "        cookie            : '" ).
+            append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+        sb.append( "        reloadHint : '" ).append( isReloadHint() ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SynchronizationInfoEnum.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SynchronizationInfoEnum.java
new file mode 100644
index 0000000..f41334f
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncInfoValue/SynchronizationInfoEnum.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue;
+
+
+/**
+ * This class describes the four possible Info values :
+ * <ul>
+ * <li>newcookie</li>
+ * <li>refreshDelete</li>
+ * <li>refreshpresent</li>
+ * <li>syncIdSet</li>
+ * </ul>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc4533.html">RFC 4533</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ */
+public enum SynchronizationInfoEnum
+{
+    NEW_COOKIE(0),
+    REFRESH_DELETE(1),
+    REFRESH_PRESENT(2),
+    SYNC_ID_SET(3);
+
+    /** The internal value */
+    private int value;
+
+
+    /**
+     * Private constructor so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param value the integer value of the enumeration.
+     */
+    private SynchronizationInfoEnum( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Get the {@link SynchronizationInfoEnum} instance from an integer value.
+     * 
+     * @param value The value we want the enum element from
+     * @return The enum element associated with this integer
+     */
+    public static SynchronizationInfoEnum getSyncMode( int value )
+    {
+        if ( value == NEW_COOKIE.getValue() )
+        {
+            return NEW_COOKIE;
+        }
+        else if ( value == REFRESH_DELETE.getValue() )
+        {
+            return REFRESH_DELETE;
+        }
+        else if ( value == REFRESH_PRESENT.getValue() )
+        {
+            return REFRESH_PRESENT;
+        }
+        else
+        {
+            return SYNC_ID_SET;
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateTypeEnum.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateTypeEnum.java
new file mode 100644
index 0000000..0b63f78
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateTypeEnum.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncState;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * 
+ * This class describes the four types of states part of the syncStateValue as described in rfc4533.
+ * 
+ *  state ENUMERATED {
+ *            present (0),
+ *            add (1),
+ *            modify (2),
+ *            delete (3),
+ *            
+ *            #includes the below ApacheDS specific values
+ *            moddn(4),
+ *   }
+ *   
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SyncStateTypeEnum
+{
+    PRESENT(0), ADD(1), MODIFY(2), DELETE(3), MODDN(4);
+
+    /** the internal value */
+    private int value;
+
+
+    /**
+     * Private constructor so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param value the integer value of the enumeration.
+     */
+    private SyncStateTypeEnum( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Get the {@link SyncStateTypeEnum} instance from an integer value.
+     * 
+     * @param value The value we want the enum element from
+     * @return The enum element associated with this integer
+     */
+    public static SyncStateTypeEnum getSyncStateType( int value )
+    {
+        if ( value == PRESENT.value )
+        {
+            return PRESENT;
+        }
+        else if ( value == ADD.value )
+        {
+            return ADD;
+        }
+        else if ( value == MODIFY.value )
+        {
+            return MODIFY;
+        }
+        else if ( value == DELETE.value )
+        {
+            return DELETE;
+        }
+        else if ( value == MODDN.value )
+        {
+            return MODDN;
+        }
+
+        throw new IllegalArgumentException( I18n.err( I18n.ERR_04163, value ) );
+    }
+
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateValue.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateValue.java
new file mode 100644
index 0000000..86cad16
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateValue.java
@@ -0,0 +1,97 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncState;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A syncStateValue object, as defined in RFC 4533 :
+ * <pre>
+ * 2.3.  Sync State Control
+ *
+ *    The Sync State Control is an LDAP Control [RFC4511] where the
+ *    controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.2 and the
+ *    controlValue, an OCTET STRING, contains a BER-encoded syncStateValue.
+ *    The criticality is FALSE.
+ *
+ *       syncStateValue ::= SEQUENCE {
+ *           state ENUMERATED {
+ *               present (0),
+ *               add (1),
+ *               modify (2),
+ *               delete (3)
+ *           },
+ *           entryUUID syncUUID,
+ *           cookie    syncCookie OPTIONAL
+ *       }
+ *
+ *    The Sync State Control is only applicable to SearchResultEntry and
+ *    SearchResultReference Messages.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SyncStateValue extends Control
+{
+    /** This control OID */
+    String OID = "1.3.6.1.4.1.4203.1.9.1.2";
+
+
+    /**
+     * @return the cookie
+     */
+    byte[] getCookie();
+
+
+    /**
+     * @param cookie the cookie to set
+     */
+    void setCookie( byte[] cookie );
+
+
+    /**
+     * @return the syncState's type
+     */
+    SyncStateTypeEnum getSyncStateType();
+
+
+    /**
+     * set the syncState's type
+     *
+     * @param syncStateType the syncState's type
+     */
+    void setSyncStateType( SyncStateTypeEnum syncStateType );
+
+
+    /**
+     * @return the entryUUID
+     */
+    byte[] getEntryUUID();
+
+
+    /**
+     * set the entryUUID
+     *
+     * @param entryUUID the entryUUID
+     */
+    void setEntryUUID( byte[] entryUUID );
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateValueImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateValueImpl.java
new file mode 100644
index 0000000..5058154
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl/syncState/SyncStateValueImpl.java
@@ -0,0 +1,195 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl.syncState;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A simple SyncStateValue {@link Control} implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncStateValueImpl extends AbstractControl implements SyncStateValue
+{
+    /** The syncStateEnum type */
+    private SyncStateTypeEnum type;
+
+    /** The Sync cookie */
+    private byte[] cookie;
+
+    /** The entryUUID */
+    private byte[] entryUuid;
+
+
+    /**SyncStateValueImpl
+     * Creates a new instance of SyncDoneValueImpl.
+     */
+    public SyncStateValueImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     *
+     * Creates a new instance of SyncStateValueImpl.
+     *
+     * @param isCritical The critical flag
+     */
+    public SyncStateValueImpl( boolean isCritical )
+    {
+        super( OID, isCritical );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        this.cookie = cookie;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyncStateTypeEnum getSyncStateType()
+    {
+        return type;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSyncStateType( SyncStateTypeEnum syncStateType )
+    {
+        this.type = syncStateType;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getEntryUUID()
+    {
+        return entryUuid;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setEntryUUID( byte[] entryUUID )
+    {
+        this.entryUuid = entryUUID;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + type.getValue();
+
+        if ( cookie != null )
+        {
+            for ( byte b : cookie )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        if ( entryUuid != null )
+        {
+            for ( byte b : entryUuid )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof SyncStateValue ) )
+        {
+            return false;
+        }
+
+        SyncStateValue otherControl = ( SyncStateValue ) o;
+
+        return ( type == otherControl.getSyncStateType() )
+            && ( Arrays.equals( entryUuid, otherControl.getEntryUUID() ) )
+            && ( Arrays.equals( cookie, otherControl.getCookie() ) )
+            && ( isCritical() == otherControl.isCritical() );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    SyncStateValue control :\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        syncStateType     : '" ).append( getSyncStateType() ).append( "'\n" );
+        sb.append( "        entryUUID         : '" ).append( Strings.dumpBytes( getEntryUUID() ) ).append( "'\n" );
+        sb.append( "        cookie            : '" ).append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewRequest.java
new file mode 100644
index 0000000..de2a1dd
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewRequest.java
@@ -0,0 +1,132 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * Virtual List View control as specified in draft-ietf-ldapext-ldapv3-vlv-09.
+ * 
+ *  VirtualListViewRequest ::= SEQUENCE {
+ *         beforeCount    INTEGER (0..maxInt),
+ *         afterCount     INTEGER (0..maxInt),
+ *         target       CHOICE {
+ *                        byOffset        [0] SEQUENCE {
+ *                             offset          INTEGER (1 .. maxInt),
+ *                             contentCount    INTEGER (0 .. maxInt) },
+ *                        greaterThanOrEqual [1] AssertionValue },
+ *         contextID     OCTET STRING OPTIONAL }
+ * 
+ * Note : the target is set accordingly to which of the setOffset() or
+ * assertionValue() method is called last.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface VirtualListViewRequest extends Control
+{
+    /** This control OID */
+    String OID = "2.16.840.1.113730.3.4.9";
+
+
+    /**
+     * @return The number of entries before the target entry that are going to be sent
+     */
+    int getBeforeCount();
+
+
+    /**
+     * @param beforeCount Set the number of entries to be returned before the target entry
+     */
+    void setBeforeCount( int beforeCount );
+
+
+    /**
+     * @return The number of entries after the target entry that are going to be sent
+     */
+    int getAfterCount();
+
+
+    /**
+     * @param beforeCount Set the number of entries to be returned after the target entry
+     */
+    void setAfterCount( int afterCount );
+
+
+    /**
+     * @return The position of the target entry
+     */
+    int getOffset();
+
+
+    /**
+     * @param the position of the target entry
+     */
+    void setOffset( int offset );
+
+
+    /**
+     * @return The number of expected entries
+     */
+    int getContentCount();
+
+
+    /**
+     * @param contentCount The number of entries
+     */
+    void setContentCount( int contentCount );
+
+
+    /**
+     * @return The AssertionValue
+     */
+    byte[] getAssertionValue();
+
+
+    /**
+     * @param assertionValue Set the AssertionValue
+     */
+    void setAssertionValue( byte[] assertionValue );
+
+
+    /**
+     * @return The ID used for this request
+     */
+    byte[] getContextId();
+
+
+    /**
+     * @param contextId Set the context ID
+     */
+    void setContextId( byte[] contextId );
+
+
+    /**
+     * @return <code>true</code> if the VLV target is an offset, false otherwise
+     */
+    boolean hasOffset();
+
+
+    /**
+     * @return <code>true</code> if the VLV target is an assertionValue, false otherwise
+     */
+    boolean hasAssertionValue();
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewRequestImpl.java
new file mode 100644
index 0000000..fc17bb5
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewRequestImpl.java
@@ -0,0 +1,295 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Virtual List View control as specified in draft-ietf-ldapext-ldapv3-vlv-09.
+ * 
+ *  VirtualListViewRequest ::= SEQUENCE {
+ *         beforeCount    INTEGER (0..maxInt),
+ *         afterCount     INTEGER (0..maxInt),
+ *         target       CHOICE {
+ *                        byOffset        [0] SEQUENCE {
+ *                             offset          INTEGER (1 .. maxInt),
+ *                             contentCount    INTEGER (0 .. maxInt) },
+ *                        greaterThanOrEqual [1] AssertionValue },
+ *         contextID     OCTET STRING OPTIONAL }
+ * 
+ * Simplistic implementation that only supports byOffset choice.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewRequestImpl extends AbstractControl implements VirtualListViewRequest
+{
+    private int beforeCount;
+    private int afterCount;
+    private int offset;
+    private int contentCount;
+    private byte[] contextId;
+
+    /** The assertionValue */
+    private byte[] assertionValue;
+
+    /** A flag used for the target. It default to OFFSET */
+    private boolean targetType = OFFSET;
+
+    private static final boolean OFFSET = true;
+    private static final boolean ASSERTION_VALUE = false;
+
+
+    /**
+     * Creates a new instance of VirtualListViewRequestImpl.
+     */
+    public VirtualListViewRequestImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getBeforeCount()
+    {
+        return beforeCount;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBeforeCount( int beforeCount )
+    {
+        this.beforeCount = beforeCount;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getAfterCount()
+    {
+        return afterCount;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAfterCount( int afterCount )
+    {
+        this.afterCount = afterCount;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getOffset()
+    {
+        return offset;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setOffset( int offset )
+    {
+        this.offset = offset;
+        targetType = OFFSET;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getContentCount()
+    {
+        return contentCount;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setContentCount( int contentCount )
+    {
+        this.contentCount = contentCount;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getAssertionValue()
+    {
+        return assertionValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAssertionValue( byte[] assertionValue )
+    {
+        this.assertionValue = assertionValue;
+        targetType = ASSERTION_VALUE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getContextId()
+    {
+        return contextId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setContextId( byte[] contextId )
+    {
+        this.contextId = contextId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasOffset()
+    {
+        return targetType == OFFSET;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasAssertionValue()
+    {
+        return targetType == ASSERTION_VALUE;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = super.hashCode();
+
+        h = h * 37 + beforeCount;
+        h = h * 37 + afterCount;
+        h = h * 37 + offset;
+        h = h * 37 + contentCount;
+
+        if ( contextId != null )
+        {
+            for ( byte b : contextId )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        VirtualListViewRequestImpl otherControl = ( VirtualListViewRequestImpl ) o;
+
+        return ( beforeCount == otherControl.getBeforeCount() )
+            && ( afterCount == otherControl.getAfterCount() )
+            && ( offset == otherControl.getOffset() )
+            && ( contentCount == otherControl.getContentCount() )
+            && Arrays.equals( contextId, otherControl.getContextId() );
+    }
+
+
+    /**
+     * Return a String representing this VirtualListViewRequestImpl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Virtual List View Request Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        beforeCount   : '" ).append( beforeCount ).append( "'\n" );
+        sb.append( "        afterCount   : '" ).append( afterCount ).append( "'\n" );
+        sb.append( "        target : \n" );
+
+        if ( targetType == OFFSET )
+        {
+            sb.append( "            offset   : '" ).append( offset ).append( "'\n" );
+            sb.append( "            contentCount   : '" ).append( contentCount ).append( "'\n" );
+        }
+        else
+        {
+            sb.append( "            assertionValue : '" ).append( Strings.utf8ToString( assertionValue ) )
+                .append( "'\n" );
+
+        }
+
+        if ( contextId != null )
+        {
+            sb.append( "        contextID   : '" ).append( Strings.dumpBytes( contextId ) ).append( "'\n" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResponse.java
new file mode 100644
index 0000000..fa828e5
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResponse.java
@@ -0,0 +1,81 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * Virtual List View response control as specified in draft-ietf-ldapext-ldapv3-vlv-09.
+ * <pre>
+ *  VirtualListViewResponse ::= SEQUENCE {
+ *         targetPosition    INTEGER (0 .. maxInt),
+ *         contentCount     INTEGER (0 .. maxInt),
+ *         virtualListViewResult ENUMERATED {
+ *              success (0),
+ *              operationsError (1),
+ *              protocolError (3),
+ *              unwillingToPerform (53),
+ *              insufficientAccessRights (50),
+ *              timeLimitExceeded (3),
+ *              adminLimitExceeded (11),
+ *              innapropriateMatching (18),
+ *              sortControlMissing (60),
+ *              offsetRangeError (61),
+ *              other(80),
+ *              ... 
+ *         },
+ *         contextID     OCTET STRING OPTIONAL 
+ * }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface VirtualListViewResponse extends Control
+{
+    /** the OID of the response control */
+    String OID = "2.16.840.1.113730.3.4.10";
+
+
+    int getTargetPosition();
+
+
+    void setTargetPosition( int targetPosition );
+
+
+    int getContentCount();
+
+
+    void setContentCount( int contentCount );
+
+
+    VirtualListViewResultCode getVirtualListViewResult();
+
+
+    void setVirtualListViewResult( VirtualListViewResultCode virtualListViewResultCode );
+
+
+    byte[] getContextId();
+
+
+    void setContextId( byte[] contextId );
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResponseImpl.java
new file mode 100644
index 0000000..ac9e30a
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResponseImpl.java
@@ -0,0 +1,189 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Virtual List View response control as specified in draft-ietf-ldapext-ldapv3-vlv-09.
+ * 
+ *  VirtualListViewResponse ::= SEQUENCE {
+ *         targetPosition    INTEGER (0 .. maxInt),
+ *         contentCount     INTEGER (0 .. maxInt),
+ *         virtualListViewResult ENUMERATED {
+ *              success (0),
+ *              operationsError (1),
+ *              protocolError (3),
+ *              unwillingToPerform (53),
+ *              insufficientAccessRights (50),
+ *              timeLimitExceeded (3),
+ *              adminLimitExceeded (11),
+ *              innapropriateMatching (18),
+ *              sortControlMissing (60),
+ *              offsetRangeError (61),
+ *              other(80),
+ *              ... },
+ *         contextID     OCTET STRING OPTIONAL }
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewResponseImpl extends AbstractControl implements VirtualListViewResponse
+{
+
+    private int targetPosition;
+    private int contentCount;
+    private VirtualListViewResultCode virtualListViewResult;
+    private byte[] contextId;
+
+
+    public VirtualListViewResponseImpl()
+    {
+        super( OID );
+    }
+
+
+    @Override
+    public int getTargetPosition()
+    {
+        return targetPosition;
+    }
+
+
+    @Override
+    public void setTargetPosition( int targetPosition )
+    {
+        this.targetPosition = targetPosition;
+    }
+
+
+    @Override
+    public int getContentCount()
+    {
+        return contentCount;
+    }
+
+
+    @Override
+    public void setContentCount( int contentCount )
+    {
+        this.contentCount = contentCount;
+    }
+
+
+    @Override
+    public VirtualListViewResultCode getVirtualListViewResult()
+    {
+        return virtualListViewResult;
+    }
+
+
+    @Override
+    public void setVirtualListViewResult( VirtualListViewResultCode virtualListViewResultCode )
+    {
+        this.virtualListViewResult = virtualListViewResultCode;
+    }
+
+
+    @Override
+    public byte[] getContextId()
+    {
+        return contextId;
+    }
+
+
+    @Override
+    public void setContextId( byte[] contextId )
+    {
+        this.contextId = contextId;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = super.hashCode();
+
+        h = h * 37 + targetPosition;
+        h = h * 37 + contentCount;
+        h = h * 37 + ( ( virtualListViewResult == null ) ? 0 : virtualListViewResult.hashCode() );
+
+        if ( contextId != null )
+        {
+            for ( byte b : contextId )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        VirtualListViewResponseImpl otherControl = ( VirtualListViewResponseImpl ) o;
+
+        return ( targetPosition == otherControl.getTargetPosition() )
+            && ( contentCount == otherControl.getContentCount() )
+            && ( virtualListViewResult == otherControl.getVirtualListViewResult() )
+            && Arrays.equals( contextId, otherControl.getContextId() );
+    }
+
+
+    /**
+     * Return a String representing this VirtualListViewResponseImpl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Virtual List View Response Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        targetPosition   : '" ).append( targetPosition ).append( "'\n" );
+        sb.append( "        contentCount   : '" ).append( contentCount ).append( "'\n" );
+        sb.append( "        virtualListViewResult   : '" ).append( virtualListViewResult ).append( "'\n" );
+
+        if ( contextId != null )
+        {
+            sb.append( "        contextID   : '" ).append( Strings.dumpBytes( contextId ) ).append( "'\n" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResultCode.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResultCode.java
new file mode 100644
index 0000000..b93c940
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv/VirtualListViewResultCode.java
@@ -0,0 +1,128 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv;
+
+
+/**
+ * Enumeration of the result codes of a Virtual List View response control as specified in draft-ietf-ldapext-ldapv3-vlv-09.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum VirtualListViewResultCode
+{
+    SUCCESS(0, "Success"),
+
+    OPERATIONSERROR(1, "Server internal failure"),
+
+    TIMELIMITEXCEEDED(3, "Timelimit exceeded"),
+
+    ADMINLIMITEXCEEDED(11, "Admin limit exceeded"),
+
+    INAPPROPRIATEMATCHING(18, "Unrecognized or inappropriate matching rule"),
+
+    INSUFFICIENTACCESSRIGHTS(50, "Insufficient access rights"),
+
+    UNWILLINGTOPERFORM(53, "Unwilling to perform"),
+
+    SORTCONTROLMISSING(60, "Sort control missing"),
+
+    OFFSETRANGEERROR(61, "Offset range error"),
+
+    OTHER(80, "Other");
+
+    /** The associated value */
+    private int value;
+    
+    /** The associated description */
+    private String desc;
+
+
+    private VirtualListViewResultCode( int value, String desc )
+    {
+        this.value = value;
+        this.desc = desc;
+    }
+
+
+    /**
+     * @return The associated integer value
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * @return The associated description
+     */
+    public String getDesc()
+    {
+        return desc;
+    }
+
+
+    /**
+     * returns the enum value representing the given code.
+     * 
+     * @param code the result code
+     * @return returns the corresponding ResultCode, throws IllegalArgumentException when there
+     *         is no matching ResultCode exists for the given value.
+     */
+    public static VirtualListViewResultCode get( int code )
+    {
+        switch ( code )
+        {
+            case 0:
+                return SUCCESS;
+
+            case 1:
+                return OPERATIONSERROR;
+
+            case 3:
+                return TIMELIMITEXCEEDED;
+
+            case 11:
+                return ADMINLIMITEXCEEDED;
+
+            case 18:
+                return INAPPROPRIATEMATCHING;
+
+            case 50:
+                return INSUFFICIENTACCESSRIGHTS;
+
+            case 53:
+                return UNWILLINGTOPERFORM;
+
+            case 60:
+                return SORTCONTROLMISSING;
+
+            case 61:
+                return OFFSETRANGEERROR;
+
+            case 80:
+                return OTHER;
+
+            default:
+                throw new IllegalArgumentException( "Unknown VLV response result code " + code );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelRequest.java
new file mode 100644
index 0000000..392f447
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelRequest.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.cancel;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+/**
+ * The CancelRequest interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CancelRequest extends ExtendedRequest
+{
+    /** The OID for the Cancel extended operation request. */
+    String EXTENSION_OID = "1.3.6.1.1.8";
+
+
+    /**
+     *  @return The id of the Message to cancel.
+     */
+    int getCancelId();
+
+
+    /**
+     * Sets the message to cancel by id.
+     *
+     * @param cancelId The id of the message to cancel.
+     */
+    void setCancelId( int cancelId );
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelRequestImpl.java
new file mode 100644
index 0000000..e577105
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelRequestImpl.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.cancel;
+
+
+import org.apache.directory.api.ldap.model.message.AbstractExtendedRequest;
+
+
+/**
+ * Implement the extended Cancel Request as described in RFC 3909.
+ * 
+ * It's grammar is :
+ * 
+ * cancelRequestValue ::= SEQUENCE {
+ *        cancelID        MessageID
+ *                        -- MessageID is as defined in [RFC2251]
+ * }
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelRequestImpl extends AbstractExtendedRequest implements CancelRequest
+{
+    /** The cancelId of the request to be canceled */
+    private int cancelId;
+
+
+    /**
+     * Creates a new instance of CancelRequest.
+     *
+     * @param messageId the message id
+     * @param cancelId the message id of the request to cancel
+     */
+    public CancelRequestImpl( int messageId, int cancelId )
+    {
+        super( messageId );
+        setRequestName( EXTENSION_OID );
+
+        this.cancelId = cancelId;
+    }
+
+
+    /**
+     * Creates a new instance of CancelRequest.
+     */
+    public CancelRequestImpl()
+    {
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    public int getCancelId()
+    {
+        return cancelId;
+    }
+
+
+    public void setCancelId( int cancelId )
+    {
+        this.cancelId = cancelId;
+    }
+
+
+    public CancelResponse getResultResponse()
+    {
+        if ( getResponse() == null )
+        {
+            setResponse( new CancelResponseImpl( cancelId ) );
+        }
+
+        return ( CancelResponse ) getResponse();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelResponse.java
new file mode 100644
index 0000000..4b0e4a2
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelResponse.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.cancel;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * The interface for Cancel ExtendedResponses.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CancelResponse extends ExtendedResponse
+{
+    /** The OID for the Cancel extended operation request. */
+    String EXTENSION_OID = CancelRequest.EXTENSION_OID;
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelResponseImpl.java
new file mode 100644
index 0000000..47b1737
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/cancel/CancelResponseImpl.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.cancel;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * 
+ * The response sent back from the server after the Cancel extended operation is performed.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelResponseImpl extends ExtendedResponseImpl implements CancelResponse
+{
+    /**
+     * Create a new CancelResponse object
+     * @param messageId The messageId
+     * @param rcode the result code
+     */
+    public CancelResponseImpl( int messageId, ResultCodeEnum rcode )
+    {
+        super( messageId );
+
+        switch ( rcode )
+        {
+            case SUCCESS:
+            case CANCELED:
+            case CANNOT_CANCEL:
+            case NO_SUCH_OPERATION:
+            case TOO_LATE:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.SUCCESS,
+                    ResultCodeEnum.OPERATIONS_ERROR, ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS ) );
+        }
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    public CancelResponseImpl( int messageId )
+    {
+        super( messageId );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    public CancelResponseImpl()
+    {
+        super( CancelRequest.EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name). It's a null value for the Cancel response
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return "";
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        // Seems simple but look at the equals() method ...
+        hash = hash * 17 + getClass().getName().hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        return ( obj instanceof CancelResponseImpl );
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationRequest.java
new file mode 100644
index 0000000..ec7b0d1
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationRequest.java
@@ -0,0 +1,61 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.certGeneration;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+/**
+ * The interface for a certificate generation request extended operation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CertGenerationRequest extends ExtendedRequest
+{
+    /** The OID for the Certificate Generation extended operation request. */
+    String EXTENSION_OID = "1.3.6.1.4.1.18060.0.1.8";
+
+
+    /** Get the Traget DN for the certificate storage */
+    String getTargetDN();
+
+
+    void setTargetDN( String targetDN );
+
+
+    String getIssuerDN();
+
+
+    void setIssuerDN( String issuerDN );
+
+
+    String getSubjectDN();
+
+
+    void setSubjectDN( String subjectDN );
+
+
+    String getKeyAlgorithm();
+
+
+    void setKeyAlgorithm( String keyAlgorithm );
+
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationRequestImpl.java
new file mode 100644
index 0000000..d34a2bf
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationRequestImpl.java
@@ -0,0 +1,174 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.certGeneration;
+
+
+import org.apache.directory.api.ldap.model.message.AbstractExtendedRequest;
+
+
+/**
+ * 
+ * An extended operation requesting the server to generate a public/private key pair and a certificate
+ * and store them in a specified target entry in the DIT.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationRequestImpl extends AbstractExtendedRequest implements
+    CertGenerationRequest
+{
+    /** the Dn of the server entry which will be updated*/
+    private String targetDN;
+
+    /** the issuer Dn that will be set in the certificate*/
+    private String issuerDN;
+
+    /** the Dn of the subject that is present in the certificate*/
+    private String subjectDN;
+
+    /** name of the algorithm used for generating the keys*/
+    private String keyAlgorithm;
+
+
+    /**
+     * Creates a new instance of CertGenerationRequest.
+     *
+     * @param messageId the message id
+     * @param targerDN the Dn of target entry whose key and certificate values will be changed
+     * @param issuerDN Dn to be used as the issuer's Dn in the certificate
+     * @param subjectDN Dn to be used as certificate's subject
+     * @param keyAlgorithm crypto algorithm name to be used for generating the keys
+     */
+    public CertGenerationRequestImpl( int messageId, String targerDN, String issuerDN, String subjectDN,
+        String keyAlgorithm )
+    {
+        super( messageId );
+        setRequestName( EXTENSION_OID );
+        this.targetDN = targerDN;
+        this.issuerDN = issuerDN;
+        this.subjectDN = subjectDN;
+        this.keyAlgorithm = keyAlgorithm;
+    }
+
+
+    /**
+     * Creates a new instance of CertGenerationRequest.
+     */
+    public CertGenerationRequestImpl()
+    {
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getTargetDN()
+    {
+        return targetDN;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTargetDN( String targetDN )
+    {
+        this.targetDN = targetDN;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getIssuerDN()
+    {
+        return issuerDN;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setIssuerDN( String issuerDN )
+    {
+        this.issuerDN = issuerDN;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSubjectDN()
+    {
+        return subjectDN;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSubjectDN( String subjectDN )
+    {
+        this.subjectDN = subjectDN;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getKeyAlgorithm()
+    {
+        return keyAlgorithm;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setKeyAlgorithm( String keyAlgorithm )
+    {
+        this.keyAlgorithm = keyAlgorithm;
+    }
+
+
+    @Override
+    public CertGenerationResponse getResultResponse()
+    {
+        if ( getResponse() == null )
+        {
+            setResponse( new CertGenerationResponseImpl() );
+        }
+
+        return ( CertGenerationResponse ) getResponse();
+    }
+
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append( "Certficate Generation Object { " ).append( " Target Dn: " ).append( targetDN ).append( ',' );
+        sb.append( " Issuer Dn: " ).append( issuerDN ).append( ',' );
+        sb.append( " Subject Dn: " ).append( subjectDN ).append( ',' );
+        sb.append( " Key Algorithm: " ).append( keyAlgorithm ).append( " }" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationResponse.java
new file mode 100644
index 0000000..4beacbb
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationResponse.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.certGeneration;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * The interface for the certificate generation extended operation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CertGenerationResponse extends ExtendedResponse
+{
+    /** The CertGenerationResponse OID */
+    String EXTENSION_OID = CertGenerationRequest.EXTENSION_OID;
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationResponseImpl.java
new file mode 100644
index 0000000..b349ef1
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/certGeneration/CertGenerationResponseImpl.java
@@ -0,0 +1,125 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.certGeneration;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * 
+ * The response sent back from the server after the CertGeneration extended operation is performed.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationResponseImpl extends ExtendedResponseImpl implements CertGenerationResponse
+{
+    public CertGenerationResponseImpl( int messageId, ResultCodeEnum rcode )
+    {
+        super( messageId, EXTENSION_OID );
+
+        switch ( rcode )
+        {
+            case SUCCESS:
+            case OPERATIONS_ERROR:
+            case INSUFFICIENT_ACCESS_RIGHTS:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.SUCCESS,
+                    ResultCodeEnum.OPERATIONS_ERROR, ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS ) );
+        }
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    public CertGenerationResponseImpl( int messageId )
+    {
+        super( messageId, EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    public CertGenerationResponseImpl()
+    {
+        super( EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+
+
+    /**
+     * Sets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @param oid
+     *            the OID of the extended response type.
+     */
+    public void setResponseName( String oid )
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04168, EXTENSION_OID ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        // Seems simple but look at the equals() method ...
+        hash = hash * 17 + getClass().getName().hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        return ( obj instanceof CertGenerationResponseImpl );
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulDisconnect/GracefulDisconnectResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulDisconnect/GracefulDisconnectResponse.java
new file mode 100644
index 0000000..ba6a6a2
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulDisconnect/GracefulDisconnectResponse.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.gracefulDisconnect;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.Referral;
+
+
+/**
+ * An unsolicited notification, extended response, intended for notifying
+ * clients of upcoming disconnection due to intended service windows. Unlike the
+ * {@link org.apache.directory.api.ldap.model.message.extended.NoticeOfDisconnect} this response contains additional information about
+ * the amount of time the server will be offline and exactly when it intends to
+ * shutdown.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface GracefulDisconnectResponse extends ExtendedResponse
+{
+    /** The OID for the graceful disconnect extended operation response. */
+    String EXTENSION_OID = "1.3.6.1.4.1.18060.0.1.5";
+
+
+    /**
+     * Gets the delay before disconnection, in seconds.
+     *
+     * @return the delay before disconnection
+     */
+    int getDelay();
+
+
+    /**
+     * Sets the delay before disconnection, in seconds.
+     *
+     * @param delay the new delay before disconnection
+     */
+    void setDelay( int delay );
+
+
+    /**
+     * Gets the offline time after disconnection, in minutes.
+     *
+     * @return the offline time after disconnection
+     */
+    int getTimeOffline();
+
+
+    /**
+     * Sets the time offline after disconnection, in minutes.
+     *
+     * @param timeOffline the new time offline after disconnection
+     */
+    void setTimeOffline( int timeOffline );
+
+
+    /**
+     * Gets the replicated contexts.
+     *
+     * @return the replicated contexts
+     */
+    Referral getReplicatedContexts();
+
+
+    /**
+     * Add a new URL of a replicated server
+     * 
+     * @param replicatedContext The replicated server to add.
+     */
+    void addReplicatedContexts( String replicatedContext );
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulDisconnect/GracefulDisconnectResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulDisconnect/GracefulDisconnectResponseImpl.java
new file mode 100644
index 0000000..504063a
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulDisconnect/GracefulDisconnectResponseImpl.java
@@ -0,0 +1,160 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.gracefulDisconnect;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An unsolicited notification, extended response, intended for notifying
+ * clients of up coming disconnection due to intended service windows. Unlike the
+ * {@link org.apache.directory.api.ldap.model.message.extended.NoticeOfDisconnect} this response contains additional information about
+ * the amount of time the server will be offline and exactly when it intends to
+ * shutdown.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectResponseImpl extends ExtendedResponseImpl implements GracefulDisconnectResponse
+{
+    /** Offline time after disconnection */
+    private int timeOffline;
+
+    /** Delay before disconnection */
+    private int delay;
+
+    /** String based LDAP URL that may be followed for replicated namingContexts */
+    private Referral replicatedContexts = new ReferralImpl();
+
+
+    /**
+     * Instantiates a new graceful disconnect.
+     */
+    public GracefulDisconnectResponseImpl()
+    {
+        super( 0, EXTENSION_OID );
+    }
+
+
+    /**
+     * Instantiates a new graceful disconnect.
+     *
+     * @param timeOffline the offline time after disconnect, in minutes
+     * @param delay the delay before disconnect, in seconds
+     */
+    public GracefulDisconnectResponseImpl( int timeOffline, int delay )
+    {
+        super( 0, EXTENSION_OID );
+        responseName = EXTENSION_OID;
+        this.timeOffline = timeOffline;
+        this.delay = delay;
+
+        StringBuffer buf = new StringBuffer();
+        buf.append( "The server will disconnect and will be unavailable for " ).append( timeOffline );
+        buf.append( " minutes in " ).append( delay ).append( " seconds." );
+
+        ldapResult.setDiagnosticMessage( buf.toString() );
+        ldapResult.setMatchedDn( null );
+        ldapResult.setResultCode( ResultCodeEnum.UNAVAILABLE );
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+
+
+    /**
+     * Sets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @param oid the OID of the extended response type.
+     */
+    public void setResponseName( String oid )
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04168, EXTENSION_OID ) );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Parameters of the Extended Response Value
+    // -----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public int getDelay()
+    {
+        return delay;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDelay( int delay )
+    {
+        this.delay = delay;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeOffline()
+    {
+        return timeOffline;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTimeOffline( int timeOffline )
+    {
+        this.timeOffline = timeOffline;
+    }
+
+
+    public Referral getReplicatedContexts()
+    {
+        return replicatedContexts;
+    }
+    
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addReplicatedContexts( String replicatedContext )
+    {
+        replicatedContexts.addLdapUrl( replicatedContext );
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownRequest.java
new file mode 100644
index 0000000..67888d4
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownRequest.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.gracefulShutdown;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+/**
+ * An extended operation requesting the server to shutdown it's LDAP service
+ * port while allowing established clients to complete or abandon operations
+ * already in progress. More information about this extended request is
+ * available here: <a href="http://docs.safehaus.org:8080/x/GR">LDAP Extensions
+ * for Graceful Shutdown</a>.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface GracefulShutdownRequest extends ExtendedRequest
+{
+    /** The OID for the graceful shutdown extended operation request. */
+    String EXTENSION_OID = "1.3.6.1.4.1.18060.0.1.3";
+
+    /** Undetermined value used for offline time */
+    int UNDETERMINED = 0;
+
+    /** The shutdown is immediate */
+    int NOW = 0;
+
+
+    /**
+     * Gets the delay before disconnection, in seconds.
+     *
+     * @return the delay before disconnection
+     */
+    int getDelay();
+
+
+    /**
+     * Sets the delay before disconnection, in seconds.
+     *
+     * @param delay the new delay before disconnection
+     */
+    void setDelay( int delay );
+
+
+    /**
+     * Gets the offline time after disconnection, in minutes.
+     *
+     * @return the offline time after disconnection
+     */
+    int getTimeOffline();
+
+
+    /**
+     * Sets the time offline after disconnection, in minutes.
+     *
+     * @param timeOffline the new time offline after disconnection
+     */
+    void setTimeOffline( int timeOffline );
+
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownRequestImpl.java
new file mode 100644
index 0000000..69d8a80
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownRequestImpl.java
@@ -0,0 +1,132 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.gracefulShutdown;
+
+
+import org.apache.directory.api.ldap.model.message.AbstractExtendedRequest;
+
+
+/**
+ * An extended operation requesting the server to shutdown it's LDAP service
+ * port while allowing established clients to complete or abandon operations
+ * already in progress. More information about this extended request is
+ * available here: <a href="http://docs.safehaus.org:8080/x/GR">LDAP Extensions
+ * for Graceful Shutdown</a>.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownRequestImpl extends AbstractExtendedRequest implements GracefulShutdownRequest
+{
+    /** Offline time after disconnection */
+    private int timeOffline;
+
+    /** Delay before disconnection */
+    private int delay;
+
+
+    /**
+     * Instantiates a new graceful shutdown request.
+     *
+     * @param messageId the message id
+     */
+    public GracefulShutdownRequestImpl( int messageId )
+    {
+        this( messageId, UNDETERMINED, NOW );
+    }
+
+
+    /**
+     * Instantiates a new graceful shutdown request.
+     *
+     * @param messageId the message id
+     */
+    public GracefulShutdownRequestImpl()
+    {
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * Instantiates a new graceful shutdown request.
+     *
+     * @param messageId the message id
+     * @param timeOffline the offline time after disconnection, in minutes
+     * @param delay the delay before disconnection, in seconds
+     */
+    public GracefulShutdownRequestImpl( int messageId, int timeOffline, int delay )
+    {
+        super( messageId );
+        setRequestName( EXTENSION_OID );
+        this.timeOffline = timeOffline;
+        this.delay = delay;
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Parameters of the Extended Request Payload
+    // -----------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getDelay()
+    {
+        return delay;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDelay( int delay )
+    {
+        this.delay = delay;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeOffline()
+    {
+        return timeOffline;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTimeOffline( int timeOffline )
+    {
+        this.timeOffline = timeOffline;
+    }
+
+
+    @Override
+    public GracefulShutdownResponse getResultResponse()
+    {
+        if ( getResponse() == null )
+        {
+            setResponse( new GracefulShutdownResponseImpl() );
+        }
+
+        return ( GracefulShutdownResponse ) getResponse();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownResponse.java
new file mode 100644
index 0000000..23a5f28
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownResponse.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.gracefulShutdown;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * The response sent back from the server when a {@link GracefulShutdownRequestImpl}
+ * extended operation is sent. Delivery of this response may block until all
+ * connected clients are sent a GracefulDisconnect unsolicited notification.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface GracefulShutdownResponse extends ExtendedResponse
+{
+    /** The OID for the graceful shutdown extended operation response. */
+    String EXTENSION_OID = GracefulShutdownRequest.EXTENSION_OID;
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownResponseImpl.java
new file mode 100644
index 0000000..fea5533
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/gracefulShutdown/GracefulShutdownResponseImpl.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.gracefulShutdown;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * The response sent back from the server when a {@link GracefulShutdownRequestImpl}
+ * extended operation is sent. Delivery of this response may block until all
+ * connected clients are sent a GracefulDisconnect unsolicited notification.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownResponseImpl extends ExtendedResponseImpl implements GracefulShutdownResponse
+{
+    /**
+     * Instantiates a new graceful shutdown response.
+     *
+     * @param messageId the message id
+     * @param rcode the result code
+     */
+    public GracefulShutdownResponseImpl( int messageId, ResultCodeEnum rcode )
+    {
+        super( messageId, EXTENSION_OID );
+
+        switch ( rcode )
+        {
+            case SUCCESS:
+                break;
+
+            case OPERATIONS_ERROR:
+                break;
+
+            case INSUFFICIENT_ACCESS_RIGHTS:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.SUCCESS,
+                    ResultCodeEnum.OPERATIONS_ERROR, ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS ) );
+        }
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    /**
+     * Instantiates a new graceful shutdown response.
+     *
+     * @param messageId the message id
+     */
+    public GracefulShutdownResponseImpl( int messageId )
+    {
+        super( messageId, EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * Instantiates a new graceful shutdown response.
+     */
+    public GracefulShutdownResponseImpl()
+    {
+        super( EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+
+
+    /**
+     * Sets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @param oid
+     *            the OID of the extended response type.
+     */
+    public void setResponseName( String oid )
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04168, EXTENSION_OID ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        // Seems simple but look at the equals() method ...
+        hash = hash * 17 + getClass().getName().hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        return ( obj instanceof GracefulShutdownResponseImpl );
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyRequest.java
new file mode 100644
index 0000000..54fd762
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyRequest.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.pwdModify;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+/**
+ * The RFC 3062 PwdModify request :
+ * 
+ * <pre>
+ *   PasswdModifyRequestValue ::= SEQUENCE {
+ *    userIdentity    [0]  OCTET STRING OPTIONAL
+ *    oldPasswd       [1]  OCTET STRING OPTIONAL
+ *    newPasswd       [2]  OCTET STRING OPTIONAL }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PasswordModifyRequest extends ExtendedRequest
+{
+    /** The OID for the pwdModify extended operation request. */
+    String EXTENSION_OID = "1.3.6.1.4.1.4203.1.11.1";
+
+
+    /**
+     * @return the userIdentity
+     */
+    byte[] getUserIdentity();
+
+
+    /**
+     * Set the user identity
+     * 
+     * @param the userIdentity to set
+     */
+    void setUserIdentity( byte[] userIdentity );
+
+
+    /**
+     * @return the oldPassword
+     */
+    byte[] getOldPassword();
+
+
+    /**
+     * Set the old password
+     * 
+     * @param the oldPassword to set
+     */
+    void setOldPassword( byte[] oldPassword );
+
+
+    /**
+     * @return the newPassword
+     */
+    byte[] getNewPassword();
+
+
+    /**
+     * Set a new password
+     * 
+     * @param the new password to set
+     */
+    void setNewPassword( byte[] newPassword );
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyRequestImpl.java
new file mode 100644
index 0000000..aa87dff
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyRequestImpl.java
@@ -0,0 +1,184 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.pwdModify;
+
+
+import org.apache.directory.api.ldap.model.message.AbstractExtendedRequest;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * The RFC 3062 PwdModify request :
+ * 
+ * <pre>
+ *   PasswdModifyRequestValue ::= SEQUENCE {
+ *    userIdentity    [0]  OCTET STRING OPTIONAL
+ *    oldPasswd       [1]  OCTET STRING OPTIONAL
+ *    newPasswd       [2]  OCTET STRING OPTIONAL }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyRequestImpl extends AbstractExtendedRequest implements PasswordModifyRequest
+{
+    /** The user identity */
+    private byte[] userIdentity;
+
+    /** The previous password */
+    private byte[] oldPassword;
+
+    /** The new password */
+    private byte[] newPassword;
+
+
+    /**
+     * Create a new instance of the PwdModifyRequest extended operation
+     */
+    public PasswordModifyRequestImpl()
+    {
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * Create a new instance of the PwdModifyRequest extended operation
+     * 
+     * @param messageId The message ID
+     */
+    public PasswordModifyRequestImpl( int messageId )
+    {
+        super( messageId );
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getUserIdentity()
+    {
+        return userIdentity;
+    }
+
+
+    /**
+     * @param userIdentity the userIdentity to set
+     */
+    public void setUserIdentity( byte[] userIdentity )
+    {
+        this.userIdentity = userIdentity;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getOldPassword()
+    {
+        return oldPassword;
+    }
+
+
+    /**
+     * @param oldPassword the oldPassword to set
+     */
+    public void setOldPassword( byte[] oldPassword )
+    {
+        this.oldPassword = oldPassword;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getNewPassword()
+    {
+        return newPassword;
+    }
+
+
+    /**
+     * @param newPassword the newPassword to set
+     */
+    public void setNewPassword( byte[] newPassword )
+    {
+        this.newPassword = newPassword;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public PasswordModifyResponse getResultResponse()
+    {
+        if ( getResponse() == null )
+        {
+            setResponse( new PasswordModifyResponseImpl( getMessageId() ) );
+        }
+
+        return ( PasswordModifyResponse ) getResponse();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "PwdModifyRequest :" );
+        sb.append( "\n    UserIdentity : " );
+
+        if ( userIdentity != null )
+        {
+            sb.append( Strings.utf8ToString( userIdentity ) );
+        }
+        else
+        {
+            sb.append( "null" );
+        }
+
+        sb.append( "\n    oldPassword : " );
+
+        if ( oldPassword != null )
+        {
+            sb.append( Strings.utf8ToString( oldPassword ) );
+        }
+        else
+        {
+            sb.append( "null" );
+        }
+
+        sb.append( "\n    newPassword : " );
+
+        if ( newPassword != null )
+        {
+            sb.append( Strings.utf8ToString( newPassword ) );
+        }
+        else
+        {
+            sb.append( "null" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyResponse.java
new file mode 100644
index 0000000..8826342
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyResponse.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.pwdModify;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * The RFC 3062 PwdModify response :
+ * 
+ * <pre>
+ * PasswdModifyResponseValue ::= SEQUENCE {
+ *    genPasswd       [0]     OCTET STRING OPTIONAL }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PasswordModifyResponse extends ExtendedResponse
+{
+    /** The OID for the PwdModify extended operation response. */
+    String EXTENSION_OID = PasswordModifyRequest.EXTENSION_OID;
+
+
+    /**
+     * Get the generated password
+     * 
+     * @return The generated password or null
+     */
+    byte[] getGenPassword();
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyResponseImpl.java
new file mode 100644
index 0000000..dbb9162
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/pwdModify/PasswordModifyResponseImpl.java
@@ -0,0 +1,138 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.pwdModify;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * The RFC 3062 PwdModify response :
+ * 
+ * <pre>
+ * PasswdModifyResponseValue ::= SEQUENCE {
+ *    genPasswd       [0]     OCTET STRING OPTIONAL }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyResponseImpl extends ExtendedResponseImpl implements PasswordModifyResponse
+{
+    /** The generated password */
+    private byte[] genPassword;
+
+    
+    /**
+     * Create a new instance for the PwdModify response
+     * @param messageId The Message ID
+     * @param rcode The result code
+     * @param diagnosticMessage The diagnostic message
+     */
+    public PasswordModifyResponseImpl( int messageId, ResultCodeEnum rcode, String diagnosticMessage )
+    {
+        super( messageId, EXTENSION_OID );
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+        super.getLdapResult().setDiagnosticMessage( diagnosticMessage );
+    }
+
+
+    /**
+     * Create a new instance for the PwdModify response
+     * @param messageId The Message ID
+     * @param rcode The result code
+     */
+    public PasswordModifyResponseImpl( int messageId, ResultCodeEnum rcode )
+    {
+        super( messageId, EXTENSION_OID );
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    /**
+     * Instantiates a new password Modify response.
+     *
+     * @param messageId the message id
+     */
+    public PasswordModifyResponseImpl( int messageId )
+    {
+        super( messageId, EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * Instantiates a new password Modify response.
+     */
+    public PasswordModifyResponseImpl()
+    {
+        super( EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getGenPassword()
+    {
+        return genPassword;
+    }
+
+
+    /**
+     * Set the generated Password
+     * @param genPassword The generated password
+     */
+    public void setGenPassword( byte[] genPassword )
+    {
+        this.genPassword = genPassword;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "PwdModifyResponse :" );
+        sb.append( "\n    genPassword : " );
+
+        if ( genPassword != null )
+        {
+            sb.append( Strings.utf8ToString( genPassword ) );
+        }
+        else
+        {
+            sb.append( "null" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsRequest.java
new file mode 100644
index 0000000..09d1c4d
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsRequest.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.startTls;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+/**
+ * The <a href="http://tools.ietf.org/html/rfc4511">RFC 4511</a> StartTLS request
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface StartTlsRequest extends ExtendedRequest
+{
+    /** The OID string for the StartTLS extended operation request. */
+    String EXTENSION_OID = "1.3.6.1.4.1.1466.20037";
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsRequestImpl.java
new file mode 100644
index 0000000..60cd599
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsRequestImpl.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.startTls;
+
+
+import org.apache.directory.api.ldap.model.message.AbstractExtendedRequest;
+
+
+/**
+ * The RFC 4511 StartTLS request
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StartTlsRequestImpl extends AbstractExtendedRequest implements StartTlsRequest
+{
+    /**
+     * Create a new instance of the StartTlsRequest extended operation
+     */
+    public StartTlsRequestImpl()
+    {
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * Create a new instance of the StartTlsRequest extended operation
+     * 
+     * @param messageId The message ID
+     */
+    public StartTlsRequestImpl( int messageId )
+    {
+        super( messageId );
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StartTlsResponse getResultResponse()
+    {
+        if ( getResponse() == null )
+        {
+            setResponse( new StartTlsResponseImpl( getMessageId() ) );
+        }
+
+        return ( StartTlsResponse ) getResponse();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return "StartTLS extended request";
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsResponse.java
new file mode 100644
index 0000000..1543496
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsResponse.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.startTls;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * The RFC 4511 StartTLS response
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface StartTlsResponse extends ExtendedResponse
+{
+    /** The OID for the StartTLS extended operation response. */
+    String EXTENSION_OID = "1.3.6.1.4.1.1466.20037";
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsResponseImpl.java
new file mode 100644
index 0000000..4cdb821
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/startTls/StartTlsResponseImpl.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.startTls;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * The RFC 4511 StartTLS response :
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StartTlsResponseImpl extends ExtendedResponseImpl implements StartTlsResponse
+{
+    /**
+     * Create a new instance for the StartTls response
+     * @param messageId The Message ID
+     * @param rcode The result code
+     * @param diagnosticMessage The diagnostic message
+     */
+    public StartTlsResponseImpl( int messageId, ResultCodeEnum rcode, String diagnosticMessage )
+    {
+        super( messageId, EXTENSION_OID );
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+        super.getLdapResult().setDiagnosticMessage( diagnosticMessage );
+    }
+
+
+    /**
+     * Create a new instance for the StartTls response
+     * @param messageId The Message ID
+     * @param rcode The result code
+     */
+    public StartTlsResponseImpl( int messageId, ResultCodeEnum rcode )
+    {
+        super( messageId, EXTENSION_OID );
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    /**
+     * Instantiates a new StartTls response.
+     *
+     * @param messageId the message id
+     */
+    public StartTlsResponseImpl( int messageId )
+    {
+        super( messageId, EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * Instantiates a new StartTls response.
+     */
+    public StartTlsResponseImpl()
+    {
+        super( EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "StartTlsResponse :" );
+        sb.append( getLdapResult() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureParameter.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureParameter.java
new file mode 100644
index 0000000..4498465
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureParameter.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.storedProcedure;
+
+
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Bean for representing a Stored Procedure Parameter
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureParameter
+{
+    /** the type of the parameter */
+    private byte[] type;
+
+    /** the value of the parameter */
+    private byte[] value;
+
+
+    /**
+     * Gets the type as a UTF8 String.
+     *
+     * @return The type as a UTF8 String.
+     */
+    public String getTypeString()
+    {
+        return Strings.utf8ToString( type );
+    }
+
+
+    /**
+     * Gets the value as a UTF8 String.
+     *
+     * @return The value as a UTF8 String.
+     */
+    public String getValueString()
+    {
+        return Strings.utf8ToString( value );
+    }
+
+
+    /**
+     * Gets the type as a byte[].
+     *
+     * @return The type as a byte[].
+     */
+    public byte[] getType()
+    {
+        if ( type == null )
+        {
+            return null;
+        }
+
+        final byte[] copy = new byte[type.length];
+        System.arraycopy( type, 0, copy, 0, type.length );
+        return copy;
+    }
+
+
+    /**
+     * Sets the type.
+     * 
+     * @param type The type as a byte[].
+     */
+    public void setType( byte[] type )
+    {
+        if ( type != null )
+        {
+            this.type = new byte[type.length];
+            System.arraycopy( type, 0, this.type, 0, type.length );
+        }
+        else
+        {
+            this.type = null;
+        }
+    }
+
+
+    /**
+     * Gets the value as a byte[].
+     *
+     * @return The value as a byte[].
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        final byte[] copy = new byte[value.length];
+        System.arraycopy( value, 0, copy, 0, value.length );
+        return copy;
+    }
+
+
+    /**
+     * Sets the value.
+     * 
+     * @param value The value as a byte[].
+     */
+    public void setValue( byte[] value )
+    {
+        if ( value != null )
+        {
+            this.value = new byte[value.length];
+            System.arraycopy( value, 0, this.value, 0, value.length );
+        }
+        else
+        {
+            this.value = null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureRequest.java
new file mode 100644
index 0000000..e68c165
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureRequest.java
@@ -0,0 +1,132 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.storedProcedure;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+/**
+ * An extended operation requesting the server to execute a stored procedure.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface StoredProcedureRequest extends ExtendedRequest
+{
+    /** The OID for the stored procedure extended operation request. */
+    String EXTENSION_OID = "1.3.6.1.4.1.18060.0.1.6";
+
+
+    /**
+     * Gets the language.
+     *
+     * @return the language
+     */
+    String getLanguage();
+
+
+    /**
+     * Sets the language.
+     *
+     * @param language the new language
+     */
+    void setLanguage( String language );
+
+
+    /**
+     * @return The byte[] containing the procedure's bytecode
+     */
+    byte[] getProcedure();
+
+
+    /**
+     * @param procedure The procedure's bytecode
+     */
+    void setProcedure( byte[] procedure );
+
+
+    /**
+     * Gets the procedure specification.
+     *
+     * @return the procedure specification
+     */
+    String getProcedureSpecification();
+
+
+    /**
+     * Size.
+     *
+     * @return the procedure's bytcode size
+     */
+    int size();
+
+
+    /**
+     * Gets the parameter type.
+     *
+     * @param index the index
+     * @return the parameter type
+     */
+    Object getParameterType( int index );
+
+
+    /**
+     * Gets the java parameter type.
+     *
+     * @param index the index
+     * @return the java parameter type
+     */
+    Class<?> getJavaParameterType( int index );
+
+
+    /**
+     * Gets the parameter value.
+     *
+     * @param index the index
+     * @return the parameter value
+     */
+    Object getParameterValue( int index );
+
+
+    /**
+     * Gets the java parameter value.
+     *
+     * @param index the index
+     * @return the java parameter value
+     */
+    Object getJavaParameterValue( int index );
+
+
+    /**
+     * Adds the parameter.
+     *
+     * @param type the type
+     * @param value the value
+     */
+    void addParameter( Object type, Object value );
+
+
+    void addParameter( StoredProcedureParameter parameter );
+
+
+    List<StoredProcedureParameter> getParameters();
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureRequestImpl.java
new file mode 100644
index 0000000..28c6d08
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureRequestImpl.java
@@ -0,0 +1,327 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.extras.extended.storedProcedure;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.AbstractExtendedRequest;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.exception.NotImplementedException;
+
+
+/**
+ * An extended operation requesting the server to execute a stored procedure.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureRequestImpl extends AbstractExtendedRequest implements StoredProcedureRequest
+{
+    private String language = "Java";
+
+    private byte[] procedure = StringConstants.EMPTY_BYTES;
+
+    private List<StoredProcedureParameter> parameters = new ArrayList<StoredProcedureParameter>();
+
+
+    /**
+     * Instantiates a new stored procedure request.
+     *
+     * @param messageId the message id
+     */
+    public StoredProcedureRequestImpl( int messageId )
+    {
+        super( messageId );
+        this.setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * Instantiates a new stored procedure request.
+     */
+    public StoredProcedureRequestImpl()
+    {
+        this.setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * Instantiates a new stored procedure request.
+     *
+     * @param messageId the message id
+     * @param procedure the procedure
+     * @param language the language
+     */
+    public StoredProcedureRequestImpl( int messageId, String procedure, String language )
+    {
+        super( messageId );
+        this.setRequestName( EXTENSION_OID );
+        this.language = language;
+        this.procedure = Strings.getBytesUtf8( procedure );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Parameters of the Extended Request Payload
+    // -----------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getLanguage()
+    {
+        return language;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLanguage( String language )
+    {
+        this.language = language;
+    }
+
+
+    public byte[] getProcedure()
+    {
+        if ( procedure == null )
+        {
+            return null;
+        }
+
+        final byte[] copy = new byte[procedure.length];
+        System.arraycopy( procedure, 0, copy, 0, procedure.length );
+        return copy;
+    }
+
+
+    public void setProcedure( byte[] procedure )
+    {
+        if ( procedure != null )
+        {
+            this.procedure = new byte[procedure.length];
+            System.arraycopy( procedure, 0, this.procedure, 0, procedure.length );
+        }
+        else
+        {
+            this.procedure = null;
+        }
+    }
+
+
+    public List<StoredProcedureParameter> getParameters()
+    {
+        return parameters;
+    }
+
+
+    public void addParameter( StoredProcedureParameter parameter )
+    {
+        parameters.add( parameter );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setProcedure( String procedure )
+    {
+        this.procedure = Strings.getBytesUtf8( procedure );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getProcedureSpecification()
+    {
+        return Strings.utf8ToString( procedure );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return parameters.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getParameterType( int index )
+    {
+        if ( !language.equals( "java" ) )
+        {
+            return parameters.get( index ).getType();
+        }
+
+        return getJavaParameterType( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getParameterTypeString( int index )
+    {
+        if ( !language.equals( "java" ) )
+        {
+            Object obj = parameters.get( index ).getType();
+            
+            if ( obj instanceof byte[] )
+            {
+                return Strings.utf8ToString( ( byte[] ) obj );
+            }
+        }
+
+        return getJavaParameterType( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Class<?> getJavaParameterType( int index )
+    {
+        throw new NotImplementedException( I18n.err( I18n.ERR_04175 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getParameterValue( int index )
+    {
+        if ( !language.equals( "java" ) )
+        {
+            return parameters.get( index ).getValue();
+        }
+
+        return getJavaParameterValue( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getParameterValueString( int index )
+    {
+        if ( !language.equals( "java" ) )
+        {
+            Object obj = parameters.get( index ).getValue();
+            
+            if ( obj instanceof byte[] )
+            {
+                String str = Strings.utf8ToString( ( byte[] ) obj );
+                String type = ( String ) getParameterTypeString( index );
+
+                if ( type.equals( "int" ) )
+                {
+                    try
+                    {
+                        return IntegerDecoder.parse( new BerValue( ( byte[] ) obj ) );
+                    }
+                    catch ( IntegerDecoderException e )
+                    {
+                        throw new RuntimeException( "Failed to decode INTEGER: "
+                            + Strings.dumpBytes( ( byte[] ) obj ), e );
+                    }
+                }
+                else
+                {
+                    return str;
+                }
+            }
+        }
+
+        return getJavaParameterValue( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getJavaParameterValue( int index )
+    {
+        throw new NotImplementedException( I18n.err( I18n.ERR_04176 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addParameter( Object type, Object value )
+    {
+        /**
+         *
+         * FIXME: Why do we check here whether it's Java or not ?
+         * Codec has nothing to do with these details.
+         *
+         if ( ! this.procedure.getLanguage().equals( "java" ) )
+         {
+             StoredProcedureParameter parameter = new StoredProcedureParameter();
+             parameter.setType( ( byte[] ) type );
+             parameter.setValue( ( byte[] ) value );
+             this.procedure.addParameter( parameter );
+         }
+         
+         * Replacing this code with the one below without the conditional check.
+         
+         */
+
+        StoredProcedureParameter parameter = new StoredProcedureParameter();
+        parameter.setType( ( byte[] ) type );
+        parameter.setValue( ( byte[] ) value );
+        parameters.add( parameter );
+
+        // below here try to convert parameters to their appropriate byte[] representations
+
+        /**
+         * FIXME: What is this for?
+         * 
+         * throw new NotImplementedException( "conversion of value to java type not implemented" );
+         */
+    }
+
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureResponse getResultResponse()
+    {
+        if ( getResponse() == null )
+        {
+            setResponse( new StoredProcedureResponseImpl( getMessageId() ) );
+        }
+
+        return ( StoredProcedureResponse ) getResponse();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureResponse.java
new file mode 100644
index 0000000..5e726ae
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureResponse.java
@@ -0,0 +1,35 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.storedProcedure;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * The stored procedure extended operation response.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface StoredProcedureResponse extends ExtendedResponse
+{
+    /** The OID for the stored procedure extended operation response. */
+    String EXTENSION_OID = StoredProcedureRequest.EXTENSION_OID;
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureResponseImpl.java
new file mode 100644
index 0000000..bcd1d0c
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/storedProcedure/StoredProcedureResponseImpl.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.storedProcedure;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+
+
+/**
+ * The response sent back from the server when a {@link StoredProcedureRequestImpl}
+ * is sent.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureResponseImpl extends ExtendedResponseImpl implements StoredProcedureResponse
+{
+    /**
+     * Instantiates a new stored procedure response.
+     *
+     * @param messageId the message id
+     */
+    public StoredProcedureResponseImpl( int messageId )
+    {
+        super( messageId, EXTENSION_OID );
+    }
+
+
+    /**
+     * Instantiates a new stored procedure response.
+     */
+    public StoredProcedureResponseImpl()
+    {
+        super( EXTENSION_OID );
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIRequest.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIRequest.java
new file mode 100644
index 0000000..b606aaf
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIRequest.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.whoAmI;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+
+
+/**
+ * The RFC 4532 WhoAmI request
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface WhoAmIRequest extends ExtendedRequest
+{
+    /** The OID for the WhoAmI extended operation request. */
+    String EXTENSION_OID = "1.3.6.1.4.1.4203.1.11.3";
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIRequestImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIRequestImpl.java
new file mode 100644
index 0000000..3e0c7f9
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIRequestImpl.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.whoAmI;
+
+
+import org.apache.directory.api.ldap.model.message.AbstractExtendedRequest;
+
+
+/**
+ * The RFC 4532 WhoAmI request
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WhoAmIRequestImpl extends AbstractExtendedRequest implements WhoAmIRequest
+{
+    /**
+     * Create a new instance of the WhoAmIRequest extended operation
+     */
+    public WhoAmIRequestImpl()
+    {
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * Create a new instance of the WhoAmIRequest extended operation
+     * 
+     * @param messageId The message ID
+     */
+    public WhoAmIRequestImpl( int messageId )
+    {
+        super( messageId );
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public WhoAmIResponse getResultResponse()
+    {
+        if ( getResponse() == null )
+        {
+            setResponse( new WhoAmIResponseImpl( getMessageId() ) );
+        }
+
+        return ( WhoAmIResponse ) getResponse();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return "Who Am I extended request";
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIResponse.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIResponse.java
new file mode 100644
index 0000000..6d11ff5
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIResponse.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.whoAmI;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * The RFC 4532 WhoAmI response :
+ * 
+ * <pre>
+ * authzid ::= OCTET STRING OPTIONAL
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface WhoAmIResponse extends ExtendedResponse
+{
+    /** The OID for the WhoAmI extended operation response. */
+    String EXTENSION_OID = WhoAmIRequest.EXTENSION_OID;
+
+    
+    /**
+     * @return true if the response contains a DN authz (dn:XXX)
+     */
+    boolean isDnAuthzId();
+    
+    
+    /**
+     * @return true if the response contains a userID authz (u:XXX)
+     */
+    boolean isUserAuthzId();
+    
+
+    /**
+     * Get the authzid as a byte[]
+     * 
+     * @return The authzid or null
+     */
+    byte[] getAuthzId();
+
+
+    /**
+     * Get the authzid as String. We will strip out the 'dn:' or 'u:' part.
+     * 
+     * @return The authzid or null
+     */
+    String getAuthzIdString();
+
+
+    /**
+     * Get the UserId
+     * 
+     * @return The userId or null
+     */
+    String getUserId();
+
+
+    /**
+     * Get the DN authzid.
+     * 
+     * @return The DN or null
+     */
+    Dn getDn();
+
+
+    /**
+     * set the authzid
+     * 
+     * @param The authzid to set
+     */
+    void setAuthzId( byte[] authzId );
+}
diff --git a/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIResponseImpl.java b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIResponseImpl.java
new file mode 100644
index 0000000..eadf75e
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/whoAmI/WhoAmIResponseImpl.java
@@ -0,0 +1,220 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.whoAmI;
+
+
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * The RFC 4532 WhoAmI response :
+ * 
+ * <pre>
+ * authzid OCTET STRING OPTIONAL
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WhoAmIResponseImpl extends ExtendedResponseImpl implements WhoAmIResponse
+{
+    /** The authzid */
+    private byte[] authzId;
+    
+    /** The authzId when it's a DN */
+    private Dn dn;
+    
+    /** The authzId when it's a userId */
+    private String userId;
+
+    
+    /**
+     * Create a new instance for the WhoAmI response
+     * @param messageId The Message ID
+     * @param rcode The result code
+     * @param diagnosticMessage The diagnostic message
+     */
+    public WhoAmIResponseImpl( int messageId, ResultCodeEnum rcode, String diagnosticMessage )
+    {
+        super( messageId, EXTENSION_OID );
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+        super.getLdapResult().setDiagnosticMessage( diagnosticMessage );
+    }
+
+
+    /**
+     * Create a new instance for the WhoAmI response
+     * @param messageId The Message ID
+     * @param rcode The result code
+     */
+    public WhoAmIResponseImpl( int messageId, ResultCodeEnum rcode )
+    {
+        super( messageId, EXTENSION_OID );
+
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    /**
+     * Instantiates a new WhoAmI response.
+     *
+     * @param messageId the message id
+     */
+    public WhoAmIResponseImpl( int messageId )
+    {
+        super( messageId, EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * Instantiates a new WhoAmI response.
+     */
+    public WhoAmIResponseImpl()
+    {
+        super( EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getAuthzId()
+    {
+        return authzId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAuthzId( byte[] authzId )
+    {
+        this.authzId = authzId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDnAuthzId()
+    {
+        if ( dn != null )
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isUserAuthzId()
+    {
+        return userId != null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getAuthzIdString()
+    {
+        return Strings.utf8ToString( authzId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getUserId()
+    {
+        return userId;
+    }
+
+
+    /**
+     * Set the userId
+     */
+    public void setUserId( String userId )
+    {
+        this.userId = userId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getDn()
+    {
+        return dn;
+    }
+
+
+    /**
+     * Set the DN
+     */
+    public void setDn( Dn dn )
+    {
+        this.dn = dn;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "WhoAmI Extended Response :" );
+        sb.append( "\n    authzid : " );
+
+        if ( authzId != null )
+        {
+            if ( isDnAuthzId() )
+            {
+                sb.append( "DN: " ).append( getDn() );
+            }
+            else
+            {
+                sb.append( "UserId: " ).append( getUserId() );
+            }
+        }
+        else
+        {
+            sb.append( "null" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec-api/src/site/site.xml b/trunk/ldap/extras/codec-api/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/extras/codec-api/src/test/resources/log4j.properties b/trunk/ldap/extras/codec-api/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/extras/codec-api/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/extras/codec/pom.xml b/trunk/ldap/extras/codec/pom.xml
new file mode 100644
index 0000000..ecdf3b2
--- /dev/null
+++ b/trunk/ldap/extras/codec/pom.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-extras-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-extras-codec</artifactId>
+  <name>Apache Directory LDAP API Extras Codec</name>
+  <packaging>bundle</packaging>
+  <description>
+    Extra LDAP controls and extended operation extentions for the Codec used
+    by clients and servers. These controls and extended operations are not 
+    standard issue. Some are very ApacheDS specific. Some may be from obscure
+    RFC draft specifications. Both ApacheDS and Studio will use these controls
+    as well as clients if the codec loads these extensions.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <groupId>org.apache.maven.plugins</groupId>
+        <configuration>
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target</workingDirectory>
+            <felix.cache.rootdir>
+              ${project.build.directory}
+            </felix.cache.rootdir>
+            <felix.cache.locking>
+              false
+            </felix.cache.locking>
+            <org.osgi.framework.storage>
+              ${project.build.directory}/osgi-cache
+            </org.osgi.framework.storage>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.extras.codec</Bundle-SymbolicName>
+            <Export-Package>
+                {local-packages};version=${project.version};-noimport:=true
+            </Export-Package>
+            <Export-Package>
+              org.apache.directory.api.ldap.extras.controls.ad_impl;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.ppolicy_impl;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.vlv_impl;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.controls.syncrepl_impl;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.startTls;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.asn1.actions;version=${project.version},
+              org.apache.directory.api.asn1.ber;version=${project.version},
+              org.apache.directory.api.asn1.ber.grammar;version=${project.version},
+              org.apache.directory.api.asn1.ber.tlv;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.codec.api;version=${project.version},
+              org.apache.directory.api.ldap.codec.osgi;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.ad;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.ppolicy;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.vlv;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue;version=${project.version},
+              org.apache.directory.api.ldap.extras.controls.syncrepl.syncState;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.cancel;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.certGeneration;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.gracefulDisconnect;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.gracefulShutdown;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.pwdModify;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.startTls;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.storedProcedure;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.whoAmI;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.url;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              org.osgi.framework;version="[1.0.0,2.0.0)",
+              org.osgi.util.tracker;version="[1.0.0,2.0.0)",
+            </Import-Package>
+            <Bundle-Activator>
+              org.apache.directory.api.ldap.extras.ExtrasBundleActivator
+            </Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/extras/codec/src/checkstyle/suppressions.xml b/trunk/ldap/extras/codec/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..74a4604
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/checkstyle/suppressions.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+</suppressions>
diff --git a/trunk/ldap/extras/codec/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/extras/codec/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/extras/codec/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/extras/codec/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/ExtrasBundleActivator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/ExtrasBundleActivator.java
new file mode 100644
index 0000000..7e2b9f1
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/ExtrasBundleActivator.java
@@ -0,0 +1,227 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras;
+
+
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSync;
+import org.apache.directory.api.ldap.extras.controls.ad_impl.AdDirSyncFactory;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncDoneValueFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncInfoValueFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncRequestValueFactory;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncStateValueFactory;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewRequest;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResponse;
+import org.apache.directory.api.ldap.extras.controls.vlv_impl.VirtualListViewRequestFactory;
+import org.apache.directory.api.ldap.extras.controls.vlv_impl.VirtualListViewResponseFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration.CertGenerationFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown.GracefulShutdownFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.startTls.StartTlsFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI.WhoAmIFactory;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelRequest;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationRequest;
+import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponse;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownRequest;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequest;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequest;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIRequest;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+
+/**
+ * A BundleActivator for the ldap codec extras extension: extra ApacheDS and 
+ * Apache Directory Studio specific controls and extended operations. 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtrasBundleActivator implements BundleActivator
+{
+
+    private ServiceTracker<LdapApiService, LdapApiService> serviceTracker;
+
+    class LdapApiServiceTracker implements ServiceTrackerCustomizer<LdapApiService, LdapApiService>
+    {
+
+        private BundleContext context;
+
+
+        public LdapApiServiceTracker( BundleContext context )
+        {
+            this.context = context;
+        }
+
+
+        @Override
+        public LdapApiService addingService( ServiceReference<LdapApiService> reference )
+        {
+            LdapApiService ldapApiService = context.getService( reference );
+            registerExtrasControls( ldapApiService );
+            registerExtrasExtendedOps( ldapApiService );
+            return ldapApiService;
+        }
+
+
+        @Override
+        public void modifiedService( ServiceReference<LdapApiService> reference, LdapApiService ldapApiService )
+        {
+        }
+
+
+        @Override
+        public void removedService( ServiceReference<LdapApiService> reference, LdapApiService ldapApiService )
+        {
+            unregisterExtrasControls( ldapApiService );
+            unregisterExtrasExtendedOps( ldapApiService );
+        }
+
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start( BundleContext context ) throws Exception
+    {
+        LdapApiServiceTracker ldapApiServiceTracker = new LdapApiServiceTracker( context );
+        serviceTracker = new ServiceTracker<LdapApiService, LdapApiService>(
+            context, LdapApiService.class, ldapApiServiceTracker );
+        serviceTracker.open();
+    }
+
+
+    /**
+     * Registers all the extras controls present in this control pack.
+     *
+     * @param codec The codec service.
+     */
+    private void registerExtrasControls( LdapApiService codec )
+    {
+        ControlFactory<SyncDoneValue> syncDoneValuefactory = new SyncDoneValueFactory( codec );
+        codec.registerControl( syncDoneValuefactory );
+
+        ControlFactory<SyncInfoValue> syncInfoValueFactory = new SyncInfoValueFactory( codec );
+        codec.registerControl( syncInfoValueFactory );
+
+        ControlFactory<SyncRequestValue> syncRequestValueFactory = new SyncRequestValueFactory( codec );
+        codec.registerControl( syncRequestValueFactory );
+
+        ControlFactory<SyncStateValue> syncStateValuefactory = new SyncStateValueFactory( codec );
+        codec.registerControl( syncStateValuefactory );
+
+        ControlFactory<PasswordPolicy> passwordPolicyFactory = new PasswordPolicyFactory( codec );
+        codec.registerControl( passwordPolicyFactory );
+
+        ControlFactory<VirtualListViewRequest> virtualListViewRequestFactory = new VirtualListViewRequestFactory( codec );
+        codec.registerControl( virtualListViewRequestFactory );
+
+        ControlFactory<VirtualListViewResponse> virtualListViewResponseFactory = new VirtualListViewResponseFactory(
+            codec );
+        codec.registerControl( virtualListViewResponseFactory );
+
+        ControlFactory<AdDirSync> adDirSyncFactory = new AdDirSyncFactory( codec );
+        codec.registerControl( adDirSyncFactory );
+    }
+
+
+    /**
+     * Registers all the extras extended operations present in this control pack.
+     *
+     * @param codec The codec service.
+     */
+    private void registerExtrasExtendedOps( LdapApiService codec )
+    {
+        // --------------------------------------------------------------------
+        // Register Extended Request Factories
+        // --------------------------------------------------------------------
+
+        CancelFactory cancelFactory = new CancelFactory( codec );
+        codec.registerExtendedRequest( cancelFactory );
+
+        CertGenerationFactory certGenerationFactory = new CertGenerationFactory( codec );
+        codec.registerExtendedRequest( certGenerationFactory );
+
+        GracefulShutdownFactory gracefulShutdownFactory = new GracefulShutdownFactory( codec );
+        codec.registerExtendedRequest( gracefulShutdownFactory );
+
+        StoredProcedureFactory storedProcedureFactory = new StoredProcedureFactory( codec );
+        codec.registerExtendedRequest( storedProcedureFactory );
+
+        PasswordModifyFactory passwordModifyFactory = new PasswordModifyFactory( codec );
+        codec.registerExtendedRequest( passwordModifyFactory );
+
+        GracefulDisconnectFactory gracefulDisconnectFactory = new GracefulDisconnectFactory( codec );
+        codec.registerExtendedRequest( gracefulDisconnectFactory );
+
+        WhoAmIFactory whoAmIFactory = new WhoAmIFactory( codec );
+        codec.registerExtendedRequest( whoAmIFactory );
+
+        StartTlsFactory startTlsFactory = new StartTlsFactory( codec );
+        codec.registerExtendedRequest( startTlsFactory );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop( BundleContext context ) throws Exception
+    {
+        serviceTracker.close();
+    }
+
+
+    private void unregisterExtrasControls( LdapApiService codec )
+    {
+        codec.unregisterControl( SyncDoneValue.OID );
+        codec.unregisterControl( SyncInfoValue.OID );
+        codec.unregisterControl( SyncRequestValue.OID );
+        codec.unregisterControl( SyncStateValue.OID );
+        codec.unregisterControl( PasswordPolicy.OID );
+        codec.unregisterControl( AdDirSync.OID );
+    }
+
+
+    private void unregisterExtrasExtendedOps( LdapApiService codec )
+    {
+        codec.unregisterExtendedRequest( CancelRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( CertGenerationRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( GracefulShutdownRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( StoredProcedureRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( GracefulDisconnectResponse.EXTENSION_OID );
+        codec.unregisterExtendedRequest( PasswordModifyRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( WhoAmIRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( StartTlsRequest.EXTENSION_OID );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncContainer.java
new file mode 100644
index 0000000..fce8bc0
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncContainer.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ad_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSync;
+
+
+/**
+ * 
+ * ASN.1 container for AD DirSync control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AdDirSyncContainer extends AbstractContainer
+{
+    /** adDirSync */
+    private AdDirSync control;
+
+    private LdapApiService codec;
+
+
+    /**
+     * 
+     * Creates a new AdDirSyncControl Container object.
+     *
+     */
+    public AdDirSyncContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        this.control = new AdDirSyncDecorator( codec );
+        setGrammar( AdDirSyncGrammar.getInstance() );
+        setTransition( AdDirSyncStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * 
+     * Creates a new AdDirSyncControl object.
+     *
+     */
+    public AdDirSyncContainer( LdapApiService codec, AdDirSync control )
+    {
+        super();
+        this.codec = codec;
+        this.control = control;
+        setGrammar( AdDirSyncGrammar.getInstance() );
+        setTransition( AdDirSyncStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return the AdDirSyncControlCodec object
+     */
+    public AdDirSync getAdDirSyncControl()
+    {
+        return control;
+    }
+
+
+    /**
+     * Set a AdDirSyncControlCodec Object into the container. It will be completed
+     * by the ldapDecoder.
+     * 
+     * @param control the AdDirSyncControlCodec to set.
+     */
+    public void setAdDirSyncControl( AdDirSync control )
+    {
+        this.control = control;
+    }
+
+
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * clean the container
+     */
+    @Override
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncDecorator.java
new file mode 100644
index 0000000..c4a2ad3
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncDecorator.java
@@ -0,0 +1,272 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ad_impl;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSync;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSyncFlag;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSyncImpl;
+import org.apache.directory.api.util.Strings;
+
+/**
+ * A decorator around AdDirSync control. It will encode and decode this control.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AdDirSyncDecorator extends ControlDecorator<AdDirSync> implements AdDirSync
+{
+    /** The global length for this control */
+    private int adDirSyncLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Creates a new instance of AdDirSyncControlCodec.
+     */
+    public AdDirSyncDecorator( LdapApiService codec )
+    {
+        super( codec, new AdDirSyncImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of AdDirSyncDecorator.
+     *
+     * @param codec The LDAP codec
+     * @param control The control to be decorated
+     */
+    public AdDirSyncDecorator( LdapApiService codec, AdDirSync control )
+    {
+        super( codec, control );
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public int getParentFirst()
+    {
+        return getDecorated().getParentFirst();
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void setParentFirst( int parentFirst )
+    {
+        getDecorated().setParentFirst( parentFirst );
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public AdDirSyncFlag getFlag()
+    {
+        return getDecorated().getFlag();
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void setFlag( AdDirSyncFlag flag )
+    {
+        getDecorated().setFlag( flag );
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public int getMaxReturnLength()
+    {
+        return getDecorated().getMaxReturnLength();
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void setMaxReturnLength( int maxReturnLength )
+    {
+        getDecorated().setMaxReturnLength( maxReturnLength );
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return getDecorated().getCookie();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        // Copy the bytes
+        if ( !Strings.isEmpty( cookie ) )
+        {
+            byte[] copy = new byte[cookie.length];
+            System.arraycopy( cookie, 0, copy, 0, cookie.length );
+            getDecorated().setCookie( copy );
+        }
+        else
+        {
+            getDecorated().setCookie( null );
+        }
+    }
+
+
+    /**
+     * Compute the AdDirSync length. We use the client side control.
+     * 0x30 L1
+     * |
+     * +--> 0x02 0x0(1-4) nnn  (parentFirst)
+     * +--> 0x02 0x0(1-4) nnn  (maxReturnLength)
+     * +--> 0x04 L2 xkcd!!!...     (cookie)
+     */
+    @Override
+    public int computeLength()
+    {
+        // the parentFirst flag length
+        adDirSyncLength = 1 + TLV.getNbBytes( getParentFirst() ) + BerValue.getNbBytes( getParentFirst() );
+
+        // the maxReturnLength length
+        adDirSyncLength += 1 + TLV.getNbBytes( getMaxReturnLength() ) + BerValue.getNbBytes( getMaxReturnLength() );
+
+        // cookie's length
+        byte[] cookie = getCookie();
+        
+        if ( cookie == null )
+        {
+            adDirSyncLength += 1 + 1;
+        }
+        else
+        {
+            adDirSyncLength += 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( adDirSyncLength ) + adDirSyncLength;
+
+        // Call the super class to compute the global control length
+        return valueLength;
+    }
+
+
+    /**
+     * Encode the AdDirSync control. We use the client side control.
+     *
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong while encoding.
+     */
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Encode the SEQ
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( adDirSyncLength ) );
+
+        // Encode the ParentFirst flag
+        BerValue.encode( buffer, getParentFirst() );
+
+        // Encode the MaxReturnLength
+        BerValue.encode( buffer, getMaxReturnLength() );
+        
+        // Encode the cookie
+        BerValue.encode( buffer, getCookie() );
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                // Encode the SEQ
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+                buffer.put( TLV.getBytes( adDirSyncLength ) );
+
+                // Encode the ParentFirst flag
+                BerValue.encode( buffer, getParentFirst() );
+
+                // Encode the MaxReturnLength
+                BerValue.encode( buffer, getMaxReturnLength() );
+                
+                // Encode the cookie
+                BerValue.encode( buffer, getCookie() );
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        AdDirSyncContainer container = new AdDirSyncContainer( getCodecService(), this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncFactory.java
new file mode 100644
index 0000000..8ca8bbd
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ad_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSync;
+
+
+/**
+ * A {@link ControlFactory} which creates {@link AdDirSync} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class AdDirSyncFactory implements ControlFactory<AdDirSync>
+{
+    /** The codec for this factory */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of AdDirSyncFactory.
+     *
+     * @param codec The codec for this factory.
+     */
+    public AdDirSyncFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return AdDirSync.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<AdDirSync> newCodecControl()
+    {
+        return new AdDirSyncDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<AdDirSync> newCodecControl( AdDirSync control )
+    {
+        return new AdDirSyncDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncGrammar.java
new file mode 100644
index 0000000..18416bd
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncGrammar.java
@@ -0,0 +1,224 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ad_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.ldap.extras.controls.ad.AdDirSyncFlag;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * 
+ * Implementation of AdDirSync Response Control. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ *
+ *  The decoded grammar is as follows :
+ *  
+ *  <pre>
+ * realReplControlValue ::= SEQUENCE {
+ *     flag                  integer
+ *     maxReturnLength       integer
+ *     cookie                OCTET STRING
+ * }
+ * </pre> 
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class AdDirSyncGrammar extends AbstractGrammar<AdDirSyncContainer>
+{
+
+    /** the logger */
+    private static final Logger LOG = LoggerFactory.getLogger( AdDirSyncGrammar.class );
+
+    /** speedup for logger */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** AdDirSyncControlGrammar singleton instance */
+    private static final AdDirSyncGrammar INSTANCE = new AdDirSyncGrammar();
+
+
+    /**
+     * 
+     * Creates a new instance of AdDirSyncControlGrammar.
+     *
+     */
+    @SuppressWarnings("unchecked")
+    private AdDirSyncGrammar()
+    {
+        setName( AdDirSyncGrammar.class.getName() );
+
+        super.transitions = new GrammarTransition[AdDirSyncStatesEnum.LAST_AD_DIR_SYNC_STATE.ordinal()][256];
+
+        /** 
+         * Transition from initial state to AdDirSync sequence
+         * AdDirSync ::= SEQUENCE {
+         *     ...
+         *     
+         * Initialize the adDirSync object
+         */
+        super.transitions[AdDirSyncStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
+            new GrammarTransition<AdDirSyncContainer>(
+            AdDirSyncStatesEnum.START_STATE, AdDirSyncStatesEnum.AD_DIR_SYNC_SEQUENCE_STATE,
+            UniversalTag.SEQUENCE.getValue(),
+            new GrammarAction<AdDirSyncContainer>( "Initialization" )
+            {
+                public void action( AdDirSyncContainer container ) throws DecoderException
+                {
+                }
+            } );
+
+        
+        /**
+         * transition from start to flag
+         * realReplControlValue ::= SEQUENCE {
+         *     flag            integer
+         *    ....
+         * }
+         */
+        super.transitions[AdDirSyncStatesEnum.AD_DIR_SYNC_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER
+            .getValue()] =
+            new GrammarTransition<AdDirSyncContainer>( AdDirSyncStatesEnum.AD_DIR_SYNC_SEQUENCE_STATE,
+                AdDirSyncStatesEnum.FLAG_STATE, UniversalTag.INTEGER.getValue(),
+                new GrammarAction<AdDirSyncContainer>( "Set AdDirSyncControl parentFirst" )
+                {
+                    public void action( AdDirSyncContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int flagValue = IntegerDecoder.parse( value );
+                            
+                            AdDirSyncFlag flag = AdDirSyncFlag.getFlag( flagValue );
+                            
+                            if ( flag == null )
+                            {
+                                String msg = "Error while decoding the AdDirSync flag, unknown value : " + flagValue;
+                                LOG.error( msg );
+                                throw new DecoderException( msg );
+                            }
+                            
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "flag = {}", flagValue );
+                            }
+                            
+                            container.getAdDirSyncControl().setFlag( flag );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = "Error while decoding the AdDirSync flag : " + ide.getMessage();
+                            LOG.error( msg, ide );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+
+        
+        /**
+         * transition from flag to maxReturnLength
+         * realReplControlValue ::= SEQUENCE {
+         *     flag                    integer
+         *     maxReturnLength         integer
+         *    ....
+         * }
+         */
+        super.transitions[AdDirSyncStatesEnum.FLAG_STATE.ordinal()][UniversalTag.INTEGER
+            .getValue()] =
+            new GrammarTransition<AdDirSyncContainer>( AdDirSyncStatesEnum.FLAG_STATE,
+                AdDirSyncStatesEnum.MAX_RETURN_LENGTH_STATE, UniversalTag.INTEGER.getValue(),
+                new GrammarAction<AdDirSyncContainer>( "Set AdDirSyncControl maxReturnLength" )
+                {
+                    public void action( AdDirSyncContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int maxReturnLength = IntegerDecoder.parse( value );
+                            
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "maxReturnLength = {}", maxReturnLength );
+                            }
+                            
+                            container.getAdDirSyncControl().setMaxReturnLength( maxReturnLength );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = "Error while decoding the AdDirSync maxReturnLength : " + ide.getMessage();
+                            LOG.error( msg, ide );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+        
+        
+        /**
+         * transition from maxReturnLength to cookie
+         *     ...
+         *     maxReturnLength         integer
+         *     cookie                  OCTET STRING
+         * }
+         */
+        super.transitions[AdDirSyncStatesEnum.MAX_RETURN_LENGTH_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<AdDirSyncContainer>( AdDirSyncStatesEnum.MAX_RETURN_LENGTH_STATE,
+                AdDirSyncStatesEnum.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<AdDirSyncContainer>( "Set AdDirSyncControl cookie" )
+                {
+                    public void action( AdDirSyncContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] cookie = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "cookie = {}", Strings.dumpBytes( cookie ) );
+                        }
+
+                        container.getAdDirSyncControl().setCookie( cookie );
+
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+    }
+
+
+    /**
+     * @return the singleton instance of the AdDirSyncControlGrammar
+     */
+    public static Grammar<AdDirSyncContainer> getInstance()
+    {
+        return INSTANCE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncStatesEnum.java
new file mode 100644
index 0000000..27c8111
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ad_impl/AdDirSyncStatesEnum.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ad_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * ASN.1 grammar constants of AdDirSync Control.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum AdDirSyncStatesEnum implements States
+{
+
+    /** The END_STATE */
+    END_STATE,
+
+    /***/
+    START_STATE,
+
+    /** sequence start state */
+    AD_DIR_SYNC_SEQUENCE_STATE,
+
+    /** flag state */
+    FLAG_STATE,
+
+    /** maxReturnLength value state */
+    MAX_RETURN_LENGTH_STATE,
+
+    /** cookie value state */
+    COOKIE_STATE,
+
+    /** terminal state */
+    LAST_AD_DIR_SYNC_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "AD_DIR_SYNC_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<AdDirSyncContainer> grammar )
+    {
+        if ( grammar instanceof AdDirSyncGrammar )
+        {
+            return "AD_DIR_SYNC_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "AD_DIR_SYNC_GRAMMAR" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AdDirSyncStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PPolicyInit.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PPolicyInit.java
new file mode 100644
index 0000000..e2debcb
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PPolicyInit.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the PasswordPolicyResponseControlContainer object
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PPolicyInit extends GrammarAction<PasswordPolicyContainer>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( PPolicyInit.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new PPolicyInit action.
+     */
+    public PPolicyInit()
+    {
+        super( "Initialize the PasswordPolicyResponseControlContainer" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( PasswordPolicyContainer container ) throws DecoderException
+    {
+        // As all the values are optional or defaulted, we can end here
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "PasswordPolicyResponseControlContainer initialized" );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyContainer.java
new file mode 100644
index 0000000..65f530c
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyContainer.java
@@ -0,0 +1,89 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyImpl;
+
+
+/**
+ * container for PasswordPolicyResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordPolicyContainer extends AbstractContainer
+{
+    private PasswordPolicyDecorator control;
+
+
+    public PasswordPolicyContainer( LdapApiService codec )
+    {
+        super();
+        control = new PasswordPolicyDecorator( codec, new PasswordPolicyImpl() );
+        setGrammar( PasswordPolicyGrammar.getInstance() );
+        setTransition( PasswordPolicyStates.START_STATE );
+    }
+
+
+    public PasswordPolicyContainer( LdapApiService codec, PasswordPolicy ppolicyResponse )
+    {
+        super();
+
+        if ( ppolicyResponse instanceof PasswordPolicyDecorator )
+        {
+            this.control = ( PasswordPolicyDecorator ) ppolicyResponse;
+        }
+        else
+        {
+            control = new PasswordPolicyDecorator( codec, ppolicyResponse );
+        }
+
+        setGrammar( PasswordPolicyGrammar.getInstance() );
+        setTransition( PasswordPolicyStates.START_STATE );
+    }
+
+
+    public PasswordPolicyDecorator getPasswordPolicyResponseControl()
+    {
+        return control;
+    }
+
+
+    public void setPasswordPolicyResponseControl( PasswordPolicyDecorator control )
+    {
+        this.control = control;
+    }
+
+
+    /**
+     * clean the container
+     */
+    @Override
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java
new file mode 100644
index 0000000..9f21ced
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java
@@ -0,0 +1,275 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyImpl;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyResponse;
+
+
+/**
+ * PasswordPolicy decorator.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordPolicyDecorator extends ControlDecorator<PasswordPolicy> implements PasswordPolicy
+{
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+    // Storage for computed lengths
+    private int ppolicySeqLength = 0;
+    private int warningLength = 0;
+
+
+    public PasswordPolicyDecorator( LdapApiService codec )
+    {
+        super( codec, new PasswordPolicyImpl() );
+    }
+
+
+    public PasswordPolicyDecorator( LdapApiService codec, boolean hasResponse )
+    {
+        super( codec, new PasswordPolicyImpl( hasResponse ) );
+    }
+
+
+    public PasswordPolicyDecorator( LdapApiService codec, PasswordPolicy policy )
+    {
+        super( codec, policy );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setValue( byte[] value )
+    {
+        if ( ( value == null ) || ( value.length <= 2 ) )
+        {
+            setResponse( null );
+        }
+        else if ( !hasResponse() )
+        {
+            setResponse( true );
+        }
+
+        super.setValue( value );
+    }
+
+
+    @Override
+    public int computeLength()
+    {
+        // reset the length values
+        valueLength = 0;
+        ppolicySeqLength = 0;
+        warningLength = 0;
+
+        if ( !hasResponse() )
+        {
+            return 0;
+        }
+
+        if ( getResponse().getTimeBeforeExpiration() >= 0 )
+        {
+            int timeBeforeExpirationValueLength = BerValue.getNbBytes( getResponse().getTimeBeforeExpiration() );
+            warningLength = 1 + TLV.getNbBytes( timeBeforeExpirationValueLength ) + timeBeforeExpirationValueLength;
+        }
+        else if ( getResponse().getGraceAuthNRemaining() >= 0 )
+        {
+            int graceAuthNsRemainingValueLength = BerValue.getNbBytes( getResponse().getGraceAuthNRemaining() );
+            warningLength = 1 + TLV.getNbBytes( graceAuthNsRemainingValueLength ) + graceAuthNsRemainingValueLength;
+        }
+
+        if ( warningLength != 0 )
+        {
+            ppolicySeqLength = 1 + TLV.getNbBytes( warningLength ) + warningLength;
+        }
+
+        if ( getResponse().getPasswordPolicyError() != null )
+        {
+            ppolicySeqLength += 1 + 1 + 1;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( ppolicySeqLength ) + ppolicySeqLength;
+
+        return valueLength;
+    }
+
+
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( !hasResponse() )
+        {
+            return buffer;
+        }
+
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Encode the Sequence tag
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( ppolicySeqLength ) );
+
+        if ( ( getResponse().getTimeBeforeExpiration() < 0 ) && ( getResponse().getGraceAuthNRemaining() < 0 ) && (
+            getResponse().getPasswordPolicyError() == null ) )
+        {
+            return buffer;
+        }
+        else
+        {
+            if ( warningLength > 0 )
+            {
+                // Encode the Warning tag
+                buffer.put( ( byte ) PasswordPolicyTags.PPOLICY_WARNING_TAG.getValue() );
+                buffer.put( TLV.getBytes( warningLength ) );
+
+                if ( getResponse().getTimeBeforeExpiration() >= 0 )
+                {
+                    BerValue.encode(
+                        buffer,
+                        ( byte ) PasswordPolicyTags.TIME_BEFORE_EXPIRATION_TAG.getValue(),
+                        getResponse().getTimeBeforeExpiration() );
+                }
+                else if ( getResponse().getGraceAuthNRemaining() >= 0 )
+                {
+                    BerValue.encode(
+                        buffer,
+                        ( byte ) PasswordPolicyTags.GRACE_AUTHNS_REMAINING_TAG.getValue(),
+                        getResponse().getGraceAuthNRemaining() );
+                }
+            }
+
+            if ( getResponse().getPasswordPolicyError() != null )
+            {
+                BerValue.encode(
+                    buffer,
+                    ( byte ) PasswordPolicyTags.PPOLICY_ERROR_TAG.getValue(),
+                    getResponse().getPasswordPolicyError().getValue() );
+            }
+        }
+
+        return buffer;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "  PasswordPolicyResponse control :\n" );
+        sb.append( "   oid          : '" ).append( getOid() ).append( '\n' );
+
+        if ( hasResponse() && getResponse().getTimeBeforeExpiration() >= 0 )
+        {
+            sb.append( "   timeBeforeExpiration          : '" ).append( getResponse().getTimeBeforeExpiration() )
+                .append( '\n' );
+        }
+        else if ( hasResponse() && getResponse().getGraceAuthNRemaining() >= 0 )
+        {
+            sb.append( "   graceAuthNsRemaining          : '" ).append( getResponse().getGraceAuthNRemaining() )
+                .append( '\n' );
+        }
+
+        if ( hasResponse() && getResponse().getPasswordPolicyError() != null )
+        {
+            sb.append( "   ppolicyError          : '" ).append( getResponse().getPasswordPolicyError().toString() )
+                .append( '\n' );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        if ( !hasResponse() )
+        {
+            return this;
+        }
+
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        PasswordPolicyContainer container = new PasswordPolicyContainer( getCodecService(), this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+
+
+    /**
+     *
+     * {@inheritDoc}
+     */
+    public boolean hasResponse()
+    {
+        return getDecorated().hasResponse();
+    }
+
+
+    /**
+     *
+     * {@inheritDoc}
+     */
+    public void setResponse( PasswordPolicyResponse response )
+    {
+        getDecorated().setResponse( response );
+    }
+
+
+    /**
+     *
+     * {@inheritDoc}
+     */
+    public PasswordPolicyResponse setResponse( boolean hasResponse )
+    {
+        return getDecorated().setResponse( hasResponse );
+    }
+
+
+    /**
+     *
+     * {@inheritDoc}
+     */
+    public PasswordPolicyResponse getResponse()
+    {
+        return getDecorated().getResponse();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyFactory.java
new file mode 100644
index 0000000..c3fc313
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyFactory.java
@@ -0,0 +1,79 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+
+
+/**
+ * A {@link ControlFactory} which creates {@link PasswordPolicy} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class PasswordPolicyFactory implements ControlFactory<PasswordPolicy>
+{
+
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of PasswordPolicyFactory.
+     *
+     */
+    public PasswordPolicyFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return PasswordPolicy.OID;
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public CodecControl<PasswordPolicy> newCodecControl()
+    {
+        return new PasswordPolicyDecorator( codec );
+    }
+
+
+    /**
+     * 
+     * {@inheritDoc}
+     */
+    public CodecControl<PasswordPolicy> newCodecControl( PasswordPolicy control )
+    {
+        return new PasswordPolicyDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java
new file mode 100644
index 0000000..990ae6e
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java
@@ -0,0 +1,132 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.asn1.actions.CheckNotNullLength;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+
+
+/**
+ * Grammar for decoding PasswordPolicyResponseControl.
+ *
+ * PasswordPolicyResponseValue ::= SEQUENCE {
+ *         warning [0] CHOICE {
+ *         timeBeforeExpiration [0] INTEGER (0 .. maxInt),
+ *         graceAuthNsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL,
+ *         
+ *      error   [1] ENUMERATED {
+ *          passwordExpired             (0),
+ *          accountLocked               (1),
+ *          changeAfterReset            (2),
+ *          passwordModNotAllowed       (3),
+ *          mustSupplyOldPassword       (4),
+ *          insufficientPasswordQuality (5),
+ *          passwordTooShort            (6),
+ *          passwordTooYoung            (7),
+ *          passwordInHistory           (8) } OPTIONAL }
+ *          
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PasswordPolicyGrammar extends AbstractGrammar<PasswordPolicyContainer>
+{
+    /** PasswordPolicyResponseControlGrammar singleton instance */
+    private static final PasswordPolicyGrammar INSTANCE = new PasswordPolicyGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    private PasswordPolicyGrammar()
+    {
+        setName( PasswordPolicyGrammar.class.getName() );
+
+        super.transitions = new GrammarTransition[PasswordPolicyStates.END_STATE.ordinal()][256];
+
+        // PasswordPolicyResponseValue ::= SEQUENCE {
+        // ...
+        super.transitions[PasswordPolicyStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition<PasswordPolicyContainer>(
+            PasswordPolicyStates.START_STATE, PasswordPolicyStates.PPOLICY_SEQ_STATE,
+            UniversalTag.SEQUENCE.getValue(),
+            new PPolicyInit() );
+
+        // PasswordPolicyResponseValue ::= SEQUENCE {
+        //              warning [0] CHOICE {
+        super.transitions[PasswordPolicyStates.PPOLICY_SEQ_STATE.ordinal()][PasswordPolicyTags.PPOLICY_WARNING_TAG
+            .getValue()] = new GrammarTransition<PasswordPolicyContainer>(
+            PasswordPolicyStates.PPOLICY_SEQ_STATE, PasswordPolicyStates.PPOLICY_WARNING_TAG_STATE,
+            PasswordPolicyTags.PPOLICY_WARNING_TAG.getValue(),
+            new CheckNotNullLength<PasswordPolicyContainer>() );
+
+        // PasswordPolicyResponseValue ::= SEQUENCE {
+        //              ...
+        //              error   [1] ENUMERATED {
+        super.transitions[PasswordPolicyStates.PPOLICY_SEQ_STATE.ordinal()][PasswordPolicyTags.PPOLICY_ERROR_TAG
+            .getValue()] = new GrammarTransition<PasswordPolicyContainer>(
+            PasswordPolicyStates.PPOLICY_SEQ_STATE, PasswordPolicyStates.PPOLICY_ERROR_TAG_STATE,
+            PasswordPolicyTags.PPOLICY_ERROR_TAG.getValue(),
+            new StoreError<PasswordPolicyContainer>() );
+
+        // PasswordPolicyResponseValue ::= SEQUENCE {
+        //              warning [0] CHOICE {
+        //                      timeBeforeExpiration [0] INTEGER (0 .. maxInt),
+        super.transitions[PasswordPolicyStates.PPOLICY_WARNING_TAG_STATE.ordinal()][PasswordPolicyTags.TIME_BEFORE_EXPIRATION_TAG
+            .getValue()] = new GrammarTransition<PasswordPolicyContainer>(
+            PasswordPolicyStates.PPOLICY_WARNING_TAG_STATE, PasswordPolicyStates.PPOLICY_TIME_BEFORE_EXPIRATION_STATE,
+            PasswordPolicyTags.TIME_BEFORE_EXPIRATION_TAG.getValue(),
+            new StoreTimeBeforeExpiration() );
+
+        // PasswordPolicyResponseValue ::= SEQUENCE {
+        //              warning [0] CHOICE {
+        //                      ...
+        //                      graceAuthNsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL,
+        super.transitions[PasswordPolicyStates.PPOLICY_WARNING_TAG_STATE.ordinal()][PasswordPolicyTags.GRACE_AUTHNS_REMAINING_TAG
+            .getValue()] = new GrammarTransition<PasswordPolicyContainer>(
+            PasswordPolicyStates.PPOLICY_WARNING_TAG_STATE, PasswordPolicyStates.PPOLICY_GRACE_AUTHNS_REMAINING_STATE,
+            PasswordPolicyTags.GRACE_AUTHNS_REMAINING_TAG.getValue(),
+            new StoreGraceAuthNRemaining() );
+
+        // PasswordPolicyResponseValue ::= SEQUENCE {
+        //              ...
+        //              error   [1] ENUMERATED {
+        super.transitions[PasswordPolicyStates.PPOLICY_TIME_BEFORE_EXPIRATION_STATE.ordinal()][PasswordPolicyTags.PPOLICY_ERROR_TAG
+            .getValue()] = new GrammarTransition<PasswordPolicyContainer>(
+            PasswordPolicyStates.PPOLICY_TIME_BEFORE_EXPIRATION_STATE, PasswordPolicyStates.PPOLICY_ERROR_TAG_STATE,
+            PasswordPolicyTags.PPOLICY_ERROR_TAG.getValue(),
+            new StoreError<PasswordPolicyContainer>() );
+
+        // PasswordPolicyResponseValue ::= SEQUENCE {
+        //              ...
+        //              error   [1] ENUMERATED {
+        super.transitions[PasswordPolicyStates.PPOLICY_GRACE_AUTHNS_REMAINING_STATE.ordinal()][PasswordPolicyTags.GRACE_AUTHNS_REMAINING_TAG
+            .getValue()] = new GrammarTransition<PasswordPolicyContainer>(
+            PasswordPolicyStates.PPOLICY_GRACE_AUTHNS_REMAINING_STATE, PasswordPolicyStates.PPOLICY_ERROR_TAG_STATE,
+            PasswordPolicyTags.GRACE_AUTHNS_REMAINING_TAG.getValue(),
+            new StoreError<PasswordPolicyContainer>() );
+    }
+
+
+    public static Grammar<PasswordPolicyContainer> getInstance()
+    {
+        return INSTANCE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java
new file mode 100644
index 0000000..df3142a
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java
@@ -0,0 +1,91 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * various states used in {@link PasswordPolicyGrammar}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum PasswordPolicyStates implements States
+{
+    START_STATE,
+    PPOLICY_SEQ_STATE,
+    PPOLICY_WARNING_TAG_STATE,
+    PPOLICY_TIME_BEFORE_EXPIRATION_STATE,
+    PPOLICY_GRACE_AUTHNS_REMAINING_STATE,
+    PPOLICY_ERROR_TAG_STATE,
+    END_STATE;
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof PasswordPolicyGrammar )
+        {
+            return "PASSWORD_POLICY_RESPONSE_CONTROL_GRAMMAR";
+        }
+
+        return "UNKNOWN_GRAMMAR";
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "PASSWORD_POLICY_RESPONSE_CONTROL_GRAMMAR";
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "PASSWORD_POLICY_RESPONSE_CONTROL_GRAMMAR" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordPolicyStates getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyTags.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyTags.java
new file mode 100644
index 0000000..2411d1b
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/PasswordPolicyTags.java
@@ -0,0 +1,54 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+/**
+ * Tags used for decoding PasswordPolicyResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum PasswordPolicyTags
+{
+    // warning [0]
+    PPOLICY_WARNING_TAG(0xA0),
+    // error [1]
+    PPOLICY_ERROR_TAG(0x81),
+    // timeBeforeExpiration [0]
+    TIME_BEFORE_EXPIRATION_TAG(0x80),
+    // graceAuthNsRemaining [1]
+    GRACE_AUTHNS_REMAINING_TAG(0x81);
+
+    /** Internal value for each tag */
+    private int value;
+
+
+    private PasswordPolicyTags( int value )
+    {
+        this.value = value;
+    }
+
+
+    public int getValue()
+    {
+        return value;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreError.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreError.java
new file mode 100644
index 0000000..213a003
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreError.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum;
+
+
+/**
+ * The action used to store the error
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreError<C extends Asn1Container> extends AbstractReadInteger<C>
+{
+
+    /**
+     * Instantiates a new StoreError action.
+     */
+    public StoreError()
+    {
+        super( "PPolicy error" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, Asn1Container container )
+    {
+        PasswordPolicyContainer ppolicyContainer = ( PasswordPolicyContainer ) container;
+
+        PasswordPolicyErrorEnum error = PasswordPolicyErrorEnum.get( value );
+        ppolicyContainer.getPasswordPolicyResponseControl().getResponse().setPasswordPolicyError( error );
+
+        ppolicyContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreGraceAuthNRemaining.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreGraceAuthNRemaining.java
new file mode 100644
index 0000000..1e66708
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreGraceAuthNRemaining.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the GraceAuthsRemains
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreGraceAuthNRemaining extends AbstractReadInteger<PasswordPolicyContainer>
+{
+
+    /**
+     * Instantiates a new StoreCusec action.
+     */
+    public StoreGraceAuthNRemaining()
+    {
+        super( "PPolicy graceAuthnsRemains" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, PasswordPolicyContainer ppolicyContainer )
+    {
+        ppolicyContainer.getPasswordPolicyResponseControl().getResponse().setGraceAuthNRemaining( value );
+
+        ppolicyContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java
new file mode 100644
index 0000000..1885a3e
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ppolicy_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the TimeBeforeExpiration
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreTimeBeforeExpiration extends AbstractReadInteger<PasswordPolicyContainer>
+{
+
+    /**
+     * Instantiates a new StoreTimeBeforeExpiration action.
+     */
+    public StoreTimeBeforeExpiration()
+    {
+        super( "PPolicy TimeBeforeExpiration" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, PasswordPolicyContainer ppolicyContainer )
+    {
+        ppolicyContainer.getPasswordPolicyResponseControl().getResponse().setTimeBeforeExpiration( value );
+
+        ppolicyContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueContainer.java
new file mode 100644
index 0000000..f3ccdda
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueContainer.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValue;
+
+
+/**
+ * 
+ * ASN.1 container for SyncDoneValueControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncDoneValueContainer extends AbstractContainer
+{
+    /** syncDoneValue*/
+    private SyncDoneValue control;
+
+    private LdapApiService codec;
+
+
+    /**
+     * 
+     * Creates a new SyncDoneValueControlContainer object.
+     *
+     */
+    public SyncDoneValueContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        this.control = new SyncDoneValueDecorator( codec );
+        setGrammar( SyncDoneValueGrammar.getInstance() );
+        setTransition( SyncDoneValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * 
+     * Creates a new SyncDoneValueControlContainer object.
+     *
+     */
+    public SyncDoneValueContainer( LdapApiService codec, SyncDoneValue control )
+    {
+        super();
+        this.codec = codec;
+        this.control = control;
+        setGrammar( SyncDoneValueGrammar.getInstance() );
+        setTransition( SyncDoneValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return the SyncDoneValueControlCodec object
+     */
+    public SyncDoneValue getSyncDoneValueControl()
+    {
+        return control;
+    }
+
+
+    /**
+     * Set a SyncDoneValueControlCodec Object into the container. It will be completed
+     * by the ldapDecoder.
+     * 
+     * @param control the SyncDoneValueControlCodec to set.
+     */
+    public void setSyncDoneValueControl( SyncDoneValue control )
+    {
+        this.control = control;
+    }
+
+
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * clean the container
+     */
+    @Override
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java
new file mode 100644
index 0000000..b11e27c
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java
@@ -0,0 +1,232 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValueImpl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A syncDoneValue object as described in rfc4533.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncDoneValueDecorator extends ControlDecorator<SyncDoneValue> implements SyncDoneValue
+{
+    /** The global length for this control */
+    private int syncDoneValueLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Creates a new instance of SyncDoneValueControlCodec.
+     */
+    public SyncDoneValueDecorator( LdapApiService codec )
+    {
+        super( codec, new SyncDoneValueImpl() );
+    }
+
+
+    /**
+     * Creates a new instance of SyncDoneValueDecorator.
+     *
+     * @param codec The LDAP codec
+     * @param control The control to be decorated
+     */
+    public SyncDoneValueDecorator( LdapApiService codec, SyncDoneValue control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * Compute the syncDoneValue length.
+     * 0x30 L1
+     * |
+     * +--> 0x04 L2 xkcd!!!...     (cookie)
+     * +--> 0x01 0x01 [0x00|0xFF]  (refreshDeletes)
+     */
+    @Override
+    public int computeLength()
+    {
+        // cookie's length
+        if ( getCookie() != null )
+        {
+            syncDoneValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
+        }
+
+        // the refreshDeletes flag length
+        if ( isRefreshDeletes() )
+        {
+            syncDoneValueLength += 1 + 1 + 1;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( syncDoneValueLength ) + syncDoneValueLength;
+
+        // Call the super class to compute the global control length
+        return valueLength;
+    }
+
+
+    /**
+     * Encode the SyncDoneValue control
+     *
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong while encoding.
+     */
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Encode the SEQ
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( syncDoneValueLength ) );
+
+        if ( getCookie() != null )
+        {
+            BerValue.encode( buffer, getCookie() );
+        }
+
+        if ( isRefreshDeletes() )
+        {
+            BerValue.encode( buffer, isRefreshDeletes() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                // Encode the SEQ
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+                buffer.put( TLV.getBytes( syncDoneValueLength ) );
+
+                if ( getCookie() != null )
+                {
+                    BerValue.encode( buffer, getCookie() );
+                }
+
+                if ( isRefreshDeletes() )
+                {
+                    BerValue.encode( buffer, isRefreshDeletes() );
+                }
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return getDecorated().getCookie();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        // Copy the bytes
+        if ( !Strings.isEmpty( cookie ) )
+        {
+            byte[] copy = new byte[cookie.length];
+            System.arraycopy( cookie, 0, copy, 0, cookie.length );
+            getDecorated().setCookie( copy );
+        }
+        else
+        {
+            getDecorated().setCookie( null );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRefreshDeletes()
+    {
+        return getDecorated().isRefreshDeletes();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRefreshDeletes( boolean refreshDeletes )
+    {
+        getDecorated().setRefreshDeletes( refreshDeletes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        SyncDoneValueContainer container = new SyncDoneValueContainer( getCodecService(), this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueFactory.java
new file mode 100644
index 0000000..da629c1
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValue;
+
+
+/**
+ * A {@link ControlFactory} which creates {@link SyncDoneValue} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncDoneValueFactory implements ControlFactory<SyncDoneValue>
+{
+    /** The codec for this factory */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SyncDoneValueFactory.
+     *
+     * @param codec The codec for this factory.
+     */
+    public SyncDoneValueFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return SyncDoneValue.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncDoneValue> newCodecControl()
+    {
+        return new SyncDoneValueDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncDoneValue> newCodecControl( SyncDoneValue control )
+    {
+        return new SyncDoneValueDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java
new file mode 100644
index 0000000..e7a3ea7
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java
@@ -0,0 +1,190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * 
+ * Implementation of SyncDoneValueControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ *
+ *  The decoded grammar is as follows :
+ *  
+ *  syncDoneValue ::= SEQUENCE 
+ *  {
+ *       cookie          syncCookie OPTIONAL,
+ *       refreshDeletes  BOOLEAN DEFAULT FALSE
+ *  }
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SyncDoneValueGrammar extends AbstractGrammar<SyncDoneValueContainer>
+{
+
+    /** the logger */
+    private static final Logger LOG = LoggerFactory.getLogger( SyncDoneValueGrammar.class );
+
+    /** speedup for logger */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** SyncDoneValueControlGrammar singleton instance */
+    private static final SyncDoneValueGrammar INSTANCE = new SyncDoneValueGrammar();
+
+
+    /**
+     * 
+     * Creates a new instance of SyncDoneValueControlGrammar.
+     *
+     */
+    @SuppressWarnings("unchecked")
+    private SyncDoneValueGrammar()
+    {
+        setName( SyncDoneValueGrammar.class.getName() );
+
+        super.transitions = new GrammarTransition[SyncDoneValueStatesEnum.LAST_SYNC_DONE_VALUE_STATE.ordinal()][256];
+
+        /** 
+         * Transition from initial state to SyncDoneValue sequence
+         * SyncDoneValue ::= SEQUENCE {
+         *     ...
+         *     
+         * Initialize the syncDoneValue object
+         */
+        super.transitions[SyncDoneValueStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition<SyncDoneValueContainer>(
+            SyncDoneValueStatesEnum.START_STATE, SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE,
+            UniversalTag.SEQUENCE.getValue(),
+            new GrammarAction<SyncDoneValueContainer>( "Initialization" )
+            {
+                public void action( SyncDoneValueContainer container ) throws DecoderException
+                {
+                    // As all the values are optional or defaulted, we can end here
+                    container.setGrammarEndAllowed( true );
+                }
+            } );
+
+        /**
+         * transition from start to cookie
+         * {
+         *    cookie          syncCookie OPTIONAL
+         *    ....
+         * }
+         */
+        super.transitions[SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<SyncDoneValueContainer>( SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE,
+                SyncDoneValueStatesEnum.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<SyncDoneValueContainer>( "Set SyncDoneValueControl cookie" )
+                {
+                    public void action( SyncDoneValueContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] cookie = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "cookie = {}", Strings.dumpBytes( cookie ) );
+                        }
+
+                        container.getSyncDoneValueControl().setCookie( cookie );
+
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        GrammarAction<SyncDoneValueContainer> refreshDeletesTagAction =
+            new GrammarAction<SyncDoneValueContainer>( "set SyncDoneValueControl refreshDeletes flag" )
+            {
+                public void action( SyncDoneValueContainer container ) throws DecoderException
+                {
+                    BerValue value = container.getCurrentTLV().getValue();
+
+                    try
+                    {
+                        boolean refreshDeletes = BooleanDecoder.parse( value );
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "refreshDeletes = {}", refreshDeletes );
+                        }
+
+                        container.getSyncDoneValueControl().setRefreshDeletes( refreshDeletes );
+
+                        // the END transition for grammar
+                        container.setGrammarEndAllowed( true );
+                    }
+                    catch ( BooleanDecoderException be )
+                    {
+                        String msg = I18n.err( I18n.ERR_04024 );
+                        LOG.error( msg, be );
+                        throw new DecoderException( msg, be );
+                    }
+
+                }
+            };
+        /**
+         * transition from cookie to refreshDeletes
+         * {
+         *    ....
+         *    refreshDeletes BOOLEAN DEFAULT FALSE
+         * }
+         */
+        super.transitions[SyncDoneValueStatesEnum.COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SyncDoneValueContainer>(
+                SyncDoneValueStatesEnum.COOKIE_STATE, SyncDoneValueStatesEnum.REFRESH_DELETES_STATE,
+                UniversalTag.BOOLEAN.getValue(), refreshDeletesTagAction );
+
+        /**
+         * transition from SEQUENCE to refreshDeletes
+         * {
+         *    ....
+         *    refreshDeletes BOOLEAN DEFAULT FALSE
+         * }
+         */
+        super.transitions[SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE.ordinal()][UniversalTag.BOOLEAN
+            .getValue()] =
+            new GrammarTransition<SyncDoneValueContainer>( SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE,
+                SyncDoneValueStatesEnum.REFRESH_DELETES_STATE, UniversalTag.BOOLEAN.getValue(), refreshDeletesTagAction );
+    }
+
+
+    /**
+     * @return the singleton instance of the SyncDoneValueControlGrammar
+     */
+    public static Grammar<SyncDoneValueContainer> getInstance()
+    {
+        return INSTANCE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueStatesEnum.java
new file mode 100644
index 0000000..a7c1539
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueStatesEnum.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * ASN.1 grammer constants of SyncDoneValueControl.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SyncDoneValueStatesEnum implements States
+{
+
+    /** The END_STATE */
+    END_STATE,
+
+    /***/
+    START_STATE,
+
+    /** sequence start state */
+    SYNC_DONE_VALUE_SEQUENCE_STATE,
+
+    /** cookie value state */
+    COOKIE_STATE,
+
+    /** refreshDeletes value state */
+    REFRESH_DELETES_STATE,
+
+    /** terminal state */
+    LAST_SYNC_DONE_VALUE_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "SYNC_DONE_VALUE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<SyncDoneValueContainer> grammar )
+    {
+        if ( grammar instanceof SyncDoneValueGrammar )
+        {
+            return "SYNC_DONE_VALUE_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "SYNC_DONE_VALUE_GRAMMAR" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyncDoneValueStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueContainer.java
new file mode 100644
index 0000000..068520d
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueContainer.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
+
+
+/**
+ * A container for the SyncInfoValue control
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncInfoValueContainer extends AbstractContainer
+{
+    /** SyncInfoValueControl */
+    private SyncInfoValue control;
+
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new SyncInfoValueControlContainer object. We will store one grammar,
+     * it's enough ...
+     */
+    public SyncInfoValueContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        this.control = new SyncInfoValueDecorator( codec );
+        setGrammar( SyncInfoValueGrammar.getInstance() );
+        setTransition( SyncInfoValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * Creates a new SyncInfoValueControlContainer object. We will store one grammar,
+     * it's enough ...
+     */
+    public SyncInfoValueContainer( LdapApiService codec, SyncInfoValue control )
+    {
+        super();
+        this.codec = codec;
+        this.control = control;
+        setGrammar( SyncInfoValueGrammar.getInstance() );
+        setTransition( SyncInfoValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the syncInfoValue control.
+     */
+    public SyncInfoValue getSyncInfoValueControl()
+    {
+        return control;
+    }
+
+
+    /**
+     * Set a SyncInfoValueControl Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param control the SyncInfoValueControlCodec to set.
+     */
+    public void setSyncInfoValueControl( SyncInfoValue control )
+    {
+        this.control = control;
+    }
+
+
+    public LdapApiService getCodecService()
+    {
+        return codec;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java
new file mode 100644
index 0000000..48c4883
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java
@@ -0,0 +1,566 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValueImpl;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SynchronizationInfoEnum;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A syncInfoValue object, as defined in RFC 4533
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncInfoValueDecorator extends ControlDecorator<SyncInfoValue> implements SyncInfoValue
+{
+    /** The syncUUIDs cumulative length */
+    private int syncUUIDsLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * The constructor for this codec. Dont't forget to set the type.
+     */
+    public SyncInfoValueDecorator( LdapApiService codec )
+    {
+        super( codec, new SyncInfoValueImpl() );
+    }
+
+
+    /**
+     * The constructor for this codec. Dont't forget to set the type.
+     */
+    public SyncInfoValueDecorator( LdapApiService codec, SyncInfoValue control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * The constructor for this codec.
+     * @param type The kind of syncInfo we will store. Can be newCookie,
+     * refreshPresent, refreshDelete or syncIdSet
+     */
+    public SyncInfoValueDecorator( LdapApiService codec, SynchronizationInfoEnum type )
+    {
+        this( codec );
+
+        setType( type );
+    }
+
+    /** The global length for this control */
+    private int syncInfoValueLength;
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SynchronizationInfoEnum getType()
+    {
+        return getDecorated().getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setType( SynchronizationInfoEnum type )
+    {
+        this.getDecorated().setType( type );
+
+        // Initialize the arrayList if needed
+        if ( ( type == SynchronizationInfoEnum.SYNC_ID_SET ) && ( getDecorated().getSyncUUIDs() == null ) )
+        {
+            getDecorated().setSyncUUIDs( new ArrayList<byte[]>() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return getDecorated().getCookie();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        // Copy the bytes
+        if ( !Strings.isEmpty( cookie ) )
+        {
+            byte[] copy = new byte[cookie.length];
+            System.arraycopy( cookie, 0, copy, 0, cookie.length );
+            getDecorated().setCookie( copy );
+        }
+        else
+        {
+            getDecorated().setCookie( null );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRefreshDone()
+    {
+        return getDecorated().isRefreshDone();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRefreshDone( boolean refreshDone )
+    {
+        getDecorated().setRefreshDone( refreshDone );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRefreshDeletes()
+    {
+        return getDecorated().isRefreshDeletes();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRefreshDeletes( boolean refreshDeletes )
+    {
+        getDecorated().setRefreshDeletes( refreshDeletes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<byte[]> getSyncUUIDs()
+    {
+        return getDecorated().getSyncUUIDs();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSyncUUIDs( List<byte[]> syncUUIDs )
+    {
+        getDecorated().setSyncUUIDs( syncUUIDs );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addSyncUUID( byte[] syncUUID )
+    {
+        getDecorated().addSyncUUID( syncUUID );
+    }
+
+
+    /**
+     * Compute the SyncInfoValue length.
+     *
+     * SyncInfoValue :
+     *
+     * 0xA0 L1 abcd                   // newCookie
+     * 0xA1 L2                        // refreshDelete
+     *   |
+     *  [+--> 0x04 L3 abcd]           // cookie
+     *  [+--> 0x01 0x01 (0x00|0xFF)   // refreshDone
+     * 0xA2 L4                        // refreshPresent
+     *   |
+     *  [+--> 0x04 L5 abcd]           // cookie
+     *  [+--> 0x01 0x01 (0x00|0xFF)   // refreshDone
+     * 0xA3 L6                        // syncIdSet
+     *   |
+     *  [+--> 0x04 L7 abcd]           // cookie
+     *  [+--> 0x01 0x01 (0x00|0xFF)   // refreshDeletes
+     *   +--> 0x31 L8                 // SET OF syncUUIDs
+     *          |
+     *         [+--> 0x04 L9 abcd]    // syncUUID    public static final int AND_FILTER_TAG = 0xA0;
+
+    public static final int OR_FILTER_TAG = 0xA1;
+
+    public static final int NOT_FILTER_TAG = 0xA2;
+
+    public static final int BIND_REQUEST_SASL_TAG = 0xA3;
+
+     */
+    @Override
+    public int computeLength()
+    {
+        // The mode length
+        syncInfoValueLength = 0;
+
+        switch ( getType() )
+        {
+            case NEW_COOKIE:
+                if ( getCookie() != null )
+                {
+                    syncInfoValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
+                }
+                else
+                {
+                    syncInfoValueLength = 1 + 1;
+                }
+
+                valueLength = syncInfoValueLength;
+
+                // Call the super class to compute the global control length
+                return valueLength;
+
+            case REFRESH_DELETE:
+            case REFRESH_PRESENT:
+                if ( getCookie() != null )
+                {
+                    syncInfoValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
+                }
+
+                // The refreshDone flag, only if not true, as it default to true
+                if ( !isRefreshDone() )
+                {
+                    syncInfoValueLength += 1 + 1 + 1;
+                }
+
+                valueLength = 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
+
+                // Call the super class to compute the global control length
+                return valueLength;
+
+            case SYNC_ID_SET:
+                if ( getCookie() != null )
+                {
+                    syncInfoValueLength = 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
+                }
+
+                // The refreshDeletes flag, default to false
+                if ( isRefreshDeletes() )
+                {
+                    syncInfoValueLength += 1 + 1 + 1;
+                }
+
+                // The syncUUIDs if any
+                syncUUIDsLength = 0;
+
+                if ( getSyncUUIDs().size() != 0 )
+                {
+                    for ( byte[] syncUUID : getSyncUUIDs() )
+                    {
+                        int uuidLength = 1 + TLV.getNbBytes( syncUUID.length ) + syncUUID.length;
+
+                        syncUUIDsLength += uuidLength;
+                    }
+                }
+
+                syncInfoValueLength += 1 + TLV.getNbBytes( syncUUIDsLength ) + syncUUIDsLength;
+                valueLength = 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
+
+                // Call the super class to compute the global control length
+                return valueLength;
+
+            default:
+
+        }
+
+        return 1 + TLV.getNbBytes( syncInfoValueLength ) + syncInfoValueLength;
+    }
+
+
+    /**
+     * Encode the SyncInfoValue control
+     *
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        switch ( getType() )
+        {
+            case NEW_COOKIE:
+                // The first case : newCookie
+                buffer.put( ( byte ) SyncInfoValueTags.NEW_COOKIE_TAG.getValue() );
+
+                // As the OCTET_STRING is absorbed by the Application tag,
+                // we have to store the L and V separately
+                if ( ( getCookie() == null ) || ( getCookie().length == 0 ) )
+                {
+                    buffer.put( ( byte ) 0 );
+                }
+                else
+                {
+                    buffer.put( TLV.getBytes( getCookie().length ) );
+                    buffer.put( getCookie() );
+                }
+
+                break;
+
+            case REFRESH_DELETE:
+                // The second case : refreshDelete
+                buffer.put( ( byte ) SyncInfoValueTags.REFRESH_DELETE_TAG.getValue() );
+                buffer.put( TLV.getBytes( syncInfoValueLength ) );
+
+                // The cookie, if any
+                if ( getCookie() != null )
+                {
+                    BerValue.encode( buffer, getCookie() );
+                }
+
+                // The refreshDone flag
+                if ( !isRefreshDone() )
+                {
+                    BerValue.encode( buffer, isRefreshDone() );
+                }
+
+                break;
+
+            case REFRESH_PRESENT:
+                // The third case : refreshPresent
+                buffer.put( ( byte ) SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue() );
+                buffer.put( TLV.getBytes( syncInfoValueLength ) );
+
+                // The cookie, if any
+                if ( getCookie() != null )
+                {
+                    BerValue.encode( buffer, getCookie() );
+                }
+
+                // The refreshDone flag
+                if ( !isRefreshDone() )
+                {
+                    BerValue.encode( buffer, isRefreshDone() );
+                }
+
+                break;
+
+            case SYNC_ID_SET:
+                // The last case : syncIdSet
+                buffer.put( ( byte ) SyncInfoValueTags.SYNC_ID_SET_TAG.getValue() );
+                buffer.put( TLV.getBytes( syncInfoValueLength ) );
+
+                // The cookie, if any
+                if ( getCookie() != null )
+                {
+                    BerValue.encode( buffer, getCookie() );
+                }
+
+                // The refreshDeletes flag if not false
+                if ( isRefreshDeletes() )
+                {
+                    BerValue.encode( buffer, isRefreshDeletes() );
+                }
+
+                // The syncUUIDs
+                buffer.put( UniversalTag.SET.getValue() );
+                buffer.put( TLV.getBytes( syncUUIDsLength ) );
+
+                // Loop on the UUIDs if any
+                if ( getSyncUUIDs().size() != 0 )
+                {
+                    for ( byte[] syncUUID : getSyncUUIDs() )
+                    {
+                        BerValue.encode( buffer, syncUUID );
+                    }
+                }
+
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected SynchronizationInfo: " + getType() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                switch ( getType() )
+                {
+                    case NEW_COOKIE:
+                        // The first case : newCookie
+                        buffer.put( ( byte ) SyncInfoValueTags.NEW_COOKIE_TAG.getValue() );
+
+                        // As the OCTET_STRING is absorbed by the Application tag,
+                        // we have to store the L and V separately
+                        if ( ( getCookie() == null ) || ( getCookie().length == 0 ) )
+                        {
+                            buffer.put( ( byte ) 0 );
+                        }
+                        else
+                        {
+                            buffer.put( TLV.getBytes( getCookie().length ) );
+                            buffer.put( getCookie() );
+                        }
+
+                        break;
+
+                    case REFRESH_DELETE:
+                        // The second case : refreshDelete
+                        buffer.put( ( byte ) SyncInfoValueTags.REFRESH_DELETE_TAG.getValue() );
+                        buffer.put( TLV.getBytes( syncInfoValueLength ) );
+
+                        // The cookie, if any
+                        if ( getCookie() != null )
+                        {
+                            BerValue.encode( buffer, getCookie() );
+                        }
+
+                        // The refreshDone flag
+                        if ( !isRefreshDone() )
+                        {
+                            BerValue.encode( buffer, isRefreshDone() );
+                        }
+
+                        break;
+
+                    case REFRESH_PRESENT:
+                        // The third case : refreshPresent
+                        buffer.put( ( byte ) SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue() );
+                        buffer.put( TLV.getBytes( syncInfoValueLength ) );
+
+                        // The cookie, if any
+                        if ( getCookie() != null )
+                        {
+                            BerValue.encode( buffer, getCookie() );
+                        }
+
+                        // The refreshDone flag
+                        if ( !isRefreshDone() )
+                        {
+                            BerValue.encode( buffer, isRefreshDone() );
+                        }
+
+                        break;
+
+                    case SYNC_ID_SET:
+                        // The last case : syncIdSet
+                        buffer.put( ( byte ) SyncInfoValueTags.SYNC_ID_SET_TAG.getValue() );
+                        buffer.put( TLV.getBytes( syncInfoValueLength ) );
+
+                        // The cookie, if any
+                        if ( getCookie() != null )
+                        {
+                            BerValue.encode( buffer, getCookie() );
+                        }
+
+                        // The refreshDeletes flag if not false
+                        if ( isRefreshDeletes() )
+                        {
+                            BerValue.encode( buffer, isRefreshDeletes() );
+                        }
+
+                        // The syncUUIDs
+                        buffer.put( UniversalTag.SET.getValue() );
+                        buffer.put( TLV.getBytes( syncUUIDsLength ) );
+
+                        // Loop on the UUIDs if any
+                        if ( getSyncUUIDs().size() != 0 )
+                        {
+                            for ( byte[] syncUUID : getSyncUUIDs() )
+                            {
+                                BerValue.encode( buffer, syncUUID );
+                            }
+                        }
+
+                        break;
+
+                    default:
+                        throw new IllegalArgumentException( "Unexpected SynchronizationInfo: " + getType() );
+                }
+
+                value = buffer.array();
+            }
+            catch ( EncoderException e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        SyncInfoValueContainer container = new SyncInfoValueContainer( getCodecService(), this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return getDecorated().toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueFactory.java
new file mode 100644
index 0000000..fe669aa
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
+
+
+/**
+ * A {@link ControlFactory} which creates {@link SyncInfoValue} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncInfoValueFactory implements ControlFactory<SyncInfoValue>
+{
+
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SyncInfoValueFactory.
+     *
+     * @param codec The codec for this factory.
+     */
+    public SyncInfoValueFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return SyncInfoValue.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncInfoValue> newCodecControl()
+    {
+        return new SyncInfoValueDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncInfoValue> newCodecControl( SyncInfoValue control )
+    {
+        return new SyncInfoValueDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueGrammar.java
new file mode 100644
index 0000000..16371e9
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueGrammar.java
@@ -0,0 +1,760 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SynchronizationInfoEnum;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the SyncInfoValueControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ * 
+ * The decoded grammar is the following :
+ * 
+ * syncInfoValue ::= CHOICE {
+ *     newcookie      [0] syncCookie,
+ *     refreshDelete  [1] SEQUENCE {
+ *         cookie         syncCookie OPTIONAL,
+ *         refreshDone    BOOLEAN DEFAULT TRUE
+ *     },
+ *     refreshPresent [2] SEQUENCE {
+ *         cookie         syncCookie OPTIONAL,
+ *         refreshDone    BOOLEAN DEFAULT TRUE
+ *     },
+ *     syncIdSet      [3] SEQUENCE {
+ *         cookie         syncCookie OPTIONAL,
+ *         refreshDeletes BOOLEAN DEFAULT FALSE,
+ *         syncUUIDs      SET OF syncUUID
+ *     }
+ * }
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SyncInfoValueGrammar extends AbstractGrammar<SyncInfoValueContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( SyncInfoValueGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. SyncInfoValueControlGrammar is a singleton */
+    private static Grammar<SyncInfoValueContainer> instance = new SyncInfoValueGrammar();
+
+
+    /**
+     * Creates a new SyncInfoValueControlGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private SyncInfoValueGrammar()
+    {
+        setName( SyncInfoValueGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[SyncInfoValueStatesEnum.LAST_SYNC_INFO_VALUE_STATE
+            .ordinal()][256];
+
+        /** 
+         * Transition from initial state to SyncInfoValue newCookie choice
+         * SyncInfoValue ::= CHOICE {
+         *     newCookie [0] syncCookie,
+         *     ...
+         *     
+         * Initialize the syncInfoValue object
+         */
+        super.transitions[SyncInfoValueStatesEnum.START_STATE.ordinal()][SyncInfoValueTags.NEW_COOKIE_TAG.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.START_STATE,
+                SyncInfoValueStatesEnum.NEW_COOKIE_STATE,
+                SyncInfoValueTags.NEW_COOKIE_TAG.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "NewCookie choice for SyncInfoValueControl" )
+                {
+                    public void action( SyncInfoValueContainer container )
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+                        control.setType( SynchronizationInfoEnum.NEW_COOKIE );
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] newCookie = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "newcookie = " + Strings.dumpBytes( newCookie ) );
+                        }
+
+                        control.setCookie( newCookie );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+
+                        container.setSyncInfoValueControl( control );
+                    }
+                } );
+
+        /** 
+         * Transition from initial state to SyncInfoValue refreshDelete choice
+         * SyncInfoValue ::= CHOICE {
+         *     ...
+         *     refreshDelete [1] SEQUENCE {
+         *     ...
+         *     
+         * Initialize the syncInfoValue object
+         */
+        super.transitions[SyncInfoValueStatesEnum.START_STATE.ordinal()][SyncInfoValueTags.REFRESH_DELETE_TAG
+            .getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.START_STATE,
+                SyncInfoValueStatesEnum.REFRESH_DELETE_STATE,
+                SyncInfoValueTags.REFRESH_DELETE_TAG.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshDelete choice for SyncInfoValueControl" )
+                {
+                    public void action( SyncInfoValueContainer container )
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+                        control.setType( SynchronizationInfoEnum.REFRESH_DELETE );
+
+                        container.setSyncInfoValueControl( control );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from refreshDelete state to cookie
+         *     refreshDelete [1] SEQUENCE {
+         *         cookie syncCookie OPTIONAL,
+         *     ...
+         *     
+         * Load the cookie object
+         */
+        super.transitions[SyncInfoValueStatesEnum.REFRESH_DELETE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.REFRESH_DELETE_STATE,
+                SyncInfoValueStatesEnum.REFRESH_DELETE_COOKIE_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshDelete cookie" )
+                {
+                    public void action( SyncInfoValueContainer container )
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] cookie = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "cookie = " + Strings.dumpBytes( cookie ) );
+                        }
+
+                        container.getSyncInfoValueControl().setCookie( cookie );
+                        container.setSyncInfoValueControl( control );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from refreshDelete cookie state to refreshDone
+         *     refreshDelete [1] SEQUENCE {
+         *         ....
+         *         refreshDone BOOLEAN DEFAULT TRUE
+         *     }
+         *     
+         * Load the refreshDone flag
+         */
+        super.transitions[SyncInfoValueStatesEnum.REFRESH_DELETE_COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN
+            .getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.REFRESH_DELETE_COOKIE_STATE,
+                SyncInfoValueStatesEnum.LAST_SYNC_INFO_VALUE_STATE,
+                UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshDelete refreshDone flag" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean refreshDone = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "refreshDone = {}", refreshDone );
+                            }
+
+                            control.setRefreshDone( refreshDone );
+
+                            container.setSyncInfoValueControl( control );
+
+                            // the END transition for grammar
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException be )
+                        {
+                            String msg = I18n.err( I18n.ERR_04025 );
+                            LOG.error( msg, be );
+                            throw new DecoderException( msg, be );
+                        }
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from refreshDelete choice state to refreshDone
+         *     refreshDelete [1] SEQUENCE {
+         *         ....
+         *         refreshDone BOOLEAN DEFAULT TRUE
+         *     }
+         *     
+         * Load the refreshDone flag
+         */
+        super.transitions[SyncInfoValueStatesEnum.REFRESH_DELETE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.REFRESH_DELETE_STATE,
+                SyncInfoValueStatesEnum.LAST_SYNC_INFO_VALUE_STATE,
+                UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshDelete refreshDone flag" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean refreshDone = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "refreshDone = {}", refreshDone );
+                            }
+
+                            control.setRefreshDone( refreshDone );
+
+                            container.setSyncInfoValueControl( control );
+
+                            // the END transition for grammar
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException be )
+                        {
+                            String msg = I18n.err( I18n.ERR_04025 );
+                            LOG.error( msg, be );
+                            throw new DecoderException( msg, be );
+                        }
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from initial state to SyncInfoValue refreshPresent choice
+         * SyncInfoValue ::= CHOICE {
+         *     ...
+         *     refreshPresent [2] SEQUENCE {
+         *     ...
+         *     
+         * Initialize the syncInfoValue object
+         */
+        super.transitions[SyncInfoValueStatesEnum.START_STATE.ordinal()][SyncInfoValueTags.REFRESH_PRESENT_TAG
+            .getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.START_STATE,
+                SyncInfoValueStatesEnum.REFRESH_PRESENT_STATE,
+                SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshDelete choice for SyncInfoValueControl" )
+                {
+                    public void action( SyncInfoValueContainer container )
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+                        control.setType( SynchronizationInfoEnum.REFRESH_PRESENT );
+
+                        container.setSyncInfoValueControl( control );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from refreshPresent state to cookie
+         *     refreshPresent [2] SEQUENCE {
+         *         cookie syncCookie OPTIONAL,
+         *     ...
+         *     
+         * Load the cookie object
+         */
+        super.transitions[SyncInfoValueStatesEnum.REFRESH_PRESENT_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.REFRESH_PRESENT_STATE,
+                SyncInfoValueStatesEnum.REFRESH_PRESENT_COOKIE_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshPresent cookie" )
+                {
+                    public void action( SyncInfoValueContainer container )
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] cookie = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "cookie = " + Strings.dumpBytes( cookie ) );
+                        }
+
+                        container.getSyncInfoValueControl().setCookie( cookie );
+                        container.setSyncInfoValueControl( control );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from refreshPresent cookie state to refreshDone
+         *     refreshPresent [2] SEQUENCE {
+         *         ....
+         *         refreshDone BOOLEAN DEFAULT TRUE
+         *     }
+         *     
+         * Load the refreshDone flag
+         */
+        super.transitions[SyncInfoValueStatesEnum.REFRESH_PRESENT_COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN
+            .getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.REFRESH_PRESENT_COOKIE_STATE,
+                SyncInfoValueStatesEnum.LAST_SYNC_INFO_VALUE_STATE,
+                UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshPresent refreshDone flag" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean refreshDone = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "refreshDone = {}", refreshDone );
+                            }
+
+                            control.setRefreshDone( refreshDone );
+
+                            container.setSyncInfoValueControl( control );
+
+                            // the END transition for grammar
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException be )
+                        {
+                            String msg = I18n.err( I18n.ERR_04025 );
+                            LOG.error( msg, be );
+                            throw new DecoderException( msg, be );
+                        }
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from refreshPresent choice state to refreshDone
+         *     refreshPresent [1] SEQUENCE {
+         *         ....
+         *         refreshDone BOOLEAN DEFAULT TRUE
+         *     }
+         *     
+         * Load the refreshDone flag
+         */
+        super.transitions[SyncInfoValueStatesEnum.REFRESH_PRESENT_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.REFRESH_PRESENT_STATE,
+                SyncInfoValueStatesEnum.LAST_SYNC_INFO_VALUE_STATE,
+                UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "RefreshPresent refreshDone flag" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean refreshDone = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "refreshDone = {}", refreshDone );
+                            }
+
+                            control.setRefreshDone( refreshDone );
+
+                            container.setSyncInfoValueControl( control );
+
+                            // the END transition for grammar
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException be )
+                        {
+                            String msg = I18n.err( I18n.ERR_04025 );
+                            LOG.error( msg, be );
+                            throw new DecoderException( msg, be );
+                        }
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from initial state to SyncInfoValue syncIdSet choice
+         * SyncInfoValue ::= CHOICE {
+         *     ...
+         *     syncIdSet [3] SEQUENCE {
+         *     ...
+         *     
+         * Initialize the syncInfoValue object
+         */
+        super.transitions[SyncInfoValueStatesEnum.START_STATE.ordinal()][SyncInfoValueTags.SYNC_ID_SET_TAG.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.START_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_STATE,
+                SyncInfoValueTags.SYNC_ID_SET_TAG.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet choice for SyncInfoValueControl" )
+                {
+                    public void action( SyncInfoValueContainer container )
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+                        control.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+                        container.setSyncInfoValueControl( control );
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet state to cookie
+         *     syncIdSet [3] SEQUENCE {
+         *         cookie syncCookie OPTIONAL,
+         *     ...
+         *     
+         * Load the cookie object
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_COOKIE_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet cookie" )
+                {
+                    public void action( SyncInfoValueContainer container )
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] cookie = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "cookie = " + Strings.dumpBytes( cookie ) );
+                        }
+
+                        container.getSyncInfoValueControl().setCookie( cookie );
+                        container.setSyncInfoValueControl( control );
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet state to refreshDeletes
+         *     syncIdSet [3] SEQUENCE {
+         *         ...
+         *         refreshDeletes BOOLEAN DEFAULT FALSE,
+         *     ...
+         *     
+         * Load the refreshDeletes flag
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE,
+                UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet refreshDeletes" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean refreshDeletes = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "refreshDeletes = {}", refreshDeletes );
+                            }
+
+                            control.setRefreshDeletes( refreshDeletes );
+
+                            container.setSyncInfoValueControl( control );
+                        }
+                        catch ( BooleanDecoderException be )
+                        {
+                            String msg = I18n.err( I18n.ERR_04026 );
+                            LOG.error( msg, be );
+                            throw new DecoderException( msg, be );
+                        }
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet cookie state to refreshDeletes
+         *     syncIdSet [3] SEQUENCE {
+         *         ...
+         *         refreshDeletes BOOLEAN DEFAULT FALSE,
+         *     ...
+         *     
+         * Load the refreshDeletes flag
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_COOKIE_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE,
+                UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet refreshDeletes" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean refreshDeletes = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "refreshDeletes = {}", refreshDeletes );
+                            }
+
+                            control.setRefreshDeletes( refreshDeletes );
+
+                            container.setSyncInfoValueControl( control );
+                        }
+                        catch ( BooleanDecoderException be )
+                        {
+                            String msg = I18n.err( I18n.ERR_04024 );
+                            LOG.error( msg, be );
+                            throw new DecoderException( msg, be );
+                        }
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet state to syncUUIDs
+         *     syncIdSet [3] SEQUENCE {
+         *         ...
+         *         syncUUIDs      *SET OF* syncUUID
+         *     }
+         *     
+         * Initialize the UUID set : no action associated, except allowing a grammar end
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_STATE.ordinal()][UniversalTag.SET.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE,
+                UniversalTag.SET.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet syncUUIDs" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet cookie state to syncUUIDs
+         *     syncIdSet [3] SEQUENCE {
+         *         ...
+         *         syncUUIDs      *SET OF* syncUUID
+         *     }
+         *     
+         * Initialize the UUID set : no action associated
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_COOKIE_STATE.ordinal()][UniversalTag.SET.getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_COOKIE_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE,
+                UniversalTag.SET.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet syncUUIDs" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet refreshDeletes state to syncUUIDs
+         *     syncIdSet [3] SEQUENCE {
+         *         ...
+         *         syncUUIDs      *SET OF* syncUUID
+         *     }
+         *     
+         * Initialize the UUID set : no action associated
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE.ordinal()][UniversalTag.SET
+            .getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE,
+                UniversalTag.SET.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet syncUUIDs" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet syncUUIDs to syncUUID
+         *     syncIdSet [3] SEQUENCE {
+         *         ...
+         *         syncUUIDs      SET OF *syncUUID*
+         *     }
+         *     
+         * Add the first UUID in the UUIDs list
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_UUID_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet first UUID" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] uuid = value.getData();
+
+                        // UUID must be exactly 16 bytes long
+                        if ( ( uuid == null ) || ( uuid.length != 16 ) )
+                        {
+                            String msg = I18n.err( I18n.ERR_04027 );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "UUID = " + Strings.dumpBytes( uuid ) );
+                        }
+
+                        // Store the UUID in the UUIDs list
+                        control.addSyncUUID( uuid );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from syncIdSet syncUUID to syncUUID
+         *     syncIdSet [3] SEQUENCE {
+         *         ...
+         *         syncUUIDs      SET OF *syncUUID*
+         *     }
+         *     
+         * Add a new UUID in the UUIDs list
+         */
+        super.transitions[SyncInfoValueStatesEnum.SYNC_ID_SET_UUID_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<SyncInfoValueContainer>( SyncInfoValueStatesEnum.SYNC_ID_SET_UUID_STATE,
+                SyncInfoValueStatesEnum.SYNC_ID_SET_UUID_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<SyncInfoValueContainer>( "SyncIdSet UUID" )
+                {
+                    public void action( SyncInfoValueContainer container ) throws DecoderException
+                    {
+                        SyncInfoValue control = container.getSyncInfoValueControl();
+
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] uuid = value.getData();
+
+                        // UUID must be exactly 16 bytes long
+                        if ( ( uuid == null ) || ( uuid.length != 16 ) )
+                        {
+                            String msg = I18n.err( I18n.ERR_04027 );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "UUID = " + Strings.dumpBytes( uuid ) );
+                        }
+
+                        // Store the UUID in the UUIDs list
+                        control.getSyncUUIDs().add( uuid );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<SyncInfoValueContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueStatesEnum.java
new file mode 100644
index 0000000..957b02e
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueStatesEnum.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the SyncInfoValueControl's grammar constants. It is also used for
+ * debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SyncInfoValueStatesEnum implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // SyncRequestValue control grammar states
+    // =========================================================================
+    /** Initial state */
+    START_STATE,
+
+    /** NewCookie state */
+    NEW_COOKIE_STATE,
+
+    /** RefreshDelete state */
+    REFRESH_DELETE_STATE,
+
+    /** RefreshDelete cookie state */
+    REFRESH_DELETE_COOKIE_STATE,
+
+    /** RefreshDelete refreshDone state */
+    REFRESH_DELETE_REFRESH_DONE_STATE,
+
+    /** RefreshPresent state */
+    REFRESH_PRESENT_STATE,
+
+    /** RefreshPresent cookie state */
+    REFRESH_PRESENT_COOKIE_STATE,
+
+    /** RefreshPresent refreshDone state */
+    REFRESH_PRESENT_REFRESH_DONE_STATE,
+
+    /** SyncIdSet state */
+    SYNC_ID_SET_STATE,
+
+    /** SyncIdSet cookie state */
+    SYNC_ID_SET_COOKIE_STATE,
+
+    /** SyncIdSet refreshDone state */
+    SYNC_ID_SET_REFRESH_DELETES_STATE,
+
+    /** SyncIdSet SET OF UUIDs state */
+    SYNC_ID_SET_SET_OF_UUIDS_STATE,
+
+    /** SyncIdSet UUID state */
+    SYNC_ID_SET_UUID_STATE,
+
+    /** terminal state */
+    LAST_SYNC_INFO_VALUE_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "SYNC_INFO_VALUE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<SyncInfoValueContainer> grammar )
+    {
+        if ( grammar instanceof SyncInfoValueGrammar )
+        {
+            return "SYNC_INFO_VALUE_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "SYNC_INFO_VALUE_END_STATE" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyncInfoValueStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueTags.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueTags.java
new file mode 100644
index 0000000..e712733
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueTags.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+/**
+ * An enumeration to store the tags used to encode and decode the syncInfoValue control.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SyncInfoValueTags
+{
+    /** The tags */
+    NEW_COOKIE_TAG(0x0080),
+    REFRESH_DELETE_TAG(0x00A1),
+    REFRESH_PRESENT_TAG(0x00A2),
+    SYNC_ID_SET_TAG(0x00A3);
+
+    /** Internal value for each tag */
+    private int value;
+
+
+    /**
+     * Create the private instance
+     * @param value The internal tag value
+     */
+    private SyncInfoValueTags( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The ASN.1 BER value for this tag.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueContainer.java
new file mode 100644
index 0000000..d15d2c4
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueContainer.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValue;
+
+
+/**
+ * A container for the SyncRequestValue control
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncRequestValueContainer extends AbstractContainer
+{
+    /** SyncRequestValueControl */
+    private SyncRequestValue control;
+
+
+    /**
+     * Creates a new SyncRequestValueControlContainer object. We will store one grammar,
+     * it's enough ...
+     */
+    public SyncRequestValueContainer()
+    {
+        super();
+        setGrammar( SyncRequestValueGrammar.getInstance() );
+        setTransition( SyncRequestValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * Creates a new SyncRequestValueControlContainer object. We will store one grammar,
+     * it's enough ...
+     */
+    public SyncRequestValueContainer( SyncRequestValue control )
+    {
+        super();
+        this.control = control;
+        setGrammar( SyncRequestValueGrammar.getInstance() );
+        setTransition( SyncRequestValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the syncRequestValue control.
+     */
+    public SyncRequestValue getSyncRequestValueControl()
+    {
+        return control;
+    }
+
+
+    /**
+     * Set a SyncRequestValueControl Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param control the SyncRequestValueControl to set.
+     */
+    public void setSyncRequestValueControl( SyncRequestValue control )
+    {
+        this.control = control;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java
new file mode 100644
index 0000000..8613241
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java
@@ -0,0 +1,263 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.SynchronizationModeEnum;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValueImpl;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A syncRequestValue object, as defined in RFC 4533
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncRequestValueDecorator extends ControlDecorator<SyncRequestValue> implements SyncRequestValue
+{
+    /** The global length for this control */
+    private int syncRequestValueLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    public SyncRequestValueDecorator( LdapApiService codec )
+    {
+        super( codec, new SyncRequestValueImpl() );
+    }
+
+
+    public SyncRequestValueDecorator( LdapApiService codec, SyncRequestValue control )
+    {
+        super( codec, control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SynchronizationModeEnum getMode()
+    {
+        return getDecorated().getMode();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMode( SynchronizationModeEnum mode )
+    {
+        getDecorated().setMode( mode );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return getDecorated().getCookie();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        // Copy the bytes
+        if ( !Strings.isEmpty( cookie ) )
+        {
+            byte[] copy = new byte[cookie.length];
+            System.arraycopy( cookie, 0, copy, 0, cookie.length );
+            getDecorated().setCookie( copy );
+        }
+        else
+        {
+            getDecorated().setCookie( null );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isReloadHint()
+    {
+        return getDecorated().isReloadHint();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReloadHint( boolean reloadHint )
+    {
+        getDecorated().setReloadHint( reloadHint );
+    }
+
+
+    /**
+     * Compute the SyncRequestValue length.
+     *
+     * SyncRequestValue :
+     * 0x30 L1
+     *  |
+     *  +--> 0x0A 0x01 [0x00|0x01|0x02|0x03] (mode)
+     * [+--> 0x04 L2 abcd...                 (cookie)
+     *  +--> 0x01 0x01 [0x00|0xFF]           (reloadHint)
+     *
+     */
+    @Override
+    public int computeLength()
+    {
+        // The mode length
+        syncRequestValueLength = 1 + 1 + 1;
+
+        // The cookie length, if we have a cookie
+        if ( getCookie() != null )
+        {
+            syncRequestValueLength += 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
+        }
+
+        // The reloadHint length, default to false
+        if ( isReloadHint() )
+        {
+            syncRequestValueLength += 1 + 1 + 1;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( syncRequestValueLength ) + syncRequestValueLength;
+
+        // Call the super class to compute the global control length
+        return valueLength;
+    }
+
+
+    /**
+     * Encode the SyncRequestValue control
+     *
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Encode the SEQ
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( syncRequestValueLength ) );
+
+        // The mode
+        buffer.put( UniversalTag.ENUMERATED.getValue() );
+        buffer.put( ( byte ) 0x01 );
+        buffer.put( BerValue.getBytes( getMode().getValue() ) );
+
+        // The cookie
+        if ( getCookie() != null )
+        {
+            BerValue.encode( buffer, getCookie() );
+        }
+
+        // The reloadHint if not false
+        if ( isReloadHint() )
+        {
+            BerValue.encode( buffer, isReloadHint() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                // Encode the SEQ
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+                buffer.put( TLV.getBytes( syncRequestValueLength ) );
+
+                // The mode
+                buffer.put( UniversalTag.ENUMERATED.getValue() );
+                buffer.put( ( byte ) 0x01 );
+                buffer.put( BerValue.getBytes( getMode().getValue() ) );
+
+                // The cookie
+                if ( getCookie() != null )
+                {
+                    BerValue.encode( buffer, getCookie() );
+                }
+
+                // The reloadHint if not false
+                if ( isReloadHint() )
+                {
+                    BerValue.encode( buffer, isReloadHint() );
+                }
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        SyncRequestValueContainer container = new SyncRequestValueContainer( this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueFactory.java
new file mode 100644
index 0000000..4055020
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValue;
+
+
+/**
+ * A {@link ControlFactory} which creates {@link SyncRequestValue} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncRequestValueFactory implements ControlFactory<SyncRequestValue>
+{
+    /** The codec for this factory */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SyncRequestValueFactory.
+     *
+     * @param codec The codec for this factory.
+     */
+    public SyncRequestValueFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return SyncRequestValue.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncRequestValue> newCodecControl()
+    {
+        return new SyncRequestValueDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncRequestValue> newCodecControl( SyncRequestValue control )
+    {
+        return new SyncRequestValueDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueGrammar.java
new file mode 100644
index 0000000..520225c
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueGrammar.java
@@ -0,0 +1,274 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.extras.controls.SynchronizationModeEnum;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the SyncRequestValueControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ * 
+ * The decoded grammar is the following :
+ * 
+ * syncRequestValue ::= SEQUENCE {
+ *     mode ENUMERATED {
+ *     -- 0 unused
+ *     refreshOnly       (1),
+ *     -- 2 reserved
+ *     refreshAndPersist (3)
+ *     },
+ *     cookie     syncCookie OPTIONAL,
+ *     reloadHint BOOLEAN DEFAULT FALSE
+ * }
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SyncRequestValueGrammar extends AbstractGrammar<SyncRequestValueContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( SyncRequestValueGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. SyncRequestValueControlGrammar is a singleton */
+    private static Grammar<SyncRequestValueContainer> instance = new SyncRequestValueGrammar();
+
+
+    /**
+     * Creates a new SyncRequestValueControlGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private SyncRequestValueGrammar()
+    {
+        setName( SyncRequestValueGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[SyncRequestValueStatesEnum.LAST_SYNC_REQUEST_VALUE_STATE.ordinal()][256];
+
+        /** 
+         * Transition from initial state to SyncRequestValue sequence
+         * SyncRequestValue ::= SEQUENCE OF {
+         *     ...
+         *     
+         * Initialize the syncRequestValue object
+         */
+        super.transitions[SyncRequestValueStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.START_STATE,
+                SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                null );
+
+        /** 
+         * Transition from SyncRequestValue sequence to Change types
+         * SyncRequestValue ::= SEQUENCE OF {
+         *     mode ENUMERATED {
+         *         -- 0 unused
+         *         refreshOnly       (1),
+         *         -- 2 reserved
+         *         refreshAndPersist (3)
+         *     },
+         *     ...
+         *     
+         * Stores the mode value
+         */
+        super.transitions[SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED
+            .getValue()] =
+            new GrammarTransition<SyncRequestValueContainer>(
+                SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE,
+                SyncRequestValueStatesEnum.MODE_STATE,
+                UniversalTag.ENUMERATED.getValue(),
+                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl mode" )
+                {
+                    public void action( SyncRequestValueContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            // Check that the value is into the allowed interval
+                            int mode = IntegerDecoder.parse( value,
+                                SynchronizationModeEnum.UNUSED.getValue(),
+                                SynchronizationModeEnum.REFRESH_AND_PERSIST.getValue() );
+
+                            SynchronizationModeEnum modeEnum = SynchronizationModeEnum.getSyncMode( mode );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "Mode = " + modeEnum );
+                            }
+
+                            container.getSyncRequestValueControl().setMode( modeEnum );
+
+                            // We can have an END transition
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04028 );
+                            LOG.error( msg, ide );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+
+        /** 
+         * Transition from mode to cookie
+         * SyncRequestValue ::= SEQUENCE OF {
+         *     ...
+         *     cookie     syncCookie OPTIONAL,
+         *     ...
+         *     
+         * Stores the cookie
+         */
+        super.transitions[SyncRequestValueStatesEnum.MODE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.MODE_STATE,
+                SyncRequestValueStatesEnum.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl cookie" )
+                {
+                    public void action( SyncRequestValueContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] cookie = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "cookie = " + Strings.dumpBytes( cookie ) );
+                        }
+
+                        container.getSyncRequestValueControl().setCookie( cookie );
+
+                        // We can have an END transition
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /** 
+         * Transition from mode to reloadHint
+         * SyncRequestValue ::= SEQUENCE OF {
+         *     ...
+         *     reloadHint BOOLEAN DEFAULT FALSE
+         * }
+         *     
+         * Stores the reloadHint flag
+         */
+        super.transitions[SyncRequestValueStatesEnum.MODE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.MODE_STATE,
+                SyncRequestValueStatesEnum.RELOAD_HINT_STATE, UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl reloadHint flag" )
+                {
+                    public void action( SyncRequestValueContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean reloadHint = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "reloadHint = " + reloadHint );
+                            }
+
+                            container.getSyncRequestValueControl().setReloadHint( reloadHint );
+
+                            // We can have an END transition
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException bde )
+                        {
+                            String msg = I18n.err( I18n.ERR_04029 );
+                            LOG.error( msg, bde );
+                            throw new DecoderException( msg, bde );
+                        }
+                    }
+                } );
+
+        /** 
+         * Transition from cookie to reloadHint
+         * SyncRequestValue ::= SEQUENCE OF {
+         *     ...
+         *     reloadHint BOOLEAN DEFAULT FALSE
+         * }
+         *     
+         * Stores the reloadHint flag
+         */
+        super.transitions[SyncRequestValueStatesEnum.COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.COOKIE_STATE,
+                SyncRequestValueStatesEnum.RELOAD_HINT_STATE, UniversalTag.BOOLEAN.getValue(),
+                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl reloadHint flag" )
+                {
+                    public void action( SyncRequestValueContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            boolean reloadHint = BooleanDecoder.parse( value );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "reloadHint = " + reloadHint );
+                            }
+
+                            container.getSyncRequestValueControl().setReloadHint( reloadHint );
+
+                            // We can have an END transition
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( BooleanDecoderException bde )
+                        {
+                            String msg = I18n.err( I18n.ERR_04029 );
+                            LOG.error( msg, bde );
+                            throw new DecoderException( msg, bde );
+                        }
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<SyncRequestValueContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueStatesEnum.java
new file mode 100644
index 0000000..81a71eb
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueStatesEnum.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the SyncRequestValueControl's grammar constants. It is also used for
+ * debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SyncRequestValueStatesEnum implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // SyncRequestValue control grammar states
+    // =========================================================================
+    /** Initial state */
+    START_STATE,
+
+    /** Sequence Value */
+    SYNC_REQUEST_VALUE_SEQUENCE_STATE,
+
+    /** mode Value */
+    MODE_STATE,
+
+    /** cookie Value */
+    COOKIE_STATE,
+
+    /** reloadHint Value */
+    RELOAD_HINT_STATE,
+
+    /** terminal state */
+    LAST_SYNC_REQUEST_VALUE_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "SYNC_REQUEST_VALUE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<SyncRequestValueContainer> grammar )
+    {
+        if ( grammar instanceof SyncRequestValueGrammar )
+        {
+            return "SYNC_REQUEST_VALUE_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "SYNC_REQUEST_VALUE_END_STATE" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyncRequestValueStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueContainer.java
new file mode 100644
index 0000000..30b36a7
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueContainer.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValue;
+
+
+/**
+ * A container for the SyncStateValue control
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncStateValueContainer extends AbstractContainer
+{
+    /** SyncStateValueControl */
+    private SyncStateValue control;
+
+
+    /**
+     * Creates a new SyncStateValueControlContainer object. We will store one grammar,
+     * it's enough ...
+     */
+    public SyncStateValueContainer()
+    {
+        super();
+        setGrammar( SyncStateValueGrammar.getInstance() );
+        setTransition( SyncStateValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * Creates a new SyncStateValueControlContainer object. We will store one grammar,
+     * it's enough ...
+     */
+    public SyncStateValueContainer( SyncStateValue control )
+    {
+        super();
+        this.control = control;
+        setGrammar( SyncStateValueGrammar.getInstance() );
+        setTransition( SyncStateValueStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the syncStateValue control.
+     */
+    public SyncStateValue getSyncStateValueControl()
+    {
+        return control;
+    }
+
+
+    /**
+     * Set a SyncStateValueControl Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param control the SyncStateValueControl to set.
+     */
+    public void setSyncStateValueControl( SyncStateValue control )
+    {
+        this.control = control;
+    }
+
+
+    /**
+     * Clean the container
+     */
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java
new file mode 100644
index 0000000..bd35e98
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateTypeEnum;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValueImpl;
+
+
+/**
+ * A syncStateValue object, as defined in RFC 4533
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyncStateValueDecorator extends ControlDecorator<SyncStateValue> implements SyncStateValue
+{
+    /** Global length for the control */
+    private int syncStateSeqLength;
+
+    /** An instance of this decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    public SyncStateValueDecorator( LdapApiService codec )
+    {
+        super( codec, new SyncStateValueImpl() );
+    }
+
+
+    public SyncStateValueDecorator( LdapApiService codec, SyncStateValue value )
+    {
+        super( codec, value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCookie()
+    {
+        return getDecorated().getCookie();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCookie( byte[] cookie )
+    {
+        getDecorated().setCookie( cookie );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyncStateTypeEnum getSyncStateType()
+    {
+        return getDecorated().getSyncStateType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSyncStateType( SyncStateTypeEnum syncStateType )
+    {
+        getDecorated().setSyncStateType( syncStateType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getEntryUUID()
+    {
+        return getDecorated().getEntryUUID();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setEntryUUID( byte[] entryUUID )
+    {
+        getDecorated().setEntryUUID( entryUUID );
+    }
+
+
+    /**
+     * Compute the SyncStateValue length.
+     *
+     * SyncStateValue :
+     * 0x30 L1
+     *  |
+     *  +--> 0x0A 0x01 [0x00|0x01|0x02|0x03] (type)
+     * [+--> 0x04 L2 abcd...                 (entryUUID)
+     * [+--> 0x04 L3 abcd...                 (cookie)
+     *
+     */
+    @Override
+    public int computeLength()
+    {
+        // The sync state type length
+        syncStateSeqLength = 1 + 1 + 1;
+
+        syncStateSeqLength += 1 + TLV.getNbBytes( getEntryUUID().length ) + getEntryUUID().length;
+
+        // The cookie length, if we have a cookie
+        if ( getCookie() != null )
+        {
+            syncStateSeqLength += 1 + TLV.getNbBytes( getCookie().length ) + getCookie().length;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( syncStateSeqLength ) + syncStateSeqLength;
+
+        return valueLength;
+    }
+
+
+    /**
+     * Encode the SyncStateValue control
+     *
+     * @param buffer The encoded sink
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws EncoderException If anything goes wrong.
+     */
+    @Override
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        // Encode the SEQ
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( syncStateSeqLength ) );
+
+        // The mode
+        buffer.put( UniversalTag.ENUMERATED.getValue() );
+        buffer.put( ( byte ) 0x01 );
+        buffer.put( BerValue.getBytes( getSyncStateType().getValue() ) );
+
+        // the entryUUID
+        BerValue.encode( buffer, getEntryUUID() );
+
+        // The cookie
+        if ( getCookie() != null )
+        {
+            BerValue.encode( buffer, getCookie() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                // Encode the SEQ
+                buffer.put( UniversalTag.SEQUENCE.getValue() );
+                buffer.put( TLV.getBytes( syncStateSeqLength ) );
+
+                // The mode
+                buffer.put( UniversalTag.ENUMERATED.getValue() );
+                buffer.put( ( byte ) 0x01 );
+                buffer.put( BerValue.getBytes( getSyncStateType().getValue() ) );
+
+                // the entryUUID
+                BerValue.encode( buffer, getEntryUUID() );
+
+                // The cookie
+                if ( getCookie() != null )
+                {
+                    BerValue.encode( buffer, getCookie() );
+                }
+
+                value = buffer.array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlBytes );
+        SyncStateValueContainer container = new SyncStateValueContainer( this );
+        DECODER.decode( bb, container );
+        return this;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueFactory.java
new file mode 100644
index 0000000..3032117
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueFactory.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValue;
+
+
+/**
+ * A {@link ControlFactory} which creates {@link SyncStateValue} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SyncStateValueFactory implements ControlFactory<SyncStateValue>
+{
+    /** The codec for this factory */
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of SyncStateValueFactory.
+     *
+     * @param codec The codec for this factory.
+     */
+    public SyncStateValueFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return SyncStateValue.OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncStateValue> newCodecControl()
+    {
+        return new SyncStateValueDecorator( codec );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CodecControl<SyncStateValue> newCodecControl( SyncStateValue control )
+    {
+        return new SyncStateValueDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueGrammar.java
new file mode 100644
index 0000000..3577811
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueGrammar.java
@@ -0,0 +1,217 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateTypeEnum;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the SyncStateValueControl. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once.
+ * 
+ * The decoded grammar is the following :
+ * 
+ *  syncStateValue ::= SEQUENCE {
+ *       state ENUMERATED {
+ *            present (0),
+ *            add (1),
+ *            modify (2),
+ *            delete (3)
+ *       },
+ *       entryUUID syncUUID,
+ *       cookie    syncCookie OPTIONAL
+ *  }
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SyncStateValueGrammar extends AbstractGrammar<SyncStateValueContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( SyncStateValueGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. SyncStateValueControlGrammar is a singleton */
+    private static Grammar<SyncStateValueContainer> instance = new SyncStateValueGrammar();
+
+
+    /**
+     * Creates a new SyncStateValueControlGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private SyncStateValueGrammar()
+    {
+        setName( SyncStateValueGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[SyncStateValueStatesEnum.LAST_SYNC_STATE_VALUE_STATE.ordinal()][256];
+
+        /** 
+         * Transition from initial state to SyncStateValue sequence
+         * SyncRequestValue ::= SEQUENCE OF {
+         *     ...
+         *     
+         * Initialize the syncStateValue object
+         */
+        super.transitions[SyncStateValueStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition<SyncStateValueContainer>(
+            SyncStateValueStatesEnum.START_STATE, SyncStateValueStatesEnum.SYNC_STATE_VALUE_SEQUENCE_STATE,
+            UniversalTag.SEQUENCE.getValue(), null );
+
+        /** 
+         * Transition from SyncStateValue sequence to state type enum
+         * SyncRequestValue ::= SEQUENCE OF {
+         *       state ENUMERATED {
+         *            present (0),
+         *            add (1),
+         *            modify (2),
+         *            delete (3)
+         *       },
+         *     ...
+         *     
+         * Stores the sync state type value
+         */
+        super.transitions[SyncStateValueStatesEnum.SYNC_STATE_VALUE_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED
+            .getValue()] = new GrammarTransition<SyncStateValueContainer>(
+            SyncStateValueStatesEnum.SYNC_STATE_VALUE_SEQUENCE_STATE,
+            SyncStateValueStatesEnum.SYNC_TYPE_STATE, UniversalTag.ENUMERATED.getValue(),
+            new GrammarAction<SyncStateValueContainer>( "Set SyncStateValueControl state type" )
+            {
+                public void action( SyncStateValueContainer container ) throws DecoderException
+                {
+                    BerValue value = container.getCurrentTLV().getValue();
+
+                    try
+                    {
+                        // Check that the value is into the allowed interval
+                        int syncStateType = IntegerDecoder.parse( value, SyncStateTypeEnum.PRESENT.getValue(),
+                            SyncStateTypeEnum.MODDN.getValue() );
+
+                        SyncStateTypeEnum syncStateTypeEnum = SyncStateTypeEnum.getSyncStateType( syncStateType );
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "SyncStateType = {}", syncStateTypeEnum );
+                        }
+
+                        container.getSyncStateValueControl().setSyncStateType( syncStateTypeEnum );
+
+                        // move on to the entryUUID transition
+                        container.setGrammarEndAllowed( false );
+                    }
+                    catch ( IntegerDecoderException ide )
+                    {
+                        String msg = I18n.err( I18n.ERR_04030 );
+                        LOG.error( msg, ide );
+                        throw new DecoderException( msg, ide );
+                    }
+                }
+            } );
+
+        /** 
+         * Transition from sync state tpe to entryUUID
+         * SyncStateValue ::= SEQUENCE OF {
+         *     ...
+         *     entryUUID     syncUUID
+         *     ...
+         *     
+         * Stores the entryUUID
+         */
+        super.transitions[SyncStateValueStatesEnum.SYNC_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition<SyncStateValueContainer>(
+            SyncStateValueStatesEnum.SYNC_TYPE_STATE, SyncStateValueStatesEnum.SYNC_UUID_STATE,
+            UniversalTag.OCTET_STRING.getValue(),
+            new GrammarAction<SyncStateValueContainer>( "Set SyncStateValueControl entryUUID" )
+            {
+                public void action( SyncStateValueContainer container ) throws DecoderException
+                {
+                    BerValue value = container.getCurrentTLV().getValue();
+
+                    byte[] entryUUID = value.getData();
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "entryUUID = {}", Strings.dumpBytes( entryUUID ) );
+                    }
+
+                    container.getSyncStateValueControl().setEntryUUID( entryUUID );
+
+                    // We can have an END transition
+                    container.setGrammarEndAllowed( true );
+                }
+            } );
+
+        /** 
+         * Transition from entryUUID to cookie
+         * SyncRequestValue ::= SEQUENCE OF {
+         *     ...
+         *     cookie    syncCookie OPTIONAL
+         * }
+         *     
+         * Stores the reloadHint flag
+         */
+        super.transitions[SyncStateValueStatesEnum.SYNC_UUID_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition<SyncStateValueContainer>(
+            SyncStateValueStatesEnum.SYNC_UUID_STATE, SyncStateValueStatesEnum.COOKIE_STATE,
+            UniversalTag.OCTET_STRING.getValue(),
+            new GrammarAction<SyncStateValueContainer>( "Set SyncStateValueControl cookie value" )
+            {
+                public void action( SyncStateValueContainer container ) throws DecoderException
+                {
+                    BerValue value = container.getCurrentTLV().getValue();
+
+                    byte[] cookie = value.getData();
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "cookie = {}", cookie );
+                    }
+
+                    container.getSyncStateValueControl().setCookie( cookie );
+
+                    // terminal state
+                    container.setGrammarEndAllowed( true );
+                }
+            } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<SyncStateValueContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueStatesEnum.java
new file mode 100644
index 0000000..e801767
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueStatesEnum.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the SyncStateValueControl's grammar constants. It is also used for
+ * debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SyncStateValueStatesEnum implements States
+{
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // SyncStateValue control grammar states
+    // =========================================================================
+    /** Initial state */
+    START_STATE,
+
+    /** Sequence Value */
+    SYNC_STATE_VALUE_SEQUENCE_STATE,
+
+    /** sync state type Value */
+    SYNC_TYPE_STATE,
+
+    /** syncUUID Value */
+    SYNC_UUID_STATE,
+
+    /** cookie Value */
+    COOKIE_STATE,
+
+    /** terminal state */
+    LAST_SYNC_STATE_VALUE_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "SYNC_REQUEST_VALUE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<SyncStateValueContainer> grammar )
+    {
+        if ( grammar instanceof SyncStateValueGrammar )
+        {
+            return "SYNC_STATE_VALUE_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "SYNC_STATE_VALUE_END_STATE" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyncStateValueStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/InitByOffsetSequence.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/InitByOffsetSequence.java
new file mode 100644
index 0000000..804e5a0
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/InitByOffsetSequence.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the ByOffset sequence object
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitByOffsetSequence extends GrammarAction<VirtualListViewRequestContainer>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitByOffsetSequence.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new ByOffsetSequence action.
+     */
+    public InitByOffsetSequence()
+    {
+        super( "Initialize the ByOffsetSequence action" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( VirtualListViewRequestContainer container ) throws DecoderException
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "VirtualListViewRequestContainer initialized" );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/InitVirtualListViewRequest.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/InitVirtualListViewRequest.java
new file mode 100644
index 0000000..9f46901
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/InitVirtualListViewRequest.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to initialize the VirtualListViewRequestContainer object
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InitVirtualListViewRequest extends GrammarAction<VirtualListViewRequestContainer>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( InitVirtualListViewRequest.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new VirtualListViewRequest action.
+     */
+    public InitVirtualListViewRequest()
+    {
+        super( "Initialize the VirtualListViewRequestContainer" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void action( VirtualListViewRequestContainer container ) throws DecoderException
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "VirtualListViewRequestContainer initialized" );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreAfterCount.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreAfterCount.java
new file mode 100644
index 0000000..a2ea4d8
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreAfterCount.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the AfterCount value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreAfterCount extends AbstractReadInteger<VirtualListViewRequestContainer>
+{
+
+    /**
+     * Instantiates a new afterCount action.
+     */
+    public StoreAfterCount()
+    {
+        super( "VirtualListViewRequest AfterCount" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, VirtualListViewRequestContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setAfterCount( value );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreAssertionValue.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreAssertionValue.java
new file mode 100644
index 0000000..f5e0c72
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreAssertionValue.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * The action used to store the assertionValue value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreAssertionValue extends GrammarAction<VirtualListViewRequestContainer>
+{
+
+    /**
+     * Instantiates a new assertionValue action.
+     */
+    public StoreAssertionValue()
+    {
+        super( "VirtualListViewRequest assertionValue" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void action( VirtualListViewRequestContainer vlvContainer )
+    {
+        TLV tlv = vlvContainer.getCurrentTLV();
+
+        if ( tlv.getLength() != 0 )
+        {
+            byte[] assertionValue = tlv.getValue().getData();
+
+            vlvContainer.getDecorator().setAssertionValue( assertionValue );
+        }
+        else
+        {
+            vlvContainer.getDecorator().setAssertionValue( Strings.EMPTY_BYTES );
+        }
+
+        // The last element is optional, we can quit here
+        vlvContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreBeforeCount.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreBeforeCount.java
new file mode 100644
index 0000000..d20e83e
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreBeforeCount.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the BeforeCount value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreBeforeCount extends AbstractReadInteger<VirtualListViewRequestContainer>
+{
+
+    /**
+     * Instantiates a new beforeCount action.
+     */
+    public StoreBeforeCount()
+    {
+        super( "VirtualListViewRequest BeforeCount" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, VirtualListViewRequestContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setBeforeCount( value );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContentCount.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContentCount.java
new file mode 100644
index 0000000..18a1351
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContentCount.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the ContentCount value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreContentCount extends AbstractReadInteger<VirtualListViewRequestContainer>
+{
+
+    /**
+     * Instantiates a new ContentCount action.
+     */
+    public StoreContentCount()
+    {
+        super( "VirtualListViewRequest ContentCount" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, VirtualListViewRequestContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setContentCount( value );
+
+        // The last element is optional, we can quit here
+        vlvContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContentCountResponse.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContentCountResponse.java
new file mode 100644
index 0000000..d2f87ae
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContentCountResponse.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the contentCount value in VLV response
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreContentCountResponse extends AbstractReadInteger<VirtualListViewResponseContainer>
+{
+    /**
+     * Instantiates a new ContentCount action.
+     */
+    public StoreContentCountResponse()
+    {
+        super( "VirtualListViewResponse contentCount" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, VirtualListViewResponseContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setContentCount( value );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContextId.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContextId.java
new file mode 100644
index 0000000..68424d7
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContextId.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadOctetString;
+
+
+/**
+ * The action used to store the ContextId value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreContextId extends AbstractReadOctetString<VirtualListViewRequestContainer>
+{
+
+    /**
+     * Instantiates a new ContextId action.
+     */
+    public StoreContextId()
+    {
+        super( "VirtualListViewRequest ContextId", true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setOctetString( byte[] value, VirtualListViewRequestContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setContextId( value );
+
+        // The last element is optional, we can quit here
+        vlvContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContextIdResponse.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContextIdResponse.java
new file mode 100644
index 0000000..f0160df
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreContextIdResponse.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadOctetString;
+
+
+/**
+ * The action used to store the contextId value in VLV reponse
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreContextIdResponse extends AbstractReadOctetString<VirtualListViewResponseContainer>
+{
+    /**
+     * Instantiates a new contextId action.
+     */
+    public StoreContextIdResponse()
+    {
+        super( "VirtualListViewResponse contextId", true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setOctetString( byte[] value, VirtualListViewResponseContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setContextId( value );
+
+        // The last element is optional, we can quit here
+        vlvContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreOffset.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreOffset.java
new file mode 100644
index 0000000..a05c231
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreOffset.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the Offset value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreOffset extends AbstractReadInteger<VirtualListViewRequestContainer>
+{
+
+    /**
+     * Instantiates a new offset action.
+     */
+    public StoreOffset()
+    {
+        super( "VirtualListViewRequest offset", 1, Integer.MAX_VALUE );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, VirtualListViewRequestContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setOffset( value );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreTargetPosition.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreTargetPosition.java
new file mode 100644
index 0000000..9aa2992
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreTargetPosition.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+
+
+/**
+ * The action used to store the targetPosition value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreTargetPosition extends AbstractReadInteger<VirtualListViewResponseContainer>
+{
+    /**
+     * Instantiates a new targetPosition action.
+     */
+    public StoreTargetPosition()
+    {
+        super( "VirtualListViewResponse targetPosition" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, VirtualListViewResponseContainer vlvContainer )
+    {
+        vlvContainer.getDecorator().setTargetPosition( value );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreVirtualListViewResult.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreVirtualListViewResult.java
new file mode 100644
index 0000000..1eb6ec1
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/StoreVirtualListViewResult.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.actions.AbstractReadInteger;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResultCode;
+
+
+/**
+ * The action used to store the virtualListViewResult value
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreVirtualListViewResult extends AbstractReadInteger<VirtualListViewResponseContainer>
+{
+    /**
+     * Instantiates a new virtualListViewResult action.
+     */
+    public StoreVirtualListViewResult()
+    {
+        super( "VirtualListViewResponse virtualListViewResult" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setIntegerValue( int value, VirtualListViewResponseContainer vlvContainer )
+    {
+        VirtualListViewResultCode code = VirtualListViewResultCode.get( value );
+        vlvContainer.getDecorator().setVirtualListViewResult( code );
+
+        vlvContainer.setGrammarEndAllowed( true );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestContainer.java
new file mode 100644
index 0000000..c28c84b
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestContainer.java
@@ -0,0 +1,87 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewRequest;
+
+
+/**
+ * A container for the VLV request control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewRequestContainer extends AbstractContainer
+{
+    private VirtualListViewRequestDecorator control;
+
+    private LdapApiService codec;
+
+
+    public VirtualListViewRequestContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( VirtualListViewRequestGrammar.getInstance() );
+        setTransition( VirtualListViewRequestStates.START_STATE );
+    }
+
+
+    public VirtualListViewRequestContainer( VirtualListViewRequestDecorator control, LdapApiService codec )
+    {
+        this( codec );
+        decorate( control );
+    }
+
+
+    public VirtualListViewRequestDecorator getDecorator()
+    {
+        return control;
+    }
+
+
+    public void decorate( VirtualListViewRequest control )
+    {
+        if ( control instanceof VirtualListViewRequestDecorator )
+        {
+            this.control = ( VirtualListViewRequestDecorator ) control;
+        }
+        else
+        {
+            this.control = new VirtualListViewRequestDecorator( codec, control );
+        }
+    }
+
+
+    public void setVirtualListViewRequestControl( VirtualListViewRequestDecorator control )
+    {
+        this.control = control;
+    }
+
+
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestDecorator.java
new file mode 100644
index 0000000..aa9b5e4
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestDecorator.java
@@ -0,0 +1,337 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewRequest;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewRequestImpl;
+
+
+/**
+ * The VirtualListView decorator
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewRequestDecorator extends ControlDecorator<VirtualListViewRequest> implements
+    VirtualListViewRequest
+{
+    private int vlvSeqLength;
+    private int targetSeqLength;
+
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    public VirtualListViewRequestDecorator( LdapApiService codec )
+    {
+        this( codec, new VirtualListViewRequestImpl() );
+    }
+
+
+    public VirtualListViewRequestDecorator( LdapApiService codec, VirtualListViewRequest vlvRequest )
+    {
+        super( codec, vlvRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int computeLength()
+    {
+        vlvSeqLength = 1 + 1 + BerValue.getNbBytes( getBeforeCount() );
+        vlvSeqLength += 1 + 1 + BerValue.getNbBytes( getAfterCount() );
+
+        if ( hasOffset() )
+        {
+            targetSeqLength = 1 + 1 + BerValue.getNbBytes( getOffset() );
+            targetSeqLength += 1 + 1 + BerValue.getNbBytes( getContentCount() );
+
+            vlvSeqLength += 1 + 1 + targetSeqLength;
+        }
+        else
+        {
+            byte[] assertionValue = getAssertionValue();
+
+            if ( assertionValue != null )
+            {
+                targetSeqLength = 1 + TLV.getNbBytes( assertionValue.length ) + assertionValue.length;
+            }
+            else
+            {
+                targetSeqLength = 1 + 1;
+            }
+
+            vlvSeqLength += targetSeqLength;
+        }
+
+        if ( getContextId() != null )
+        {
+            vlvSeqLength += 1 + TLV.getNbBytes( getContextId().length ) + getContextId().length;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( vlvSeqLength ) + vlvSeqLength;
+
+        return valueLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( vlvSeqLength ) );
+
+        BerValue.encode( buffer, getBeforeCount() );
+        BerValue.encode( buffer, getAfterCount() );
+
+        if ( hasOffset() )
+        {
+            // The byOffset tag
+            buffer.put( ( byte ) VirtualListViewerTags.BY_OFFSET_TAG.getValue() );
+            buffer.put( TLV.getBytes( targetSeqLength ) );
+
+            // The by offset values
+            BerValue.encode( buffer, getOffset() );
+            BerValue.encode( buffer, getContentCount() );
+        }
+        else
+        {
+            buffer.put( ( byte ) VirtualListViewerTags.ASSERTION_VALUE_TAG.getValue() );
+            byte[] value = getAssertionValue();
+
+            if ( value != null )
+            {
+                buffer.put( TLV.getBytes( value.length ) );
+
+                // The by assertionValue value
+                buffer.put( value );
+            }
+            else
+            {
+                buffer.put( TLV.getBytes( 0 ) );
+            }
+        }
+
+        if ( getContextId() != null )
+        {
+            BerValue.encode( buffer, getContextId() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                value = encode( buffer ).array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer buffer = ByteBuffer.wrap( controlBytes );
+        VirtualListViewRequestContainer container = new VirtualListViewRequestContainer( this, getCodecService() );
+        DECODER.decode( buffer, container );
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getBeforeCount()
+    {
+        return getDecorated().getBeforeCount();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBeforeCount( int beforeCount )
+    {
+        getDecorated().setBeforeCount( beforeCount );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getAfterCount()
+    {
+        return getDecorated().getAfterCount();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAfterCount( int afterCount )
+    {
+        getDecorated().setAfterCount( afterCount );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getOffset()
+    {
+        return getDecorated().getOffset();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setOffset( int offset )
+    {
+        getDecorated().setOffset( offset );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getContentCount()
+    {
+        return getDecorated().getContentCount();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setContentCount( int contentCount )
+    {
+        getDecorated().setContentCount( contentCount );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getContextId()
+    {
+        return getDecorated().getContextId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setContextId( byte[] contextId )
+    {
+        getDecorated().setContextId( contextId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getAssertionValue()
+    {
+        return getDecorated().getAssertionValue();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setAssertionValue( byte[] assertionValue )
+    {
+        getDecorated().setAssertionValue( assertionValue );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasOffset()
+    {
+        return getDecorated().hasOffset();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasAssertionValue()
+    {
+        return getDecorated().hasAssertionValue();
+    }
+
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestFactory.java
new file mode 100644
index 0000000..babba5a
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestFactory.java
@@ -0,0 +1,66 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewRequest;
+
+
+/**
+ * A {@link ControlFactory} for {@link VirtualListViewRequest} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewRequestFactory implements ControlFactory<VirtualListViewRequest>
+{
+    private LdapApiService codec;
+
+
+    public VirtualListViewRequestFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    @Override
+    public String getOid()
+    {
+        return VirtualListViewRequest.OID;
+    }
+
+
+    @Override
+    public CodecControl<VirtualListViewRequest> newCodecControl()
+    {
+        return new VirtualListViewRequestDecorator( codec );
+    }
+
+
+    @Override
+    public CodecControl<VirtualListViewRequest> newCodecControl( VirtualListViewRequest control )
+    {
+        return new VirtualListViewRequestDecorator( codec, control );
+    }
+
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestGrammar.java
new file mode 100644
index 0000000..e4537c0
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestGrammar.java
@@ -0,0 +1,128 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * TODO VirtualListViewRequestGrammar.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class VirtualListViewRequestGrammar extends AbstractGrammar<VirtualListViewRequestContainer>
+{
+    static final Logger LOG = LoggerFactory.getLogger( VirtualListViewRequestGrammar.class );
+
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    private static Grammar<?> instance = new VirtualListViewRequestGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    private VirtualListViewRequestGrammar()
+    {
+        setName( VirtualListViewRequestGrammar.class.getName() );
+
+        super.transitions = new GrammarTransition[VirtualListViewRequestStates.END_STATE.ordinal()][256];
+
+        super.transitions[VirtualListViewRequestStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.START_STATE,
+                VirtualListViewRequestStates.VLV_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                null );
+
+        super.transitions[VirtualListViewRequestStates.VLV_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_SEQUENCE_STATE,
+                VirtualListViewRequestStates.VLV_BEFORE_COUNT_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new StoreBeforeCount() );
+
+        super.transitions[VirtualListViewRequestStates.VLV_BEFORE_COUNT_STATE.ordinal()][UniversalTag.INTEGER
+            .getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_BEFORE_COUNT_STATE,
+                VirtualListViewRequestStates.VLV_AFTER_COUNT_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new StoreAfterCount() );
+
+        super.transitions[VirtualListViewRequestStates.VLV_AFTER_COUNT_STATE.ordinal()][VirtualListViewerTags.BY_OFFSET_TAG
+            .getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_AFTER_COUNT_STATE,
+                VirtualListViewRequestStates.VLV_TARGET_BY_OFFSET_STATE,
+                ( byte ) VirtualListViewerTags.BY_OFFSET_TAG.getValue(),
+                null );
+
+        super.transitions[VirtualListViewRequestStates.VLV_AFTER_COUNT_STATE.ordinal()][VirtualListViewerTags.ASSERTION_VALUE_TAG
+            .getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_AFTER_COUNT_STATE,
+                VirtualListViewRequestStates.VLV_ASSERTION_VALUE_STATE,
+                ( byte ) VirtualListViewerTags.ASSERTION_VALUE_TAG.getValue(),
+                new StoreAssertionValue() );
+
+        super.transitions[VirtualListViewRequestStates.VLV_TARGET_BY_OFFSET_STATE.ordinal()][UniversalTag.INTEGER
+            .getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_TARGET_BY_OFFSET_STATE,
+                VirtualListViewRequestStates.VLV_OFFSET_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new StoreOffset() );
+
+        super.transitions[VirtualListViewRequestStates.VLV_OFFSET_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_OFFSET_STATE,
+                VirtualListViewRequestStates.VLV_CONTENT_COUNT_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new StoreContentCount() );
+
+        super.transitions[VirtualListViewRequestStates.VLV_CONTENT_COUNT_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_CONTENT_COUNT_STATE,
+                VirtualListViewRequestStates.VLV_CONTEXT_ID_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new StoreContextId() );
+
+        super.transitions[VirtualListViewRequestStates.VLV_ASSERTION_VALUE_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<VirtualListViewRequestContainer>(
+                VirtualListViewRequestStates.VLV_ASSERTION_VALUE_STATE,
+                VirtualListViewRequestStates.VLV_CONTEXT_ID_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new StoreContextId() );
+    }
+
+
+    public static Grammar<?> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestStates.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestStates.java
new file mode 100644
index 0000000..4ebc79d
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewRequestStates.java
@@ -0,0 +1,82 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the VirtualListViewRequest grammar constants. It is also used for
+ * debugging purposes.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum VirtualListViewRequestStates implements States
+{
+    START_STATE,
+    VLV_SEQUENCE_STATE,
+    VLV_BEFORE_COUNT_STATE,
+    VLV_AFTER_COUNT_STATE,
+    VLV_TARGET_BY_OFFSET_STATE,
+    VLV_OFFSET_STATE,
+    VLV_CONTENT_COUNT_STATE,
+    VLV_CONTEXT_ID_STATE,
+    VLV_ASSERTION_VALUE_STATE,
+    END_STATE;
+
+    public String getGrammarName( int grammar )
+    {
+        return "VLV_REQUEST_GRAMMAR";
+    }
+
+
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof VirtualListViewRequestGrammar )
+        {
+            return "VLV_REQUEST_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "VLV_REQUEST_END_STATE" : name() );
+    }
+
+
+    @Override
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    @Override
+    public Enum<?> getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseContainer.java
new file mode 100644
index 0000000..6644c19
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseContainer.java
@@ -0,0 +1,87 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResponse;
+
+
+/**
+ * A container for the VLV response control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewResponseContainer extends AbstractContainer
+{
+    private VirtualListViewResponseDecorator control;
+
+    private LdapApiService codec;
+
+
+    public VirtualListViewResponseContainer( LdapApiService codec )
+    {
+        super();
+        this.codec = codec;
+        setGrammar( VirtualListViewResponseGrammar.getInstance() );
+        setTransition( VirtualListViewResponseStates.START_STATE );
+    }
+
+
+    public VirtualListViewResponseContainer( VirtualListViewResponseDecorator control, LdapApiService codec )
+    {
+        this( codec );
+        decorate( control );
+    }
+
+
+    public VirtualListViewResponseDecorator getDecorator()
+    {
+        return control;
+    }
+
+
+    public void decorate( VirtualListViewResponse control )
+    {
+        if ( control instanceof VirtualListViewResponseDecorator )
+        {
+            this.control = ( VirtualListViewResponseDecorator ) control;
+        }
+        else
+        {
+            this.control = new VirtualListViewResponseDecorator( codec, control );
+        }
+    }
+
+
+    public void setVirtualListViewResponseControl( VirtualListViewResponseDecorator control )
+    {
+        this.control = control;
+    }
+
+
+    public void clean()
+    {
+        super.clean();
+        control = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseDecorator.java
new file mode 100644
index 0000000..50e6d79
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseDecorator.java
@@ -0,0 +1,232 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ControlDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResponse;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResponseImpl;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResultCode;
+
+
+/**
+ * The VirtualListView response decorator
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewResponseDecorator extends ControlDecorator<VirtualListViewResponse> implements
+    VirtualListViewResponse
+{
+    private int vlvSeqLength;
+
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    public VirtualListViewResponseDecorator( LdapApiService codec )
+    {
+        this( codec, new VirtualListViewResponseImpl() );
+    }
+
+
+    public VirtualListViewResponseDecorator( LdapApiService codec, VirtualListViewResponse vlvRequest )
+    {
+        super( codec, vlvRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int computeLength()
+    {
+        vlvSeqLength = 1 + 1 + BerValue.getNbBytes( getTargetPosition() );
+        vlvSeqLength += 1 + 1 + BerValue.getNbBytes( getContentCount() );
+
+        // result code : always one byte long
+        vlvSeqLength += 1 + 1 + 1;
+
+        if ( getContextId() != null )
+        {
+            vlvSeqLength += 1 + TLV.getNbBytes( getContextId().length ) + getContextId().length;
+        }
+
+        valueLength = 1 + TLV.getNbBytes( vlvSeqLength ) + vlvSeqLength;
+
+        return valueLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
+    {
+        if ( buffer == null )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04023 ) );
+        }
+
+        buffer.put( UniversalTag.SEQUENCE.getValue() );
+        buffer.put( TLV.getBytes( vlvSeqLength ) );
+
+        BerValue.encode( buffer, getTargetPosition() );
+        BerValue.encode( buffer, getContentCount() );
+
+        BerValue.encodeEnumerated( buffer, getVirtualListViewResult().getValue() );
+
+        if ( getContextId() != null )
+        {
+            BerValue.encode( buffer, getContextId() );
+        }
+
+        return buffer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( value == null )
+        {
+            try
+            {
+                computeLength();
+                ByteBuffer buffer = ByteBuffer.allocate( valueLength );
+
+                value = encode( buffer ).array();
+            }
+            catch ( Exception e )
+            {
+                return null;
+            }
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Asn1Object decode( byte[] controlBytes ) throws DecoderException
+    {
+        ByteBuffer buffer = ByteBuffer.wrap( controlBytes );
+        VirtualListViewResponseContainer container = new VirtualListViewResponseContainer( this, getCodecService() );
+        DECODER.decode( buffer, container );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getTargetPosition()
+    {
+        return getDecorated().getTargetPosition();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setTargetPosition( int targetPosition )
+    {
+        getDecorated().setTargetPosition( targetPosition );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getContentCount()
+    {
+        return getDecorated().getContentCount();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setContentCount( int contentCount )
+    {
+        getDecorated().setContentCount( contentCount );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public VirtualListViewResultCode getVirtualListViewResult()
+    {
+        return getDecorated().getVirtualListViewResult();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setVirtualListViewResult( VirtualListViewResultCode virtualListViewResult )
+    {
+        getDecorated().setVirtualListViewResult( virtualListViewResult );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getContextId()
+    {
+        return getDecorated().getContextId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setContextId( byte[] contextId )
+    {
+        getDecorated().setContextId( contextId );
+    }
+
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseFactory.java
new file mode 100644
index 0000000..40b3ee2
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseFactory.java
@@ -0,0 +1,65 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.ControlFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.vlv.VirtualListViewResponse;
+
+
+/**
+ * A {@link ControlFactory} for {@link VirtualListViewResponse} controls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VirtualListViewResponseFactory implements ControlFactory<VirtualListViewResponse>
+{
+    private LdapApiService codec;
+
+
+    public VirtualListViewResponseFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    @Override
+    public String getOid()
+    {
+        return VirtualListViewResponse.OID;
+    }
+
+
+    @Override
+    public CodecControl<VirtualListViewResponse> newCodecControl()
+    {
+        return new VirtualListViewResponseDecorator( codec );
+    }
+
+
+    @Override
+    public CodecControl<VirtualListViewResponse> newCodecControl( VirtualListViewResponse control )
+    {
+        return new VirtualListViewResponseDecorator( codec, control );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseGrammar.java
new file mode 100644
index 0000000..f534186
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseGrammar.java
@@ -0,0 +1,120 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The grammar for the VLV response which described as :
+ * 
+ * <pre>
+ *  VirtualListViewResponse ::= SEQUENCE {
+ *         targetPosition    INTEGER (0 .. maxInt),
+ *         contentCount     INTEGER (0 .. maxInt),
+ *         virtualListViewResult ENUMERATED {
+ *              success (0),
+ *              operationsError (1),
+ *              protocolError (3),
+ *              unwillingToPerform (53),
+ *              insufficientAccessRights (50),
+ *              timeLimitExceeded (3),
+ *              adminLimitExceeded (11),
+ *              innapropriateMatching (18),
+ *              sortControlMissing (60),
+ *              offsetRangeError (61),
+ *              other(80),
+ *              ... 
+ *         },
+ *         contextID     OCTET STRING OPTIONAL 
+ * }
+ * </pre>
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class VirtualListViewResponseGrammar extends AbstractGrammar<VirtualListViewResponseContainer>
+{
+    static final Logger LOG = LoggerFactory.getLogger( VirtualListViewResponseGrammar.class );
+
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    private static Grammar<?> instance = new VirtualListViewResponseGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    private VirtualListViewResponseGrammar()
+    {
+        setName( VirtualListViewResponseGrammar.class.getName() );
+
+        super.transitions = new GrammarTransition[VirtualListViewResponseStates.END_STATE.ordinal()][256];
+
+        super.transitions[VirtualListViewResponseStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<VirtualListViewResponseContainer>(
+                VirtualListViewResponseStates.START_STATE,
+                VirtualListViewResponseStates.VLV_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                null );
+
+        super.transitions[VirtualListViewResponseStates.VLV_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<VirtualListViewResponseContainer>(
+                VirtualListViewResponseStates.VLV_SEQUENCE_STATE,
+                VirtualListViewResponseStates.VLV_TARGET_POSITION_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new StoreTargetPosition() );
+
+        super.transitions[VirtualListViewResponseStates.VLV_TARGET_POSITION_STATE.ordinal()][UniversalTag.INTEGER
+            .getValue()] =
+            new GrammarTransition<VirtualListViewResponseContainer>(
+                VirtualListViewResponseStates.VLV_TARGET_POSITION_STATE,
+                VirtualListViewResponseStates.VLV_CONTENT_COUNT_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new StoreContentCountResponse() );
+
+        super.transitions[VirtualListViewResponseStates.VLV_CONTENT_COUNT_STATE.ordinal()][UniversalTag.ENUMERATED
+            .getValue()] =
+            new GrammarTransition<VirtualListViewResponseContainer>(
+                VirtualListViewResponseStates.VLV_CONTENT_COUNT_STATE,
+                VirtualListViewResponseStates.VLV_VIRTUAL_LIST_VIEW_RESULT_STATE,
+                UniversalTag.ENUMERATED.getValue(),
+                new StoreVirtualListViewResult() );
+
+        super.transitions[VirtualListViewResponseStates.VLV_VIRTUAL_LIST_VIEW_RESULT_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<VirtualListViewResponseContainer>(
+                VirtualListViewResponseStates.VLV_VIRTUAL_LIST_VIEW_RESULT_STATE,
+                VirtualListViewResponseStates.VLV_CONTEXT_ID_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new StoreContextIdResponse() );
+    }
+
+
+    public static Grammar<?> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseStates.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseStates.java
new file mode 100644
index 0000000..b9d4666
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewResponseStates.java
@@ -0,0 +1,79 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the VirtualListViewResponse grammar constants. It is also used for
+ * debugging purposes.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum VirtualListViewResponseStates implements States
+{
+    START_STATE,
+    VLV_SEQUENCE_STATE,
+    VLV_TARGET_POSITION_STATE,
+    VLV_CONTENT_COUNT_STATE,
+    VLV_VIRTUAL_LIST_VIEW_RESULT_STATE,
+    VLV_CONTEXT_ID_STATE,
+    END_STATE;
+
+    public String getGrammarName( int grammar )
+    {
+        return "VLV_RESPONSE_GRAMMAR";
+    }
+
+
+    public String getGrammarName( Grammar<?> grammar )
+    {
+        if ( grammar instanceof VirtualListViewResponseGrammar )
+        {
+            return "VLV_RESPONSE_GRAMMAR";
+        }
+
+        return "UNKNOWN GRAMMAR";
+    }
+
+
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "VLV_RESPONSE_END_STATE" : name() );
+    }
+
+
+    @Override
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    @Override
+    public Enum<?> getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewerTags.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewerTags.java
new file mode 100644
index 0000000..546e756
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/controls/vlv_impl/VirtualListViewerTags.java
@@ -0,0 +1,50 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv_impl;
+
+
+/**
+ * Tags used for decoding VirtualListViewerRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum VirtualListViewerTags
+{
+    // byOffset [0]
+    BY_OFFSET_TAG(0xA0),
+    // greaterThanOrEqual [1]
+    ASSERTION_VALUE_TAG(0x81);
+
+    /** Internal value for each tag */
+    private int value;
+
+
+    private VirtualListViewerTags( int value )
+    {
+        this.value = value;
+    }
+
+
+    public int getValue()
+    {
+        return value;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelContainer.java
new file mode 100644
index 0000000..60cbba8
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelContainer.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for the Cancel codec.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelContainer extends AbstractContainer
+{
+    /** Cancel */
+    private CancelRequestDecorator cancel;
+
+
+    /**
+     * Creates a new CancelContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public CancelContainer()
+    {
+        super();
+        setGrammar( CancelGrammar.getInstance() );
+        setTransition( CancelStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the Cancel object.
+     */
+    public CancelRequestDecorator getCancel()
+    {
+        return cancel;
+    }
+
+
+    /**
+     * Set a Cancel Object into the container. It will be completed
+     * by the ldapDecoder.
+     * 
+     * @param cancel the Cancel to set.
+     */
+    public void setCancel( CancelRequestDecorator cancel )
+    {
+        this.cancel = cancel;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    public void clean()
+    {
+        super.clean();
+        cancel = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelDecoder.java
new file mode 100644
index 0000000..7ee355b
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelDecoder.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelRequest;
+
+
+/**
+ * A decoder for Cancel.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Decode a PDU which must contain a Cancel extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return An Cancel object
+     * @throws DecoderException If the decoding failed
+     */
+    public CancelRequest decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        CancelContainer container = new CancelContainer();
+        DECODER.decode( bb, container );
+        CancelRequest cancel = container.getCancel();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return cancel;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelFactory.java
new file mode 100644
index 0000000..b16f2f9
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelFactory.java
@@ -0,0 +1,110 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelRequest;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelResponse;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    public CancelFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return CancelRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CancelResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        CancelResponseDecorator response = new CancelResponseDecorator( codec, new CancelResponseImpl() );
+        response.setResponseValue( encodedValue );
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CancelRequest newRequest( byte[] value )
+    {
+        CancelRequestDecorator req = new CancelRequestDecorator( codec, new CancelRequestImpl() );
+        req.setRequestValue( value );
+
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CancelRequestDecorator decorate( ExtendedRequest modelRequest )
+    {
+        if ( modelRequest instanceof CancelRequestDecorator )
+        {
+            return ( CancelRequestDecorator ) modelRequest;
+        }
+
+        return new CancelRequestDecorator( codec, ( CancelRequest ) modelRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CancelResponseDecorator decorate( ExtendedResponse decoratedMessage )
+    {
+        if ( decoratedMessage instanceof CancelResponseDecorator )
+        {
+            return ( CancelResponseDecorator ) decoratedMessage;
+        }
+
+        return new CancelResponseDecorator( codec, ( CancelResponse ) decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelGrammar.java
new file mode 100644
index 0000000..3cc0cb8
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelGrammar.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelRequestImpl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the Cancel operation. All the actions are declared
+ * in this class. As it is a singleton, these declaration are only done once.
+ * The grammar is :
+ * 
+ * <pre>
+ *  cancelRequestValue ::= SEQUENCE {
+ *      cancelId     MessageID 
+ *                   -- MessageID is as defined in [RFC2251]
+ * }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class CancelGrammar extends AbstractGrammar<CancelContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( CancelGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. CancelGrammar is a singleton */
+    private static Grammar<CancelContainer> instance = new CancelGrammar();
+
+
+    /**
+     * Creates a new GracefulDisconnectGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private CancelGrammar()
+    {
+        setName( CancelGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[CancelStatesEnum.LAST_CANCEL_STATE.ordinal()][256];
+
+        /**
+         * Transition from init state to cancel sequence
+         * cancelRequestValue ::= SEQUENCE {
+         *     ... 
+         * 
+         * Creates the Cancel object
+         */
+        super.transitions[CancelStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<CancelContainer>( CancelStatesEnum.START_STATE,
+                CancelStatesEnum.CANCEL_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                new GrammarAction<CancelContainer>( "Init Cancel" )
+                {
+                    public void action( CancelContainer cancelContainer )
+                    {
+                        CancelRequestDecorator cancel = new CancelRequestDecorator(
+                            LdapApiServiceFactory.getSingleton(),
+                            new CancelRequestImpl() );
+
+                        cancelContainer.setCancel( cancel );
+                    }
+                } );
+
+        /**
+         * Transition from cancel SEQ to cancelId
+         * 
+         * cancelRequestValue ::= SEQUENCE {
+         *     cancelId   MessageID 
+         * }
+         *     
+         * Set the cancelId value into the Cancel object.    
+         */
+        super.transitions[CancelStatesEnum.CANCEL_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
+            new GrammarTransition<CancelContainer>( CancelStatesEnum.CANCEL_SEQUENCE_STATE,
+                CancelStatesEnum.CANCEL_ID_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new GrammarAction<CancelContainer>( "Stores CancelId" )
+                {
+                    public void action( CancelContainer cancelContainer ) throws DecoderException
+                    {
+                        BerValue value = cancelContainer.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int cancelId = IntegerDecoder.parse( value, 0, Integer.MAX_VALUE );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "CancelId = " + cancelId );
+                            }
+
+                            cancelContainer.getCancel().setCancelId( cancelId );
+                            cancelContainer.setGrammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04031, Strings.dumpBytes( value.getData() ) );
+                            LOG.error( msg );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<CancelContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelRequestDecorator.java
new file mode 100644
index 0000000..3934a34
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelRequestDecorator.java
@@ -0,0 +1,181 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.Asn1Object;
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for CancelRequests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelRequestDecorator extends ExtendedRequestDecorator<CancelRequest> implements
+    CancelRequest, Asn1Object
+{
+    private static final Logger LOG = LoggerFactory.getLogger( CancelRequestDecorator.class );
+
+    /** The Id of the the message to cancel */
+    private CancelRequest cancelRequest;
+
+    /** Length of the sequence */
+    private int cancelSequenceLength;
+
+
+    public CancelRequestDecorator( LdapApiService codec, CancelRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        cancelRequest = decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getCancelId()
+    {
+        return cancelRequest.getCancelId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCancelId( int cancelId )
+    {
+        if ( cancelId == cancelRequest.getCancelId() )
+        {
+            return;
+        }
+
+        this.requestValue = null;
+        cancelRequest.setCancelId( cancelId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getRequestValue()
+    {
+        if ( requestValue == null )
+        {
+            try
+            {
+                requestValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04164 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        return requestValue;
+    }
+
+
+    /**
+     * Sets the extended request's <b>requestValue</b> portion of the PDU.
+     *
+     * @param payload byte array of data encapsulating ext. req. parameters
+     */
+    @Override
+    public void setRequestValue( byte[] requestValue )
+    {
+        CancelDecoder decoder = new CancelDecoder();
+
+        try
+        {
+            if ( requestValue != null )
+            {
+                CancelRequest cancel = decoder.decode( requestValue );
+                cancelRequest.setCancelId( cancel.getCancelId() );
+
+                this.requestValue = new byte[requestValue.length];
+                System.arraycopy( requestValue, 0, this.requestValue, 0, requestValue.length );
+            }
+            else
+            {
+                this.requestValue = null;
+                cancelRequest.setCancelId( 0 );
+            }
+
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165 ), e );
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * Compute the Cancel length 
+     * 
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x02 0x0(1-4) [0..2^31-1] 
+     */
+    /* no qualifier */int computeLengthInternal()
+    {
+        // The messageId length
+        cancelSequenceLength = 1 + 1 + BerValue.getNbBytes( cancelRequest.getCancelId() );
+
+        // Add the sequence and the length
+        return 1 + 1 + cancelSequenceLength;
+    }
+
+
+    /**
+     * Encodes the cancel extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* no qualifier */ByteBuffer encodeInternal() throws EncoderException
+    {
+        // Allocate the bytes buffer.
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        // The sequence
+        bb.put( UniversalTag.SEQUENCE.getValue() );
+        bb.put( TLV.getBytes( cancelSequenceLength ) );
+
+        // The messageId
+        BerValue.encode( bb, cancelRequest.getCancelId() );
+
+        return bb;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelResponseDecorator.java
new file mode 100644
index 0000000..4097fcd
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelResponseDecorator.java
@@ -0,0 +1,45 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.cancel.CancelResponse;
+
+
+/**
+ * A Decorator for CancelResponses.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelResponseDecorator extends ExtendedResponseDecorator<CancelResponse> implements CancelResponse
+{
+    /**
+     * Creates a new instance of CancelResponseDecorator.
+     *
+     * @param codec
+     * @param decoratedMessage
+     */
+    public CancelResponseDecorator( LdapApiService codec, CancelResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelStatesEnum.java
new file mode 100644
index 0000000..61d6ee6
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelStatesEnum.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the Cancel's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum CancelStatesEnum implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // Cancel grammar states
+    // =========================================================================
+    /** Initial state */
+    START_STATE,
+
+    /** Sequence */
+    CANCEL_SEQUENCE_STATE,
+
+    /** cancelId */
+    CANCEL_ID_STATE,
+
+    /** terminal state */
+    LAST_CANCEL_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "CANCEL_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<CancelContainer> grammar )
+    {
+        return "CANCEL_GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "CANCEL_END_STATE" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CancelStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationContainer.java
new file mode 100644
index 0000000..7261f79
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationContainer.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for certificate generation request codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationContainer extends AbstractContainer
+{
+    /** CertGenerationObject */
+    private CertGenerationRequestDecorator certGenerationRequest;
+
+
+    /**
+     * Creates a new CertGenContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public CertGenerationContainer()
+    {
+        super();
+        setGrammar( CertGenerationGrammar.getInstance() );
+        setTransition( CertGenerationStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the CertGenerationRequest instance.
+     */
+    public CertGenerationRequestDecorator getCertGenerationRequest()
+    {
+        return certGenerationRequest;
+    }
+
+
+    /**
+     * Set a CertGenerationRequest instance into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param certGenerationRequest the CertGenerationRequest to set.
+     */
+    public void setCertGenerationRequest( CertGenerationRequestDecorator certGenerationRequest )
+    {
+        this.certGenerationRequest = certGenerationRequest;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    public void clean()
+    {
+        super.clean();
+        certGenerationRequest = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationDecoder.java
new file mode 100644
index 0000000..36bba1f
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationDecoder.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationRequest;
+
+
+/**
+ * A decoder for CertGenerationObject.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Decode a PDU which must contain a CertGenRequest extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return a CertGenerationObject object
+     * @throws org.apache.directory.api.asn1.DecoderException If the decoding failed
+     */
+    public CertGenerationRequest decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        CertGenerationContainer container = new CertGenerationContainer();
+        DECODER.decode( bb, container );
+        CertGenerationRequestDecorator certGenerationRequestDecorator = container.getCertGenerationRequest();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return certGenerationRequestDecorator.getCertGenerationRequest();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationFactory.java
new file mode 100644
index 0000000..6d75617
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationFactory.java
@@ -0,0 +1,110 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationRequest;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationResponse;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating certificate generation extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    public CertGenerationFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return CertGenerationRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CertGenerationResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        CertGenerationResponseDecorator response = new CertGenerationResponseDecorator( codec,
+            new CertGenerationResponseImpl() );
+        response.setResponseValue( encodedValue );
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CertGenerationRequest newRequest( byte[] value )
+    {
+        CertGenerationRequestDecorator req = new CertGenerationRequestDecorator( codec, new CertGenerationRequestImpl() );
+        req.setRequestValue( value );
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CertGenerationRequestDecorator decorate( ExtendedRequest modelRequest )
+    {
+        if ( modelRequest instanceof CertGenerationRequestDecorator )
+        {
+            return ( CertGenerationRequestDecorator ) modelRequest;
+        }
+
+        return new CertGenerationRequestDecorator( codec, ( CertGenerationRequest ) modelRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CertGenerationResponseDecorator decorate( ExtendedResponse decoratedMessage )
+    {
+        if ( decoratedMessage instanceof CertGenerationResponseDecorator )
+        {
+            return ( CertGenerationResponseDecorator ) decoratedMessage;
+        }
+
+        return new CertGenerationResponseDecorator( codec, ( CertGenerationResponse ) decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationGrammar.java
new file mode 100644
index 0000000..b4599c8
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationGrammar.java
@@ -0,0 +1,280 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationRequestImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the Certificate generation extended operation's ASN.1 grammer. 
+ * All the actions are declared in this class. As it is a singleton, 
+ * these declaration are only done once. The grammar is :
+ * 
+ * <pre>
+ *   CertGenerateObject ::= SEQUENCE 
+ *   {
+ *      targetDN        IA5String,
+ *      issuerDN        IA5String,
+ *      subjectDN       IA5String,
+ *      keyAlgorithm    IA5String
+ *   }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+public class CertGenerationGrammar extends AbstractGrammar<CertGenerationContainer>
+{
+
+    /** logger */
+    private static final Logger LOG = LoggerFactory.getLogger( CertGenerationGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. CertGenerationObjectGrammar is a singleton */
+    private static Grammar<CertGenerationContainer> instance = new CertGenerationGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    public CertGenerationGrammar()
+    {
+        setName( CertGenerationGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[CertGenerationStatesEnum.LAST_CERT_GENERATION_STATE.ordinal()][256];
+
+        /**
+         * Transition from init state to certificate generation
+         * 
+         * CertGenerationObject ::= SEQUENCE {
+         *     ...
+         *     
+         * Creates the CertGenerationObject object
+         */
+        super.transitions[CertGenerationStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<CertGenerationContainer>(
+                CertGenerationStatesEnum.START_STATE, CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), new GrammarAction<CertGenerationContainer>(
+                    "Init CertGenerationObject" )
+                {
+                    public void action( CertGenerationContainer container )
+                    {
+                        CertGenerationRequestDecorator certGenerationRequest = new CertGenerationRequestDecorator(
+                            LdapApiServiceFactory.getSingleton(), new CertGenerationRequestImpl() );
+                        container.setCertGenerationRequest( certGenerationRequest );
+                    }
+                } );
+
+        /**
+         * Transition from certificate generation request to targetDN
+         *
+         * CertGenerationObject ::= SEQUENCE { 
+         *     targetDN IA5String,
+         *     ...
+         *     
+         * Set the targetDN value into the CertGenerationObject instance.
+         */
+        super.transitions[CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<CertGenerationContainer>(
+                CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE,
+                CertGenerationStatesEnum.TARGETDN_STATE, UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<CertGenerationContainer>( "Set Cert Generation target Dn value" )
+                {
+                    public void action( CertGenerationContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        String targetDN = Strings.utf8ToString( value.getData() );
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "Target Dn = " + targetDN );
+                        }
+
+                        if ( ( targetDN != null ) && ( targetDN.trim().length() > 0 ) )
+                        {
+                            if ( !Dn.isValid( targetDN ) )
+                            {
+                                String msg = I18n.err( I18n.ERR_04032, targetDN );
+                                LOG.error( msg );
+                                throw new DecoderException( msg );
+                            }
+
+                            container.getCertGenerationRequest().setTargetDN( targetDN );
+                        }
+                        else
+                        {
+                            String msg = I18n.err( I18n.ERR_04033, Strings.dumpBytes( value.getData() ) );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                    }
+                } );
+
+        /**
+         * Transition from targetDN state to issuerDN
+         *
+         * CertGenerationObject ::= SEQUENCE { 
+         *     ...
+         *     issuerDN IA5String,
+         *     ...
+         *     
+         * Set the issuerDN value into the CertGenerationObject instance.
+         */
+        super.transitions[CertGenerationStatesEnum.TARGETDN_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.TARGETDN_STATE,
+                CertGenerationStatesEnum.ISSUER_STATE, UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<CertGenerationContainer>( "Set Cert Generation issuer Dn value" )
+                {
+                    public void action( CertGenerationContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        String issuerDN = Strings.utf8ToString( value.getData() );
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "Issuer Dn = " + issuerDN );
+                        }
+
+                        if ( ( issuerDN != null ) && ( issuerDN.trim().length() > 0 ) )
+                        {
+                            if ( !Dn.isValid( issuerDN ) )
+                            {
+                                String msg = I18n.err( I18n.ERR_04034, issuerDN );
+                                LOG.error( msg );
+                                throw new DecoderException( msg );
+                            }
+
+                            container.getCertGenerationRequest().setIssuerDN( issuerDN );
+                        }
+                    }
+                } );
+
+        /**
+         * Transition from issuerDN state to subjectDN
+         *
+         * CertGenerationObject ::= SEQUENCE {
+         *     ... 
+         *     subjectDN IA5String,
+         *     ...
+         *     
+         * Set the subjectDN value into the CertGenerationObject instance.
+         */
+        super.transitions[CertGenerationStatesEnum.ISSUER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.ISSUER_STATE,
+                CertGenerationStatesEnum.SUBJECT_STATE, UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<CertGenerationContainer>( "Set Cert Generation subject Dn value" )
+                {
+                    public void action( CertGenerationContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        String subjectDN = Strings.utf8ToString( value.getData() );
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "subject Dn = " + subjectDN );
+                        }
+
+                        if ( ( subjectDN != null ) && ( subjectDN.trim().length() > 0 ) )
+                        {
+                            if ( !Dn.isValid( subjectDN ) )
+                            {
+                                String msg = I18n.err( I18n.ERR_04035, subjectDN );
+                                LOG.error( msg );
+                                throw new DecoderException( msg );
+                            }
+
+                            container.getCertGenerationRequest().setSubjectDN( subjectDN );
+                        }
+                        else
+                        {
+                            String msg = I18n.err( I18n.ERR_04033, Strings.dumpBytes( value.getData() ) );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                    }
+                } );
+
+        /**
+         * Transition from subjectDN state to keyAlgo
+         *
+         * CertGenerationObject ::= SEQUENCE { 
+         *     ...
+         *     keyAlgorithm IA5String
+         *     
+         * Set the key algorithm value into the CertGenerationObject instance.
+         */
+        super.transitions[CertGenerationStatesEnum.SUBJECT_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.SUBJECT_STATE,
+                CertGenerationStatesEnum.KEY_ALGORITHM_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<CertGenerationContainer>( "Set Cert Generation key algorithm value" )
+                {
+                    public void action( CertGenerationContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        String keyAlgorithm = Strings.utf8ToString( value.getData() );
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "key algorithm = " + keyAlgorithm );
+                        }
+
+                        if ( keyAlgorithm != null && ( keyAlgorithm.trim().length() > 0 ) )
+                        {
+                            container.getCertGenerationRequest().setKeyAlgorithm( keyAlgorithm );
+                        }
+
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<CertGenerationContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationRequestDecorator.java
new file mode 100644
index 0000000..bd5e05a
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationRequestDecorator.java
@@ -0,0 +1,258 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationRequest;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationResponse;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for certificate generation extended request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationRequestDecorator extends ExtendedRequestDecorator<CertGenerationRequest>
+    implements CertGenerationRequest
+{
+    private static final Logger LOG = LoggerFactory.getLogger( CertGenerationRequestDecorator.class );
+
+    private CertGenerationRequest certGenerationRequest;
+
+    /** stores the length of the request*/
+    private int requestLength = 0;
+
+
+    public CertGenerationRequestDecorator( LdapApiService codec, CertGenerationRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        certGenerationRequest = decoratedMessage;
+    }
+
+
+    public CertGenerationRequest getCertGenerationRequest()
+    {
+        return certGenerationRequest;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setRequestValue( byte[] requestValue )
+    {
+        CertGenerationDecoder decoder = new CertGenerationDecoder();
+
+        try
+        {
+            certGenerationRequest = decoder.decode( requestValue );
+
+            if ( requestValue != null )
+            {
+                this.requestValue = new byte[requestValue.length];
+                System.arraycopy( requestValue, 0, this.requestValue, 0, requestValue.length );
+            }
+            else
+            {
+                this.requestValue = null;
+            }
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165 ), e );
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getRequestValue()
+    {
+        if ( requestValue == null )
+        {
+            try
+            {
+                requestValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04167 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        final byte[] copy = new byte[requestValue.length];
+        System.arraycopy( requestValue, 0, copy, 0, requestValue.length );
+
+        return copy;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public CertGenerationResponse getResultResponse()
+    {
+        return ( CertGenerationResponse ) getDecorated().getResultResponse();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getTargetDN()
+    {
+        return getDecorated().getTargetDN();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTargetDN( String targetDN )
+    {
+        getDecorated().setTargetDN( targetDN );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getIssuerDN()
+    {
+        return getDecorated().getIssuerDN();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setIssuerDN( String issuerDN )
+    {
+        getDecorated().setIssuerDN( issuerDN );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSubjectDN()
+    {
+        return getDecorated().getSubjectDN();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSubjectDN( String subjectDN )
+    {
+        getDecorated().setSubjectDN( subjectDN );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getKeyAlgorithm()
+    {
+        return getDecorated().getKeyAlgorithm();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setKeyAlgorithm( String keyAlgorithm )
+    {
+        getDecorated().setKeyAlgorithm( keyAlgorithm );
+    }
+
+
+    /**
+     * Compute the CertGenerationRequest length 
+     * 
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x04 LL target DN
+     *   +--> 0x04 LL issuer DN
+     *   +--> 0x04 LL subject DN
+     *   +--> 0x04 LL key algorithm
+     * </pre>
+     */
+    /* no qualifier */int computeLengthInternal()
+    {
+        int len = Strings.getBytesUtf8( certGenerationRequest.getTargetDN() ).length;
+        requestLength = 1 + TLV.getNbBytes( len ) + len;
+
+        len = Strings.getBytesUtf8( certGenerationRequest.getIssuerDN() ).length;
+        requestLength += 1 + TLV.getNbBytes( len ) + len;
+
+        len = Strings.getBytesUtf8( certGenerationRequest.getSubjectDN() ).length;
+        requestLength += 1 + TLV.getNbBytes( len ) + len;
+
+        len = Strings.getBytesUtf8( certGenerationRequest.getKeyAlgorithm() ).length;
+        requestLength += 1 + TLV.getNbBytes( len ) + len;
+
+        return 1 + TLV.getNbBytes( requestLength ) + requestLength;
+    }
+
+
+    /**
+     * Encodes the CertGenerationRequest extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* no qualifier */ByteBuffer encodeInternal() throws EncoderException
+    {
+        // Allocate the bytes buffer.
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        bb.put( UniversalTag.SEQUENCE.getValue() );
+        bb.put( TLV.getBytes( requestLength ) );
+
+        BerValue.encode( bb, certGenerationRequest.getTargetDN() );
+        BerValue.encode( bb, certGenerationRequest.getIssuerDN() );
+        BerValue.encode( bb, certGenerationRequest.getSubjectDN() );
+        BerValue.encode( bb, certGenerationRequest.getKeyAlgorithm() );
+
+        return bb;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationResponseDecorator.java
new file mode 100644
index 0000000..e68c683
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationResponseDecorator.java
@@ -0,0 +1,46 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationResponse;
+
+
+/**
+ * A Decorator for  certificate generation Responses.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationResponseDecorator extends ExtendedResponseDecorator<CertGenerationResponse> implements
+    CertGenerationResponse
+{
+    /**
+     * Creates a new instance of CancelResponseDecorator.
+     *
+     * @param codec
+     * @param decoratedMessage
+     */
+    public CertGenerationResponseDecorator( LdapApiService codec, CertGenerationResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationStatesEnum.java
new file mode 100644
index 0000000..9d39788
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationStatesEnum.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the CertGeneration's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum CertGenerationStatesEnum implements States
+{
+
+    /** The END_STATE */
+    END_STATE,
+
+    /** start state*/
+    START_STATE,
+
+    /** sequence*/
+    CERT_GENERATION_REQUEST_SEQUENCE_STATE,
+
+    /** the target Dn*/
+    TARGETDN_STATE,
+
+    /** the issuer Dn*/
+    ISSUER_STATE,
+
+    /** the subject Dn*/
+    SUBJECT_STATE,
+
+    /** the key algorithm*/
+    KEY_ALGORITHM_STATE,
+
+    /** terminal state */
+    LAST_CERT_GENERATION_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<CertGenerationContainer> grammar )
+    {
+        return "CERT_GENERATION_GRAMMER";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "CERT_GENERATION_GRAMMER";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "CERT_GENERATION_END_STATE" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CertGenerationStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulActionConstants.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulActionConstants.java
new file mode 100644
index 0000000..af5e0c0
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulActionConstants.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+/**
+ * Graceful Disconnect and Shutdown extended operation constants
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class GracefulActionConstants
+{
+    /** This is the TAG used for the delay. It's a contextual primitive Tag */
+    public static final int GRACEFUL_ACTION_DELAY_TAG = 0x80;
+
+
+    /**
+     * Private constructor.
+     */
+    private GracefulActionConstants()
+    {
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectContainer.java
new file mode 100644
index 0000000..51e568e
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectContainer.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for the GracefulDisconnect codec.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectContainer extends AbstractContainer
+{
+    /** GracefulShutdown */
+    private GracefulDisconnectResponseDecorator gracefulDisconnectResponse;
+
+
+    /**
+     * Creates a new GracefulDisconnectContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public GracefulDisconnectContainer()
+    {
+        super();
+        setGrammar( GracefulDisconnectGrammar.getInstance() );
+        setTransition( GracefulDisconnectStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the GracefulDisconnectResponse object.
+     */
+    public GracefulDisconnectResponseDecorator getGracefulDisconnectResponse()
+    {
+        return gracefulDisconnectResponse;
+    }
+
+
+    /**
+     * Set a GracefulDisconnectResponse Object into the container. It will be completed
+     * by the ldapDecoder.
+     * 
+     * @param gracefulDisconnectResponse the GracefulShutdown to set.
+     */
+    public void setGracefulDisconnectResponse( GracefulDisconnectResponseDecorator gracefulDisconnectResponse )
+    {
+        this.gracefulDisconnectResponse = gracefulDisconnectResponse;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    public void clean()
+    {
+        super.clean();
+        gracefulDisconnectResponse = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectDecoder.java
new file mode 100644
index 0000000..295cfeb
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectDecoder.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponse;
+
+
+/**
+ * A decoder for GracefulDisconnects.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Decode a PDU which must contain a GracefulDisconnect extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return An GracefulDisconnect object
+     * @throws DecoderException If the decoding failed
+     */
+    public GracefulDisconnectResponse decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+        DECODER.decode( bb, container );
+        GracefulDisconnectResponseDecorator gracefulDisconnect = container.getGracefulDisconnectResponse();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return gracefulDisconnect;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectFactory.java
new file mode 100644
index 0000000..17130f0
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectFactory.java
@@ -0,0 +1,105 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponse;
+import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    public GracefulDisconnectFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequestDecorator<ExtendedRequest> decorate(
+        ExtendedRequest modelRequest )
+    {
+        // Nothing to do (there's no request associated to GracefulDisconnectResponse)
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse decorate( ExtendedResponse decoratedMessage )
+    {
+        if ( decoratedMessage instanceof GracefulDisconnectResponseDecorator )
+        {
+            return decoratedMessage;
+        }
+
+        return new GracefulDisconnectResponseDecorator( codec, ( GracefulDisconnectResponse ) decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return GracefulDisconnectResponse.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest newRequest( byte[] value )
+    {
+        // Nothing to do (there's no request associated to GracefulDisconnectResponse)
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulDisconnectResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        GracefulDisconnectResponseDecorator req = new GracefulDisconnectResponseDecorator( codec,
+            new GracefulDisconnectResponseImpl() );
+        req.setResponseValue( encodedValue );
+        
+        return req;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectGrammar.java
new file mode 100644
index 0000000..c8eb197
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectGrammar.java
@@ -0,0 +1,357 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponseImpl;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the Graceful Disconnect. All the actions are declared
+ * in this class. As it is a singleton, these declaration are only done once.
+ * The grammar is :
+ * 
+ * <pre>
+ *  GracefulDisconnect ::= SEQUENCE {
+ *      timeOffline INTEGER (0..720) DEFAULT 0,
+ *      delay [0] INTEGER (0..86400) DEFAULT 0,
+ *      replicatedContexts Referral OPTIONAL
+ * }
+ *  
+ *  Referral ::= SEQUENCE OF LDAPURL
+ *  
+ *  LDAPURL ::= LDAPString -- limited to characters permitted in URLs
+ *  
+ *  LDAPString ::= OCTET STRING
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class GracefulDisconnectGrammar extends AbstractGrammar<GracefulDisconnectContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. GracefulDisconnectnGrammar is a singleton */
+    private static GracefulDisconnectGrammar instance = new GracefulDisconnectGrammar();
+
+    /**
+     * The action used to store a Time Offline.
+     */
+    private GrammarAction<GracefulDisconnectContainer> storeDelay =
+        new GrammarAction<GracefulDisconnectContainer>( "Set Graceful Disconnect Delay" )
+        {
+            public void action( GracefulDisconnectContainer container ) throws DecoderException
+            {
+                BerValue value = container.getCurrentTLV().getValue();
+
+                try
+                {
+                    int delay = IntegerDecoder.parse( value, 0, 86400 );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Delay = " + delay );
+                    }
+
+                    container.getGracefulDisconnectResponse().setDelay( delay );
+                    container.setGrammarEndAllowed( true );
+                }
+                catch ( IntegerDecoderException ide )
+                {
+                    String msg = I18n.err( I18n.ERR_04036, Strings.dumpBytes( value.getData() ) );
+                    LOG.error( msg );
+                    throw new DecoderException( msg, ide );
+                }
+            }
+        };
+
+    /**
+     * The action used to store a referral.
+     */
+    private GrammarAction<GracefulDisconnectContainer> storeReferral =
+        new GrammarAction<GracefulDisconnectContainer>( "Stores a referral" )
+        {
+            public void action( GracefulDisconnectContainer container ) throws DecoderException
+            {
+                BerValue value = container.getCurrentTLV().getValue();
+
+                try
+                {
+                    if ( Strings.isEmpty( value.getData() ) )
+                    {
+                        String msg = "failed to decode a null URL";
+                        LOG.error( msg );
+                        throw new DecoderException( msg );
+                    }
+
+                    String url = Strings.utf8ToString( value.getData() );
+
+                    LdapUrl ldapUrl = new LdapUrl( url );
+                    container.getGracefulDisconnectResponse().addReplicatedContexts( url );
+                    container.setGrammarEndAllowed( true );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Stores a referral : {}", ldapUrl );
+                    }
+                }
+                catch ( LdapURLEncodingException luee )
+                {
+                    String msg = "failed to decode the URL '" + Strings.dumpBytes( value.getData() ) + "'";
+                    LOG.error( msg );
+                    throw new DecoderException( msg, luee );
+                }
+            }
+        };
+
+    /**
+     * The action used to store a Time Offline.
+     */
+    private GrammarAction<GracefulDisconnectContainer> storeTimeOffline =
+        new GrammarAction<GracefulDisconnectContainer>( "Set Graceful Disconnect time offline" )
+        {
+            public void action( GracefulDisconnectContainer container ) throws DecoderException
+            {
+                BerValue value = container.getCurrentTLV().getValue();
+
+                try
+                {
+                    int timeOffline = IntegerDecoder.parse( value, 0, 720 );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Time Offline = " + timeOffline );
+                    }
+
+                    container.getGracefulDisconnectResponse().setTimeOffline( timeOffline );
+                    container.setGrammarEndAllowed( true );
+                }
+                catch ( IntegerDecoderException ide )
+                {
+                    String msg = I18n.err( I18n.ERR_04037, Strings.dumpBytes( value.getData() ) );
+                    LOG.error( msg );
+                    throw new DecoderException( msg, ide );
+                }
+            }
+        };
+
+
+    /**
+     * Creates a new GracefulDisconnectGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private GracefulDisconnectGrammar()
+    {
+        setName( GracefulDisconnectGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[GracefulDisconnectStatesEnum.LAST_GRACEFUL_DISCONNECT_STATE.ordinal()][256];
+
+        /**
+         * Transition from init state to graceful disconnect
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         * 
+         * Creates the GracefulDisconnect object
+         */
+        super.transitions[GracefulDisconnectStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.START_STATE,
+                GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                new GrammarAction<GracefulDisconnectContainer>( "Init Graceful Disconnect" )
+                {
+                    public void action( GracefulDisconnectContainer container )
+                    {
+                        GracefulDisconnectResponseDecorator gracefulDisconnectResponse = 
+                            new GracefulDisconnectResponseDecorator(
+                                LdapApiServiceFactory.getSingleton(),
+                                new GracefulDisconnectResponseImpl()
+                                );
+                        container.setGracefulDisconnectResponse( gracefulDisconnectResponse );
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from graceful disconnect to time offline
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     timeOffline INTEGER (0..720) DEFAULT 0, 
+         *     ... 
+         *     
+         * Set the time offline value into the GracefulDisconnect object.    
+         */
+        super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER
+            .getValue()] =
+            new GrammarTransition<GracefulDisconnectContainer>(
+                GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+                GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
+                UniversalTag.INTEGER.getValue(), storeTimeOffline );
+
+        /**
+         * Transition from graceful disconnect to delay
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         *     delay [0] INTEGER (0..86400) DEFAULT 0,
+         *     ... 
+         *     
+         * Set the delay value into the GracefulDisconnect object.    
+         */
+        super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] =
+            new GrammarTransition<GracefulDisconnectContainer>(
+                GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+                GracefulDisconnectStatesEnum.DELAY_STATE,
+                GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
+                storeDelay );
+
+        /**
+         * Transition from graceful disconnect to replicated Contexts
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         *     replicatedContexts Referral OPTIONAL } 
+         *     
+         * Referral ::= SEQUENCE OF LDAPURL
+         *     
+         * Get some replicated contexts. Nothing to do    
+         */
+        super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][UniversalTag.SEQUENCE
+            .getValue()] =
+            new GrammarTransition<GracefulDisconnectContainer>(
+                GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        /**
+         * Transition from time offline to delay
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         *     delay [0] INTEGER (0..86400) DEFAULT 0,
+         *     ... 
+         *     
+         * Set the delay value into the GracefulDisconnect object.    
+         */
+        super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] =
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
+                GracefulDisconnectStatesEnum.DELAY_STATE,
+                GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
+                storeDelay );
+
+        /**
+         * Transition from time offline to replicated Contexts
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         *     replicatedContexts Referral OPTIONAL } 
+         *     
+         * Referral ::= SEQUENCE OF LDAPURL
+         *     
+         * Get some replicated contexts. Nothing to do    
+         */
+        super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        /**
+         * Transition from delay to replicated contexts
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         *     replicatedContexts Referral OPTIONAL } 
+         *     
+         * Referral ::= SEQUENCE OF LDAPURL
+         *     
+         * Get some replicated contexts. Nothing to do    
+         */
+        super.transitions[GracefulDisconnectStatesEnum.DELAY_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.DELAY_STATE,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
+
+        /**
+         * Transition from replicated contexts to referral
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         *     replicatedContexts Referral OPTIONAL } 
+         *     
+         * Referral ::= SEQUENCE OF LDAPURL
+         *     
+         * Stores the referral
+         */
+        super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
+                GracefulDisconnectStatesEnum.REFERRAL_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                storeReferral );
+
+        /**
+         * Transition from referral to referral
+         * 
+         * GracefulDisconnect ::= SEQUENCE { 
+         *     ... 
+         *     replicatedContexts Referral OPTIONAL } 
+         *     
+         * Referral ::= SEQUENCE OF LDAPURL
+         *     
+         * Stores the referral
+         */
+        super.transitions[GracefulDisconnectStatesEnum.REFERRAL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.REFERRAL_STATE,
+                GracefulDisconnectStatesEnum.REFERRAL_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                storeReferral );
+
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static GracefulDisconnectGrammar getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectResponseDecorator.java
new file mode 100644
index 0000000..e890bb8
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectResponseDecorator.java
@@ -0,0 +1,305 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponse;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for CancelResponses.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectResponseDecorator extends ExtendedResponseDecorator<GracefulDisconnectResponse>
+    implements GracefulDisconnectResponse
+{
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectResponseDecorator.class );
+
+    /** Length of the sequence */
+    private int gracefulDisconnectSequenceLength;
+
+    /** Length of the replicated contexts */
+    private int replicatedContextsLength;
+    
+    /** The encoded LDAP URL list */
+    private List<byte[]> ldapUrlBytes;
+
+    private GracefulDisconnectResponse gracefulDisconnectResponse;
+
+    /**
+     * Creates a new instance of CancelResponseDecorator.
+     *
+     * @param codec
+     * @param decoratedMessage
+     */
+    public GracefulDisconnectResponseDecorator( LdapApiService codec, GracefulDisconnectResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        gracefulDisconnectResponse = decoratedMessage;
+    }
+
+    
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the response OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponseValue()
+    {
+        if ( responseValue == null )
+        {
+            try
+            {
+                responseValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04164 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        return responseValue;
+    }
+
+
+    /**
+     * Sets the response OID specific encoded response values.
+     * 
+     * @param responseValue the response specific encoded response values.
+     */
+    public void setResponseValue( byte[] responseValue )
+    {
+        GracefulDisconnectDecoder decoder = new GracefulDisconnectDecoder();
+
+        try
+        {
+            if ( responseValue != null )
+            {
+                decoder.decode( responseValue );
+                this.responseValue = new byte[responseValue.length];
+                System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length );
+            }
+            else
+            {
+                this.responseValue = null;
+            }
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04172 ), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getDelay()
+    {
+        return gracefulDisconnectResponse.getDelay();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDelay( int delay )
+    {
+        gracefulDisconnectResponse.setDelay( delay );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeOffline()
+    {
+        return gracefulDisconnectResponse.getTimeOffline();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTimeOffline( int timeOffline )
+    {
+        gracefulDisconnectResponse.setTimeOffline( timeOffline );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Referral getReplicatedContexts()
+    {
+        return gracefulDisconnectResponse.getReplicatedContexts();
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void addReplicatedContexts( String replicatedContext )
+    {
+        gracefulDisconnectResponse.getReplicatedContexts().addLdapUrl( replicatedContext );
+    }
+
+
+    /**
+     * Compute the GracefulDisconnect length 
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *   +--> [ 0x02 0x0(1-4) [0..720] ] 
+     *   +--> [ 0x80 0x0(1-3) [0..86400] ] 
+     *   +--> [ 0x30 L2 
+     *           | 
+     *           +--> (0x04 L3 value) + ]
+     * </pre>
+     */
+    /* no qualifier */ int computeLengthInternal()
+    {
+        gracefulDisconnectSequenceLength = 0;
+
+        if ( gracefulDisconnectResponse.getTimeOffline() != 0 )
+        {
+            gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getTimeOffline() );
+        }
+
+        if ( gracefulDisconnectResponse.getDelay() != 0 )
+        {
+            gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getDelay() );
+        }
+
+        if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null )
+            && ( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() != 0 ) )
+        {
+            replicatedContextsLength = 0;
+            
+            ldapUrlBytes = new ArrayList<byte[]>( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() );
+
+            // We may have more than one reference.
+            for ( String replicatedContext : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() )
+            {
+                byte[] bytes = Strings.getBytesUtf8( replicatedContext );
+                ldapUrlBytes.add( bytes );
+                int ldapUrlLength = bytes.length;
+                replicatedContextsLength += 1 + TLV.getNbBytes( ldapUrlLength ) + ldapUrlLength;
+            }
+
+            gracefulDisconnectSequenceLength += 1 + TLV.getNbBytes( replicatedContextsLength )
+                + replicatedContextsLength;
+        }
+
+        return 1 + TLV.getNbBytes( gracefulDisconnectSequenceLength ) + gracefulDisconnectSequenceLength;
+    }
+
+
+    /**
+     * Encodes the gracefulDisconnect extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* no qualifier */ ByteBuffer encodeInternal() throws EncoderException
+    {
+        // Allocate the bytes buffer.
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+
+        bb.put( UniversalTag.SEQUENCE.getValue() );
+        bb.put( TLV.getBytes( gracefulDisconnectSequenceLength ) );
+
+        if ( gracefulDisconnectResponse.getTimeOffline() != 0 )
+        {
+            BerValue.encode( bb, gracefulDisconnectResponse.getTimeOffline() );
+        }
+
+        if ( gracefulDisconnectResponse.getDelay() != 0 )
+        {
+            bb.put( ( byte ) GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG );
+            bb.put( ( byte ) TLV.getNbBytes( gracefulDisconnectResponse.getDelay() ) );
+            bb.put( BerValue.getBytes( gracefulDisconnectResponse.getDelay() ) );
+        }
+
+        if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null )
+            && ( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() != 0 ) )
+        {
+            bb.put( UniversalTag.SEQUENCE.getValue() );
+            bb.put( TLV.getBytes( replicatedContextsLength ) );
+
+            // We may have more than one reference.
+            for ( byte[] replicatedContext : ldapUrlBytes )
+            {
+                BerValue.encode( bb, replicatedContext );
+            }
+        }
+
+        return bb;
+    }
+
+
+    /**
+     * Return a string representation of the graceful disconnect
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "Graceful Disconnect extended operation" );
+        sb.append( "    TimeOffline : " ).append( gracefulDisconnectResponse.getTimeOffline() ).append( '\n' );
+        sb.append( "    Delay : " ).append( gracefulDisconnectResponse.getDelay() ).append( '\n' );
+
+        if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) && ( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() != 0 ) )
+        {
+            sb.append( "    Replicated contexts :" );
+
+            // We may have more than one reference.
+            for ( String url : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() )
+            {
+                sb.append( "\n        " ).append( url );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectStatesEnum.java
new file mode 100644
index 0000000..6c4fa71
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectStatesEnum.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the GracefulDisconnect's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum GracefulDisconnectStatesEnum implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // GracefulDisconnect grammar states
+    // =========================================================================
+    /** Initial state */
+    START_STATE,
+
+    /** Sequence */
+    GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+
+    /** Time offline */
+    TIME_OFFLINE_STATE,
+
+    /** Delay */
+    DELAY_STATE,
+
+    /** Replicated contexts */
+    REPLICATED_CONTEXTS_STATE,
+
+    /** Referral */
+    REFERRAL_STATE,
+
+    /** terminal state */
+    LAST_GRACEFUL_DISCONNECT_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "GRACEFUL_DISCONNECT_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<GracefulDisconnectContainer> grammar )
+    {
+        return "GRACEFUL_DISCONNECT_GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "GRACEFUL_DISCONNECT_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulDisconnectStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownContainer.java
new file mode 100644
index 0000000..a2c6b4a
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownContainer.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for the GracefulShutdown codec.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownContainer extends AbstractContainer
+{
+    /** GracefulShutdown */
+    private GracefulShutdownRequestDecorator gracefulShutdownRequest;
+
+
+    /**
+     * Creates a new GracefulShutdownContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public GracefulShutdownContainer()
+    {
+        super();
+        setGrammar( GracefulShutdownGrammar.getInstance() );
+        setTransition( GracefulShutdownStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the Graceful Shutdown object.
+     */
+    public GracefulShutdownRequestDecorator getGracefulShutdownRequest()
+    {
+        return gracefulShutdownRequest;
+    }
+
+
+    /**
+     * Set a GracefulShutdown Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param gracefulShutdown the GracefulShutdown to set.
+     */
+    public void setGracefulShutdownRequest( GracefulShutdownRequestDecorator gracefulShutdown )
+    {
+        this.gracefulShutdownRequest = gracefulShutdown;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    public void clean()
+    {
+        super.clean();
+        gracefulShutdownRequest = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownDecoder.java
new file mode 100644
index 0000000..417739f
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownDecoder.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownRequest;
+
+
+/**
+ * A decoder for GracefulShutdowns.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Decode a PDU which must contain a GracefulShutdown extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return An GracefulShutdown object
+     * @throws org.apache.directory.api.asn1.DecoderException If the decoding failed
+     */
+    public GracefulShutdownRequest decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+        DECODER.decode( bb, container );
+        GracefulShutdownRequestDecorator gracefulShutdown = container.getGracefulShutdownRequest();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return gracefulShutdown;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownFactory.java
new file mode 100644
index 0000000..898eade
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownFactory.java
@@ -0,0 +1,110 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownRequest;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownResponse;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    public GracefulShutdownFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return GracefulShutdownRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulShutdownResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        GracefulShutdownResponseDecorator response = new GracefulShutdownResponseDecorator(
+            codec, new GracefulShutdownResponseImpl() );
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulShutdownRequest newRequest( byte[] value )
+    {
+        GracefulShutdownRequestDecorator req = new GracefulShutdownRequestDecorator( codec,
+            new GracefulShutdownRequestImpl() );
+        req.setRequestValue( value );
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest decorate( ExtendedRequest modelRequest )
+    {
+        if ( modelRequest instanceof GracefulShutdownRequestDecorator )
+        {
+            return modelRequest;
+        }
+
+        return new GracefulShutdownRequestDecorator( codec, ( GracefulShutdownRequest ) modelRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse decorate( ExtendedResponse decoratedMessage )
+    {
+        if ( decoratedMessage instanceof GracefulShutdownResponseDecorator )
+        {
+            return decoratedMessage;
+        }
+
+        return new GracefulShutdownResponseDecorator( codec, ( GracefulShutdownResponse ) decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownGrammar.java
new file mode 100644
index 0000000..2546647
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownGrammar.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulActionConstants;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownRequestImpl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the Graceful shutdown. All the actions are declared in
+ * this class. As it is a singleton, these declaration are only done once. The
+ * grammar is :
+ * 
+ * <pre>
+ *  GracefulShutdwon ::= SEQUENCE {
+ *      timeOffline INTEGER (0..720) DEFAULT 0,
+ *      delay [0] INTEGER (0..86400) DEFAULT 0
+ *  }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class GracefulShutdownGrammar extends AbstractGrammar<GracefulShutdownContainer>
+{
+    /** The logger */
+    static final Logger LOG = LoggerFactory.getLogger( GracefulShutdownGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. GracefulShutdownGrammar is a singleton */
+    private static GracefulShutdownGrammar instance = new GracefulShutdownGrammar();
+
+
+    /**
+     * Creates a new GracefulShutdownGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private GracefulShutdownGrammar()
+    {
+        setName( GracefulShutdownGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[GracefulShutdownStatesEnum.LAST_GRACEFUL_SHUTDOWN_STATE.ordinal()][256];
+
+        /**
+         * Transition from init state to graceful shutdown
+         * 
+         * GracefulShutdown ::= SEQUENCE {
+         *     ...
+         *     
+         * Creates the GracefulShutdown object
+         */
+        super.transitions[GracefulShutdownStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<GracefulShutdownContainer>( GracefulShutdownStatesEnum.START_STATE,
+                GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                new GrammarAction<GracefulShutdownContainer>( "Init GracefulShutdown" )
+                {
+                    public void action( GracefulShutdownContainer container )
+                    {
+                        GracefulShutdownRequestDecorator gracefulShutdownRequest = new GracefulShutdownRequestDecorator(
+                            LdapApiServiceFactory.getSingleton(),
+                            new GracefulShutdownRequestImpl() );
+                        container.setGracefulShutdownRequest( gracefulShutdownRequest );
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from graceful shutdown to time offline
+         *
+         * GracefulShutdown ::= SEQUENCE { 
+         *     timeOffline INTEGER (0..720) DEFAULT 0,
+         *     ...
+         *     
+         * Set the time offline value into the GracefulShutdown
+         * object.
+         */
+        super.transitions[GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER
+            .getValue()] =
+            new GrammarTransition<GracefulShutdownContainer>(
+                GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE,
+                GracefulShutdownStatesEnum.TIME_OFFLINE_STATE,
+                UniversalTag.INTEGER.getValue(),
+                new GrammarAction<GracefulShutdownContainer>( "Set Graceful Shutdown time offline" )
+                {
+                    public void action( GracefulShutdownContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int timeOffline = IntegerDecoder.parse( value, 0, 720 );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "Time Offline = " + timeOffline );
+                            }
+
+                            container.getGracefulShutdownRequest().setTimeOffline( timeOffline );
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04037, Strings.dumpBytes( value.getData() ) );
+                            LOG.error( msg );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+
+        /**
+         * Transition from time offline to delay
+         * 
+         * GracefulShutdown ::= SEQUENCE { 
+         *     ... 
+         *     delay [0] INTEGER (0..86400) DEFAULT 0 }
+         * 
+         * Set the delay value into the GracefulShutdown
+         * object.
+         */
+        super.transitions[GracefulShutdownStatesEnum.TIME_OFFLINE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] =
+            new GrammarTransition<GracefulShutdownContainer>( GracefulShutdownStatesEnum.TIME_OFFLINE_STATE,
+                GracefulShutdownStatesEnum.DELAY_STATE,
+                GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
+
+                new GrammarAction<GracefulShutdownContainer>( "Set Graceful Shutdown Delay" )
+                {
+                    public void action( GracefulShutdownContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int delay = IntegerDecoder.parse( value, 0, 86400 );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "Delay = " + delay );
+                            }
+
+                            container.getGracefulShutdownRequest().setDelay( delay );
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04036, Strings.dumpBytes( value.getData() ) );
+                            LOG.error( msg );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+
+        /**
+         * Transition from graceful shutdown to delay
+         * 
+         * GracefulShutdown ::= SEQUENCE { 
+         *     ... 
+         *     delay [0] INTEGER (0..86400) DEFAULT 0 }
+         * 
+         * Set the delay value into the GracefulShutdown
+         * object.
+         */
+        super.transitions[GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] =
+            new GrammarTransition<GracefulShutdownContainer>(
+                GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE,
+                GracefulShutdownStatesEnum.DELAY_STATE,
+                GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
+
+                new GrammarAction<GracefulShutdownContainer>( "Set Graceful Shutdown Delay" )
+                {
+                    public void action( GracefulShutdownContainer container ) throws DecoderException
+                    {
+                        GracefulShutdownContainer gracefulShutdownContainer = ( GracefulShutdownContainer ) container;
+                        BerValue value = gracefulShutdownContainer.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int delay = IntegerDecoder.parse( value, 0, 86400 );
+
+                            if ( IS_DEBUG )
+                            {
+                                LOG.debug( "Delay = " + delay );
+                            }
+
+                            gracefulShutdownContainer.getGracefulShutdownRequest().setDelay( delay );
+                            gracefulShutdownContainer.setGrammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            String msg = I18n.err( I18n.ERR_04036, Strings.dumpBytes( value.getData() ) );
+                            LOG.error( msg );
+                            throw new DecoderException( msg, ide );
+                        }
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static GracefulShutdownGrammar getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownRequestDecorator.java
new file mode 100644
index 0000000..b9305eb
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownRequestDecorator.java
@@ -0,0 +1,227 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulActionConstants;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for GracefulShutdownRequests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownRequestDecorator extends ExtendedRequestDecorator<GracefulShutdownRequest>
+    implements GracefulShutdownRequest
+{
+    private static final Logger LOG = LoggerFactory.getLogger( GracefulShutdownRequestDecorator.class );
+
+    /** Length of the sequence */
+    private int gracefulSequenceLength;
+
+    private GracefulShutdownRequest gracefulShutdownRequest;
+
+
+    /**
+     * Creates a new instance of GracefulShutdownRequestDecorator.
+     *
+     * @param codec
+     * @param decoratedMessage
+     */
+    public GracefulShutdownRequestDecorator( LdapApiService codec, GracefulShutdownRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        gracefulShutdownRequest = decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRequestValue( byte[] requestValue )
+    {
+        GracefulShutdownDecoder decoder = new GracefulShutdownDecoder();
+
+        try
+        {
+            if ( requestValue != null )
+            {
+                gracefulShutdownRequest = decoder.decode( requestValue );
+
+                this.requestValue = new byte[requestValue.length];
+                System.arraycopy( requestValue, 0, this.requestValue, 0, requestValue.length );
+            }
+            else
+            {
+                this.requestValue = null;
+            }
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165 ), e );
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getRequestValue()
+    {
+        if ( requestValue == null )
+        {
+            try
+            {
+                requestValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04164 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        return requestValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getDelay()
+    {
+        return getDecorated().getDelay();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDelay( int delay )
+    {
+        getDecorated().setDelay( delay );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeOffline()
+    {
+        return getDecorated().getTimeOffline();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setTimeOffline( int timeOffline )
+    {
+        getDecorated().setTimeOffline( timeOffline );
+    }
+
+
+    /**
+     * Compute the GracefulShutdown length 
+     * 
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *   +--> [0x02 0x0(1-4) [0..720] ] 
+     *   +--> [0x80 0x0(1-3) [0..86400] ] 
+     * </pre>  
+     * L1 will always be &lt 11.
+     */
+    /* no qualifier */int computeLengthInternal()
+    {
+        int gracefulLength = 1 + 1;
+        gracefulSequenceLength = 0;
+
+        if ( gracefulShutdownRequest.getTimeOffline() != 0 )
+        {
+            gracefulSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulShutdownRequest.getTimeOffline() );
+        }
+
+        if ( gracefulShutdownRequest.getDelay() != 0 )
+        {
+            gracefulSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulShutdownRequest.getDelay() );
+        }
+
+        return gracefulLength + gracefulSequenceLength;
+    }
+
+
+    /**
+     * Encodes the gracefulShutdown extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* no qualifier */ByteBuffer encodeInternal() throws EncoderException
+    {
+        // Allocate the bytes buffer.
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        bb.put( UniversalTag.SEQUENCE.getValue() );
+        bb.put( TLV.getBytes( gracefulSequenceLength ) );
+
+        if ( gracefulShutdownRequest.getTimeOffline() != 0 )
+        {
+            BerValue.encode( bb, gracefulShutdownRequest.getTimeOffline() );
+        }
+
+        if ( gracefulShutdownRequest.getDelay() != 0 )
+        {
+            bb.put( ( byte ) GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG );
+            bb.put( ( byte ) BerValue.getNbBytes( gracefulShutdownRequest.getDelay() ) );
+            bb.put( BerValue.getBytes( gracefulShutdownRequest.getDelay() ) );
+        }
+        return bb;
+    }
+
+
+    /**
+     * Return a string representation of the graceful shutdown
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "Graceful Shutdown extended operation" );
+        sb.append( "    TimeOffline : " ).append( gracefulShutdownRequest.getTimeOffline() ).append( '\n' );
+        sb.append( "    Delay : " ).append( gracefulShutdownRequest.getDelay() ).append( '\n' );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownResponseDecorator.java
new file mode 100644
index 0000000..099ab48
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownResponseDecorator.java
@@ -0,0 +1,46 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.gracefulShutdown.GracefulShutdownResponse;
+
+
+/**
+ * A Decorator for CancelResponses.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownResponseDecorator extends ExtendedResponseDecorator<GracefulShutdownResponse> implements
+    GracefulShutdownResponse
+{
+    /**
+     * Creates a new instance of GracefulShutdownResponseDecorator.
+     *
+     * @param codec
+     * @param decoratedMessage
+     */
+    public GracefulShutdownResponseDecorator( LdapApiService codec, GracefulShutdownResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownStatesEnum.java
new file mode 100644
index 0000000..51863d3
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownStatesEnum.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the GracefulShutdown's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum GracefulShutdownStatesEnum implements States
+{
+    // ~ Static fields/initializers
+    // -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    // =========================================================================
+    // GracefulShutdown grammar states
+    // =========================================================================
+
+    /** Initial state */
+    START_STATE,
+
+    /** Sequence */
+    GRACEFUL_SHUTDOWN_SEQUENCE_STATE,
+
+    /** Time offline */
+    TIME_OFFLINE_STATE,
+
+    /** Delay */
+    DELAY_STATE,
+
+    /** terminal state */
+    LAST_GRACEFUL_SHUTDOWN_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "GRACEFUL_SHUTDOWN_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<GracefulShutdownContainer> grammar )
+    {
+        return "GRACEFUL_SHUTDOWN_GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "GRACEFUL_SHUTDOWN_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulShutdownStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyFactory.java
new file mode 100644
index 0000000..aa640eb
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyFactory.java
@@ -0,0 +1,175 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequest;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponse;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponseImpl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating PwdModify extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    public PasswordModifyFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return PasswordModifyRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordModifyResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        PasswordModifyResponseDecorator response = new PasswordModifyResponseDecorator( codec,
+            new PasswordModifyResponseImpl() );
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordModifyRequest newRequest( byte[] value )
+    {
+        PasswordModifyRequestDecorator req = new PasswordModifyRequestDecorator( codec, new PasswordModifyRequestImpl() );
+
+        if ( value != null )
+        {
+            req.setRequestValue( value );
+        }
+
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordModifyRequestDecorator decorate( ExtendedRequest modelRequest )
+    {
+        if ( modelRequest instanceof PasswordModifyRequestDecorator )
+        {
+            return ( PasswordModifyRequestDecorator ) modelRequest;
+        }
+
+        return new PasswordModifyRequestDecorator( codec, ( PasswordModifyRequest ) modelRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordModifyResponseDecorator decorate( ExtendedResponse decoratedResponse )
+    {
+        if ( decoratedResponse instanceof PasswordModifyResponseDecorator )
+        {
+            return ( PasswordModifyResponseDecorator ) decoratedResponse;
+        }
+
+        if ( decoratedResponse instanceof PasswordModifyResponse )
+        {
+            return new PasswordModifyResponseDecorator( codec, ( PasswordModifyResponse ) decoratedResponse );
+        }
+
+        // It's an opaque extended operation
+        @SuppressWarnings("unchecked")
+        ExtendedResponseDecorator<ExtendedResponse> response = ( ExtendedResponseDecorator<ExtendedResponse> ) decoratedResponse;
+
+        // Decode the response, as it's an opaque operation
+        Asn1Decoder decoder = new Asn1Decoder();
+
+        byte[] value = response.getResponseValue();
+        ByteBuffer buffer = ByteBuffer.wrap( value );
+
+        PasswordModifyResponseContainer container = new PasswordModifyResponseContainer();
+        PasswordModifyResponse pwdModifyResponse = null;
+
+        try
+        {
+            decoder.decode( buffer, container );
+
+            pwdModifyResponse = container.getPwdModifyResponse();
+
+            // Now, update the created response with what we got from the extendedResponse
+            pwdModifyResponse.getLdapResult().setResultCode( response.getLdapResult().getResultCode() );
+            pwdModifyResponse.getLdapResult().setDiagnosticMessage( response.getLdapResult().getDiagnosticMessage() );
+            pwdModifyResponse.getLdapResult().setMatchedDn( response.getLdapResult().getMatchedDn() );
+            pwdModifyResponse.getLdapResult().setReferral( response.getLdapResult().getReferral() );
+        }
+        catch ( DecoderException de )
+        {
+            StringWriter sw = new StringWriter();
+            de.printStackTrace( new PrintWriter( sw ) );
+            String stackTrace = sw.toString();
+
+            // Error while decoding the value. 
+            pwdModifyResponse = new PasswordModifyResponseImpl(
+                decoratedResponse.getMessageId(),
+                ResultCodeEnum.OPERATIONS_ERROR,
+                stackTrace );
+        }
+
+        PasswordModifyResponseDecorator decorated = new PasswordModifyResponseDecorator( codec, pwdModifyResponse );
+
+        Control ppolicyControl = response.getControl( PasswordPolicy.OID );
+
+        if ( ppolicyControl != null )
+        {
+            decorated.addControl( ppolicyControl );
+        }
+
+        return decorated;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestConstants.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestConstants.java
new file mode 100644
index 0000000..15ef52c
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestConstants.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+/**
+ * PasswordModifyRequest extended operation constants
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PasswordModifyRequestConstants
+{
+    /** This is the TAG used for the userIdentity. It's a contextual primitive Tag */
+    public static final int USER_IDENTITY_TAG = 0x80;
+
+    /** This is the TAG used for the userIdentity. It's a contextual primitive Tag */
+    public static final int OLD_PASSWORD_TAG = 0x81;
+
+    /** This is the TAG used for the userIdentity. It's a contextual primitive Tag */
+    public static final int NEW_PASSWORD_TAG = 0x82;
+
+
+    /**
+     * Private constructor.
+     */
+    private PasswordModifyRequestConstants()
+    {
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestContainer.java
new file mode 100644
index 0000000..b920282
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestContainer.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for PasswordModifyRequest codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyRequestContainer extends AbstractContainer
+{
+    /** PasswordModifyRequest decorator*/
+    private PasswordModifyRequestDecorator passwordModifyRequest;
+
+
+    /**
+     * Creates a new PasswordModifyContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public PasswordModifyRequestContainer()
+    {
+        super();
+        setGrammar( PasswordModifyRequestGrammar.getInstance() );
+        setTransition( PasswordModifyRequestStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the PwdModifyRequest instance.
+     */
+    public PasswordModifyRequestDecorator getPwdModifyRequest()
+    {
+        return passwordModifyRequest;
+    }
+
+
+    /**
+     * Set a PasswordModifyRequest Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param passwordModifyRequestDecorator the PasswordModifyRequest to set.
+     */
+    public void setPasswordModifyRequest( PasswordModifyRequestDecorator passwordModifyRequestDecorator )
+    {
+        this.passwordModifyRequest = passwordModifyRequestDecorator;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    public void clean()
+    {
+        super.clean();
+        passwordModifyRequest = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestDecoder.java
new file mode 100644
index 0000000..4fb0fb4
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestDecoder.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequest;
+
+
+/**
+ * 
+ * A decoder for PasswordModifyRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyRequestDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Decode a PDU which must contain a PwdModifyRequest extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return a PwdModifyRequest object
+     * @throws org.apache.directory.api.asn1.DecoderException If the decoding failed
+     */
+    public PasswordModifyRequest decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+        DECODER.decode( bb, container );
+        PasswordModifyRequestDecorator passwordModifyRequest = container.getPwdModifyRequest();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return passwordModifyRequest;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestDecorator.java
new file mode 100644
index 0000000..19bc201
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestDecorator.java
@@ -0,0 +1,259 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequest;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for PasswordModifyRequest extended request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyRequestDecorator extends ExtendedRequestDecorator<PasswordModifyRequest>
+    implements PasswordModifyRequest
+{
+    private static final Logger LOG = LoggerFactory.getLogger( PasswordModifyRequestDecorator.class );
+
+    /** The internal PasswordModifyRequest */
+    private PasswordModifyRequest passwordModifyRequest;
+
+    /** stores the length of the request*/
+    private int requestLength = 0;
+
+
+    /**
+     * Create a new decorator instance 
+     * @param codec The codec service
+     * @param decoratedMessage The decorated PwdModifyRequest
+     */
+    public PasswordModifyRequestDecorator( LdapApiService codec, PasswordModifyRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        passwordModifyRequest = decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setRequestValue( byte[] requestValue )
+    {
+        PasswordModifyRequestDecoder decoder = new PasswordModifyRequestDecoder();
+
+        try
+        {
+            if ( requestValue != null )
+            {
+                passwordModifyRequest = decoder.decode( requestValue );
+
+                this.requestValue = new byte[requestValue.length];
+                System.arraycopy( requestValue, 0, this.requestValue, 0, requestValue.length );
+            }
+            else
+            {
+                this.requestValue = null;
+            }
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165 ), e );
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getRequestValue()
+    {
+        if ( requestValue == null )
+        {
+            try
+            {
+                requestValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04167 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        return requestValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public PasswordModifyResponse getResultResponse()
+    {
+        return ( PasswordModifyResponse ) passwordModifyRequest.getResultResponse();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getUserIdentity()
+    {
+        return passwordModifyRequest.getUserIdentity();
+    }
+
+
+    /**
+     * @param userIdentity the userIdentity to set
+     */
+    public void setUserIdentity( byte[] userIdentity )
+    {
+        passwordModifyRequest.setUserIdentity( userIdentity );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getOldPassword()
+    {
+        return passwordModifyRequest.getOldPassword();
+    }
+
+
+    /**
+     * @param oldPassword the oldPassword to set
+     */
+    public void setOldPassword( byte[] oldPassword )
+    {
+        passwordModifyRequest.setOldPassword( oldPassword );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getNewPassword()
+    {
+        return passwordModifyRequest.getNewPassword();
+    }
+
+
+    /**
+     * @param newPassword the newPassword to set
+     */
+    public void setNewPassword( byte[] newPassword )
+    {
+        passwordModifyRequest.setNewPassword( newPassword );
+    }
+
+
+    /**
+     * Compute the PasswordModifyRequest extended operation length
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *  [+-- 0x80 L2 userIdentity] 
+     *  [+-- 0x81 L3 oldPassword] 
+     *  [+-- 0x82 L4 newPassword] 
+     * </pre>
+     */
+    /* No qualifier */int computeLengthInternal()
+    {
+        requestLength = 0;
+
+        if ( passwordModifyRequest.getUserIdentity() != null )
+        {
+            int len = passwordModifyRequest.getUserIdentity().length;
+            requestLength = 1 + TLV.getNbBytes( len ) + len;
+        }
+
+        if ( passwordModifyRequest.getOldPassword() != null )
+        {
+            int len = passwordModifyRequest.getOldPassword().length;
+            requestLength += 1 + TLV.getNbBytes( len ) + len;
+        }
+
+        if ( passwordModifyRequest.getNewPassword() != null )
+        {
+            int len = passwordModifyRequest.getNewPassword().length;
+            requestLength += 1 + TLV.getNbBytes( len ) + len;
+        }
+
+        return 1 + TLV.getNbBytes( requestLength ) + requestLength;
+    }
+
+
+    /**
+     * Encodes the PasswordModifyRequest extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* No qualifier */ByteBuffer encodeInternal() throws EncoderException
+    {
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        bb.put( UniversalTag.SEQUENCE.getValue() );
+        bb.put( TLV.getBytes( requestLength ) );
+
+        if ( passwordModifyRequest.getUserIdentity() != null )
+        {
+            byte[] userIdentity = passwordModifyRequest.getUserIdentity();
+            bb.put( ( byte ) PasswordModifyRequestConstants.USER_IDENTITY_TAG );
+            bb.put( TLV.getBytes( userIdentity.length ) );
+            bb.put( userIdentity );
+        }
+
+        if ( passwordModifyRequest.getOldPassword() != null )
+        {
+            byte[] oldPassword = passwordModifyRequest.getOldPassword();
+            bb.put( ( byte ) PasswordModifyRequestConstants.OLD_PASSWORD_TAG );
+            bb.put( TLV.getBytes( oldPassword.length ) );
+            bb.put( oldPassword );
+        }
+
+        if ( passwordModifyRequest.getNewPassword() != null )
+        {
+            byte[] newPassword = passwordModifyRequest.getNewPassword();
+            bb.put( ( byte ) PasswordModifyRequestConstants.NEW_PASSWORD_TAG );
+            bb.put( TLV.getBytes( newPassword.length ) );
+            bb.put( newPassword );
+        }
+
+        return bb;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestGrammar.java
new file mode 100644
index 0000000..b9179c2
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestGrammar.java
@@ -0,0 +1,357 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequestImpl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the PasswordModify extended operation's ASN.1 grammer. 
+ * All the actions are declared in this class. As it is a singleton, 
+ * these declaration are only done once. The grammar is :
+ * 
+ * <pre>
+ *  PasswdModifyRequestValue ::= SEQUENCE {
+ *    userIdentity    [0]  OCTET STRING OPTIONAL
+ *    oldPasswd       [1]  OCTET STRING OPTIONAL
+ *    newPasswd       [2]  OCTET STRING OPTIONAL }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+public class PasswordModifyRequestGrammar extends AbstractGrammar<PasswordModifyRequestContainer>
+{
+
+    /** logger */
+    private static final Logger LOG = LoggerFactory.getLogger( PasswordModifyRequestGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. PasswdModifyRequestGrammar is a singleton */
+    private static Grammar<PasswordModifyRequestContainer> instance = new PasswordModifyRequestGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    public PasswordModifyRequestGrammar()
+    {
+        setName( PasswordModifyRequestGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[PasswordModifyRequestStatesEnum.LAST_PASSWORD_MODIFY_REQUEST_STATE
+            .ordinal()][256];
+
+        /**
+         * Transition from init state to PasswordModify Request Value
+         * 
+         * PasswdModifyRequestValue ::= SEQUENCE {
+         *     ...
+         *     
+         * Creates the PasswdModifyRequest object
+         */
+        super.transitions[PasswordModifyRequestStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<PasswordModifyRequestContainer>(
+                PasswordModifyRequestStatesEnum.START_STATE,
+                PasswordModifyRequestStatesEnum.PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), new GrammarAction<PasswordModifyRequestContainer>(
+                    "Init PasswordModifyRequest" )
+                {
+                    public void action( PasswordModifyRequestContainer container )
+                    {
+                        PasswordModifyRequestDecorator passwordModifyRequestDecorator = new PasswordModifyRequestDecorator(
+                            LdapApiServiceFactory.getSingleton(), new PasswordModifyRequestImpl() );
+                        container.setPasswordModifyRequest( passwordModifyRequestDecorator );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from PasswordModify Request Value to userIdentity
+         *
+         * PasswdModifyRequestValue ::= SEQUENCE {
+         *     userIdentity    [0]  OCTET STRING OPTIONAL
+         *     ...
+         *     
+         * Set the userIdentity into the PasswdModifyRequest instance.
+         */
+        super.transitions[PasswordModifyRequestStatesEnum.PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE.ordinal()][PasswordModifyRequestConstants.USER_IDENTITY_TAG] =
+            new GrammarTransition<PasswordModifyRequestContainer>(
+                PasswordModifyRequestStatesEnum.PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE,
+                PasswordModifyRequestStatesEnum.USER_IDENTITY_STATE,
+                PasswordModifyRequestConstants.USER_IDENTITY_TAG,
+                new GrammarAction<PasswordModifyRequestContainer>( "Set PasswordModifyRequest user identity" )
+                {
+                    public void action( PasswordModifyRequestContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] userIdentity = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "UserIdentity = " + Strings.dumpBytes( userIdentity ) );
+                        }
+
+                        if ( userIdentity == null )
+                        {
+                            userIdentity = Strings.EMPTY_BYTES;
+                        }
+
+                        ( ( PasswordModifyRequestDecorator ) container.getPwdModifyRequest() )
+                            .setUserIdentity( userIdentity );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from userIdentity to oldPassword
+         *
+         * PasswdModifyRequestValue ::= SEQUENCE {
+         *     userIdentity    [0]  OCTET STRING OPTIONAL
+         *     oldPassword     [1]  OCTET STRING OPTIONAL
+         *     ...
+         *     
+         * Set the oldPassword into the PasswdModifyRequest instance.
+         */
+        super.transitions[PasswordModifyRequestStatesEnum.USER_IDENTITY_STATE.ordinal()][PasswordModifyRequestConstants.OLD_PASSWORD_TAG] =
+            new GrammarTransition<PasswordModifyRequestContainer>(
+                PasswordModifyRequestStatesEnum.USER_IDENTITY_STATE,
+                PasswordModifyRequestStatesEnum.OLD_PASSWORD_STATE,
+                PasswordModifyRequestConstants.OLD_PASSWORD_TAG,
+                new GrammarAction<PasswordModifyRequestContainer>( "Set PasswordModifyRequest oldPassword" )
+                {
+                    public void action( PasswordModifyRequestContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] oldPassword = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "oldPassword = " + Strings.dumpBytes( oldPassword ) );
+                        }
+
+                        if ( oldPassword == null )
+                        {
+                            oldPassword = Strings.EMPTY_BYTES;
+                        }
+
+                        ( ( PasswordModifyRequestDecorator ) container.getPwdModifyRequest() )
+                            .setOldPassword( oldPassword );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from userIdentity to newPassword
+         *
+         * PasswdModifyRequestValue ::= SEQUENCE {
+         *     userIdentity    [0]  OCTET STRING OPTIONAL
+         *     ...
+         *     newPassword     [2]  OCTET STRING OPTIONAL
+         * 
+         *     
+         * Set the newPassword into the PasswdModifyRequest instance.
+         */
+        super.transitions[PasswordModifyRequestStatesEnum.USER_IDENTITY_STATE.ordinal()][PasswordModifyRequestConstants.NEW_PASSWORD_TAG] =
+            new GrammarTransition<PasswordModifyRequestContainer>(
+                PasswordModifyRequestStatesEnum.USER_IDENTITY_STATE,
+                PasswordModifyRequestStatesEnum.NEW_PASSWORD_STATE,
+                PasswordModifyRequestConstants.NEW_PASSWORD_TAG,
+                new GrammarAction<PasswordModifyRequestContainer>( "Set PasswordModifyRequest newPassword" )
+                {
+                    public void action( PasswordModifyRequestContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] newPassword = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "newPassword = " + Strings.dumpBytes( newPassword ) );
+                        }
+
+                        if ( newPassword == null )
+                        {
+                            newPassword = Strings.EMPTY_BYTES;
+                        }
+
+                        ( ( PasswordModifyRequestDecorator ) container.getPwdModifyRequest() )
+                            .setNewPassword( newPassword );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from PasswordModify Request Value to oldPassword
+         *
+         * PasswdModifyRequestValue ::= SEQUENCE {
+         *     ...
+         *     oldPassword    [1]  OCTET STRING OPTIONAL
+         *     ...
+         *     
+         * Set the oldPassword into the PasswdModifyRequest instance.
+         */
+        super.transitions[PasswordModifyRequestStatesEnum.PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE.ordinal()][PasswordModifyRequestConstants.OLD_PASSWORD_TAG] =
+            new GrammarTransition<PasswordModifyRequestContainer>(
+                PasswordModifyRequestStatesEnum.PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE,
+                PasswordModifyRequestStatesEnum.OLD_PASSWORD_STATE,
+                PasswordModifyRequestConstants.OLD_PASSWORD_TAG,
+                new GrammarAction<PasswordModifyRequestContainer>( "Set PasswordModifyRequest oldPassword" )
+                {
+                    public void action( PasswordModifyRequestContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] oldPassword = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "OldPassword = " + Strings.dumpBytes( oldPassword ) );
+                        }
+
+                        if ( oldPassword == null )
+                        {
+                            oldPassword = Strings.EMPTY_BYTES;
+                        }
+
+                        ( ( PasswordModifyRequestDecorator ) container.getPwdModifyRequest() )
+                            .setOldPassword( oldPassword );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from PasswordModify Request Value to newPassword
+         *
+         * PasswdModifyRequestValue ::= SEQUENCE {
+         *     ...
+         *     newPassword    [2]  OCTET STRING OPTIONAL
+         * }
+         *     
+         * Set the newPassword into the PasswdModifyRequest instance.
+         */
+        super.transitions[PasswordModifyRequestStatesEnum.PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE.ordinal()][PasswordModifyRequestConstants.NEW_PASSWORD_TAG] =
+            new GrammarTransition<PasswordModifyRequestContainer>(
+                PasswordModifyRequestStatesEnum.PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE,
+                PasswordModifyRequestStatesEnum.NEW_PASSWORD_STATE,
+                PasswordModifyRequestConstants.NEW_PASSWORD_TAG,
+                new GrammarAction<PasswordModifyRequestContainer>( "Set PasswordModifyRequest newPassword" )
+                {
+                    public void action( PasswordModifyRequestContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] newPassword = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "NewPassword = " + Strings.dumpBytes( newPassword ) );
+                        }
+
+                        if ( newPassword == null )
+                        {
+                            newPassword = Strings.EMPTY_BYTES;
+                        }
+
+                        ( ( PasswordModifyRequestDecorator ) container.getPwdModifyRequest() )
+                            .setNewPassword( newPassword );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from oldPassword to newPassword
+         *
+         *     ...
+         *     oldPassword    [1]  OCTET STRING OPTIONAL
+         *     newPassword    [2]  OCTET STRING OPTIONAL
+         * }
+         *     
+         * Set the newPassword into the PasswdModifyRequest instance.
+         */
+        super.transitions[PasswordModifyRequestStatesEnum.OLD_PASSWORD_STATE.ordinal()][PasswordModifyRequestConstants.NEW_PASSWORD_TAG] =
+            new GrammarTransition<PasswordModifyRequestContainer>(
+                PasswordModifyRequestStatesEnum.OLD_PASSWORD_STATE,
+                PasswordModifyRequestStatesEnum.NEW_PASSWORD_STATE,
+                PasswordModifyRequestConstants.NEW_PASSWORD_TAG,
+                new GrammarAction<PasswordModifyRequestContainer>( "Set PasswordModifyRequest newPassword" )
+                {
+                    public void action( PasswordModifyRequestContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] newPassword = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "NewPassword = " + Strings.dumpBytes( newPassword ) );
+                        }
+
+                        if ( newPassword == null )
+                        {
+                            newPassword = Strings.EMPTY_BYTES;
+                        }
+
+                        ( ( PasswordModifyRequestDecorator ) container.getPwdModifyRequest() )
+                            .setNewPassword( newPassword );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<PasswordModifyRequestContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestStatesEnum.java
new file mode 100644
index 0000000..0f2c604
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestStatesEnum.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the PasswordModifyRequest's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum PasswordModifyRequestStatesEnum implements States
+{
+
+    /** The END_STATE */
+    END_STATE,
+
+    /** start state*/
+    START_STATE,
+
+    /** sequence*/
+    PASSWORD_MODIFY_REQUEST_SEQUENCE_STATE,
+
+    /** the UserIdentity */
+    USER_IDENTITY_STATE,
+
+    /** the old password */
+    OLD_PASSWORD_STATE,
+
+    /** the new password*/
+    NEW_PASSWORD_STATE,
+
+    /** Last state */
+    LAST_PASSWORD_MODIFY_REQUEST_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<PasswordModifyRequestContainer> grammar )
+    {
+        return "PASSWORD_MODIFY_REQUEST_GRAMMER";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "PASSWORD_MODIFY_REQUEST_GRAMMER";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "PASSWORD_MODIFY_REQUEST_GRAMMER" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordModifyRequestStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseConstants.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseConstants.java
new file mode 100644
index 0000000..86066eb
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseConstants.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+/**
+ * PasswordModifyResponse extended operation constants
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PasswordModifyResponseConstants
+{
+    /** This is the TAG used for the genPassword. It's a contextual primitive Tag */
+    public static final int GEN_PASSWORD_TAG = 0x80;
+
+
+    /**
+     * Private constructor.
+     */
+    private PasswordModifyResponseConstants()
+    {
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseContainer.java
new file mode 100644
index 0000000..fe5c4ee
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseContainer.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for PasswordModifyResponse codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyResponseContainer extends AbstractContainer
+{
+    /** PasswordModifyResponse decorator*/
+    private PasswordModifyResponseDecorator passwordModifyResponse;
+
+
+    /**
+     * Creates a new PasswordModifyResponseContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public PasswordModifyResponseContainer()
+    {
+        super();
+        setGrammar( PasswordModifyResponseGrammar.getInstance() );
+        setTransition( PasswordModifyResponseStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the PwdModifyResponset instance.
+     */
+    public PasswordModifyResponseDecorator getPwdModifyResponse()
+    {
+        return passwordModifyResponse;
+    }
+
+
+    /**
+     * Set a PasswordModifyResponse Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param passwordModifyResponseDecorator the PasswordModifyResponse to set.
+     */
+    public void setPasswordModifyResponse( PasswordModifyResponseDecorator passwordModifyResponseDecorator )
+    {
+        this.passwordModifyResponse = passwordModifyResponseDecorator;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    public void clean()
+    {
+        super.clean();
+        passwordModifyResponse = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseDecoder.java
new file mode 100644
index 0000000..3b0ea02
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseDecoder.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponse;
+
+
+/**
+ * 
+ * A decoder for PasswordModifyRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyResponseDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Decode a PDU which must contain a PwdModifyRequest extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return a PwdModifyRequest object
+     * @throws org.apache.directory.api.asn1.DecoderException If the decoding failed
+     */
+    public PasswordModifyResponse decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        PasswordModifyResponseContainer container = new PasswordModifyResponseContainer();
+        DECODER.decode( bb, container );
+        PasswordModifyResponseDecorator pwdModifyResponse = container.getPwdModifyResponse();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return pwdModifyResponse;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseDecorator.java
new file mode 100644
index 0000000..b68805b
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseDecorator.java
@@ -0,0 +1,188 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponse;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponseImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for PasswordModifyResponse extended request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordModifyResponseDecorator extends ExtendedResponseDecorator<PasswordModifyResponse>
+    implements PasswordModifyResponse
+{
+    private static final Logger LOG = LoggerFactory.getLogger( PasswordModifyResponseDecorator.class );
+
+    private PasswordModifyResponse passwordModifyResponse;
+
+    /** stores the length of the request*/
+    private int requestLength = 0;
+
+
+    public PasswordModifyResponseDecorator( LdapApiService codec, PasswordModifyResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        passwordModifyResponse = decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setResponseValue( byte[] responseValue )
+    {
+        PasswordModifyResponseDecoder decoder = new PasswordModifyResponseDecoder();
+
+        try
+        {
+            if ( responseValue != null )
+            {
+                passwordModifyResponse = decoder.decode( responseValue );
+
+                this.responseValue = new byte[responseValue.length];
+                System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length );
+            }
+            else
+            {
+                this.responseValue = null;
+            }
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165 ), e );
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getResponseValue()
+    {
+        if ( responseValue == null )
+        {
+            try
+            {
+                responseValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04167 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        return responseValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getGenPassword()
+    {
+        return getDecorated().getGenPassword();
+    }
+
+
+    /**
+     * @param genPassword the genPassword to set
+     */
+    public void setGenPassword( byte[] genPassword )
+    {
+        ( ( PasswordModifyResponseImpl ) getDecorated() ).setGenPassword( genPassword );
+    }
+
+
+    /**
+     * Overload the parent's getResponseName method, as the pwdModify response should not
+     * contain the responseName.
+     */
+    public String getResponseName()
+    {
+        return null;
+    }
+
+
+    /**
+     * Compute the PasswordModifyResponse extended operation length
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *  [+-- 0x80 L2 genPassword] 
+     * </pre>
+     */
+    /* no qualifier */int computeLengthInternal()
+    {
+        requestLength = 0;
+
+        if ( passwordModifyResponse.getGenPassword() != null )
+        {
+            int len = passwordModifyResponse.getGenPassword().length;
+            requestLength = 1 + TLV.getNbBytes( len ) + len;
+        }
+
+        return 1 + TLV.getNbBytes( requestLength ) + requestLength;
+    }
+
+
+    /**
+     * Encodes the PasswordModifyResponse extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* no qualifier */ByteBuffer encodeInternal() throws EncoderException
+    {
+        // Allocate the bytes buffer.
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        bb.put( UniversalTag.SEQUENCE.getValue() );
+        bb.put( TLV.getBytes( requestLength ) );
+
+        if ( passwordModifyResponse.getGenPassword() != null )
+        {
+            byte[] userIdentity = passwordModifyResponse.getGenPassword();
+            bb.put( ( byte ) PasswordModifyResponseConstants.GEN_PASSWORD_TAG );
+            bb.put( TLV.getBytes( userIdentity.length ) );
+            bb.put( userIdentity );
+        }
+
+        return bb;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseGrammar.java
new file mode 100644
index 0000000..3348d15
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseGrammar.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponseImpl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the PasswordModifyResponse extended operation's ASN.1 grammer. 
+ * All the actions are declared in this class. As it is a singleton, 
+ * these declaration are only done once. The grammar is :
+ * 
+ * <pre>
+ *  PasswdModifyResponseValue ::= SEQUENCE {
+ *      genPasswd       [0]     OCTET STRING OPTIONAL }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+public class PasswordModifyResponseGrammar extends AbstractGrammar<PasswordModifyResponseContainer>
+{
+
+    /** logger */
+    private static final Logger LOG = LoggerFactory.getLogger( PasswordModifyResponseGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. PasswdModifyResponseGrammar is a singleton */
+    private static Grammar<PasswordModifyResponseContainer> instance = new PasswordModifyResponseGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    public PasswordModifyResponseGrammar()
+    {
+        setName( PasswordModifyResponseGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[PasswordModifyResponseStatesEnum.LAST_PASSWORD_MODIFY_RESPONSE_STATE
+            .ordinal()][256];
+
+        /**
+         * Transition from init state to PasswordModify Response Value
+         * 
+         * PasswdModifyResponseValue ::= SEQUENCE {
+         *     ...
+         *     
+         * Creates the PasswdModifyResponse object
+         */
+        super.transitions[PasswordModifyResponseStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<PasswordModifyResponseContainer>(
+                PasswordModifyResponseStatesEnum.START_STATE,
+                PasswordModifyResponseStatesEnum.PASSWORD_MODIFY_RESPONSE_SEQUENCE_STATE,
+                UniversalTag.SEQUENCE.getValue(), new GrammarAction<PasswordModifyResponseContainer>(
+                    "Init PasswordModifyResponse" )
+                {
+                    public void action( PasswordModifyResponseContainer container )
+                    {
+                        PasswordModifyResponseDecorator passwordModifyResponse = new PasswordModifyResponseDecorator(
+                            LdapApiServiceFactory.getSingleton(), new PasswordModifyResponseImpl() );
+                        container.setPasswordModifyResponse( passwordModifyResponse );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        /**
+         * Transition from PasswordModify Response Value to genPassword
+         *
+         * PasswdModifyResponseValue ::= SEQUENCE {
+         *     genPassword    [0]  OCTET STRING OPTIONAL
+         *     ...
+         *     
+         * Set the userIdentity into the PasswdModifyResponset instance.
+         */
+        super.transitions[PasswordModifyResponseStatesEnum.PASSWORD_MODIFY_RESPONSE_SEQUENCE_STATE.ordinal()][PasswordModifyResponseConstants.GEN_PASSWORD_TAG] =
+            new GrammarTransition<PasswordModifyResponseContainer>(
+                PasswordModifyResponseStatesEnum.PASSWORD_MODIFY_RESPONSE_SEQUENCE_STATE,
+                PasswordModifyResponseStatesEnum.GEN_PASSWORD_STATE,
+                PasswordModifyResponseConstants.GEN_PASSWORD_TAG,
+                new GrammarAction<PasswordModifyResponseContainer>( "Set PasswordModifyResponse user identity" )
+                {
+                    public void action( PasswordModifyResponseContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        byte[] genPassword = value.getData();
+
+                        if ( IS_DEBUG )
+                        {
+                            LOG.debug( "GenPassword = " + Strings.dumpBytes( genPassword ) );
+                        }
+
+                        if ( genPassword == null )
+                        {
+                            genPassword = Strings.EMPTY_BYTES;
+                        }
+
+                        ( ( PasswordModifyResponseDecorator ) container.getPwdModifyResponse() )
+                            .setGenPassword( genPassword );
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<PasswordModifyResponseContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseStatesEnum.java
new file mode 100644
index 0000000..5d54884
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseStatesEnum.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the PasswordModifyResponse's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum PasswordModifyResponseStatesEnum implements States
+{
+
+    /** The END_STATE */
+    END_STATE,
+
+    /** start state*/
+    START_STATE,
+
+    /** sequence*/
+    PASSWORD_MODIFY_RESPONSE_SEQUENCE_STATE,
+
+    /** the generated password */
+    GEN_PASSWORD_STATE,
+
+    /** Last state */
+    LAST_PASSWORD_MODIFY_RESPONSE_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<PasswordModifyResponseContainer> grammar )
+    {
+        return "PASSWORD_MODIFY_RESPONSE_GRAMMER";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "PASSWORD_MODIFY_RESPONSE_GRAMMER";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "PASSWORD_MODIFY_RESPONSE_GRAMMER" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public PasswordModifyResponseStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsFactory.java
new file mode 100644
index 0000000..552b406
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsFactory.java
@@ -0,0 +1,131 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.startTls;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponse;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating SartTls extended reques/response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StartTlsFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    public StartTlsFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return StartTlsRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StartTlsResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        StartTlsResponseDecorator response = new StartTlsResponseDecorator( codec,
+            new StartTlsResponseImpl() );
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StartTlsRequest newRequest( byte[] value )
+    {
+        StartTlsRequestDecorator req = new StartTlsRequestDecorator( codec, new StartTlsRequestImpl() );
+
+        if ( value != null )
+        {
+            req.setRequestValue( value );
+        }
+
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StartTlsRequestDecorator decorate( ExtendedRequest modelRequest )
+    {
+        if ( modelRequest instanceof StartTlsRequestDecorator )
+        {
+            return ( StartTlsRequestDecorator ) modelRequest;
+        }
+
+        return new StartTlsRequestDecorator( codec, ( StartTlsRequest ) modelRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StartTlsResponseDecorator decorate( ExtendedResponse decoratedResponse )
+    {
+        if ( decoratedResponse instanceof StartTlsResponseDecorator )
+        {
+            return ( StartTlsResponseDecorator ) decoratedResponse;
+        }
+
+        if ( decoratedResponse instanceof StartTlsResponse )
+        {
+            return new StartTlsResponseDecorator( codec, ( StartTlsResponse ) decoratedResponse );
+        }
+
+        // It's an opaque extended operation
+        @SuppressWarnings("unchecked")
+        ExtendedResponseDecorator<ExtendedResponse> response = ( ExtendedResponseDecorator<ExtendedResponse> ) decoratedResponse;
+
+        // Decode the response, as it's an opaque operation
+        StartTlsResponse startTlsResponse = new StartTlsResponseImpl( response.getMessageId() );
+        
+        startTlsResponse.getLdapResult().setResultCode( response.getLdapResult().getResultCode() );
+        startTlsResponse.getLdapResult().setDiagnosticMessage( response.getLdapResult().getDiagnosticMessage() );
+        StartTlsResponseDecorator decorated = new StartTlsResponseDecorator( codec, new StartTlsResponseImpl() );
+
+        return decorated;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsRequestDecorator.java
new file mode 100644
index 0000000..6ee58d2
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsRequestDecorator.java
@@ -0,0 +1,59 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.startTls;
+
+
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequest;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponse;
+
+
+/**
+ * A Decorator for StartTlsRequest extended request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StartTlsRequestDecorator extends ExtendedRequestDecorator<StartTlsRequest> implements StartTlsRequest
+{
+    /** The internal StartTlsRequest */
+    private StartTlsRequest startTlsRequest;
+
+    /**
+     * Create a new decorator instance 
+     * @param codec The codec service
+     * @param decoratedMessage The decorated StartTlsRequest
+     */
+    public StartTlsRequestDecorator( LdapApiService codec, StartTlsRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        startTlsRequest = decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public StartTlsResponse getResultResponse()
+    {
+        return ( StartTlsResponse ) startTlsRequest.getResultResponse();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsResponseDecorator.java
new file mode 100644
index 0000000..cbfa80f
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/startTls/StartTlsResponseDecorator.java
@@ -0,0 +1,59 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.startTls;
+
+
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsResponse;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A Decorator for StartTlsResponse extended request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StartTlsResponseDecorator extends ExtendedResponseDecorator<StartTlsResponse> implements StartTlsResponse
+{
+    public StartTlsResponseDecorator( LdapApiService codec, StartTlsResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setResponseValue( byte[] responseValue )
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getResponseValue()
+    {
+        return Strings.EMPTY_BYTES;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureContainer.java
new file mode 100644
index 0000000..e533176
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureContainer.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for the StoredProcedure codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureContainer extends AbstractContainer
+{
+    // ~ Instance fields
+    // ----------------------------------------------------------------------------
+
+    /** StoredProcedure */
+    private StoredProcedureRequestDecorator storedProcedure;
+
+
+    // ~ Constructors
+    // -------------------------------------------------------------------------------
+
+    public StoredProcedureContainer()
+    {
+        super();
+        setGrammar( StoredProcedureGrammar.getInstance() );
+        setTransition( StoredProcedureStatesEnum.START_STATE );
+    }
+
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+    /**
+     * @return Returns the ldapMessage.
+     */
+    public StoredProcedureRequestDecorator getStoredProcedure()
+    {
+        return storedProcedure;
+    }
+
+
+    /**
+     * Set a StoredProcedure object into the container. It will be completed by the
+     * ldapDecoder.
+     * 
+     * @param ldapMessage
+     *            The ldapMessage to set.
+     */
+    public void setStoredProcedure( StoredProcedureRequestDecorator storedProcedure )
+    {
+        this.storedProcedure = storedProcedure;
+    }
+
+
+    public void clean()
+    {
+        super.clean();
+        storedProcedure = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureDecoder.java
new file mode 100644
index 0000000..1d02d7d
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureDecoder.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+
+
+/**
+ * StoredProcedure Decoder
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureDecoder extends Asn1Decoder
+{
+
+    public StoredProcedureDecoder()
+    {
+    }
+
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureFactory.java
new file mode 100644
index 0000000..f860303
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureFactory.java
@@ -0,0 +1,117 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequest;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureResponse;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    /**
+     * Creates a new instance of StoredProcedureFactory.
+     *
+     * @param codec
+     */
+    public StoredProcedureFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return StoredProcedureRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        StoredProcedureResponseDecorator response = new StoredProcedureResponseDecorator( codec,
+            new StoredProcedureResponseImpl() );
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureRequest newRequest( byte[] value )
+    {
+        StoredProcedureRequestDecorator req = new StoredProcedureRequestDecorator( codec );
+
+        if ( value != null )
+        {
+            req.setRequestValue( value );
+        }
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureRequestDecorator decorate( ExtendedRequest modelRequest )
+    {
+        if ( modelRequest instanceof StoredProcedureRequestDecorator )
+        {
+            return ( StoredProcedureRequestDecorator ) modelRequest;
+        }
+
+        return new StoredProcedureRequestDecorator( codec, ( StoredProcedureRequest ) modelRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureResponseDecorator decorate( ExtendedResponse decoratedMessage )
+    {
+        if ( decoratedMessage instanceof StoredProcedureResponseDecorator )
+        {
+            return ( StoredProcedureResponseDecorator ) decoratedMessage;
+        }
+
+        return new StoredProcedureResponseDecorator( codec, ( StoredProcedureResponse ) decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureGrammar.java
new file mode 100644
index 0000000..0298a6c
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureGrammar.java
@@ -0,0 +1,310 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureParameter;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * ASN.1 BER Grammar for Stored Procedure Extended Operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class StoredProcedureGrammar extends AbstractGrammar<StoredProcedureContainer>
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** The logger */
+    //private static final Logger log = LoggerFactory.getLogger( StoredProcedureGrammar.class );
+    static final Logger LOG = LoggerFactory.getLogger( StoredProcedureGrammar.class );
+
+    /** The instance of grammar. StoredProcedureGrammar is a singleton. */
+    private static StoredProcedureGrammar instance = new StoredProcedureGrammar();
+
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Creates a new StoredProcedureGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    private StoredProcedureGrammar()
+    {
+        setName( StoredProcedureGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[StoredProcedureStatesEnum.LAST_STORED_PROCEDURE_STATE.ordinal()][256];
+
+        //============================================================================================
+        // StoredProcedure Message
+        //============================================================================================
+        // StoredProcedure ::= SEQUENCE {
+        //   ...
+        // Nothing to do.
+        super.transitions[StoredProcedureStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.START_STATE,
+                StoredProcedureStatesEnum.STORED_PROCEDURE_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                null );
+
+        //    language OCTETSTRING, (Tag)
+        //    ...
+        //
+        // Creates the storeProcedure and stores the language
+        super.transitions[StoredProcedureStatesEnum.STORED_PROCEDURE_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.STORED_PROCEDURE_STATE,
+                StoredProcedureStatesEnum.LANGUAGE_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<StoredProcedureContainer>( "Stores the language" )
+                {
+                    public void action( StoredProcedureContainer container ) throws DecoderException
+                    {
+                        TLV tlv = container.getCurrentTLV();
+
+                        StoredProcedureRequestDecorator storedProcedure = container.getStoredProcedure();
+                        if ( storedProcedure == null )
+                        {
+                            storedProcedure = new StoredProcedureRequestDecorator( LdapApiServiceFactory.getSingleton() );
+                            container.setStoredProcedure( storedProcedure );
+                        }
+
+                        // Store the value.
+                        if ( tlv.getLength() == 0 )
+                        {
+                            // We can't have a void language !
+                            String msg = I18n.err( I18n.ERR_04038 );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                        else
+                        {
+                            // Only this field's type is String by default
+                            String language = Strings.utf8ToString( tlv.getValue().getData() );
+
+                            if ( LOG.isDebugEnabled() )
+                            {
+                                LOG.debug( "SP language found: " + language );
+                            }
+
+                            storedProcedure.setLanguage( language );
+                        }
+                    }
+                } );
+
+        //    procedure OCTETSTRING, (Value)
+        //    ...
+        // Stores the procedure.
+        super.transitions[StoredProcedureStatesEnum.LANGUAGE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.LANGUAGE_STATE,
+                StoredProcedureStatesEnum.PROCEDURE_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<StoredProcedureContainer>( "Stores the procedure" )
+                {
+                    public void action( StoredProcedureContainer container ) throws DecoderException
+                    {
+                        TLV tlv = container.getCurrentTLV();
+
+                        StoredProcedureRequestDecorator storedProcedure = container.getStoredProcedure();
+
+                        // Store the value.
+                        if ( tlv.getLength() == 0 )
+                        {
+                            // We can't have a void procedure !
+                            String msg = I18n.err( I18n.ERR_04039 );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                        else
+                        {
+                            byte[] procedure = tlv.getValue().getData();
+
+                            storedProcedure.setProcedure( procedure );
+                        }
+
+                        if ( LOG.isDebugEnabled() )
+                        {
+                            LOG.debug( "Procedure found : " + storedProcedure.getProcedureSpecification() );
+                        }
+                    }
+                } );
+
+        // parameters SEQUENCE OF Parameter { (Value)
+        //    ...
+        // The list of parameters will be created with the first parameter.
+        // We can have an empty list of parameters, so the PDU can be empty
+        super.transitions[StoredProcedureStatesEnum.PROCEDURE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PROCEDURE_STATE,
+                StoredProcedureStatesEnum.PARAMETERS_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                new GrammarAction<StoredProcedureContainer>( "Stores the parameters" )
+                {
+                    public void action( StoredProcedureContainer container ) throws DecoderException
+                    {
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        // parameter SEQUENCE OF { (Value)
+        //    ...
+        // Nothing to do. 
+        super.transitions[StoredProcedureStatesEnum.PARAMETERS_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETERS_STATE,
+                StoredProcedureStatesEnum.PARAMETER_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                null );
+
+        // Parameter ::= {
+        //    type OCTETSTRING, (Value)
+        //    ...
+        //
+        // We can create a parameter, and store its type
+        super.transitions[StoredProcedureStatesEnum.PARAMETER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETER_STATE,
+                StoredProcedureStatesEnum.PARAMETER_TYPE_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<StoredProcedureContainer>( "Store parameter type" )
+                {
+                    public void action( StoredProcedureContainer container ) throws DecoderException
+                    {
+                        TLV tlv = container.getCurrentTLV();
+                        StoredProcedureRequestDecorator storedProcedure = container.getStoredProcedure();
+
+                        // Store the value.
+                        if ( tlv.getLength() == 0 )
+                        {
+                            // We can't have a void parameter type !
+                            String msg = I18n.err( I18n.ERR_04040 );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                        else
+                        {
+                            StoredProcedureParameter parameter = new StoredProcedureParameter();
+
+                            byte[] parameterType = tlv.getValue().getData();
+
+                            parameter.setType( parameterType );
+
+                            // We store the type in the current parameter.
+                            storedProcedure.setCurrentParameter( parameter );
+
+                            if ( LOG.isDebugEnabled() )
+                            {
+                                LOG.debug( "Parameter type found : " + Strings.dumpBytes( parameterType ) );
+                            }
+
+                        }
+                    }
+                } );
+
+        // Parameter ::= {
+        //    ...
+        //    value OCTETSTRING (Tag)
+        // }
+        // Store the parameter value
+        super.transitions[StoredProcedureStatesEnum.PARAMETER_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING
+            .getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETER_TYPE_STATE,
+                StoredProcedureStatesEnum.PARAMETER_VALUE_STATE,
+                UniversalTag.OCTET_STRING.getValue(),
+                new GrammarAction<StoredProcedureContainer>( "Store parameter value" )
+                {
+                    public void action( StoredProcedureContainer container ) throws DecoderException
+                    {
+                        StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
+
+                        TLV tlv = storedProcedureContainer.getCurrentTLV();
+                        StoredProcedureRequestDecorator storedProcedure = storedProcedureContainer.getStoredProcedure();
+
+                        // Store the value.
+                        if ( tlv.getLength() == 0 )
+                        {
+                            // We can't have a void parameter value !
+                            String msg = I18n.err( I18n.ERR_04041 );
+                            LOG.error( msg );
+                            throw new DecoderException( msg );
+                        }
+                        else
+                        {
+                            byte[] parameterValue = tlv.getValue().getData();
+
+                            if ( parameterValue.length != 0 )
+                            {
+                                StoredProcedureParameter parameter = storedProcedure.getCurrentParameter();
+                                parameter.setValue( parameterValue );
+
+                                // We can now add a new Parameter to the procedure
+                                storedProcedure.addParameter( parameter );
+
+                                if ( LOG.isDebugEnabled() )
+                                {
+                                    LOG.debug( "Parameter value found : " + Strings.dumpBytes( parameterValue ) );
+                                }
+                            }
+                            else
+                            {
+                                String msg = I18n.err( I18n.ERR_04042 );
+                                LOG.error( msg );
+                                throw new DecoderException( msg );
+                            }
+                        }
+
+                        // The only possible END state for the grammar is here
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        // Parameters ::= SEQUENCE OF Parameter
+        // 
+        // Loop on next parameter
+        super.transitions[StoredProcedureStatesEnum.PARAMETER_VALUE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETER_VALUE_STATE,
+                StoredProcedureStatesEnum.PARAMETER_STATE,
+                UniversalTag.SEQUENCE.getValue(),
+                null );
+    }
+
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Get the instance of this grammar
+     *
+     * @return An instance on the StoredProcedure Grammar
+     */
+    public static StoredProcedureGrammar getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureRequestDecorator.java
new file mode 100644
index 0000000..6cccad2
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureRequestDecorator.java
@@ -0,0 +1,427 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureParameter;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequest;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequestImpl;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for stored procedure extended operation requests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureRequestDecorator extends ExtendedRequestDecorator<StoredProcedureRequest>
+    implements StoredProcedureRequest
+{
+    private static final Logger LOG = LoggerFactory.getLogger( StoredProcedureRequestDecorator.class );
+
+    private StoredProcedureParameter currentParameter;
+
+    /** The stored procedure length */
+    private int storedProcedureLength;
+
+    /** The parameters length */
+    private int parametersLength;
+
+    /** The list of all parameter lengths */
+    private List<Integer> parameterLength;
+
+    /** The list of all parameter type lengths */
+    private List<Integer> paramTypeLength;
+
+    /** The list of all parameter value lengths */
+    private List<Integer> paramValueLength;
+
+
+    public StoredProcedureRequestDecorator( LdapApiService codec )
+    {
+        super( codec, new StoredProcedureRequestImpl() );
+    }
+
+
+    public StoredProcedureRequestDecorator( LdapApiService codec, StoredProcedureRequest decoratedRequest )
+    {
+        super( codec, decoratedRequest );
+        if ( decoratedRequest == null )
+        {
+            throw new NullPointerException( "decorated stored procedulre request is null" );
+        }
+    }
+
+
+    public StoredProcedureParameter getCurrentParameter()
+    {
+        return currentParameter;
+    }
+
+
+    public void setCurrentParameter( StoredProcedureParameter currentParameter )
+    {
+        this.currentParameter = currentParameter;
+    }
+
+
+    /**
+     * Compute the StoredProcedure length 
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *   +--> 0x04 L2 language
+     *   +--> 0x04 L3 procedure
+     *  [+--> 0x30 L4 (parameters)
+     *          |
+     *          +--> 0x30 L5-1 (parameter)
+     *          |      |
+     *          |      +--> 0x04 L6-1 type
+     *          |      +--> 0x04 L7-1 value
+     *          |      
+     *          +--> 0x30 L5-2 (parameter)
+     *          |      |
+     *          |      +--> 0x04 L6-2 type
+     *          |      +--> 0x04 L7-2 value
+     *          |
+     *          +--> ...
+     *          |      
+     *          +--> 0x30 L5-m (parameter)
+     *                 |
+     *                 +--> 0x04 L6-m type
+     *                 +--> 0x04 L7-m value
+     * </pre>
+     */
+    /* no qualifier */ int computeLengthInternal()
+    {
+        // The language
+        byte[] languageBytes = Strings.getBytesUtf8( getDecorated().getLanguage() );
+
+        int languageLength = 1 + TLV.getNbBytes( languageBytes.length )
+            + languageBytes.length;
+
+        byte[] procedure = getDecorated().getProcedure();
+
+        // The procedure
+        int procedureLength = 1 + TLV.getNbBytes( procedure.length )
+            + procedure.length;
+
+        // Compute parameters length value
+        if ( getDecorated().getParameters() != null )
+        {
+            parameterLength = new LinkedList<Integer>();
+            paramTypeLength = new LinkedList<Integer>();
+            paramValueLength = new LinkedList<Integer>();
+
+            for ( StoredProcedureParameter spParam : getDecorated().getParameters() )
+            {
+                int localParameterLength = 0;
+                int localParamTypeLength = 0;
+                int localParamValueLength = 0;
+
+                localParamTypeLength = 1 + TLV.getNbBytes( spParam.getType().length ) + spParam.getType().length;
+                localParamValueLength = 1 + TLV.getNbBytes( spParam.getValue().length ) + spParam.getValue().length;
+
+                localParameterLength = localParamTypeLength + localParamValueLength;
+
+                parametersLength += 1 + TLV.getNbBytes( localParameterLength ) + localParameterLength;
+
+                parameterLength.add( localParameterLength );
+                paramTypeLength.add( localParamTypeLength );
+                paramValueLength.add( localParamValueLength );
+            }
+        }
+
+        int localParametersLength = 1 + TLV.getNbBytes( parametersLength ) + parametersLength;
+        storedProcedureLength = languageLength + procedureLength + localParametersLength;
+
+        return 1 + TLV.getNbBytes( storedProcedureLength ) + storedProcedureLength;
+    }
+
+
+    /**
+     * Encodes the StoredProcedure extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* no qualifier */ ByteBuffer encodeInternal() throws EncoderException
+    {
+        // Allocate the bytes buffer.
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        try
+        {
+            // The StoredProcedure Tag
+            bb.put( UniversalTag.SEQUENCE.getValue() );
+            bb.put( TLV.getBytes( storedProcedureLength ) );
+
+            // The language
+            BerValue.encode( bb, getDecorated().getLanguage() );
+
+            // The procedure
+            BerValue.encode( bb, getDecorated().getProcedure() );
+
+            // The parameters sequence
+            bb.put( UniversalTag.SEQUENCE.getValue() );
+            bb.put( TLV.getBytes( parametersLength ) );
+
+            // The parameters list
+            if ( ( getDecorated().getParameters() != null ) && ( getDecorated().getParameters().size() != 0 ) )
+            {
+                int parameterNumber = 0;
+
+                for ( StoredProcedureParameter spParam : getDecorated().getParameters() )
+                {
+                    // The parameter sequence
+                    bb.put( UniversalTag.SEQUENCE.getValue() );
+                    int localParameterLength = parameterLength.get( parameterNumber );
+                    bb.put( TLV.getBytes( localParameterLength ) );
+
+                    // The parameter type
+                    BerValue.encode( bb, spParam.getType() );
+
+                    // The parameter value
+                    BerValue.encode( bb, spParam.getValue() );
+
+                    // Go to the next parameter;
+                    parameterNumber++;
+                }
+            }
+        }
+        catch ( BufferOverflowException boe )
+        {
+            throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe );
+        }
+
+        return bb;
+    }
+
+
+    /**
+     * Returns the StoredProcedure string
+     * 
+     * @return The StoredProcedure string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    StoredProcedure\n" );
+        sb.append( "        Language : '" ).append( getDecorated().getLanguage() ).append( "'\n" );
+        sb.append( "        Procedure\n" ).append( getDecorated().getProcedureSpecification() ).append( "'\n" );
+
+        if ( ( getDecorated().getParameters() == null ) || ( getDecorated().getParameters().size() == 0 ) )
+        {
+            sb.append( "        No parameters\n" );
+        }
+        else
+        {
+            sb.append( "        Parameters\n" );
+
+            int i = 1;
+
+            for ( StoredProcedureParameter spParam : getDecorated().getParameters() )
+            {
+                sb.append( "            type[" ).append( i ).append( "] : '" ).
+                    append( Strings.utf8ToString( spParam.getType() ) ).append( "'\n" );
+                sb.append( "            value[" ).append( i ).append( "] : '" ).
+                    append( Strings.dumpBytes( spParam.getValue() ) ).append( "'\n" );
+            }
+        }
+
+        return sb.toString();
+    }
+
+
+    public void setProcedure( byte[] procedure )
+    {
+        getDecorated().setProcedure( procedure );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRequestValue( byte[] payload )
+    {
+        StoredProcedureDecoder decoder = new StoredProcedureDecoder();
+        StoredProcedureContainer container = new StoredProcedureContainer();
+
+        container.setStoredProcedure( this );
+
+        try
+        {
+            decoder.decode( ByteBuffer.wrap( payload ), container );
+        }
+        catch ( Exception e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165 ), e );
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getRequestValue()
+    {
+        if ( requestValue == null )
+        {
+            try
+            {
+                requestValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04174 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        return requestValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getLanguage()
+    {
+        return getDecorated().getLanguage();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLanguage( String language )
+    {
+        getDecorated().setLanguage( language );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getProcedureSpecification()
+    {
+        return getDecorated().getProcedureSpecification();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return getDecorated().size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getParameterType( int index )
+    {
+        return getDecorated().getParameterType( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    public Class<?> getJavaParameterType( int index )
+    {
+        return getDecorated().getJavaParameterType( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+
+    public Object getParameterValue( int index )
+    {
+        return getDecorated().getParameterValue( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getJavaParameterValue( int index )
+    {
+        return getDecorated().getJavaParameterValue( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addParameter( Object type, Object value )
+    {
+        getDecorated().addParameter( type, value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getProcedure()
+    {
+        return getDecorated().getProcedure();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<StoredProcedureParameter> getParameters()
+    {
+        return getDecorated().getParameters();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addParameter( StoredProcedureParameter parameter )
+    {
+        getDecorated().addParameter( parameter );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureResponseDecorator.java
new file mode 100644
index 0000000..d9f8ec9
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureResponseDecorator.java
@@ -0,0 +1,46 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureResponse;
+
+
+/**
+ * A Decorator for CancelResponses.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureResponseDecorator extends ExtendedResponseDecorator<StoredProcedureResponse> implements
+    StoredProcedureResponse
+{
+    /**
+     * Creates a new instance of CancelResponseDecorator.
+     *
+     * @param codec
+     * @param decoratedMessage
+     */
+    public StoredProcedureResponseDecorator( LdapApiService codec, StoredProcedureResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureStatesEnum.java
new file mode 100644
index 0000000..ab6f1e5
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureStatesEnum.java
@@ -0,0 +1,126 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * Constants for StoredProcedureGrammar.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum StoredProcedureStatesEnum implements States
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** The END_STATE */
+    END_STATE,
+
+    //=========================================================================
+    // StoredProcedure
+    //=========================================================================
+    /** starting state */
+    START_STATE,
+
+    /** StoredProcedure */
+    STORED_PROCEDURE_STATE,
+
+    // Language ---------------------------------------------------------------
+    /** Language */
+    LANGUAGE_STATE,
+
+    // Procedure --------------------------------------------------------------
+    /** Procedure */
+    PROCEDURE_STATE,
+
+    // Parameters -------------------------------------------------------------
+    /** Parameters */
+    PARAMETERS_STATE,
+
+    // Parameter --------------------------------------------------------------
+    /** Parameter */
+    PARAMETER_STATE,
+
+    // Parameter type ---------------------------------------------------------
+    /** Parameter type */
+    PARAMETER_TYPE_STATE,
+
+    // Parameters value -------------------------------------------------------
+    /** Parameter value */
+    PARAMETER_VALUE_STATE,
+
+    /** Last Stored Procedure */
+    LAST_STORED_PROCEDURE_STATE;
+
+    /**
+     * Get the grammar name
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "STORED_PROCEDURE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the grammar name
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<StoredProcedureContainer> grammar )
+    {
+        return "STORED_PROCEDURE_GRAMMAR";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "STORED_PROCEDURE_END_STATE" : name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIFactory.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIFactory.java
new file mode 100644
index 0000000..fdb26f7
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIFactory.java
@@ -0,0 +1,166 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIRequest;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIRequestImpl;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponse;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponseImpl;
+import org.apache.directory.api.ldap.model.message.ExtendedRequest;
+import org.apache.directory.api.ldap.model.message.ExtendedResponse;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An {@link ExtendedOperationFactory} for creating WhoAmI extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WhoAmIFactory implements ExtendedOperationFactory
+{
+    private LdapApiService codec;
+
+
+    public WhoAmIFactory( LdapApiService codec )
+    {
+        this.codec = codec;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return WhoAmIRequest.EXTENSION_OID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public WhoAmIResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        WhoAmIResponseDecorator response = new WhoAmIResponseDecorator( codec,
+            new WhoAmIResponseImpl() );
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public WhoAmIRequest newRequest( byte[] value )
+    {
+        WhoAmIRequestDecorator req = new WhoAmIRequestDecorator( codec, new WhoAmIRequestImpl() );
+
+        if ( value != null )
+        {
+            req.setRequestValue( value );
+        }
+
+        return req;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public WhoAmIRequestDecorator decorate( ExtendedRequest modelRequest )
+    {
+        if ( modelRequest instanceof WhoAmIRequestDecorator )
+        {
+            return ( WhoAmIRequestDecorator ) modelRequest;
+        }
+
+        return new WhoAmIRequestDecorator( codec, ( WhoAmIRequest ) modelRequest );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public WhoAmIResponseDecorator decorate( ExtendedResponse decoratedResponse )
+    {
+        if ( decoratedResponse instanceof WhoAmIResponseDecorator )
+        {
+            return ( WhoAmIResponseDecorator ) decoratedResponse;
+        }
+
+        if ( decoratedResponse instanceof WhoAmIResponse )
+        {
+            return new WhoAmIResponseDecorator( codec, ( WhoAmIResponse ) decoratedResponse );
+        }
+
+        // It's an opaque extended operation
+        @SuppressWarnings("unchecked")
+        ExtendedResponseDecorator<ExtendedResponse> response = ( ExtendedResponseDecorator<ExtendedResponse> ) decoratedResponse;
+
+        // Decode the response, as it's an opaque operation
+        Asn1Decoder decoder = new Asn1Decoder();
+
+        byte[] value = response.getResponseValue();
+        ByteBuffer buffer = ByteBuffer.wrap( value );
+
+        WhoAmIResponseContainer container = new WhoAmIResponseContainer();
+        WhoAmIResponse whoAmIResponse = null;
+
+        try
+        {
+            decoder.decode( buffer, container );
+
+            whoAmIResponse = container.getWhoAmIResponse();
+
+            // Now, update the created response with what we got from the extendedResponse
+            whoAmIResponse.getLdapResult().setResultCode( response.getLdapResult().getResultCode() );
+            whoAmIResponse.getLdapResult().setDiagnosticMessage( response.getLdapResult().getDiagnosticMessage() );
+            whoAmIResponse.getLdapResult().setMatchedDn( response.getLdapResult().getMatchedDn() );
+            whoAmIResponse.getLdapResult().setReferral( response.getLdapResult().getReferral() );
+        }
+        catch ( DecoderException de )
+        {
+            StringWriter sw = new StringWriter();
+            de.printStackTrace( new PrintWriter( sw ) );
+            String stackTrace = sw.toString();
+
+            // Error while decoding the value. 
+            whoAmIResponse = new WhoAmIResponseImpl(
+                decoratedResponse.getMessageId(),
+                ResultCodeEnum.OPERATIONS_ERROR,
+                stackTrace );
+        }
+
+        WhoAmIResponseDecorator decorated = new WhoAmIResponseDecorator( codec, whoAmIResponse );
+
+        return decorated;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIRequestDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIRequestDecorator.java
new file mode 100644
index 0000000..2c1f65f
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIRequestDecorator.java
@@ -0,0 +1,59 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIRequest;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponse;
+
+
+/**
+ * A Decorator for WhoAmIRequest extended request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WhoAmIRequestDecorator extends ExtendedRequestDecorator<WhoAmIRequest> implements WhoAmIRequest
+{
+    /** The internal WhoAmIRequest */
+    private WhoAmIRequest whoAmIRequest;
+
+    /**
+     * Create a new decorator instance 
+     * @param codec The codec service
+     * @param decoratedMessage The decorated WhoAmIRequest
+     */
+    public WhoAmIRequestDecorator( LdapApiService codec, WhoAmIRequest decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        whoAmIRequest = decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public WhoAmIResponse getResultResponse()
+    {
+        return ( WhoAmIResponse ) whoAmIRequest.getResultResponse();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseContainer.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseContainer.java
new file mode 100644
index 0000000..6f9c6cd
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseContainer.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+
+
+/**
+ * A container for WhoAmIResponse codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WhoAmIResponseContainer extends AbstractContainer
+{
+    /** WhoAmIResponse decorator*/
+    private WhoAmIResponseDecorator whoAmIResponse;
+
+
+    /**
+     * Creates a new WhoAmIResponseContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public WhoAmIResponseContainer()
+    {
+        super();
+        setGrammar( WhoAmIResponseGrammar.getInstance() );
+        setTransition( WhoAmIResponseStatesEnum.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the WhoAmIResponse instance.
+     */
+    public WhoAmIResponseDecorator getWhoAmIResponse()
+    {
+        return whoAmIResponse;
+    }
+
+
+    /**
+     * Set a WhoAmIResponse Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param whoAmIResponseDecorator the WhoAmIResponse to set.
+     */
+    public void setWhoAmIResponse( WhoAmIResponseDecorator whoAmIResponseDecorator )
+    {
+        this.whoAmIResponse = whoAmIResponseDecorator;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    public void clean()
+    {
+        super.clean();
+        whoAmIResponse = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseDecoder.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseDecoder.java
new file mode 100644
index 0000000..6418c87
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseDecoder.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponse;
+
+
+/**
+ * 
+ * A decoder for WhoAmIRequest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WhoAmIResponseDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+
+    /**
+     * Decode a PDU which must contain a WhoAmIRequest extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return a WhoAmIRequest object
+     * @throws org.apache.directory.api.asn1.DecoderException If the decoding failed
+     */
+    public WhoAmIResponse decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        WhoAmIResponseContainer container = new WhoAmIResponseContainer();
+        DECODER.decode( bb, container );
+        WhoAmIResponseDecorator whoAmIResponse = container.getWhoAmIResponse();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return whoAmIResponse;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseDecorator.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseDecorator.java
new file mode 100644
index 0000000..c179f57
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseDecorator.java
@@ -0,0 +1,233 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponse;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponseImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Decorator for WhoAmIResponse extended request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WhoAmIResponseDecorator extends ExtendedResponseDecorator<WhoAmIResponse>
+    implements WhoAmIResponse
+{
+    private static final Logger LOG = LoggerFactory.getLogger( WhoAmIResponseDecorator.class );
+
+    private WhoAmIResponse whoAmIResponse;
+
+
+    public WhoAmIResponseDecorator( LdapApiService codec, WhoAmIResponse decoratedMessage )
+    {
+        super( codec, decoratedMessage );
+        whoAmIResponse = decoratedMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setResponseValue( byte[] responseValue )
+    {
+        WhoAmIResponseDecoder decoder = new WhoAmIResponseDecoder();
+
+        try
+        {
+            if ( responseValue != null )
+            {
+                whoAmIResponse = decoder.decode( responseValue );
+
+                this.responseValue = new byte[responseValue.length];
+                System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length );
+            }
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165 ), e );
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public byte[] getResponseValue()
+    {
+        if ( responseValue == null )
+        {
+            try
+            {
+                responseValue = encodeInternal().array();
+            }
+            catch ( EncoderException e )
+            {
+                LOG.error( I18n.err( I18n.ERR_04167 ), e );
+                throw new RuntimeException( e );
+            }
+        }
+
+        return responseValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getAuthzId()
+    {
+        return getDecorated().getAuthzId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAuthzId( byte[] authzId )
+    {
+        ( ( WhoAmIResponseImpl ) getDecorated() ).setAuthzId( authzId );
+    }
+
+
+    /**
+     * Set the userId
+     */
+    /* no qualifier*/void setUserId( String userId )
+    {
+        ( ( WhoAmIResponseImpl ) whoAmIResponse ).setUserId( userId );
+    }
+
+
+    /**
+     * Set the DnId
+     */
+    /* no qualifier*/void setDn( Dn dn )
+    {
+        ( ( WhoAmIResponseImpl ) whoAmIResponse ).setDn( dn );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDnAuthzId()
+    {
+        return whoAmIResponse.isDnAuthzId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isUserAuthzId()
+    {
+        return whoAmIResponse.isUserAuthzId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getAuthzIdString()
+    {
+        return whoAmIResponse.getAuthzIdString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getUserId()
+    {
+        return whoAmIResponse.getUserId();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getDn()
+    {
+        return whoAmIResponse.getDn();
+    }
+
+
+    /**
+     * Overload the parent's getResponseName method, as the WhoAmI response should not
+     * contain the responseName.
+     */
+    public String getResponseName()
+    {
+        return null;
+    }
+
+
+    /**
+     * Compute the WhoAmIResponse extended operation length
+     * <pre>
+     * 0x04 L1 authzId
+     * </pre>
+     */
+    /* no qualifier */int computeLengthInternal()
+    {
+        if ( whoAmIResponse.getAuthzId() != null )
+        {
+            return 1 + TLV.getNbBytes( whoAmIResponse.getAuthzId().length )
+                + whoAmIResponse.getAuthzId().length;
+        }
+        else
+        {
+            return 1 + 1;
+        }
+    }
+
+
+    /**
+     * Encodes the WhoAmIResponse extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* no qualifier */ByteBuffer encodeInternal() throws EncoderException
+    {
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        BerValue.encode( bb, whoAmIResponse.getAuthzId() );
+
+        return bb;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseGrammar.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseGrammar.java
new file mode 100644
index 0000000..ed171c1
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseGrammar.java
@@ -0,0 +1,201 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.whoAmI.WhoAmIResponseImpl;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the WhoAmIResponse extended operation's ASN.1 grammer. 
+ * All the actions are declared in this class. As it is a singleton, 
+ * these declaration are only done once. The grammar is :
+ * 
+ * <pre>
+ *  WhoAmIResponseValue ::= OCTET STRING OPTIONAL }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+public class WhoAmIResponseGrammar extends AbstractGrammar<WhoAmIResponseContainer>
+{
+    /** logger */
+    private static final Logger LOG = LoggerFactory.getLogger( WhoAmIResponseGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. WhoAmIResponseGrammar is a singleton */
+    private static Grammar<WhoAmIResponseContainer> instance = new WhoAmIResponseGrammar();
+
+
+    @SuppressWarnings("unchecked")
+    public WhoAmIResponseGrammar()
+    {
+        setName( WhoAmIResponseGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[WhoAmIResponseStatesEnum.LAST_WHO_AM_I_RESPONSE_STATE
+            .ordinal()][256];
+
+        /**
+         * Transition from init state to WhoAmI Authzid Response Value
+         * 
+         * authzId ::= OCTET STRING OPTIONAL
+         *     
+         * Creates the authzid object
+         */
+        super.transitions[WhoAmIResponseStatesEnum.START_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+            new GrammarTransition<WhoAmIResponseContainer>(
+                WhoAmIResponseStatesEnum.START_STATE,
+                WhoAmIResponseStatesEnum.AUTHZ_ID_RESPONSE_STATE,
+                UniversalTag.OCTET_STRING.getValue(), new GrammarAction<WhoAmIResponseContainer>(
+                    "Store AuthzId" )
+                {
+                    public void action( WhoAmIResponseContainer container ) throws DecoderException
+                    {
+                        WhoAmIResponseDecorator whoAmIResponse = new WhoAmIResponseDecorator(
+                            LdapApiServiceFactory.getSingleton(), new WhoAmIResponseImpl() );
+                        container.setWhoAmIResponse( whoAmIResponse );
+                        
+                        byte[] data = container.getCurrentTLV().getValue().getData();
+                        
+                        if ( data != null )
+                        {
+                            switch ( data.length )
+                            {
+                                case 0:
+                                    // Error
+                                case 1:
+                                    // Error
+                                    String msg = "authzId too short. Must starts with either u: or dn:";
+                                    LOG.error( msg );
+                                    throw new DecoderException( msg );
+
+                                case 2 :
+                                    if ( ( data[0] == 'u' ) && ( data[1] == ':' ) )
+                                    {
+                                        whoAmIResponse.setAuthzId( data );
+                                        whoAmIResponse.setUserId( Strings.utf8ToString( data, 3, data.length - 3 ) );
+                                    }
+                                    else
+                                    {
+                                        msg = "authzId Must starts with either u: or dn:, it starts with " + Strings.utf8ToString( data );
+                                        LOG.error( msg );
+                                        throw new DecoderException( msg );
+                                    }
+                                    
+                                    break;
+                                    
+                                default :
+                                    switch ( data[0] )
+                                    {
+                                        case 'u' :
+                                            if ( data[1] == ':' )
+                                            {
+                                                whoAmIResponse.setAuthzId( data );
+                                                whoAmIResponse.setUserId( Strings.utf8ToString( data, 3, data.length - 3 ) );
+                                            }
+                                            else
+                                            {
+                                                msg = "authzId Must starts with either u: or dn:, it starts with " + Strings.utf8ToString( data );
+                                                LOG.error( msg );
+                                                throw new DecoderException( msg );
+                                            }
+                                            
+                                            break;
+                                            
+                                        case 'd' :
+                                            if ( ( data[1] == 'n' ) && ( data[2] == ':' ) )
+                                            {
+                                                // Check that the remaining bytes are a valid DN
+                                                if ( Dn.isValid( Strings.utf8ToString( data, 3, data.length - 3 ) ) )
+                                                {
+                                                    whoAmIResponse.setAuthzId( data );
+                                                    
+                                                    try
+                                                    {
+                                                        whoAmIResponse.setDn( new Dn( Strings.utf8ToString( data, 3, data.length - 3 ) ) );
+                                                    }
+                                                    catch ( LdapInvalidDnException e )
+                                                    {
+                                                        // Should never happen
+                                                    }
+                                                }
+                                                else
+                                                {
+                                                    msg = "authzId Must starts with either u: or dn:, it starts with " + Strings.utf8ToString( data );
+                                                    LOG.error( msg );
+                                                    throw new DecoderException( msg );
+                                                }
+                                            }
+                                            else
+                                            {
+                                                msg = "authzId Must starts with either u: or dn:, it starts with " + Strings.utf8ToString( data );
+                                                LOG.error( msg );
+                                                throw new DecoderException( msg );
+                                            }
+                                            
+                                            break;
+
+                                        default :
+                                            msg = "authzId Must starts with either u: or dn:, it starts with " + Strings.utf8ToString( data );
+                                            LOG.error( msg );
+                                            throw new DecoderException( msg );
+                                    }
+                                    
+                                    break;
+                            }
+                        }
+                        else
+                        {
+                            whoAmIResponse.setAuthzId( null );
+                        }
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<WhoAmIResponseContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseStatesEnum.java b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseStatesEnum.java
new file mode 100644
index 0000000..f3da5cb
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseStatesEnum.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.States;
+
+
+/**
+ * This class store the WhoAmIResponse's grammar constants. It is also used
+ * for debugging purposes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum WhoAmIResponseStatesEnum implements States
+{
+
+    /** The END_STATE */
+    END_STATE,
+
+    /** start state*/
+    START_STATE,
+
+    /** the authzid */
+    AUTHZ_ID_RESPONSE_STATE,
+
+    /** Last state */
+    LAST_WHO_AM_I_RESPONSE_STATE;
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar class
+     * @return The grammar name
+     */
+    public String getGrammarName( Grammar<WhoAmIResponseContainer> grammar )
+    {
+        return "WHO_AM_I_RESPONSE_GRAMMER";
+    }
+
+
+    /**
+     * Get the grammar name
+     * 
+     * @param grammar The grammar code
+     * @return The grammar name
+     */
+    public String getGrammarName( int grammar )
+    {
+        return "WHO_AM_I_RESPONSE_GRAMMER";
+    }
+
+
+    /**
+     * Get the string representing the state
+     * 
+     * @param state The state number
+     * @return The String representing the state
+     */
+    public String getState( int state )
+    {
+        return ( ( state == END_STATE.ordinal() ) ? "WHO_AM_I_RESPONSE_GRAMMER" : this.name() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEndState()
+    {
+        return this == END_STATE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public WhoAmIResponseStatesEnum getStartState()
+    {
+        return START_STATE;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/site/site.xml b/trunk/ldap/extras/codec/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/AbstractCodecServiceTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/AbstractCodecServiceTest.java
new file mode 100644
index 0000000..65204d0
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/AbstractCodecServiceTest.java
@@ -0,0 +1,63 @@
+package org.apache.directory.api.ldap.extras;
+
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+import org.apache.directory.api.ldap.codec.api.LdapEncoder;
+import org.apache.directory.api.ldap.codec.osgi.DefaultLdapCodecService;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+
+/**
+ * Initialize the Codec service. This can later be removed.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractCodecServiceTest
+{
+    protected static DefaultLdapCodecService codec;
+
+    /** The encoder instance */
+    protected static LdapEncoder encoder;
+
+
+    /**
+     * Initialize the codec service
+     */
+    @BeforeClass
+    public static void setupLdapCodecService()
+    {
+        codec = new DefaultLdapCodecService();
+        encoder = new LdapEncoder( codec );
+    }
+
+
+    /**
+     * Shutdown the codec service
+     */
+    @AfterClass
+    public static void tearDownLdapCodecService()
+    {
+        codec = null;
+        encoder = null;
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncControlTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncControlTest.java
new file mode 100644
index 0000000..4e674fa
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/ad/AdDirSyncControlTest.java
@@ -0,0 +1,212 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.ad;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.extras.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.extras.controls.ad_impl.AdDirSyncDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * 
+ * TestCase for AdDirSyncControlCodec .
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AdDirSyncControlTest extends AbstractCodecServiceTest
+{
+    @Test
+    public void testAdDirSyncControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0E );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x0C,
+                  0x02, 0x01, 0x01,  // flag (LDAP_DIRSYNC_OBJECT_SECURITY)
+                  0x02, 0x01, 0x00,  // maxReturnLength (no limit)
+                  0x04, 0x04, 'x', 'k', 'c', 'd' // the cookie 
+        } );
+
+        bb.flip();
+
+        AdDirSync decorator = new AdDirSyncDecorator( codec );
+
+        AdDirSync adDirSync = ( AdDirSync ) ( ( AdDirSyncDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( AdDirSyncFlag.LDAP_DIRSYNC_OBJECT_SECURITY, adDirSync.getFlag() );
+        assertEquals( 0, adDirSync.getMaxReturnLength() );
+        assertEquals( "xkcd", Strings.utf8ToString( adDirSync.getCookie() ) );
+
+        // test encoding
+        adDirSync.setParentFirst( 1 );
+        
+        try
+        {
+            ByteBuffer buffer = ( ( AdDirSyncDecorator ) adDirSync ).encode( ByteBuffer
+                .allocate( ( ( AdDirSyncDecorator ) adDirSync ).computeLength() ) );
+            String expected = "0x30 0x0C 0x02 0x01 0x01 0x02 0x01 0x00 0x04 0x04 0x78 0x6B 0x63 0x64 ";
+            String decoded = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+
+
+    @Test
+    public void testAdDirSyncControlNoCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x08,
+                  0x02, 0x01, 0x01,  // flag (LDAP_DIRSYNC_OBJECT_SECURITY)
+                  0x02, 0x01, 0x00,  // maxReturnLength (no limit)
+                  0x04, 0x00         // the cookie 
+        } );
+
+        bb.flip();
+
+        AdDirSync decorator = new AdDirSyncDecorator( codec );
+
+        AdDirSync adDirSync = ( AdDirSync ) ( ( AdDirSyncDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( AdDirSyncFlag.LDAP_DIRSYNC_OBJECT_SECURITY, adDirSync.getFlag() );
+        assertEquals( 0, adDirSync.getMaxReturnLength() );
+        assertEquals( "", Strings.utf8ToString( adDirSync.getCookie() ) );
+
+        // test encoding
+        adDirSync.setParentFirst( 1 );
+
+        try
+        {
+            ByteBuffer buffer = ( ( AdDirSyncDecorator ) adDirSync ).encode( ByteBuffer
+                .allocate( ( ( AdDirSyncDecorator ) adDirSync ).computeLength() ) );
+            String expected = "0x30 0x08 0x02 0x01 0x01 0x02 0x01 0x00 0x04 0x00 ";
+            String decoded = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+    
+    
+    @Test
+    public void testAdDirSyncControlAbsentCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x06,
+                  0x02, 0x01, 0x00,  // parentFirst (false)
+                  0x02, 0x01, 0x00   // maxReturnLength (no limit)
+        } );
+
+        bb.flip();
+
+        AdDirSync decorator = new AdDirSyncDecorator( codec );
+
+        try
+        {
+            ( ( AdDirSyncDecorator ) decorator ).decode( bb.array() );
+            fail();
+        }
+        catch ( DecoderException de )
+        {
+            // expected
+        }
+    }
+    
+    
+    @Test
+    public void testAdDirSyncControlAbsentParentFirst() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x05,
+                  0x02, 0x01, 0x00,  // maxReturnLength (no limit)
+                  0x04, 0x00         // cookie
+        } );
+
+        bb.flip();
+
+        AdDirSync decorator = new AdDirSyncDecorator( codec );
+
+        try
+        {
+            ( ( AdDirSyncDecorator ) decorator ).decode( bb.array() );
+            fail();
+        }
+        catch ( DecoderException de )
+        {
+            // expected
+        }
+    }
+    
+    
+    @Test
+    public void testAdDirSyncControlEmpty() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x00,
+        } );
+
+        bb.flip();
+
+        AdDirSync decorator = new AdDirSyncDecorator( codec );
+
+        try
+        {
+            ( ( AdDirSyncDecorator ) decorator ).decode( bb.array() );
+            fail();
+        }
+        catch ( DecoderException de )
+        {
+            // expected
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyTest.java
new file mode 100644
index 0000000..baddce3
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/ppolicy/PasswordPolicyTest.java
@@ -0,0 +1,206 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.ppolicy;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.ldap.extras.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+
+
+/**
+ * PasswordPolicyResponseControlTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordPolicyTest extends AbstractCodecServiceTest
+{
+    @Test
+    public void testDecodeRespWithExpiryWarningAndError() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0xA );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x08,
+                ( byte ) 0xA0, 0x03, // timeBeforeExpiration
+                ( byte ) 0x80,
+                0x01,
+                0x01,
+                ( byte ) 0x81,
+                0x01,
+                0x01 // ppolicyError
+        } );
+
+        bb.flip();
+
+        PasswordPolicyDecorator control = new PasswordPolicyDecorator( codec, true );
+        PasswordPolicy passwordPolicy = ( PasswordPolicy ) control.decode( bb.array() );
+
+        assertTrue( passwordPolicy.hasResponse() );
+        assertEquals( 1, passwordPolicy.getResponse().getTimeBeforeExpiration() );
+        assertEquals( 1, passwordPolicy.getResponse().getPasswordPolicyError().getValue() );
+
+        ByteBuffer encoded = ( ( PasswordPolicyDecorator ) passwordPolicy ).encode(
+            ByteBuffer.allocate( ( ( PasswordPolicyDecorator ) passwordPolicy ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeRespWithGraceAuthWarningAndError() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0xA );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x08,
+                ( byte ) 0xA0, 0x03, // warning
+                ( byte ) 0x81,
+                0x01,
+                0x01, // graceAuthNsRemaining
+                ( byte ) 0x81,
+                0x01,
+                0x01 // error
+        } );
+
+        bb.flip();
+
+        PasswordPolicyDecorator control = new PasswordPolicyDecorator( codec, true );
+        PasswordPolicy passwordPolicy = ( PasswordPolicy ) control.decode( bb.array() );
+
+        assertTrue( passwordPolicy.hasResponse() );
+        assertEquals( 1, passwordPolicy.getResponse().getGraceAuthNRemaining() );
+        assertEquals( 1, passwordPolicy.getResponse().getPasswordPolicyError().getValue() );
+
+        ByteBuffer encoded = ( ( PasswordPolicyDecorator ) passwordPolicy ).encode(
+            ByteBuffer.allocate( ( ( PasswordPolicyDecorator ) passwordPolicy ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeRespWithTimeBeforeExpiryWarningOnly() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 7 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x05,
+                ( byte ) 0xA0, 0x03,
+                ( byte ) 0x80, 0x01, 0x01 //  timeBeforeExpiration
+        } );
+
+        bb.flip();
+
+        PasswordPolicyDecorator control = new PasswordPolicyDecorator( codec, true );
+        PasswordPolicy passwordPolicy = ( PasswordPolicy ) control.decode( bb.array() );
+
+        assertTrue( passwordPolicy.hasResponse() );
+        assertEquals( 1, passwordPolicy.getResponse().getTimeBeforeExpiration() );
+
+        ByteBuffer encoded = ( ( PasswordPolicyDecorator ) passwordPolicy ).encode(
+            ByteBuffer.allocate( ( ( PasswordPolicyDecorator ) passwordPolicy ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeRespWithGraceAuthWarningOnly() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 7 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x05,
+                ( byte ) 0xA0, 0x03,
+                ( byte ) 0x81, 0x01, 0x01 //  graceAuthNsRemaining
+        } );
+
+        bb.flip();
+
+        PasswordPolicyDecorator control = new PasswordPolicyDecorator( codec, true );
+        PasswordPolicy passwordPolicy = ( PasswordPolicy ) control.decode( bb.array() );
+
+        assertTrue( passwordPolicy.hasResponse() );
+        assertEquals( 1, passwordPolicy.getResponse().getGraceAuthNRemaining() );
+
+        ByteBuffer encoded = ( ( PasswordPolicyDecorator ) passwordPolicy ).encode(
+            ByteBuffer.allocate( ( ( PasswordPolicyDecorator ) passwordPolicy ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeRespWithErrorOnly() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 5 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x03,
+                ( byte ) 0x81, 0x01, 0x01 //  error
+        } );
+
+        bb.flip();
+
+        PasswordPolicyDecorator control = new PasswordPolicyDecorator( codec, true );
+        PasswordPolicy passwordPolicy = ( PasswordPolicy ) control.decode( bb.array() );
+
+        assertTrue( passwordPolicy.hasResponse() );
+        assertEquals( 1, passwordPolicy.getResponse().getPasswordPolicyError().getValue() );
+
+        ByteBuffer encoded = ( ( PasswordPolicyDecorator ) passwordPolicy ).encode(
+            ByteBuffer.allocate( ( ( PasswordPolicyDecorator ) passwordPolicy ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeRespWithoutWarningAndError() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 2 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x00
+        } );
+
+        bb.flip();
+
+        PasswordPolicyDecorator control = new PasswordPolicyDecorator( codec, true );
+        PasswordPolicy passwordPolicy = ( PasswordPolicy ) control.decode( bb.array() );
+
+        assertNotNull( passwordPolicy );
+        assertTrue( passwordPolicy.hasResponse() );
+
+        ByteBuffer encoded = ( ( PasswordPolicyDecorator ) passwordPolicy ).encode(
+            ByteBuffer.allocate( ( ( PasswordPolicyDecorator ) passwordPolicy ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java
new file mode 100644
index 0000000..8b73449
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.extras.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncDone.SyncDoneValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncDoneValueDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * 
+ * TestCase for SyncDoneValueControlCodec .
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SyncDoneValueControlTest extends AbstractCodecServiceTest
+{
+    @Test
+    public void testSyncDoneValueControl() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 11 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x09,
+                0x04, 0x04, 'x', 'k', 'c', 'd', // the cookie 
+                0x01,
+                0x01,
+                ( byte ) 0xFF // refreshDeletes flag TRUE
+        } );
+
+        bb.flip();
+
+        SyncDoneValue decorator = new SyncDoneValueDecorator( codec );
+
+        SyncDoneValue control = ( SyncDoneValue ) ( ( SyncDoneValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( "xkcd", Strings.utf8ToString( control.getCookie() ) );
+        assertTrue( control.isRefreshDeletes() );
+
+        // test encoding
+        try
+        {
+            ByteBuffer buffer = ( ( SyncDoneValueDecorator ) control ).encode( ByteBuffer
+                .allocate( ( ( SyncDoneValueDecorator ) control ).computeLength() ) );
+            String expected = Strings.dumpBytes( bb.array() );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+
+
+    @Test
+    public void testSyncDoneValueControlWithoutCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 5 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x03,
+                // null cookie
+                0x01,
+                0x01,
+                ( byte ) 0xFF // refreshDeletes flag TRUE
+        } );
+
+        bb.flip();
+
+        SyncDoneValue decorator = new SyncDoneValueDecorator( codec );
+
+        SyncDoneValue control = ( SyncDoneValue ) ( ( SyncDoneValueDecorator ) decorator ).decode( bb.array() );
+
+        assertNull( control.getCookie() );
+        assertTrue( control.isRefreshDeletes() );
+
+        // test encoding
+        try
+        {
+            ByteBuffer buffer = ( ( SyncDoneValueDecorator ) control ).encode( ByteBuffer
+                .allocate( ( ( SyncDoneValueDecorator ) control ).computeLength() ) );
+            String expected = Strings.dumpBytes( bb.array() );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+
+
+    @Test
+    public void testSyncDoneValueWithSequenceOnly() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 2 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x00
+        } );
+
+        bb.flip();
+
+        SyncDoneValue decorator = new SyncDoneValueDecorator( codec );
+
+        SyncDoneValue control = ( SyncDoneValue ) ( ( SyncDoneValueDecorator ) decorator ).decode( bb.array() );
+
+        assertNull( control.getCookie() );
+        assertFalse( control.isRefreshDeletes() );
+    }
+
+
+    @Test
+    public void testSyncDoneValueControlWithEmptyCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 7 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x05,
+                0x04, 0x00, // empty cookie
+                0x01,
+                0x01,
+                0x00 // refreshDeletes flag FALSE
+        } );
+
+        bb.flip();
+
+        SyncDoneValue decorator = new SyncDoneValueDecorator( codec );
+
+        SyncDoneValue control = ( SyncDoneValue ) ( ( SyncDoneValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( "", Strings.utf8ToString( control.getCookie() ) );
+        assertFalse( control.isRefreshDeletes() );
+
+        // test encoding
+        try
+        {
+            ByteBuffer buffer = ( ( SyncDoneValueDecorator ) control ).encode( ByteBuffer
+                .allocate( ( ( SyncDoneValueDecorator ) control ).computeLength() ) );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            assertEquals( "0x30 0x00 ", decoded );
+        }
+        catch ( Exception e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java
new file mode 100644
index 0000000..6494f07
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java
@@ -0,0 +1,1650 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.extras.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncInfoValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SynchronizationInfoEnum;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncInfoValueDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the SyncInfoControlValue codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SyncInfoValueControlTest extends AbstractCodecServiceTest
+{
+    //--------------------------------------------------------------------------------
+    // NewCookie choice tests
+    //--------------------------------------------------------------------------------
+
+    /**
+     * Test the decoding of a SyncInfoValue control, newCookie choice
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlNewCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0x80, 0x03, // syncInfoValue ::= CHOICE {
+                'a',
+                'b',
+                'c' //     newCookie [0] syncCookie
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+        decorator.setType( SynchronizationInfoEnum.NEW_COOKIE );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.NEW_COOKIE, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, empty newCookie choice
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlEmptyNewCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0x80, 0x00, // syncInfoValue ::= CHOICE {
+                                     //     newCookie [0] syncCookie
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+        decorator.setType( SynchronizationInfoEnum.NEW_COOKIE );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.NEW_COOKIE, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    //--------------------------------------------------------------------------------
+    // RefreshDelete choice tests
+    //--------------------------------------------------------------------------------
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshDelete choice,
+     * refreshDone = true
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshDelete() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA1, 0x08, // syncInfoValue ::= CHOICE {
+                                     //     refreshDelete [1] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie       syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                ( byte ) 0xFF //         refreshDone  BOOLEAN DEFAULT TRUE
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_DELETE );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_DELETE, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ByteBuffer.allocate( 0x07 );
+            buffer.put( new byte[]
+                {
+                    ( byte ) 0xA1, 0x05, // syncInfoValue ::= CHOICE {
+                                         //     refreshDelete [1] SEQUENCE {
+                    0x04,
+                    0x03,
+                    'a',
+                    'b',
+                    'c' //         cookie       syncCookie OPTIONAL,
+            } );
+            buffer.flip();
+
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( buffer.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshDelete choice,
+     * refreshDone = false
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshDeleteRefreshDoneFalse() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA1, 0x08, // syncInfoValue ::= CHOICE {
+                                     //     refreshDelete [1] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie       syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                ( byte ) 0x00 //         refreshDone  BOOLEAN DEFAULT TRUE
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_DELETE );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_DELETE, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshDelete choice,
+     * no refreshDone
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshDeleteNoRefreshDone() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA1, 0x05, // syncInfoValue ::= CHOICE {
+                                     //     refreshDelete [1] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c' //         cookie       syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_DELETE );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_DELETE, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshDelete choice,
+     * no cookie
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshDeleteNoCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA1, 0x03, // syncInfoValue ::= CHOICE {
+                                     //     refreshDelete [1] SEQUENCE {
+                0x01,
+                0x01,
+                0x00 //        refreshDone  BOOLEAN DEFAULT TRUE
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_DELETE );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_DELETE, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshDelete choice,
+     * no cookie, no refreshDone
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshDeleteNoCookieNoRefreshDone() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA1, 0x00 // syncInfoValue ::= CHOICE {
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_DELETE );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_DELETE, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    //--------------------------------------------------------------------------------
+    // RefreshPresent choice tests
+    //--------------------------------------------------------------------------------
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshPresent choice,
+     * refreshDone = true
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshPresent() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA2, 0x08, // syncInfoValue ::= CHOICE {
+                                     //     refreshPresent [2] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie       syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                ( byte ) 0xFF //         refreshDone  BOOLEAN DEFAULT TRUE
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_PRESENT );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_PRESENT, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ByteBuffer.allocate( 0x07 );
+            buffer.put( new byte[]
+                {
+                    ( byte ) 0xA2, 0x05, // syncInfoValue ::= CHOICE {
+                                         //     refreshPresent [2] SEQUENCE {
+                    0x04,
+                    0x03,
+                    'a',
+                    'b',
+                    'c' //         cookie       syncCookie OPTIONAL,
+            } );
+            buffer.flip();
+
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( buffer.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshPresent choice,
+     * refreshDone = false
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshPresentRefreshDoneFalse() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA2, 0x08, // syncInfoValue ::= CHOICE {
+                                     //     refreshPresent [2] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie       syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                ( byte ) 0x00 //         refreshDone  BOOLEAN DEFAULT TRUE
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_PRESENT );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_PRESENT, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshPresent choice,
+     * no refreshDone
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshPresentNoRefreshDone() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA2, 0x05, // syncInfoValue ::= CHOICE {
+                                     //     refreshPresent [2] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c' //         cookie       syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_PRESENT );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_PRESENT, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshPresent choice,
+     * no cookie
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshPresentNoCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA2, 0x03, // syncInfoValue ::= CHOICE {
+                                     //     refreshPresent [2] SEQUENCE {
+                0x01,
+                0x01,
+                0x00 //        refreshDone  BOOLEAN DEFAULT TRUE
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_PRESENT );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_PRESENT, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, refreshPresent choice,
+     * no cookie, no refreshDone
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlRefreshPresentNoCookieNoRefreshDone() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA2, 0x00 // syncInfoValue ::= CHOICE {
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.REFRESH_PRESENT );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.REFRESH_PRESENT, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDone() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    //--------------------------------------------------------------------------------
+    // syncIdSet choice tests
+    //--------------------------------------------------------------------------------
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, empty
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetEmpty()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x00, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        try
+        {
+            ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+            fail( "Should not get there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, cookie
+     * but no UUID set
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetCookieNoSet()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x05, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie       syncCookie OPTIONAL,
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        try
+        {
+            ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+            fail( "Should not get there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, no cookie
+     * a refreshDeletes flag, but no UUID set
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetNoCookieRefreshDeletesNoSet()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x03, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x01,
+                0x01,
+                0x00, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        try
+        {
+            ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+            fail( "Should not get there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, a cookie
+     * a refreshDeletes flag, but no UUID set
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetCookieRefreshDeletesNoSet()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x08, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie         syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                0x00, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        try
+        {
+            ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+            fail( "Should not get there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, no cookie
+     * no refreshDeletes flag, an empty UUID set
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetNoCookieNoRefreshDeletesEmptySet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x04 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x02, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x31,
+                0x00, //         syncUUIDs SET OF syncUUID
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 0, syncInfoValue.getSyncUUIDs().size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, no cookie
+     * no refreshDeletes flag, a UUID set with some values
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetNoCookieNoRefreshDeletesUUIDsSet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x3A );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x38, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x31,
+                0x36, //         syncUUIDs SET OF syncUUID
+                0x04,
+                0x10, // syncUUID
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x04,
+                0x10, // syncUUID
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x04,
+                0x10, // syncUUID
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 3, syncInfoValue.getSyncUUIDs().size() );
+
+        for ( int i = 0; i < 3; i++ )
+        {
+            byte[] uuid = syncInfoValue.getSyncUUIDs().get( i );
+
+            for ( int j = 0; j < 16; j++ )
+            {
+                assertEquals( i + 1, uuid[j] );
+            }
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, A cookie
+     * no refreshDeletes flag, an empty UUID set
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetCookieNoRefreshDeletesEmptySet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x09 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x07, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie         syncCookie OPTIONAL,
+                0x31,
+                0x00, //         syncUUIDs SET OF syncUUID
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 0, syncInfoValue.getSyncUUIDs().size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, a cookie
+     * no refreshDeletes flag, a UUID set with some values
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetCookieNoRefreshDeletesUUIDsSet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x3F );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x3D, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie         syncCookie OPTIONAL,
+                0x31,
+                0x36, //         syncUUIDs SET OF syncUUID
+                0x04,
+                0x10, // syncUUID
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x04,
+                0x10, // syncUUID
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x04,
+                0x10, // syncUUID
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertFalse( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 3, syncInfoValue.getSyncUUIDs().size() );
+
+        for ( int i = 0; i < 3; i++ )
+        {
+            byte[] uuid = syncInfoValue.getSyncUUIDs().get( i );
+
+            for ( int j = 0; j < 16; j++ )
+            {
+                assertEquals( i + 1, uuid[j] );
+            }
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, no cookie
+     * a refreshDeletes flag, an empty UUID set
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetNoCookieRefreshDeletesEmptySet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x05, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x01,
+                0x01,
+                0x10, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                0x31,
+                0x00, //         syncUUIDs SET OF syncUUID
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 0, syncInfoValue.getSyncUUIDs().size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ByteBuffer.allocate( 0x07 );
+            buffer.put( new byte[]
+                {
+                    ( byte ) 0xA3, 0x05, // syncInfoValue ::= CHOICE {
+                                         //     syncIdSet [3] SEQUENCE {
+                    0x01,
+                    0x01,
+                    ( byte ) 0xFF, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                    0x31,
+                    0x00, //         syncUUIDs SET OF syncUUID
+                } );
+            buffer.flip();
+
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( buffer.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, a cookie
+     * no refreshDeletes flag, a UUID set with some values
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetNoCookieRefreshDeletesUUIDsSet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x3D );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x3B, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x01,
+                0x01,
+                0x10, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                0x31,
+                0x36, //         syncUUIDs SET OF syncUUID
+                0x04,
+                0x10, // syncUUID
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x04,
+                0x10, // syncUUID
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x04,
+                0x10, // syncUUID
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 3, syncInfoValue.getSyncUUIDs().size() );
+
+        for ( int i = 0; i < 3; i++ )
+        {
+            byte[] uuid = syncInfoValue.getSyncUUIDs().get( i );
+
+            for ( int j = 0; j < 16; j++ )
+            {
+                assertEquals( i + 1, uuid[j] );
+            }
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ByteBuffer.allocate( 0x3D );
+            buffer.put( new byte[]
+                {
+                    ( byte ) 0xA3, 0x3B, // syncInfoValue ::= CHOICE {
+                                         //     syncIdSet [3] SEQUENCE {
+                    0x01,
+                    0x01,
+                    ( byte ) 0xFF, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                    0x31,
+                    0x36, //         syncUUIDs SET OF syncUUID
+                    0x04,
+                    0x10, // syncUUID
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x04,
+                    0x10, // syncUUID
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x04,
+                    0x10, // syncUUID
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03
+            } );
+            buffer.flip();
+
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( buffer.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, a cookie
+     * a refreshDeletes flag, an empty UUID set
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetCookieRefreshDeletesEmptySet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0C );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x0A, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie         syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                0x10, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                0x31,
+                0x00, //         syncUUIDs SET OF syncUUID
+            } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 0, syncInfoValue.getSyncUUIDs().size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ByteBuffer.allocate( 0x0C );
+            buffer.put( new byte[]
+                {
+                    ( byte ) 0xA3, 0x0A, // syncInfoValue ::= CHOICE {
+                                         //     syncIdSet [3] SEQUENCE {
+                    0x04,
+                    0x03,
+                    'a',
+                    'b',
+                    'c', //         cookie         syncCookie OPTIONAL,
+                    0x01,
+                    0x01,
+                    ( byte ) 0xFF, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                    0x31,
+                    0x00, //         syncUUIDs SET OF syncUUID
+                } );
+            buffer.flip();
+
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( buffer.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, a cookie
+     * a refreshDeletes flag, a UUID set with some values
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetCookieRefreshDeletesUUIDsSet() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x42 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x40, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie         syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                0x10, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                0x31,
+                0x36, //         syncUUIDs SET OF syncUUID
+                0x04,
+                0x10, // syncUUID
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x04,
+                0x10, // syncUUID
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x02,
+                0x04,
+                0x10, // syncUUID
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03,
+                0x03
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        SyncInfoValue syncInfoValue = ( SyncInfoValue ) ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+
+        assertEquals( SynchronizationInfoEnum.SYNC_ID_SET, syncInfoValue.getType() );
+        assertEquals( "abc", Strings.utf8ToString( syncInfoValue.getCookie() ) );
+        assertTrue( syncInfoValue.isRefreshDeletes() );
+        assertEquals( 3, syncInfoValue.getSyncUUIDs().size() );
+
+        for ( int i = 0; i < 3; i++ )
+        {
+            byte[] uuid = syncInfoValue.getSyncUUIDs().get( i );
+
+            for ( int j = 0; j < 16; j++ )
+            {
+                assertEquals( i + 1, uuid[j] );
+            }
+        }
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ByteBuffer.allocate( 0x42 );
+            buffer.put( new byte[]
+                {
+                    ( byte ) 0xA3, 0x40, // syncInfoValue ::= CHOICE {
+                                         //     syncIdSet [3] SEQUENCE {
+                    0x04,
+                    0x03,
+                    'a',
+                    'b',
+                    'c', //         cookie         syncCookie OPTIONAL,
+                    0x01,
+                    0x01,
+                    ( byte ) 0xFF, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                    0x31,
+                    0x36, //         syncUUIDs SET OF syncUUID
+                    0x04,
+                    0x10, // syncUUID
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x01,
+                    0x04,
+                    0x10, // syncUUID
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x02,
+                    0x04,
+                    0x10, // syncUUID
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03,
+                    0x03
+            } );
+            buffer.flip();
+
+            ByteBuffer encoded = ( ( SyncInfoValueDecorator ) syncInfoValue ).encode( ByteBuffer
+                .allocate( ( ( SyncInfoValueDecorator ) syncInfoValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( buffer.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, with some
+     * invalid UUID
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetTooSmallUUID()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x1D );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x1B, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie         syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                0x10, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                0x31,
+                0x11, //         syncUUIDs SET OF syncUUID
+                0x04,
+                0x0F, // syncUUID
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        try
+        {
+            ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+            fail( "Should not be there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncInfoValue control, syncIdSet choice, with some
+     * invalid UUID
+     */
+    @Test
+    public void testDecodeSyncInfoValueControlSyncIdSetTooLongUUID()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x20 );
+        bb.put( new byte[]
+            {
+                ( byte ) 0xA3, 0x1E, // syncInfoValue ::= CHOICE {
+                                     //     syncIdSet [3] SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //         cookie         syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                0x10, //         refreshDeletes BOOLEAN DEFAULT FALSE,
+                0x31,
+                0x13, //         syncUUIDs SET OF syncUUID
+                0x04,
+                0x11, // syncUUID
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01,
+                0x01
+        } );
+        bb.flip();
+
+        SyncInfoValue decorator = new SyncInfoValueDecorator( codec );
+        decorator.setType( SynchronizationInfoEnum.SYNC_ID_SET );
+
+        try
+        {
+            ( ( SyncInfoValueDecorator ) decorator ).decode( bb.array() );
+            fail( "Should not be there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java
new file mode 100644
index 0000000..ea6df28
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java
@@ -0,0 +1,510 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.extras.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.extras.controls.SynchronizationModeEnum;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncInfoValue.SyncRequestValueImpl;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncRequestValueDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the SyncRequestControlValue codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SyncRequestValueControlTest extends AbstractCodecServiceTest
+{
+    @Test
+    public void testEncodeSyncRequestValue() throws Exception
+    {
+        SyncRequestValue syncRequestValue = new SyncRequestValueImpl();
+        syncRequestValue.setMode( SynchronizationModeEnum.REFRESH_ONLY );
+        
+        SyncRequestValueDecorator decorator = new SyncRequestValueDecorator( codec, syncRequestValue );
+        
+        ByteBuffer buffer = decorator.encode( ByteBuffer.allocate( decorator.computeLength() ) );
+        
+        String expected = Strings.dumpBytes( new byte[]{ 0x30, 0x03, 0x0A, 0x01, 0x01 } );
+        assertEquals( expected, Strings.dumpBytes( buffer.array() ) );
+    }
+    
+    
+    /**
+     * Test the decoding of a SyncRequestValue control with a refreshOnly mode
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlRefreshOnlySuccess() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0D );
+        bb.put( new byte[]
+            {
+                0x30, 0x0B,         // syncRequestValue ::= SEQUENCE {
+                  0x0A, 0x01, 0x01, //     mode ENUMERATED {
+                                    //         refreshOnly (1)
+                                    //     }
+                  0x04, 0x03,
+                    'a', 'b', 'c',  //     cookie syncCookie OPTIONAL,
+                  0x01, 0x01, 0x00  //     reloadHint BOOLEAN DEFAULT FALSE
+        } );
+        
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        SyncRequestValue syncRequestValue = ( SyncRequestValue ) ( ( SyncRequestValueDecorator ) decorator ).decode( bb
+            .array() );
+
+        assertEquals( SynchronizationModeEnum.REFRESH_ONLY, syncRequestValue.getMode() );
+        assertEquals( "abc", Strings.utf8ToString( syncRequestValue.getCookie() ) );
+        assertEquals( false, syncRequestValue.isReloadHint() );
+
+        // Check the encoding
+        try
+        {
+            bb = ByteBuffer.allocate( 0x0A );
+            bb.put( new byte[]
+                {
+                    0x30, 0x08, // syncRequestValue ::= SEQUENCE {
+                    0x0A,
+                    0x01,
+                    0x01, //     mode ENUMERATED {
+                          //         refreshOnly (1)
+                          //     }
+                    0x04,
+                    0x03,
+                    'a',
+                    'b',
+                    'c' //     cookie syncCookie OPTIONAL,
+            } );
+            bb.flip();
+
+            ByteBuffer buffer = ( ( SyncRequestValueDecorator ) syncRequestValue ).encode( ByteBuffer
+                .allocate( ( ( SyncRequestValueDecorator ) syncRequestValue ).computeLength() ) );
+            String decoded = Strings.dumpBytes( bb.array() );
+            String expected = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with a refreshAndPersist mode
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlRefreshAndPersistSuccess() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0D );
+        bb.put( new byte[]
+            {
+                0x30, 0x0B, // syncRequestValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x03, //     mode ENUMERATED {
+                      //         refreshAndPersist (3)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //     cookie syncCookie OPTIONAL,
+                0x01,
+                0x01,
+                0x00 //     reloadHint BOOLEAN DEFAULT FALSE
+        } );
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        SyncRequestValue syncRequestValue = ( SyncRequestValue ) ( ( SyncRequestValueDecorator ) decorator ).decode( bb
+            .array() );
+
+        assertEquals( SynchronizationModeEnum.REFRESH_AND_PERSIST, syncRequestValue.getMode() );
+        assertEquals( "abc", Strings.utf8ToString( syncRequestValue.getCookie() ) );
+        assertEquals( false, syncRequestValue.isReloadHint() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ByteBuffer.allocate( 0x0A );
+            buffer.put( new byte[]
+                {
+                    0x30, 0x08, // syncRequestValue ::= SEQUENCE {
+                    0x0A,
+                    0x01,
+                    0x03, //     mode ENUMERATED {
+                          //         refreshAndPersist (3)
+                          //     }
+                    0x04,
+                    0x03,
+                    'a',
+                    'b',
+                    'c' //     cookie syncCookie OPTIONAL,
+            } );
+            buffer.flip();
+
+            bb = ( ( SyncRequestValueDecorator ) syncRequestValue ).encode( ByteBuffer
+                .allocate( ( ( SyncRequestValueDecorator ) syncRequestValue ).computeLength() ) );
+            String decoded = Strings.dumpBytes( bb.array() );
+            String expected = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with no cookie
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlNoCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            {
+                0x30, 0x06, // syncRequestValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x03, //     mode ENUMERATED {
+                      //         refreshAndPersist (3)
+                      //     }
+                0x01,
+                0x01,
+                0x00 //     reloadHint BOOLEAN DEFAULT FALSE
+        } );
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        SyncRequestValue syncRequestValue = ( SyncRequestValue ) ( ( SyncRequestValueDecorator ) decorator ).decode( bb
+            .array() );
+
+        assertEquals( SynchronizationModeEnum.REFRESH_AND_PERSIST, syncRequestValue.getMode() );
+        assertNull( syncRequestValue.getCookie() );
+        assertEquals( false, syncRequestValue.isReloadHint() );
+
+        // Check the encoding
+        try
+        {
+            bb = ByteBuffer.allocate( 0x05 );
+            bb.put( new byte[]
+                {
+                    0x30, 0x03, // syncRequestValue ::= SEQUENCE {
+                    0x0A,
+                    0x01,
+                    0x03 //     mode ENUMERATED {
+                         //         refreshAndPersist (3)
+                         //     }
+            } );
+            bb.flip();
+
+            ByteBuffer buffer = ( ( SyncRequestValueDecorator ) syncRequestValue ).encode( ByteBuffer
+                .allocate( ( ( SyncRequestValueDecorator ) syncRequestValue ).computeLength() ) );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            String expected = Strings.dumpBytes( bb.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with no cookie, a true
+     * reloadHint
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlNoCookieReloadHintTrue() throws Exception
+    {
+        ByteBuffer buffer = ByteBuffer.allocate( 0x08 );
+        buffer.put( new byte[]
+            {
+                0x30, 0x06, // syncRequestValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x03, //     mode ENUMERATED {
+                      //         refreshAndPersist (3)
+                      //     }
+                0x01,
+                0x01,
+                ( byte ) 0xFF //     reloadHint BOOLEAN DEFAULT FALSE
+        } );
+        buffer.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        SyncRequestValue syncRequestValue = ( SyncRequestValue ) ( ( SyncRequestValueDecorator ) decorator )
+            .decode( buffer.array() );
+
+        assertEquals( SynchronizationModeEnum.REFRESH_AND_PERSIST, syncRequestValue.getMode() );
+        assertNull( syncRequestValue.getCookie() );
+        assertEquals( true, syncRequestValue.isReloadHint() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = ( ( SyncRequestValueDecorator ) syncRequestValue ).encode( ByteBuffer
+                .allocate( ( ( SyncRequestValueDecorator ) syncRequestValue ).computeLength() ) );
+            String decoded = Strings.dumpBytes( bb.array() );
+            String expected = Strings.dumpBytes( buffer.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with no cookie, no
+     * reloadHint
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlNoCookieNoReloadHint() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                0x30, 0x03, // syncRequestValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x03 //     mode ENUMERATED {
+                     //         refreshAndPersist (3)
+                     //     }
+        } );
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        SyncRequestValue syncRequestValue = ( SyncRequestValue ) ( ( SyncRequestValueDecorator ) decorator ).decode( bb
+            .array() );
+
+        assertEquals( SynchronizationModeEnum.REFRESH_AND_PERSIST, syncRequestValue.getMode() );
+        assertNull( syncRequestValue.getCookie() );
+        assertEquals( false, syncRequestValue.isReloadHint() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ( ( SyncRequestValueDecorator ) syncRequestValue ).encode( ByteBuffer
+                .allocate( ( ( SyncRequestValueDecorator ) syncRequestValue ).computeLength() ) );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            String expected = Strings.dumpBytes( bb.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with no reloadHint
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlNoReloadHintSuccess() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            {
+                0x30, 0x08, // syncRequestValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x03, //     mode ENUMERATED {
+                      //         refreshAndPersist (3)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c' //     cookie syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        SyncRequestValue syncRequestValue = ( SyncRequestValue ) ( ( SyncRequestValueDecorator ) decorator ).decode( bb
+            .array() );
+
+        assertEquals( SynchronizationModeEnum.REFRESH_AND_PERSIST, syncRequestValue.getMode() );
+        assertEquals( "abc", Strings.utf8ToString( syncRequestValue.getCookie() ) );
+        assertEquals( false, syncRequestValue.isReloadHint() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer buffer = ( ( SyncRequestValueDecorator ) syncRequestValue ).encode( ByteBuffer
+                .allocate( ( ( SyncRequestValueDecorator ) syncRequestValue ).computeLength() ) );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            String expected = Strings.dumpBytes( bb.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with an empty cookie
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlEmptyCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                0x30, 0x05, // syncRequestValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x03, //     mode ENUMERATED {
+                      //         refreshAndPersist (3)
+                      //     }
+                0x04,
+                0x00, //     cookie syncCookie OPTIONAL,
+            } );
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        SyncRequestValue syncRequestValue = ( SyncRequestValue ) ( ( SyncRequestValueDecorator ) decorator ).decode( bb
+            .array() );
+
+        assertEquals( SynchronizationModeEnum.REFRESH_AND_PERSIST, syncRequestValue.getMode() );
+        assertEquals( "", Strings.utf8ToString( syncRequestValue.getCookie() ) );
+        assertEquals( false, syncRequestValue.isReloadHint() );
+
+        // Check the encoding
+        try
+        {
+            bb = ByteBuffer.allocate( 0x05 );
+            bb.put( new byte[]
+                {
+                    0x30, 0x03, // syncRequestValue ::= SEQUENCE {
+                    0x0A,
+                    0x01,
+                    0x03 //     mode ENUMERATED {
+                         //         refreshAndPersist (3)
+                         //     }
+            } );
+            bb.flip();
+
+            ByteBuffer buffer = ( ( SyncRequestValueDecorator ) syncRequestValue ).encode( ByteBuffer
+                .allocate( ( ( SyncRequestValueDecorator ) syncRequestValue ).computeLength() ) );
+            String decoded = Strings.dumpBytes( buffer.array() );
+            String expected = Strings.dumpBytes( bb.array() );
+            assertEquals( expected, decoded );
+        }
+        catch ( EncoderException ee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with an empty sequence
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlEmptySequence()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                0x30, 0x00 // syncRequestValue ::= SEQUENCE {
+        } );
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        try
+        {
+            ( ( SyncRequestValueDecorator ) decorator ).decode( bb.array() );
+            fail( "we should not get there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncRequestValue control with no mode
+     */
+    @Test
+    public void testDecodeSyncRequestValueControlNoMode()
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                0x30, 0x05, // syncRequestValue ::= SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c' //     cookie syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncRequestValue decorator = new SyncRequestValueDecorator( codec );
+
+        try
+        {
+            ( ( SyncRequestValueDecorator ) decorator ).decode( bb.array() );
+            fail( "we should not get there" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java
new file mode 100644
index 0000000..0999852
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java
@@ -0,0 +1,330 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.controls.syncrepl_impl;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.extras.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateTypeEnum;
+import org.apache.directory.api.ldap.extras.controls.syncrepl.syncState.SyncStateValue;
+import org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncStateValueDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the SyncStateControlValue codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SyncStateValueControlTest extends AbstractCodecServiceTest
+{
+    /**
+     * Test the decoding of a SyncStateValue control with a refreshOnly mode
+     */
+    @Test
+    public void testDecodeSyncStateValueControlWithStateType() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 16 );
+        bb.put( new byte[]
+            {
+                0x30, ( byte ) 14, // SyncStateValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x00, //     state ENUMERATED {
+                      //         present (0)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //     entryUUID syncUUID OPTIONAL,
+                0x04,
+                0x04,
+                'x',
+                'k',
+                'c',
+                'd' //     cookie syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncStateValue decorator = new SyncStateValueDecorator( codec );
+
+        SyncStateValue syncStateValue = ( SyncStateValue ) ( ( SyncStateValueDecorator ) decorator )
+            .decode( bb.array() );
+
+        assertEquals( SyncStateTypeEnum.PRESENT, syncStateValue.getSyncStateType() );
+        assertEquals( "abc", Strings.utf8ToString( syncStateValue.getEntryUUID() ) );
+        assertEquals( "xkcd", Strings.utf8ToString( syncStateValue.getCookie() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncStateValueDecorator ) syncStateValue ).encode( ByteBuffer
+                .allocate( ( ( SyncStateValueDecorator ) syncStateValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncStateValue control with no cookie
+     */
+    @Test
+    public void testDecodeSyncStateValueControlNoCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 10 );
+        bb.put( new byte[]
+            { 0x30, 0x08, // SyncStateValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x01, //     state ENUMERATED {
+                      //         add (1)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c' //     entryUUID syncUUID OPTIONAL
+        } );
+        bb.flip();
+
+        SyncStateValue decorator = new SyncStateValueDecorator( codec );
+
+        SyncStateValue syncStateValue = ( SyncStateValue ) ( ( SyncStateValueDecorator ) decorator )
+            .decode( bb.array() );
+
+        assertEquals( SyncStateTypeEnum.ADD, syncStateValue.getSyncStateType() );
+        assertEquals( "abc", Strings.utf8ToString( syncStateValue.getEntryUUID() ) );
+        assertNull( syncStateValue.getCookie() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncStateValueDecorator ) syncStateValue ).encode( ByteBuffer
+                .allocate( ( ( SyncStateValueDecorator ) syncStateValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncStateValue control with an empty cookie
+     */
+    @Test
+    public void testDecodeSyncStateValueControlEmptyCookie() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0C );
+        bb.put( new byte[]
+            { 0x30, 0x0A, // SyncStateValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x02, //     state ENUMERATED {
+                      //         modify (2)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //     entryUUID syncUUID OPTIONAL
+                0x04,
+                0x00 //     cookie syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncStateValue decorator = new SyncStateValueDecorator( codec );
+
+        SyncStateValue syncStateValue = ( SyncStateValue ) ( ( SyncStateValueDecorator ) decorator )
+            .decode( bb.array() );
+
+        assertEquals( SyncStateTypeEnum.MODIFY, syncStateValue.getSyncStateType() );
+        assertEquals( "abc", Strings.utf8ToString( syncStateValue.getEntryUUID() ) );
+        assertEquals( "", Strings.utf8ToString( syncStateValue.getCookie() ) );
+
+        // Check the encoding
+        try
+        {
+            bb = ByteBuffer.allocate( 0x0A );
+            bb.put( new byte[]
+                { 0x30, 0x08, // SyncStateValue ::= SEQUENCE {
+                    0x0A,
+                    0x01,
+                    0x02, //     state ENUMERATED {
+                          //         modify (2)
+                          //     }
+                    0x04,
+                    0x03,
+                    'a',
+                    'b',
+                    'c' //     entryUUID syncUUID OPTIONAL
+            } );
+            bb.flip();
+
+            ByteBuffer encoded = ( ( SyncStateValueDecorator ) syncStateValue ).encode( ByteBuffer
+                .allocate( ( ( SyncStateValueDecorator ) syncStateValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a SyncStateValue control with an empty sequence
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeSyncStateValueControlEmptySequence() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            {
+                0x30, 0x00 // SyncStateValue ::= SEQUENCE {
+        } );
+        bb.flip();
+
+        SyncStateValue decorator = new SyncStateValueDecorator( codec );
+
+        ( ( SyncStateValueDecorator ) decorator ).decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a SyncStateValue control with no syncState
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeSyncStateValueControlNoSyancState() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            {
+                0x30, 0x05, // SyncStateValue ::= SEQUENCE {
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c' //     cookie syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncStateValue decorator = new SyncStateValueDecorator( codec );
+
+        ( ( SyncStateValueDecorator ) decorator ).decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a SyncStateValue control with no syncUUID
+     */
+    @Test(expected = DecoderException.class)
+    public void testDecodeSyncStateValueControlNoSyncUUID() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            {
+                0x30, 0x03, // SyncStateValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x02, //     state ENUMERATED {
+                      //         modify (2)
+                      //     }
+            } );
+        bb.flip();
+
+        SyncStateValue decorator = new SyncStateValueDecorator( codec );
+
+        ( ( SyncStateValueDecorator ) decorator ).decode( bb.array() );
+    }
+
+
+    /**
+     * Test the decoding of a SyncStateValue control with a refreshOnly mode
+     * and MODDN state type
+     */
+    @Test
+    public void testDecodeSyncStateValueControlWithModDnStateType() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 16 );
+        bb.put( new byte[]
+            {
+                0x30, ( byte ) 14, // SyncStateValue ::= SEQUENCE {
+                0x0A,
+                0x01,
+                0x04, //     state ENUMERATED {
+                      //         present (0)
+                      //     }
+                0x04,
+                0x03,
+                'a',
+                'b',
+                'c', //     entryUUID syncUUID OPTIONAL,
+                0x04,
+                0x04,
+                'x',
+                'k',
+                'c',
+                'd' //     cookie syncCookie OPTIONAL,
+        } );
+        bb.flip();
+
+        SyncStateValue decorator = new SyncStateValueDecorator( codec );
+
+        SyncStateValue syncStateValue = ( SyncStateValue ) ( ( SyncStateValueDecorator ) decorator )
+            .decode( bb.array() );
+
+        assertEquals( SyncStateTypeEnum.MODDN, syncStateValue.getSyncStateType() );
+        assertEquals( "abc", Strings.utf8ToString( syncStateValue.getEntryUUID() ) );
+        assertEquals( "xkcd", Strings.utf8ToString( syncStateValue.getCookie() ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer encoded = ( ( SyncStateValueDecorator ) syncStateValue ).encode( ByteBuffer
+                .allocate( ( ( SyncStateValueDecorator ) syncStateValue ).computeLength() ) );
+            assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+        }
+        catch ( EncoderException ee )
+        {
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/vlv/VLVTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/vlv/VLVTest.java
new file mode 100644
index 0000000..9aaf71f
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/controls/vlv/VLVTest.java
@@ -0,0 +1,544 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.extras.controls.vlv;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.ldap.extras.AbstractCodecServiceTest;
+import org.apache.directory.api.ldap.extras.controls.vlv_impl.VirtualListViewRequestDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+
+
+/**
+ * VLV control tests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class VLVTest extends AbstractCodecServiceTest
+{
+    @Test
+    public void testDecodeOffsetWithContextID() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x16 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x14,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0xA0,
+                0x06,
+                0x02, // offset
+                0x01,
+                0x01,
+                0x02, // contentCount
+                0x01,
+                0x01,
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        VirtualListViewRequest virtualListView = ( VirtualListViewRequest ) control.decode( bb.array() );
+
+        assertEquals( 1, virtualListView.getBeforeCount() );
+        assertEquals( 1, virtualListView.getAfterCount() );
+        assertTrue( virtualListView.hasOffset() );
+        assertEquals( 1, virtualListView.getOffset() );
+        assertEquals( 1, virtualListView.getContentCount() );
+        assertEquals( "abcd", Strings.utf8ToString( virtualListView.getContextId() ) );
+
+        ByteBuffer encoded = ( ( VirtualListViewRequestDecorator ) virtualListView ).encode(
+            ByteBuffer.allocate( ( ( VirtualListViewRequestDecorator ) virtualListView ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeOffsetWithoutContextID() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x10 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x0E,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0xA0,
+                0x06,
+                0x02, // offset
+                0x01,
+                0x01,
+                0x02, // ContentCount
+                0x01,
+                0x01
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        VirtualListViewRequest virtualListView = ( VirtualListViewRequest ) control.decode( bb.array() );
+
+        assertEquals( 1, virtualListView.getBeforeCount() );
+        assertEquals( 1, virtualListView.getAfterCount() );
+        assertTrue( virtualListView.hasOffset() );
+        assertEquals( 1, virtualListView.getOffset() );
+        assertEquals( 1, virtualListView.getContentCount() );
+        assertNull( virtualListView.getContextId() );
+
+        ByteBuffer encoded = ( ( VirtualListViewRequestDecorator ) virtualListView ).encode(
+            ByteBuffer.allocate( ( ( VirtualListViewRequestDecorator ) virtualListView ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeOffsetEmptyContextID() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x12 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x10,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0xA0,
+                0x06,
+                0x02, // offset
+                0x01,
+                0x01,
+                0x02, // ContentCount
+                0x01,
+                0x01,
+                0x04, // ContextID
+                0x00
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        VirtualListViewRequest virtualListView = ( VirtualListViewRequest ) control.decode( bb.array() );
+
+        assertEquals( 1, virtualListView.getBeforeCount() );
+        assertEquals( 1, virtualListView.getAfterCount() );
+        assertTrue( virtualListView.hasOffset() );
+        assertEquals( 1, virtualListView.getOffset() );
+        assertEquals( 1, virtualListView.getContentCount() );
+        assertNull( virtualListView.getContextId() );
+
+        ByteBuffer encoded = ( ( VirtualListViewRequestDecorator ) virtualListView ).encode(
+            ByteBuffer.allocate( ( ( VirtualListViewRequestDecorator ) virtualListView ).computeLength() ) );
+        assertEquals( "0x30 0x0E 0x02 0x01 0x01 0x02 0x01 0x01 0xA0 0x06 0x02 0x01 0x01 0x02 0x01 0x01 ",
+            Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeAssertionValueWithContextID() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x14 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x12,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0x81,
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd',
+                0x04,
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        VirtualListViewRequest virtualListView = ( VirtualListViewRequest ) control.decode( bb.array() );
+
+        assertEquals( 1, virtualListView.getBeforeCount() );
+        assertEquals( 1, virtualListView.getAfterCount() );
+        assertTrue( virtualListView.hasAssertionValue() );
+        assertEquals( "abcd", Strings.utf8ToString( virtualListView.getAssertionValue() ) );
+        assertEquals( "abcd", Strings.utf8ToString( virtualListView.getContextId() ) );
+
+        ByteBuffer encoded = ( ( VirtualListViewRequestDecorator ) virtualListView ).encode(
+            ByteBuffer.allocate( ( ( VirtualListViewRequestDecorator ) virtualListView ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeAssertionValueEmptyContextID() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x10 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x0E,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0x81,
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd',
+                0x04,
+                0x00
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        VirtualListViewRequest virtualListView = ( VirtualListViewRequest ) control.decode( bb.array() );
+
+        assertEquals( 1, virtualListView.getBeforeCount() );
+        assertEquals( 1, virtualListView.getAfterCount() );
+        assertTrue( virtualListView.hasAssertionValue() );
+        assertEquals( "abcd", Strings.utf8ToString( virtualListView.getAssertionValue() ) );
+        assertNull( virtualListView.getContextId() );
+
+        ByteBuffer encoded = ( ( VirtualListViewRequestDecorator ) virtualListView ).encode(
+            ByteBuffer.allocate( ( ( VirtualListViewRequestDecorator ) virtualListView ).computeLength() ) );
+        assertEquals( "0x30 0x0C 0x02 0x01 0x01 0x02 0x01 0x01 0x81 0x04 0x61 0x62 0x63 0x64 ",
+            Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test
+    public void testDecodeAssertionValueWithoutContextID() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0E );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x0C,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0x81,
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        VirtualListViewRequest virtualListView = ( VirtualListViewRequest ) control.decode( bb.array() );
+
+        assertEquals( 1, virtualListView.getBeforeCount() );
+        assertEquals( 1, virtualListView.getAfterCount() );
+        assertTrue( virtualListView.hasAssertionValue() );
+        assertEquals( "abcd", Strings.utf8ToString( virtualListView.getAssertionValue() ) );
+        assertNull( virtualListView.getContextId() );
+
+        ByteBuffer encoded = ( ( VirtualListViewRequestDecorator ) virtualListView ).encode(
+            ByteBuffer.allocate( ( ( VirtualListViewRequestDecorator ) virtualListView ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeEmptySequence() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x2 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x00
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        control.decode( bb.array() );
+        fail();
+    }
+
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeNoBeforeCount() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x13 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x11,
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0xA0,
+                0x06,
+                0x02, // offset
+                0x01,
+                0x01,
+                0x02, // contentCount
+                0x01,
+                0x01,
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        control.decode( bb.array() );
+        fail();
+    }
+
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeNoAfterCount() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x13 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x11,
+                0x02, 0x01, 0x01, // beforeCount
+                ( byte ) 0xA0,
+                0x06,
+                0x02, // offset
+                0x01,
+                0x01,
+                0x02, // contentCount
+                0x01,
+                0x01,
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        control.decode( bb.array() );
+        fail();
+    }
+
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeNoTarget() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x0E );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x0C,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        control.decode( bb.array() );
+        fail();
+    }
+
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeEmptyByOffset() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x10 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x0E,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0xA0,
+                0x00,
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        control.decode( bb.array() );
+        fail();
+    }
+
+
+    @Test
+    public void testDecodeEmptyAssertionValue() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x10 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x0E,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0x81,
+                0x00,
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        VirtualListViewRequest virtualListView = ( VirtualListViewRequest ) control.decode( bb.array() );
+
+        assertEquals( 1, virtualListView.getBeforeCount() );
+        assertEquals( 1, virtualListView.getAfterCount() );
+        assertTrue( virtualListView.hasAssertionValue() );
+        assertEquals( "", Strings.utf8ToString( virtualListView.getAssertionValue() ) );
+        assertEquals( "abcd", Strings.utf8ToString( virtualListView.getContextId() ) );
+
+        ByteBuffer encoded = ( ( VirtualListViewRequestDecorator ) virtualListView ).encode(
+            ByteBuffer.allocate( ( ( VirtualListViewRequestDecorator ) virtualListView ).computeLength() ) );
+        assertEquals( Strings.dumpBytes( bb.array() ), Strings.dumpBytes( encoded.array() ) );
+    }
+
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeByOffsetNoOffsetOrContentCount() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x13 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x11,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0xA0,
+                0x03,
+                0x02,
+                0x01,
+                0x01,
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        control.decode( bb.array() );
+        fail();
+    }
+
+
+    @Test(expected = DecoderException.class)
+    public void testDecodeByOffsetWrongOffset() throws Exception
+    {
+        ByteBuffer bb = ByteBuffer.allocate( 0x16 );
+
+        bb.put( new byte[]
+            {
+                0x30, 0x14,
+                0x02, 0x01, 0x01, // beforeCount
+                0x02,
+                0x01,
+                0x01, // afterCount
+                ( byte ) 0xA0,
+                0x06,
+                0x02,
+                0x01,
+                0x00,
+                0x02,
+                0x01,
+                0x01,
+                0x04, // ContextID
+                0x04,
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        bb.flip();
+
+        VirtualListViewRequestDecorator control = new VirtualListViewRequestDecorator( codec );
+        control.decode( bb.array() );
+        fail();
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelRequestTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelRequestTest.java
new file mode 100644
index 0000000..9083a09
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/cancel/CancelRequestTest.java
@@ -0,0 +1,233 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelDecoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelRequestDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/*
+ * TestCase for a Cancel Extended Operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CancelRequestTest
+{
+    /**
+     * Test the normal Cancel message
+     */
+    @Test
+    public void testDecodeCancel()
+    {
+        Asn1Decoder cancelDecoder = new CancelDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x05 );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x03,
+                0x02, 0x01, 0x01
+        } ).flip();
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+
+        // Allocate a Cancel Container
+        Asn1Container cancelContainer = new CancelContainer();
+
+        // Decode a Cancel message
+        try
+        {
+            cancelDecoder.decode( stream, cancelContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        CancelRequestDecorator cancel = ( ( CancelContainer ) cancelContainer ).getCancel();
+
+        assertEquals( 1, cancel.getCancelId() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = cancel.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test a Cancel message with no cancelId
+     */
+    @Test
+    public void testDecodeCancelNoCancelId()
+    {
+        Asn1Decoder cancelDecoder = new CancelDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x02 );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x00
+        } ).flip();
+
+        // Allocate a Cancel Container
+        Asn1Container cancelContainer = new CancelContainer();
+
+        // Decode a Cancel message
+        try
+        {
+            cancelDecoder.decode( stream, cancelContainer );
+            fail( "CancelID expected" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test a Cancel message with an empty cancelId
+     */
+    @Test
+    public void testDecodeCancelEmptyCancelId()
+    {
+        Asn1Decoder cancelDecoder = new CancelDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x04 );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x02,
+                0x02, 0x00
+        } ).flip();
+
+        // Allocate a Cancel Container
+        Asn1Container cancelContainer = new CancelContainer();
+
+        // Decode a Cancel message
+        try
+        {
+            cancelDecoder.decode( stream, cancelContainer );
+            fail( "CancelID expected" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test a Cancel message with a bad cancelId
+     */
+    @Test
+    public void testDecodeCancelBadCancelId()
+    {
+        Asn1Decoder cancelDecoder = new CancelDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x08 );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x06,
+                0x02, 0x04, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF
+        } ).flip();
+
+        // Allocate a Cancel Container
+        Asn1Container cancelContainer = new CancelContainer();
+
+        // Decode a Cancel message
+        try
+        {
+            cancelDecoder.decode( stream, cancelContainer );
+            fail( "CancelID expected" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test a Cancel message with more than one cancelId
+     */
+    @Test
+    public void testDecodeCancelMoreThanOneCancelId()
+    {
+        Asn1Decoder cancelDecoder = new CancelDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x08 );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x06,
+                0x02, 0x01, 0x01,
+                0x02, 0x01, 0x02
+        } ).flip();
+
+        // Allocate a Cancel Container
+        Asn1Container cancelContainer = new CancelContainer();
+
+        // Decode a Cancel message
+        try
+        {
+            cancelDecoder.decode( stream, cancelContainer );
+            fail( "CancelID expected" );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationRequestTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationRequestTest.java
new file mode 100644
index 0000000..0fd5ace
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/certGeneration/CertGenerationRequestTest.java
@@ -0,0 +1,345 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration.CertGenerationContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration.CertGenerationRequestDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * 
+ * Test case for CertGenerate extended operation request.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CertGenerationRequestTest
+{
+
+    /**
+     * test the decode operation
+     */
+    @Test
+    public void testCertGenrationDecode()
+    {
+        String dn = "uid=admin,ou=system";
+        String keyAlgo = "RSA";
+
+        Asn1Decoder decoder = new Asn1Decoder();
+
+        int dnLen = dn.length();
+
+        // start Tag + L is 2 bytes
+        // the same value of Dn is used for all target,issuer and subject DNs so
+        // it is ( ( OCTET_STRING Tag + Len ) + dnLen ) * 3 
+        // finally for keyAlgo ( OCTET_STRING Tag + Len ) + keyAlgoLen
+
+        int bufLen = 2 + ( ( 2 + dnLen ) * 3 ) + ( keyAlgo.length() + 2 );
+
+        ByteBuffer bb = ByteBuffer.allocate( bufLen );
+
+        bb.put( new byte[]
+            { 0x30, ( byte ) ( bufLen - 2 ) } ); // CertGenerateObject ::= SEQUENCE {
+
+        /*  targetDN IA5String,
+        *   issuerDN IA5String,
+        *   subjectDN IA5String,
+        *   keyAlgorithm IA5String
+        */
+        for ( int i = 0; i < 3; i++ )
+        {
+            bb.put( new byte[]
+                { 0x04, ( byte ) dnLen } );
+            for ( char c : dn.toCharArray() )
+            {
+                bb.put( ( byte ) c );
+            }
+        }
+        bb.put( new byte[]
+            { 0x04, 0x03, 'R', 'S', 'A' } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        CertGenerationContainer container = new CertGenerationContainer();
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException e )
+        {
+            fail( e.getMessage() );
+        }
+
+        CertGenerationRequestDecorator req = container.getCertGenerationRequest();
+        assertEquals( dn, req.getTargetDN() );
+        assertEquals( dn, req.getIssuerDN() );
+        assertEquals( dn, req.getSubjectDN() );
+        assertEquals( keyAlgo, req.getKeyAlgorithm() );
+
+        assertEquals( bufLen, req.computeLengthInternal() );
+
+        try
+        {
+            ByteBuffer encodedBuf = req.encodeInternal();
+            String encodedPdu = Strings.dumpBytes( encodedBuf.array() );
+
+            assertEquals( decodedPdu, encodedPdu );
+        }
+        catch ( EncoderException e )
+        {
+            e.getMessage();
+            fail( e.getMessage() );
+        }
+
+    }
+
+
+    @Test
+    public void testCertGenerationDecodeTargetDN()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+
+        ByteBuffer bb = ByteBuffer.allocate( 5 );
+
+        bb.put( new byte[]
+            { 0x30, 0x03, // CertGenerateObject ::= SEQUENCE {
+                0x04,
+                0x01,
+                ' ' } ); // empty targetDN value
+
+        bb.flip();
+
+        CertGenerationContainer container = new CertGenerationContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+            fail( "shouldn't accept the empty targetDN" );
+        }
+        catch ( DecoderException e )
+        {
+            assertTrue( true );
+        }
+
+        String dn = "=sys";
+
+        bb = ByteBuffer.allocate( dn.length() + 2 + 2 );
+
+        bb.put( new byte[]
+            { 0x30, ( byte ) ( dn.length() + 2 ), // CertGenerateObject ::= SEQUENCE {
+                0x04,
+                ( byte ) dn.length(),
+                '=',
+                's',
+                'y',
+                's' } ); // empty targetDN value
+
+        bb.flip();
+
+        try
+        {
+            decoder.decode( bb, container );
+            fail( "shouldn't accept the invalid targetDN" );
+        }
+        catch ( DecoderException e )
+        {
+            assertTrue( true );
+        }
+
+    }
+
+
+    @Test
+    public void testCertGenerationDecodeIssuerDN()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+
+        ByteBuffer bb = ByteBuffer.allocate( 11 );
+
+        bb.put( new byte[]
+            { 0x30, 0x09, // CertGenerateObject ::= SEQUENCE {
+                0x04,
+                0x04,
+                'c',
+                'n',
+                '=',
+                'x', // target Dn string
+                0x04,
+                0x01,
+                ' ' } ); // empty issuer Dn
+
+        CertGenerationContainer container = new CertGenerationContainer();
+        bb.flip();
+
+        try
+        {
+            decoder.decode( bb, container );
+            fail();
+        }
+        catch ( DecoderException e )
+        {
+            assertTrue( true );
+        }
+
+        bb = ByteBuffer.allocate( 12 );
+
+        bb.put( new byte[]
+            { 0x30, 0x10, // CertGenerateObject ::= SEQUENCE {
+                0x04,
+                0x04,
+                'c',
+                'n',
+                '=',
+                'x', // target Dn string
+                0x04,
+                0x02,
+                '=',
+                'x' } ); // empty issuer Dn
+
+        bb.flip();
+
+        try
+        {
+            decoder.decode( bb, container );
+            fail( "shouldn't accept the invalid issuerDN" );
+        }
+        catch ( DecoderException e )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCertGenerationDecodeWithoutSubjectDN()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+
+        ByteBuffer bb = ByteBuffer.allocate( 17 );
+
+        bb.put( new byte[]
+            { 0x30, 0x15, // CertGenerateObject ::= SEQUENCE {
+                0x04,
+                0x04,
+                'c',
+                'n',
+                '=',
+                'x', // target Dn string
+                0x04,
+                0x04,
+                'c',
+                'n',
+                '=',
+                'x', // issuer Dn
+                0x04,
+                0x01,
+                ' ' } ); // empty subject Dn
+
+        CertGenerationContainer container = new CertGenerationContainer();
+        bb.flip();
+
+        try
+        {
+            decoder.decode( bb, container );
+            fail();
+        }
+        catch ( DecoderException e )
+        {
+            assertTrue( true );
+        }
+
+        bb = ByteBuffer.allocate( 18 );
+
+        bb.put( new byte[]
+            { 0x30, 0x16, // CertGenerateObject ::= SEQUENCE {
+                0x04,
+                0x04,
+                'c',
+                'n',
+                '=',
+                'x', // target Dn string
+                0x04,
+                0x04,
+                'c',
+                'n',
+                '=',
+                'x', // issuer Dn
+                0x04,
+                0x02,
+                '=',
+                'x' } ); // invalid subject Dn
+
+        bb.flip();
+
+        try
+        {
+            decoder.decode( bb, container );
+            fail( "shouldn't accept the invalid subject Dn" );
+        }
+        catch ( DecoderException e )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testDecodeEmptySequence()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+
+        ByteBuffer bb = ByteBuffer.allocate( 2 );
+
+        bb.put( new byte[]
+            { 0x30, 0x00 } ); // CertGenerateObject ::= SEQUENCE {
+
+        CertGenerationContainer container = new CertGenerationContainer();
+        bb.flip();
+
+        try
+        {
+            decoder.decode( bb, container );
+            // The PDU with an empty sequence is not allowed
+            fail();
+        }
+        catch ( DecoderException e )
+        {
+            assertTrue( true );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectResponseTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectResponseTest.java
new file mode 100644
index 0000000..5c6860e
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulDisconnect/GracefulDisconnectResponseTest.java
@@ -0,0 +1,803 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectDecoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectResponseDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the GracefulDisconnectTest codec
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class GracefulDisconnectResponseTest
+{
+    /**
+     * Test the decoding of a GracefulDisconnect
+     */
+    @Test
+    public void testDecodeGracefulDisconnectSuccess()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer stream = ByteBuffer.allocate( 0x70 );
+        stream.put( new byte[]
+            { 0x30, 0x6E, // GracefulDisconnec ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // timeOffline INTEGER (0..720) DEFAULT 0,
+                ( byte ) 0x80,
+                0x01,
+                0x01, // delay INTEGER (0..86400) DEFAULT
+                      // 0
+                // replicatedContexts Referral OPTIONAL
+                0x30,
+                0x66,
+                0x04,
+                0x1F,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                'd',
+                'i',
+                'r',
+                'e',
+                'c',
+                't',
+                'o',
+                'r',
+                'y',
+                '.',
+                'a',
+                'p',
+                'a',
+                'c',
+                'h',
+                'e',
+                '.',
+                'o',
+                'r',
+                'g',
+                ':',
+                '8',
+                '0',
+                '/',
+                0x04,
+                0x43,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                'l',
+                'd',
+                'a',
+                'p',
+                '.',
+                'n',
+                'e',
+                't',
+                's',
+                'c',
+                'a',
+                'p',
+                'e',
+                '.',
+                'c',
+                'o',
+                'm',
+                '/',
+                'o',
+                '=',
+                'B',
+                'a',
+                'b',
+                's',
+                'c',
+                'o',
+                ',',
+                'c',
+                '=',
+                'U',
+                'S',
+                '?',
+                '?',
+                '?',
+                '(',
+                'i',
+                'n',
+                't',
+                '=',
+                '%',
+                '5',
+                'c',
+                '0',
+                '0',
+                '%',
+                '5',
+                'c',
+                '0',
+                '0',
+                '%',
+                '5',
+                'c',
+                '0',
+                '0',
+                '%',
+                '5',
+                'c',
+                '0',
+                '4',
+                ')'
+            // }
+        } );
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulDisconnectResponseDecorator gracefulDisconnect = container.getGracefulDisconnectResponse();
+        assertEquals( 1, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 1, gracefulDisconnect.getDelay() );
+        assertEquals( 2, gracefulDisconnect.getReplicatedContexts().getLdapUrls().size() );
+        
+        Iterator<String> ldapUrls = gracefulDisconnect.getReplicatedContexts().getLdapUrls().iterator();
+        assertEquals( "ldap://directory.apache.org:80/", ldapUrls.next() );
+        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)", ldapUrls.next() );
+
+        // Check the length
+        assertEquals( 0x70, gracefulDisconnect.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = gracefulDisconnect.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a timeOffline only
+     */
+    @Test
+    public void testDecodeGracefulDisconnectTimeOffline()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            { 0x30, 0x03, // GracefulDisconnect ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01 // timeOffline INTEGER (0..720) DEFAULT 0,
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulDisconnectResponseDecorator gracefulDisconnect = container.getGracefulDisconnectResponse();
+        assertEquals( 1, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 0, gracefulDisconnect.getDelay() );
+        assertEquals( 0, gracefulDisconnect.getReplicatedContexts().getLdapUrls().size() );
+
+        // Check the length
+        assertEquals( 0x05, gracefulDisconnect.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulDisconnect.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a delay only
+     */
+    @Test
+    public void testDecodeGracefulDisconnectDelay()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            { 0x30, 0x03, // GracefulDisconnect ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x01,
+                0x01 // delay INTEGER (0..86400) DEFAULT
+                     // 0
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulDisconnectResponseDecorator gracefulDisconnect = container.getGracefulDisconnectResponse();
+        assertEquals( 0, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 1, gracefulDisconnect.getDelay() );
+        assertEquals( 0, gracefulDisconnect.getReplicatedContexts().getLdapUrls().size() );
+
+        // Check the length
+        assertEquals( 0x05, gracefulDisconnect.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulDisconnect.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a timeOffline and a delay
+     */
+    @Test
+    public void testDecodeGracefulDisconnectTimeOfflineDelay()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            { 0x30, 0x06, // GracefulDisconnect ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // timeOffline INTEGER (0..720) DEFAULT 0,
+                ( byte ) 0x80,
+                0x01,
+                0x01, // timeOffline INTEGER (0..720)
+                      // DEFAULT 0,
+            } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulDisconnectResponseDecorator gracefulDisconnect = container.getGracefulDisconnectResponse();
+        assertEquals( 1, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 1, gracefulDisconnect.getDelay() );
+        assertEquals( 0, gracefulDisconnect.getReplicatedContexts().getLdapUrls().size() );
+
+        // Check the length
+        assertEquals( 0x08, gracefulDisconnect.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb2 = gracefulDisconnect.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb2.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with replicatedContexts only
+     */
+    @Test
+    public void testDecodeGracefulDisconnectReplicatedContextsOnly()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer stream = ByteBuffer.allocate( 0x6A );
+        stream.put( new byte[]
+            {
+                0x30, 0x68, // GracefulDisconnec ::= SEQUENCE {
+                0x30,
+                0x66, // replicatedContexts Referral OPTIONAL
+                0x04,
+                0x1F,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                'd',
+                'i',
+                'r',
+                'e',
+                'c',
+                't',
+                'o',
+                'r',
+                'y',
+                '.',
+                'a',
+                'p',
+                'a',
+                'c',
+                'h',
+                'e',
+                '.',
+                'o',
+                'r',
+                'g',
+                ':',
+                '8',
+                '0',
+                '/',
+                0x04,
+                0x43,
+                'l',
+                'd',
+                'a',
+                'p',
+                ':',
+                '/',
+                '/',
+                'l',
+                'd',
+                'a',
+                'p',
+                '.',
+                'n',
+                'e',
+                't',
+                's',
+                'c',
+                'a',
+                'p',
+                'e',
+                '.',
+                'c',
+                'o',
+                'm',
+                '/',
+                'o',
+                '=',
+                'B',
+                'a',
+                'b',
+                's',
+                'c',
+                'o',
+                ',',
+                'c',
+                '=',
+                'U',
+                'S',
+                '?',
+                '?',
+                '?',
+                '(',
+                'i',
+                'n',
+                't',
+                '=',
+                '%',
+                '5',
+                'c',
+                '0',
+                '0',
+                '%',
+                '5',
+                'c',
+                '0',
+                '0',
+                '%',
+                '5',
+                'c',
+                '0',
+                '0',
+                '%',
+                '5',
+                'c',
+                '0',
+                '4',
+                ')'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( stream, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulDisconnectResponseDecorator gracefulDisconnect = container.getGracefulDisconnectResponse();
+        assertEquals( 0, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 0, gracefulDisconnect.getDelay() );
+        assertEquals( 2, gracefulDisconnect.getReplicatedContexts().getLdapUrls().size() );
+        
+        Iterator<String> ldapUrls = gracefulDisconnect.getReplicatedContexts().getLdapUrls().iterator();
+        assertEquals( "ldap://directory.apache.org:80/", ldapUrls.next() );
+        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)", ldapUrls.next() );
+
+        // Check the length
+        assertEquals( 0x6A, gracefulDisconnect.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = gracefulDisconnect.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a empty GracefulDisconnect
+     */
+    @Test
+    public void testDecodeGracefulDisconnectEmpty()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            { 0x30, 0x00 // GracefulDisconnect ::= SEQUENCE {
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulDisconnectResponseDecorator gracefulDisconnect = container.getGracefulDisconnectResponse();
+        assertEquals( 0, gracefulDisconnect.getTimeOffline() );
+        assertEquals( 0, gracefulDisconnect.getDelay() );
+        assertEquals( 0, gracefulDisconnect.getReplicatedContexts().getLdapUrls().size() );
+
+        // Check the length
+        assertEquals( 0x02, gracefulDisconnect.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulDisconnect.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    // Defensive tests
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a timeOffline off limit
+     */
+    @Test
+    public void testDecodeGracefulDisconnectTimeOfflineOffLimit()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            { 0x30, 0x04, // GracefulDisconnect ::= SEQUENCE {
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8 // timeOffline INTEGER (0..720)
+                              // DEFAULT 0,
+        } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with a delay off limit
+     */
+    @Test
+    public void testDecodeGracefulDisconnectDelayOffLimit()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            { 0x30, 0x05, // GracefulDisconnect ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x03,
+                0x01,
+                ( byte ) 0x86,
+                ( byte ) 0xA0 // delay
+                              // INTEGER
+                              // (0..86400)
+                              // DEFAULT
+                              // 0
+        } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with an empty TimeOffline
+     */
+    @Test
+    public void testDecodeGracefulDisconnectTimeOfflineEmpty()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            { 0x30, 0x02, // GracefulDisconnect ::= SEQUENCE {
+                0x02,
+                0x00 // timeOffline INTEGER (0..720) DEFAULT 0,
+        } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with an empty delay
+     */
+    @Test
+    public void testDecodeGracefulDisconnectDelayEmpty()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            { 0x30, 0x02, // GracefulDisconnect ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x00 // delay INTEGER (0..86400) DEFAULT 0
+        } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with an empty replicated
+     * contexts
+     */
+    @Test
+    public void testDecodeGracefulDisconnectReplicatedContextsEmpty()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x04 );
+        bb.put( new byte[]
+            { 0x30, 0x02, // GracefulDisconnect ::= SEQUENCE {
+                0x30,
+                0x00 // replicatedContexts Referral OPTIONAL
+        } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulDisconnect with an invalid replicated
+     * context
+     */
+    @Test
+    public void testDecodeGracefulDisconnectReplicatedContextsInvalid()
+    {
+        Asn1Decoder decoder = new GracefulDisconnectDecoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x06 );
+        bb.put( new byte[]
+            { 0x30, 0x04, // GracefulDisconnect ::= SEQUENCE {
+                0x30,
+                0x02, // replicatedContexts Referral OPTIONAL
+                0x04,
+                0x00 } );
+        bb.flip();
+
+        GracefulDisconnectContainer container = new GracefulDisconnectContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownTest.java
new file mode 100644
index 0000000..46101de
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/gracefulShutdown/GracefulShutdownTest.java
@@ -0,0 +1,578 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown.GracefulShutdownContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown.GracefulShutdownRequestDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the GracefulShutdownTest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class GracefulShutdownTest
+{
+    /**
+     * Test the decoding of a GracefulShutdown
+     */
+    @Test
+    public void testDecodeGracefulShutdownSuccess()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            { 0x30, 0x06, // GracefulShutdown ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01, // timeOffline INTEGER (0..720) DEFAULT 0,
+                ( byte ) 0x80,
+                0x01,
+                0x01 // delay INTEGER (0..86400) DEFAULT
+                     // 0
+            // }
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulShutdownRequestDecorator gracefulShutdownRequest = container.getGracefulShutdownRequest();
+        assertEquals( 1, gracefulShutdownRequest.getTimeOffline() );
+        assertEquals( 1, gracefulShutdownRequest.getDelay() );
+
+        // Check the length
+        assertEquals( 0x08, gracefulShutdownRequest.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulShutdownRequest.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with a timeOffline only
+     */
+    @Test
+    public void testDecodeGracefulShutdownTimeOffline()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            { 0x30, 0x03, // GracefulShutdown ::= SEQUENCE {
+                0x02,
+                0x01,
+                0x01 // timeOffline INTEGER (0..720) DEFAULT 0,
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulShutdownRequestDecorator gracefulShutdownRequest = container.getGracefulShutdownRequest();
+        assertEquals( 1, gracefulShutdownRequest.getTimeOffline() );
+        assertEquals( 0, gracefulShutdownRequest.getDelay() );
+
+        // Check the length
+        assertEquals( 0x05, gracefulShutdownRequest.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulShutdownRequest.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with a delay only
+     */
+    @Test
+    public void testDecodeGracefulShutdownDelay()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            { 0x30, 0x03, // GracefulShutdown ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x01,
+                0x01 // delay INTEGER (0..86400) DEFAULT
+                     // 0
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulShutdownRequestDecorator gracefulShutdownRequest = container.getGracefulShutdownRequest();
+        assertEquals( 0, gracefulShutdownRequest.getTimeOffline() );
+        assertEquals( 1, gracefulShutdownRequest.getDelay() );
+
+        // Check the length
+        assertEquals( 0x05, gracefulShutdownRequest.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulShutdownRequest.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a empty GracefulShutdown
+     */
+    @Test
+    public void testDecodeGracefulShutdownEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            { 0x30, 0x00 // GracefulShutdown ::= SEQUENCE {
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulShutdownRequestDecorator gracefulShutdownRequest = container.getGracefulShutdownRequest();
+        assertEquals( 0, gracefulShutdownRequest.getTimeOffline() );
+        assertEquals( 0, gracefulShutdownRequest.getDelay() );
+
+        // Check the length
+        assertEquals( 0x02, gracefulShutdownRequest.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulShutdownRequest.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with a delay above 128
+     */
+    @Test
+    public void testDecodeGracefulShutdownDelayHigh()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x06 );
+        bb.put( new byte[]
+            { 0x30, 0x04, // GracefulShutdown ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x02,
+                0x01,
+                ( byte ) 0xF4 // delay INTEGER
+                              // (0..86400)
+                              // DEFAULT 0
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulShutdownRequestDecorator gracefulShutdownRequest = container.getGracefulShutdownRequest();
+        assertEquals( 0, gracefulShutdownRequest.getTimeOffline() );
+        assertEquals( 500, gracefulShutdownRequest.getDelay() );
+
+        // Check the length
+        assertEquals( 0x06, gracefulShutdownRequest.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulShutdownRequest.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with a delay equals 32767
+     */
+    @Test
+    public void testDecodeGracefulShutdownDelay32767()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x06 );
+        bb.put( new byte[]
+            { 0x30, 0x04, // GracefulShutdown ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x02,
+                0x7F,
+                ( byte ) 0xFF // delay INTEGER
+                              // (0..86400)
+                              // DEFAULT 0
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulShutdownRequestDecorator gracefulShutdownRequest = container.getGracefulShutdownRequest();
+        assertEquals( 0, gracefulShutdownRequest.getTimeOffline() );
+        assertEquals( 32767, gracefulShutdownRequest.getDelay() );
+
+        // Check the length
+        assertEquals( 0x06, gracefulShutdownRequest.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulShutdownRequest.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with a delay above 32768
+     */
+    @Test
+    public void testDecodeGracefulShutdownDelay32768()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x07 );
+        bb.put( new byte[]
+            { 0x30, 0x05, // GracefulShutdown ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x03,
+                0x00,
+                ( byte ) 0x80,
+                ( byte ) 0x00 // delay
+                              // INTEGER
+                              // (0..86400)
+                              // DEFAULT
+                              // 0
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        GracefulShutdownRequestDecorator gracefulShutdownRequest = container.getGracefulShutdownRequest();
+        assertEquals( 0, gracefulShutdownRequest.getTimeOffline() );
+        assertEquals( 32768, gracefulShutdownRequest.getDelay() );
+
+        // Check the length
+        assertEquals( 0x07, gracefulShutdownRequest.computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = gracefulShutdownRequest.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    // Defensive tests
+
+    /**
+     * Test the decoding of a GracefulShutdown with a timeOffline off limit
+     */
+    @Test
+    public void testDecodeGracefulShutdownTimeOfflineOffLimit()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x06 );
+        bb.put( new byte[]
+            { 0x30, 0x04, // GracefulShutdown ::= SEQUENCE {
+                0x02,
+                0x02,
+                0x03,
+                ( byte ) 0xE8 // timeOffline INTEGER (0..720)
+                              // DEFAULT 0,
+        } );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with a delay off limit
+     */
+    @Test
+    public void testDecodeGracefulShutdownDelayOffLimit()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            { 0x30, 0x05, // GracefulShutdown ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x03,
+                0x01,
+                ( byte ) 0x86,
+                ( byte ) 0xA0 // delay
+                              // INTEGER
+                              // (0..86400)
+                              // DEFAULT
+                              // 0
+        } );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with an empty TimeOffline
+     */
+    @Test
+    public void testDecodeGracefulShutdownTimeOfflineEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            { 0x30, 0x02, // GracefulShutdown ::= SEQUENCE {
+                0x02,
+                0x00 // timeOffline INTEGER (0..720) DEFAULT 0,
+        } );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+
+
+    /**
+     * Test the decoding of a GracefulShutdown with an empty delay
+     */
+    @Test
+    public void testDecodeGracefulShutdownDelayEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0b );
+        bb.put( new byte[]
+            { 0x30, 0x02, // GracefulShutdown ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x00 // delay INTEGER (0..86400) DEFAULT 0
+        } );
+        bb.flip();
+
+        GracefulShutdownContainer container = new GracefulShutdownContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            assertTrue( true );
+            return;
+        }
+
+        fail( "We should not reach this point" );
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestTest.java
new file mode 100644
index 0000000..b2038dd
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyRequestTest.java
@@ -0,0 +1,863 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyRequestContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyRequestDecorator;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyRequest;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the PasswordModifyRequest codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PasswordModifyRequestTest
+{
+    /**
+     * Test the decoding of a PasswordModifyRequest with nothing in it
+     */
+    @Test
+    public void testDecodePasswordModifyRequestEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            { 0x30, 0x00, // PasswordModifyRequest ::= SEQUENCE {
+            } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNull( pwdModifyRequest.getUserIdentity() );
+        assertNull( pwdModifyRequest.getOldPassword() );
+        assertNull( pwdModifyRequest.getNewPassword() );
+
+        // Check the length
+        assertEquals( 0x02, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with an empty user identity
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityNull()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x04 );
+        bb.put( new byte[]
+            { 0x30, 0x02, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x00 // userIdentity    [0]  OCTET STRING OPTIONAL
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( 0, pwdModifyRequest.getUserIdentity().length );
+        assertNull( pwdModifyRequest.getOldPassword() );
+        assertNull( pwdModifyRequest.getNewPassword() );
+
+        // Check the length
+        assertEquals( 0x04,  ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with a user identity
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityValue()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            { 0x30, 0x06, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // userIdentity    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getUserIdentity() ) );
+        assertNull( pwdModifyRequest.getOldPassword() );
+        assertNull( pwdModifyRequest.getNewPassword() );
+
+        // Check the length
+        assertEquals( 0x08, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with a user identity and
+     * an empty newPassword
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityValueNewPasswordEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            { 0x30, 0x08, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // userIdentity    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x82, // newPassword    [2]  OCTET STRING OPTIONAL
+                0x00
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getUserIdentity() ) );
+        assertNull( pwdModifyRequest.getOldPassword() );
+        assertNotNull( pwdModifyRequest.getNewPassword() );
+        assertEquals( 0, pwdModifyRequest.getNewPassword().length );
+
+        // Check the length
+        assertEquals( 0x0A, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with a user identity and
+     * a newPassword
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityValueNewPassword()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0E );
+        bb.put( new byte[]
+            { 0x30, 0x0C, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // userIdentity    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x82, // newPassword    [2]  OCTET STRING OPTIONAL
+                0x04,
+                'e',
+                'f',
+                'g',
+                'h'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getUserIdentity() ) );
+        assertNull( pwdModifyRequest.getOldPassword() );
+        assertNotNull( pwdModifyRequest.getNewPassword() );
+        assertEquals( "efgh", Strings.utf8ToString( pwdModifyRequest.getNewPassword() ) );
+
+        // Check the length
+        assertEquals( 0x0E, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with a user identity
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityValueOldPasswordEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            { 0x30, 0x08, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // userIdentity    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x81,
+                0x00 // oldPassword    [1]  OCTET STRING OPTIONAL
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getUserIdentity() ) );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( 0, pwdModifyRequest.getOldPassword().length );
+        assertNull( pwdModifyRequest.getNewPassword() );
+
+        // Check the length
+        assertEquals( 0x0A, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with a user identity
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityValueOldPasswordValue()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0E );
+        bb.put( new byte[]
+            { 0x30, 0x0C, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // userIdentity    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x81,
+                0x04, // oldPassword    [1]  OCTET STRING OPTIONAL
+                'e',
+                'f',
+                'g',
+                'h'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getUserIdentity() ) );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( "efgh", Strings.utf8ToString( pwdModifyRequest.getOldPassword() ) );
+        assertNull( pwdModifyRequest.getNewPassword() );
+
+        // Check the length
+        assertEquals( 0x0E, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with a user identity, and oldPassword and
+     * and empty newPassword
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityValueOldPasswordValueNewPasswordNull()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x10 );
+        bb.put( new byte[]
+            { 0x30, 0x0E, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // userIdentity    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x81,
+                0x04, // oldPassword    [1]  OCTET STRING OPTIONAL
+                'e',
+                'f',
+                'g',
+                'h',
+                ( byte ) 0x82, // newPassword    [2]  OCTET STRING OPTIONAL
+                0x00
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getUserIdentity() ) );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( "efgh", Strings.utf8ToString( pwdModifyRequest.getOldPassword() ) );
+        assertNotNull( pwdModifyRequest.getNewPassword() );
+        assertEquals( 0, pwdModifyRequest.getNewPassword().length );
+
+        // Check the length
+        assertEquals( 0x10, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with a user identity, and oldPassword and
+     * and a newPassword
+     */
+    @Test
+    public void testDecodePasswordModifyRequestUserIdentityValueOldPasswordValueNewPasswordValue()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x14 );
+        bb.put( new byte[]
+            { 0x30, 0x12, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // userIdentity    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x81,
+                0x04, // oldPassword    [1]  OCTET STRING OPTIONAL
+                'e',
+                'f',
+                'g',
+                'h',
+                ( byte ) 0x82, // newPassword    [2]  OCTET STRING OPTIONAL
+                0x04,
+                'i',
+                'j',
+                'k',
+                'l'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNotNull( pwdModifyRequest.getUserIdentity() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getUserIdentity() ) );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( "efgh", Strings.utf8ToString( pwdModifyRequest.getOldPassword() ) );
+        assertNotNull( pwdModifyRequest.getNewPassword() );
+        assertEquals( "ijkl", Strings.utf8ToString( pwdModifyRequest.getNewPassword() ) );
+
+        // Check the length
+        assertEquals( 0x14, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with an empty user identity
+     */
+    @Test
+    public void testDecodePasswordModifyRequestOldPasswordNull()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x04 );
+        bb.put( new byte[]
+            { 0x30, 0x02, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x81,
+                0x00 // oldPassword    [1]  OCTET STRING OPTIONAL
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNull( pwdModifyRequest.getUserIdentity() );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( 0, pwdModifyRequest.getOldPassword().length );
+        assertNull( pwdModifyRequest.getNewPassword() );
+
+        // Check the length
+        assertEquals( 0x04, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with an oldPassword
+     */
+    @Test
+    public void testDecodePasswordModifyRequestOldPasswordValue()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            { 0x30, 0x06, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x81,
+                0x04, // oldPassword    [1]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNull( pwdModifyRequest.getUserIdentity() );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getOldPassword() ) );
+        assertNull( pwdModifyRequest.getNewPassword() );
+
+        // Check the length
+        assertEquals( 0x08, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with an oldPassword and an
+     * empty  newPassword
+     */
+    @Test
+    public void testDecodePasswordModifyRequestOldPasswordValueNewPasswordEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0A );
+        bb.put( new byte[]
+            { 0x30, 0x08, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x81,
+                0x04, // oldPassword    [1]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x82, // newPassword    [2]  OCTET STRING OPTIONAL
+                0x00
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNull( pwdModifyRequest.getUserIdentity() );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getOldPassword() ) );
+        assertNotNull( pwdModifyRequest.getNewPassword() );
+        assertEquals( 0, pwdModifyRequest.getNewPassword().length );
+
+        // Check the length
+        assertEquals( 0x0A, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyRequest with an oldPassword and an
+     * newPassword
+     */
+    @Test
+    public void testDecodePasswordModifyRequestOldPasswordValueNewPasswordValue()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x0E );
+        bb.put( new byte[]
+            { 0x30, 0x0C, // PasswordModifyRequest ::= SEQUENCE {
+                ( byte ) 0x81,
+                0x04, // oldPassword    [1]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd',
+                ( byte ) 0x82, // newPassword    [2]  OCTET STRING OPTIONAL
+                0x04,
+                'e',
+                'f',
+                'g',
+                'h'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyRequestContainer container = new PasswordModifyRequestContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyRequest pwdModifyRequest = container.getPwdModifyRequest();
+        assertNull( pwdModifyRequest.getUserIdentity() );
+        assertNotNull( pwdModifyRequest.getOldPassword() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyRequest.getOldPassword() ) );
+        assertNotNull( pwdModifyRequest.getNewPassword() );
+        assertEquals( "efgh", Strings.utf8ToString( pwdModifyRequest.getNewPassword() ) );
+
+        // Check the length
+        assertEquals( 0x0E, ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyRequestDecorator ) pwdModifyRequest ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseTest.java
new file mode 100644
index 0000000..436b76a
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/pwdModify/PasswordModifyResponseTest.java
@@ -0,0 +1,211 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyResponseContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.pwdModify.PasswordModifyResponseDecorator;
+import org.apache.directory.api.ldap.extras.extended.pwdModify.PasswordModifyResponse;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the PasswordModifyReponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PasswordModifyResponseTest
+{
+    /**
+     * Test the decoding of a PasswordModifyResponse with nothing in it
+     */
+    @Test
+    public void testDecodePasswordModifyResponseEmpty()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            { 0x30, 0x00, // PasswordModifyResponse ::= SEQUENCE {
+            } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyResponseContainer container = new PasswordModifyResponseContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyResponse pwdModifyResponse = container.getPwdModifyResponse();
+        assertNull( pwdModifyResponse.getGenPassword() );
+
+        // Check the length
+        assertEquals( 0x02, ( ( PasswordModifyResponseDecorator ) pwdModifyResponse ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyResponseDecorator ) pwdModifyResponse ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyResponse with an empty genPassword
+     */
+    @Test
+    public void testDecodePasswordModifyResponseUserIdentityNull()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x04 );
+        bb.put( new byte[]
+            { 0x30, 0x02, // PasswordModifyResponse ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x00 // genPassword    [0]  OCTET STRING OPTIONAL
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyResponseContainer container = new PasswordModifyResponseContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyResponse pwdModifyResponse = container.getPwdModifyResponse();
+        assertNotNull( pwdModifyResponse.getGenPassword() );
+        assertEquals( 0, pwdModifyResponse.getGenPassword().length );
+
+        // Check the length
+        assertEquals( 0x04, ( ( PasswordModifyResponseDecorator ) pwdModifyResponse ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyResponseDecorator ) pwdModifyResponse ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test the decoding of a PasswordModifyResponse with a genPassword
+     */
+    @Test
+    public void testDecodePasswordModifyResponseUserIdentityValue()
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x08 );
+        bb.put( new byte[]
+            { 0x30, 0x06, // PasswordModifyResponse ::= SEQUENCE {
+                ( byte ) 0x80,
+                0x04, // genPassword    [0]  OCTET STRING OPTIONAL
+                'a',
+                'b',
+                'c',
+                'd'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+
+        PasswordModifyResponseContainer container = new PasswordModifyResponseContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        PasswordModifyResponse pwdModifyResponse = container.getPwdModifyResponse();
+        assertNotNull( pwdModifyResponse.getGenPassword() );
+        assertEquals( "abcd", Strings.utf8ToString( pwdModifyResponse.getGenPassword() ) );
+
+        // Check the length
+        assertEquals( 0x08, ( ( PasswordModifyResponseDecorator ) pwdModifyResponse ).computeLengthInternal() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb1 = ( ( PasswordModifyResponseDecorator ) pwdModifyResponse ).encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureTest.java
new file mode 100644
index 0000000..b2259d5
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/storedProcedure/StoredProcedureTest.java
@@ -0,0 +1,246 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureDecoder;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureRequestDecorator;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/*
+ * TestCase for a Stored Procedure Extended Operation ASN.1 codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class StoredProcedureTest
+{
+    @Test
+    public void testDecodeStoredProcedureNParams() throws IntegerDecoderException
+    {
+        Asn1Decoder storedProcedureDecoder = new StoredProcedureDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x44 );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x42,
+                0x04, 0x04, 'J', 'a', 'v', 'a',
+                0x04, 0x07, 'e', 'x', 'e', 'c', 'u', 't', 'e',
+                0x30, 0x31,
+                0x30, 0x08,
+                0x04, 0x03, 'i', 'n', 't',
+                0x04, 0x01, 0x01,
+                0x30, 0x0F,
+                0x04, 0x07, 'b', 'o', 'o', 'l', 'e', 'a', 'n',
+                0x04, 0x04, 't', 'r', 'u', 'e',
+                0x30, 0x14,
+                0x04, 0x06, 'S', 't', 'r', 'i', 'n', 'g',
+                0x04, 0x0A, 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', '3'
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a StoredProcedure Container
+        StoredProcedureContainer storedProcedureContainer = new StoredProcedureContainer();
+
+        // Decode a StoredProcedure message
+        try
+        {
+            storedProcedureDecoder.decode( stream, storedProcedureContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        StoredProcedureRequestDecorator storedProcedure = storedProcedureContainer.getStoredProcedure();
+
+        assertEquals( "Java", storedProcedure.getLanguage() );
+
+        assertEquals( "execute", storedProcedure.getProcedureSpecification() );
+
+        assertEquals( 3, storedProcedure.size() );
+
+        assertEquals( "int", Strings.utf8ToString( ( byte[] ) storedProcedure.getParameterType( 0 ) ) );
+        assertEquals( 1, IntegerDecoder.parse( new BerValue( ( byte[] ) storedProcedure.getParameterValue( 0 ) ) ) );
+
+        assertEquals( "boolean", Strings.utf8ToString( ( byte[] ) storedProcedure.getParameterType( 1 ) ) );
+        assertEquals( "true", Strings.utf8ToString( ( byte[] ) storedProcedure.getParameterValue( 1 ) ) );
+
+        assertEquals( "String", Strings.utf8ToString( ( byte[] ) storedProcedure.getParameterType( 2 ) ) );
+        assertEquals( "parameter3", Strings.utf8ToString( ( byte[] ) storedProcedure.getParameterValue( 2 ) ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = storedProcedure.encodeInternal();
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    @Test
+    public void testDecodeStoredProcedureNoParam()
+    {
+        Asn1Decoder storedProcedureDecoder = new StoredProcedureDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x13 );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x11,
+                0x04, 0x04, 'J', 'a', 'v', 'a',
+                0x04, 0x07, 'e', 'x', 'e', 'c', 'u', 't', 'e',
+                0x30, 0x00
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a StoredProcedure Container
+        StoredProcedureContainer storedProcedureContainer = new StoredProcedureContainer();
+
+        // Decode a StoredProcedure message
+        try
+        {
+            storedProcedureDecoder.decode( stream, storedProcedureContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        StoredProcedureRequestDecorator storedProcedure = storedProcedureContainer.getStoredProcedure();
+
+        assertEquals( "Java", storedProcedure.getLanguage() );
+
+        assertEquals( "execute", storedProcedure.getProcedureSpecification() );
+
+        assertEquals( 0, storedProcedure.size() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = storedProcedure.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    @Test
+    public void testDecodeStoredProcedureOneParam() throws IntegerDecoderException
+    {
+        Asn1Decoder storedProcedureDecoder = new StoredProcedureDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x1D );
+
+        stream.put( new byte[]
+            {
+                0x30, 0x1B,
+                0x04, 0x04, 'J', 'a', 'v', 'a',
+                0x04, 0x07, 'e', 'x', 'e', 'c', 'u', 't', 'e',
+                0x30, 0x0A,
+                0x30, 0x08,
+                0x04, 0x03, 'i', 'n', 't',
+                0x04, 0x01, 0x01,
+        } );
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+        stream.flip();
+
+        // Allocate a StoredProcedure Container
+        StoredProcedureContainer storedProcedureContainer = new StoredProcedureContainer();
+
+        // Decode a StoredProcedure message
+        try
+        {
+            storedProcedureDecoder.decode( stream, storedProcedureContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        StoredProcedureRequestDecorator storedProcedure = storedProcedureContainer.getStoredProcedure();
+
+        assertEquals( "Java", storedProcedure.getLanguage() );
+
+        assertEquals( "execute", storedProcedure.getProcedureSpecification() );
+
+        assertEquals( 1, storedProcedure.size() );
+
+        assertEquals( "int", Strings.utf8ToString( ( byte[] ) storedProcedure.getParameterType( 0 ) ) );
+        assertEquals( 1, IntegerDecoder.parse( new BerValue( ( byte[] ) storedProcedure.getParameterValue( 0 ) ) ) );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = storedProcedure.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseTest.java b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseTest.java
new file mode 100644
index 0000000..6816059
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/whoAmI/WhoAmIResponseTest.java
@@ -0,0 +1,242 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.extras.extended.ads_impl.whoAmI;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Container;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/*
+ * TestCase for a WhoAmI response Extended Operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class WhoAmIResponseTest
+{
+    /**
+     * Test the normal WhoAmI response message
+     */
+    @Test
+    public void testDecodeWhoAmINull()
+    {
+        Asn1Decoder whoAmIResponseDecoder = new WhoAmIResponseDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x00 );
+
+        stream.put( new byte[]
+            {} ).flip();
+
+        Strings.dumpBytes( stream.array() );
+
+        // Allocate a WhoAmI Container
+        Asn1Container whoAmIResponseContainer = new WhoAmIResponseContainer();
+
+        // Decode a WhoAmI message
+        try
+        {
+            whoAmIResponseDecoder.decode( stream, whoAmIResponseContainer );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        WhoAmIResponseDecorator whoAmIResponse = ( ( WhoAmIResponseContainer ) whoAmIResponseContainer ).getWhoAmIResponse();
+
+        assertNull( whoAmIResponse );
+    }
+
+
+    /**
+     * Test a WhoAmI message with no authzId
+     */
+    @Test
+    public void testDecodeWhoAmINoWhoAmIAuthzIdEmpty()
+    {
+        Asn1Decoder whoAmIResponseDecoder = new WhoAmIResponseDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x02 );
+
+        stream.put( new byte[]
+            {
+                0x04, 0x00
+        } ).flip();
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+
+        // Allocate a WhoAmI Container
+        Asn1Container whoAmIResponseContainer = new WhoAmIResponseContainer();
+
+        // Decode a WhoAmI message
+        try
+        {
+            whoAmIResponseDecoder.decode( stream, whoAmIResponseContainer );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+        
+        WhoAmIResponseDecorator whoAmIResponse = ( (WhoAmIResponseContainer ) whoAmIResponseContainer ).getWhoAmIResponse();
+
+        assertNull( whoAmIResponse.getAuthzId() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = whoAmIResponse.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test a WhoAmI message with a DN authzId
+     */
+    @Test
+    public void testDecodeWhoAmINoWhoAmIAuthzIdDN()
+    {
+        Asn1Decoder whoAmIResponseDecoder = new WhoAmIResponseDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x0E );
+
+        stream.put( new byte[]
+            {
+                0x04, 0x0C,
+                  'd', 'n', ':', 'o', 'u', '=', 's', 'y', 's', 't', 'e', 'm'
+        } ).flip();
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+
+        // Allocate a WhoAmI Container
+        Asn1Container whoAmIResponseContainer = new WhoAmIResponseContainer();
+
+        // Decode a WhoAmI message
+        try
+        {
+            whoAmIResponseDecoder.decode( stream, whoAmIResponseContainer );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+        
+        WhoAmIResponseDecorator whoAmIResponse = ( (WhoAmIResponseContainer ) whoAmIResponseContainer ).getWhoAmIResponse();
+
+        assertNotNull( whoAmIResponse.getAuthzId() );
+        assertEquals( "dn:ou=system", Strings.utf8ToString( whoAmIResponse.getAuthzId() ) );
+        
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = whoAmIResponse.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+
+
+    /**
+     * Test a WhoAmI message with a UserId authzId
+     */
+    @Test
+    public void testDecodeWhoAmINoWhoAmIAuthzIdUserId()
+    {
+        Asn1Decoder whoAmIResponseDecoder = new WhoAmIResponseDecoder();
+
+        ByteBuffer stream = ByteBuffer.allocate( 0x09 );
+
+        stream.put( new byte[]
+            {
+                0x04, 0x07,
+                  'u', ':', 't', 'e', 's', 't', 0x00
+        } ).flip();
+
+        String decodedPdu = Strings.dumpBytes( stream.array() );
+
+        // Allocate a WhoAmI Container
+        Asn1Container whoAmIResponseContainer = new WhoAmIResponseContainer();
+
+        // Decode a WhoAmI message
+        try
+        {
+            whoAmIResponseDecoder.decode( stream, whoAmIResponseContainer );
+        }
+        catch ( DecoderException de )
+        {
+            fail();
+        }
+        
+        WhoAmIResponseDecorator whoAmIResponse = ( (WhoAmIResponseContainer ) whoAmIResponseContainer ).getWhoAmIResponse();
+
+        assertNotNull( whoAmIResponse.getAuthzId() );
+
+        // Check the encoding
+        try
+        {
+            ByteBuffer bb = whoAmIResponse.encodeInternal();
+
+            String encodedPdu = Strings.dumpBytes( bb.array() );
+
+            assertEquals( encodedPdu, decodedPdu );
+        }
+        catch ( EncoderException ee )
+        {
+            ee.printStackTrace();
+            fail( ee.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/extras/codec/src/test/resources/log4j.properties b/trunk/ldap/extras/codec/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/extras/codec/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/extras/pom.xml b/trunk/ldap/extras/pom.xml
new file mode 100644
index 0000000..e736d81
--- /dev/null
+++ b/trunk/ldap/extras/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-extras-parent</artifactId>
+  <name>Apache Directory LDAP API Extras</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>aci</module>
+    <module>codec</module>
+    <module>codec-api</module>
+    <module>sp</module>
+    <module>trigger</module>
+    <module>util</module>
+  </modules>
+
+</project>
diff --git a/trunk/ldap/extras/sp/pom.xml b/trunk/ldap/extras/sp/pom.xml
new file mode 100644
index 0000000..b566b2d
--- /dev/null
+++ b/trunk/ldap/extras/sp/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-extras-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-extras-sp</artifactId>
+  <name>Apache Directory LDAP API Extras Stored Procedures</name>
+  <packaging>bundle</packaging>
+  <description>Extras LDAP API stored procedure packages used by clients and servers</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-codec</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.extras.sp</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.sp;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.commons.io;version=${commons.io.version},
+              org.apache.commons.lang;version=${commons.lang.version},
+              org.apache.directory.api.ldap.codec.api;version=${project.version},
+              org.apache.directory.api.ldap.extras.extended.storedProcedure;version=${project.version},
+              org.apache.directory.api.ldap.model.constants;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              javax.naming,
+              javax.naming.directory,
+              javax.naming.ldap
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/extras/sp/src/checkstyle/suppressions.xml b/trunk/ldap/extras/sp/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..f1fb9c4
--- /dev/null
+++ b/trunk/ldap/extras/sp/src/checkstyle/suppressions.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <!-- UnixCrypt is from external, no formatting is applied -->
+    <suppress files="org.apache.directory.api.util.UnixCrypt" checks="[A-Za-z0-9]" />
+    
+    <!-- hashcode() is final in super class -->
+    <suppress files="org.apache.directory.api.ldap.model.schema.SyntaxChecker" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.Normalizer" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LoadableSchemaObject" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LdapComparator" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.DITStructureRule" checks="EqualsHashCode" />
+    
+    <!-- No Javadoc for schema constants required -->
+    <suppress files="org.apache.directory.api.ldap.model.constants.SchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.MetaSchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.PasswordPolicySchemaConstants" checks="JavadocVariable" />
+
+    <!-- Classes in org.apache.directory.api.asn1.der are forked from Bouncy Castle -->
+    <suppress files="org.apache.directory.api.asn1.der" checks="[A-Za-z0-9]" />
+</suppressions>
diff --git a/trunk/ldap/extras/sp/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/extras/sp/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/extras/sp/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/extras/sp/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/extras/sp/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/extras/sp/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/extras/sp/src/main/java/org/apache/directory/api/ldap/sp/JavaStoredProcUtils.java b/trunk/ldap/extras/sp/src/main/java/org/apache/directory/api/ldap/sp/JavaStoredProcUtils.java
new file mode 100644
index 0000000..4044832
--- /dev/null
+++ b/trunk/ldap/extras/sp/src/main/java/org/apache/directory/api/ldap/sp/JavaStoredProcUtils.java
@@ -0,0 +1,201 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+
+package org.apache.directory.api.ldap.sp;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.ExtendedRequest;
+import javax.naming.ldap.ExtendedResponse;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.commons.lang.SerializationUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequestImpl;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+
+
+/**
+ * A utility class for working with Java Stored Procedures at the base level.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class JavaStoredProcUtils
+{
+
+    /**
+     * Private constructor.
+     */
+    private JavaStoredProcUtils()
+    {
+    }
+
+
+    /**
+     * Returns the stream data of a Java class.
+     * 
+     * @param clazz
+     *           The class whose stream data will be retrieved.
+     * @return
+     *           Stream data of the class file as a byte array.
+     * @throws NamingException
+     *           If an IO error occurs during reading the class file.
+     */
+    public static byte[] getClassFileAsStream( Class<?> clazz ) throws NamingException
+    {
+        String fullClassName = clazz.getName();
+        int lastDot = fullClassName.lastIndexOf( '.' );
+        String classFileName = fullClassName.substring( lastDot + 1 ) + ".class";
+        URL url = clazz.getResource( classFileName );
+        InputStream in;
+        
+        try
+        {
+            in = url.openStream();
+        }
+        catch ( IOException ioe )
+        {
+            NamingException ne = new NamingException();
+            ne.setRootCause( ioe );
+            throw ne;
+        }
+        
+        File file;
+        
+        try
+        {
+            file = new File( url.toURI() );
+        }
+        catch ( URISyntaxException urie )
+        {
+            NamingException ne = new NamingException();
+            ne.setRootCause( urie );
+            throw ne;
+        }
+        
+        int size = ( int ) file.length();
+        byte[] buf = new byte[size];
+
+        try
+        {
+            in.read( buf );
+        }
+        catch ( IOException e )
+        {
+            NamingException ne = new NamingException();
+            ne.setRootCause( e );
+            throw ne;
+        }
+        finally
+        {
+            IOUtils.closeQuietly( in );
+        }
+
+        return buf;
+    }
+
+
+    /**
+     * Loads a Java class's stream data as a subcontext of an LdapContext given.
+     * 
+     * @param ctx
+     *           The parent context of the Java class entry to be loaded.
+     * @param clazz
+     *           Class to be loaded.
+     * @throws NamingException
+     *           If an error occurs during creating the subcontext.
+     */
+    public static void loadStoredProcedureClass( LdapContext ctx, Class<?> clazz ) throws NamingException
+    {
+        byte[] buf = getClassFileAsStream( clazz );
+        String fullClassName = clazz.getName();
+
+        Attributes attributes = new BasicAttributes( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, true );
+        attributes.get( SchemaConstants.OBJECT_CLASS_AT ).add( "storedProcUnit" );
+        attributes.get( SchemaConstants.OBJECT_CLASS_AT ).add( "javaStoredProcUnit" );
+        attributes.put( "storedProcLangId", "Java" );
+        attributes.put( "storedProcUnitName", fullClassName );
+        attributes.put( "javaByteCode", buf );
+
+        ctx.createSubcontext( "storedProcUnitName=" + fullClassName, attributes );
+    }
+
+
+    public static Object callStoredProcedure( LdapContext ctx, String procedureName, Object[] arguments )
+        throws NamingException
+    {
+        String language = "Java";
+
+        Object responseObject;
+        try
+        {
+            /**
+             * Create a new stored procedure execution request.
+             */
+            StoredProcedureRequestImpl req = new StoredProcedureRequestImpl( 0, procedureName, language );
+
+            /**
+             * For each argument UTF-8-encode the type name
+             * and Java-serialize the value
+             * and add them to the request as a parameter object.
+             */
+            for ( int i = 0; i < arguments.length; i++ )
+            {
+                byte[] type;
+                byte[] value;
+                type = arguments[i].getClass().getName().getBytes( "UTF-8" );
+                value = SerializationUtils.serialize( ( Serializable ) arguments[i] );
+                req.addParameter( type, value );
+            }
+
+            /**
+             * Call the stored procedure via the extended operation
+             * and get back its return value.
+             */
+            ExtendedRequest jndiReq = LdapApiServiceFactory.getSingleton().toJndi( req );
+            ExtendedResponse resp = ctx.extendedOperation( jndiReq );
+
+            /**
+             * Restore a Java object from the return value.
+             */
+            byte[] responseStream = resp.getEncodedValue();
+            responseObject = SerializationUtils.deserialize( responseStream );
+        }
+        catch ( Exception e )
+        {
+            NamingException ne = new NamingException();
+            ne.setRootCause( e );
+            throw ne;
+        }
+
+        return responseObject;
+    }
+
+}
diff --git a/trunk/ldap/extras/sp/src/main/java/org/apache/directory/api/ldap/sp/LdapContextParameter.java b/trunk/ldap/extras/sp/src/main/java/org/apache/directory/api/ldap/sp/LdapContextParameter.java
new file mode 100644
index 0000000..a252b15
--- /dev/null
+++ b/trunk/ldap/extras/sp/src/main/java/org/apache/directory/api/ldap/sp/LdapContextParameter.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.sp;
+
+
+import java.io.Serializable;
+
+
+/**
+ * A class for representing the special SP parameter: $ldapContext.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapContextParameter implements Serializable
+{
+    private static final long serialVersionUID = -8703671542595407603L;
+
+    private String name;
+
+
+    public LdapContextParameter( String name )
+    {
+        this.name = name;
+    }
+
+
+    public String getValue()
+    {
+        return name;
+    }
+}
diff --git a/trunk/ldap/extras/sp/src/site/site.xml b/trunk/ldap/extras/sp/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/extras/sp/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/extras/sp/src/test/resources/log4j.properties b/trunk/ldap/extras/sp/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/extras/sp/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/extras/src/site/site.xml b/trunk/ldap/extras/src/site/site.xml
new file mode 100644
index 0000000..b6ec180
--- /dev/null
+++ b/trunk/ldap/extras/src/site/site.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="modules" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/extras/trigger/pom.xml b/trunk/ldap/extras/trigger/pom.xml
new file mode 100644
index 0000000..ca5539f
--- /dev/null
+++ b/trunk/ldap/extras/trigger/pom.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-extras-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-extras-trigger</artifactId>
+  <name>Apache Directory LDAP API Extras Trigger</name>
+  <packaging>bundle</packaging>
+  <description>Extra LDAP API Trigger API</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+
+  <!-- The original antlr artifact is needed by the antlr-maven-plugin which 
+    checks for its existence within the classpath. Use scope provided to avoid 
+    propagation to dependent projects. Choosen artifact is a valid OSGi bundle 
+    repackaged by ServiceMix team, kudos to them. -->
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.antlr</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>antlr-maven-plugin</artifactId>
+        <configuration>
+          <grammars>*.g</grammars>
+        </configuration>
+        <executions>
+           <execution>
+              <goals>
+                 <goal>generate</goal>
+              </goals>
+           </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.extras.trigger</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.trigger;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              antlr;version=${antlr.version},
+              antlr.collections.impl;version=${antlr.version},
+              org.apache.commons.lang;version=${commons.lang.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.model.constants;version=${project.version},
+              org.apache.directory.api.ldap.model.entry;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.schema;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              javax.naming,
+              javax.naming.directory,
+              javax.naming.ldap
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/extras/trigger/src/checkstyle/suppressions.xml b/trunk/ldap/extras/trigger/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..9fdad6f
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/checkstyle/suppressions.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <suppress files="org.apache.directory.api.ldap.trigger.StoredProcedureParameter" checks="TypeName" />
+
+    <!-- Exclude Antlr generated sources -->
+    <suppress files="[\\/]generated-sources[\\/]" checks="[a-zA-Z0-9]*"/>
+</suppressions>
diff --git a/trunk/ldap/extras/trigger/src/main/antlr/TriggerSpecification.g b/trunk/ldap/extras/trigger/src/main/antlr/TriggerSpecification.g
new file mode 100644
index 0000000..d44aeee
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/antlr/TriggerSpecification.g
@@ -0,0 +1,588 @@
+header
+{
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+
+package org.apache.directory.api.ldap.trigger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.NormalizerMappingResolver;
+import org.apache.directory.api.ldap.trigger.StoredProcedureOption;
+import org.apache.directory.api.ldap.trigger.StoredProcedureParameter;
+import org.apache.directory.api.ldap.trigger.TriggerSpecification.SPSpec;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The ANTLR generated TriggerSpecification parser.
+ * 
+ * @see http://docs.safehaus.org/display/APACHEDS/Grammar+for+Triggers
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrTriggerSpecificationParser extends Parser;
+
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 1;
+    defaultErrorHandler = false;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser initialization
+// ----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrTriggerSpecificationParser.class );
+    
+    private NormalizerMappingResolver resolver;
+    
+    private ActionTime triggerActionTime;
+    
+    private LdapOperation triggerLdapOperation;
+    
+    private String triggerStoredProcedureName;
+    
+    private List<StoredProcedureParameter> triggerStoredProcedureParameters;
+    
+    private List<StoredProcedureOption> triggerStoredProcedureOptions;
+    
+    private List<SPSpec> spSpecs;   
+    
+    public void init()
+    {
+    }
+
+
+    /**
+     * Sets the NameComponentNormalizer for this parser's dnParser.
+     */
+    public void setNormalizerMappingResolver( NormalizerMappingResolver resolver )
+    {
+        this.resolver = resolver;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+//  parser productions
+// ----------------------------------------------------------------------------
+
+wrapperEntryPoint returns [ TriggerSpecification triggerSpec ]
+{
+    log.debug( "entered wrapperEntryPoint()" );
+    triggerSpec = null;
+    spSpecs = new ArrayList<SPSpec>(); 
+}
+    :
+    ( SP )* triggerSpec=triggerSpecification EOF
+    ;
+
+// -----------------------------------------------------------------------------
+//  main rules
+// -----------------------------------------------------------------------------
+
+triggerSpecification returns [ TriggerSpecification triggerSpec ]
+{
+    log.debug( "entered triggerSpecification()" );
+    triggerSpec = null;
+}
+    :
+    actionTime ( SP )+ ldapOperationAndStoredProcedureCalls
+    { triggerSpec = new TriggerSpecification( triggerLdapOperation,
+                                              triggerActionTime,
+                                              spSpecs
+                                            );
+    }
+    ;
+
+// Currently we only support "AFTER" Triggers   
+actionTime
+{
+    log.debug( "entered actionTime()" );
+}
+    : ID_AFTER { triggerActionTime = ActionTime.AFTER; }
+    ;
+    
+ldapOperationAndStoredProcedureCalls
+{
+    log.debug( "entered ldapOperationAndStoredProcedureCall()" );
+}
+    : modifyOperationAndStoredProcedureCalls { triggerLdapOperation = LdapOperation.MODIFY; }
+    | addOperationAndStoredProcedureCalls { triggerLdapOperation = LdapOperation.ADD; }
+    | deleteOperationAndStoredProcedureCalls { triggerLdapOperation = LdapOperation.DELETE; }
+    | modifyDNOperationAndStoredProcedureCalls // Will decide operation type for this one later
+    ;
+
+// -----------------------------------------------------------------------------
+//  XXXOperationAndStoredProcedureCalls
+// -----------------------------------------------------------------------------
+
+modifyOperationAndStoredProcedureCalls
+{
+    log.debug( "entered modifyOperationAndStoredProcedureCalls()" );
+}
+    :
+    ID_modify ( SP )+
+    ( theCompositeRuleForCallAndSPNameAndSPOptionList
+    OPEN_PARAN ( SP )*
+        ( modifyStoredProcedureParameterList )?
+    CLOSE_PARAN ( SP )* SEMI ( SP )*
+    {
+        spSpecs.add( new SPSpec(triggerStoredProcedureName, triggerStoredProcedureOptions, triggerStoredProcedureParameters ) );
+    })+
+    ;
+
+addOperationAndStoredProcedureCalls
+{
+    log.debug( "entered addOperationAndStoredProcedureCalls()" );
+}
+    :
+    ID_add ( SP )+
+    ( theCompositeRuleForCallAndSPNameAndSPOptionList
+    OPEN_PARAN ( SP )*
+        ( addStoredProcedureParameterList )?
+    CLOSE_PARAN ( SP )* SEMI ( SP )*
+    {
+        spSpecs.add( new SPSpec(triggerStoredProcedureName, triggerStoredProcedureOptions, triggerStoredProcedureParameters ) );
+    }
+    )+
+    ;
+
+deleteOperationAndStoredProcedureCalls
+{
+    log.debug( "entered deleteOperationAndStoredProcedureCalls()" );
+}
+    :
+    ID_delete ( SP )+
+    ( theCompositeRuleForCallAndSPNameAndSPOptionList
+    OPEN_PARAN ( SP )*
+        ( deleteStoredProcedureParameterList )?
+    CLOSE_PARAN ( SP )* SEMI ( SP )*
+    {
+        spSpecs.add( new SPSpec(triggerStoredProcedureName, triggerStoredProcedureOptions, triggerStoredProcedureParameters ) );
+    }
+    )+
+    ;
+
+modifyDNOperationAndStoredProcedureCalls
+{
+    log.debug( "entered modifyDNOperationAndStoredProcedureCalls()" );
+}
+    :
+    ID_modifyDN DOT
+    ( ( ID_modifyDNRename { triggerLdapOperation = LdapOperation.MODIFYDN_RENAME; }
+    | ID_modifyDNExport { triggerLdapOperation = LdapOperation.MODIFYDN_EXPORT; }
+    | ID_modifyDNImport { triggerLdapOperation = LdapOperation.MODIFYDN_IMPORT; } )
+    ( SP )+ theCompositeRuleForCallAndSPNameAndSPOptionList
+    OPEN_PARAN ( SP )*
+        ( modifyDNStoredProcedureParameterList )?
+    CLOSE_PARAN ( SP )* SEMI ( SP )*
+    {
+        spSpecs.add( new SPSpec(triggerStoredProcedureName, triggerStoredProcedureOptions, triggerStoredProcedureParameters ) );
+    }
+    )+
+    ;
+
+// -----------------------------------------------------------------------------
+// The following rule does not make any sense semantically. Just placed for
+// reducing repetition. All OperationAndStoredProcedureCall type are heavily
+// context sensitive where their StoredProcedureParameterList depends on their
+// Operation type. Other elements that sit between these two dependent elements
+// are repeated for all OperationAndStoredProcedureCall type rules. So the
+// the following rule is for the part falling between those two dependent parts.
+// -----------------------------------------------------------------------------
+
+theCompositeRuleForCallAndSPNameAndSPOptionList
+{
+    log.debug( "entered theCompositeRuleForCallAndSPNameAndSPOptionList()" );
+}
+    :
+    ID_CALL
+    {
+        triggerStoredProcedureName = null;
+        triggerStoredProcedureParameters = new ArrayList<StoredProcedureParameter>();
+        triggerStoredProcedureOptions = new ArrayList<StoredProcedureOption>();
+    }
+    ( SP )+ triggerStoredProcedureName=fullyQualifiedStoredProcedureName ( SP )*
+        ( genericStoredProcedureOptionList ( SP )* )?
+    { }
+    ;
+
+// -----------------------------------------------------------------------------
+//  XXXStoredProcedureParameterList
+// -----------------------------------------------------------------------------
+
+modifyStoredProcedureParameterList
+{
+    log.debug( "entered modifyStoredProcedureParameterList()" );
+}
+    :
+    modifyStoredProcedureParameter ( SP )*
+        ( SEP ( SP )* modifyStoredProcedureParameter ( SP )* )*
+    ;
+
+addStoredProcedureParameterList
+{
+    log.debug( "entered addStoredProcedureParameterList()" );
+}
+    :
+    addStoredProcedureParameter ( SP )*
+        ( SEP ( SP )* addStoredProcedureParameter ( SP )* )*
+    ;
+
+deleteStoredProcedureParameterList
+{
+    log.debug( "entered deleteStoredProcedureParameterList()" );
+}
+    :
+    deleteStoredProcedureParameter ( SP )*
+        ( SEP ( SP )* deleteStoredProcedureParameter ( SP )* )*
+    ;
+
+modifyDNStoredProcedureParameterList
+{
+    log.debug( "entered modifyDNStoredProcedureParameterList()" );
+}
+    :
+    modifyDNStoredProcedureParameter ( SP )*
+        ( SEP ( SP )* modifyDNStoredProcedureParameter ( SP )* )*
+    ;
+
+// -----------------------------------------------------------------------------
+// XXXStoredProcedureParameter
+// -----------------------------------------------------------------------------
+
+modifyStoredProcedureParameter
+{
+    log.debug( "entered modifyStoredProcedureParameter()" );
+}
+    : ID_object { triggerStoredProcedureParameters.add( StoredProcedureParameter.Modify_OBJECT.instance() ); }
+    | ID_modification { triggerStoredProcedureParameters.add( StoredProcedureParameter.Modify_MODIFICATION.instance() ); }
+    | ID_oldEntry { triggerStoredProcedureParameters.add( StoredProcedureParameter.Modify_OLD_ENTRY.instance() ); }
+    | ID_newEntry { triggerStoredProcedureParameters.add( StoredProcedureParameter.Modify_NEW_ENTRY.instance() ); }
+    | genericStoredProcedureParameter
+    ;
+
+addStoredProcedureParameter
+{
+    log.debug( "entered addStoredProcedureParameter()" );
+}
+    : ID_entry { triggerStoredProcedureParameters.add( StoredProcedureParameter.Add_ENTRY.instance() ); }
+    | ID_attributes { triggerStoredProcedureParameters.add( StoredProcedureParameter.Add_ATTRIBUTES.instance() ); }
+    | genericStoredProcedureParameter
+    ;
+
+deleteStoredProcedureParameter
+{
+    log.debug( "entered deleteStoredProcedureParameter()" );
+}
+    : ID_name { triggerStoredProcedureParameters.add( StoredProcedureParameter.Delete_NAME.instance() ); }
+    | ID_deletedEntry { triggerStoredProcedureParameters.add( StoredProcedureParameter.Delete_DELETED_ENTRY.instance() ); }
+    | genericStoredProcedureParameter
+    ;
+
+modifyDNStoredProcedureParameter
+{
+    log.debug( "entered modifyDNStoredProcedureParameter()" );
+}
+    : ID_entry { triggerStoredProcedureParameters.add( StoredProcedureParameter.ModifyDN_ENTRY.instance() ); }
+    | ID_newrdn { triggerStoredProcedureParameters.add( StoredProcedureParameter.ModifyDN_NEW_RDN.instance() ); }
+    | ID_deleteoldrdn { triggerStoredProcedureParameters.add( StoredProcedureParameter.ModifyDN_DELETE_OLD_RDN.instance() ); }
+    | ID_newSuperior { triggerStoredProcedureParameters.add( StoredProcedureParameter.ModifyDN_NEW_SUPERIOR.instance() ); }
+    | ID_oldRDN { triggerStoredProcedureParameters.add( StoredProcedureParameter.ModifyDN_OLD_RDN.instance() ); }
+    | ID_oldSuperiorDN { triggerStoredProcedureParameters.add( StoredProcedureParameter.ModifyDN_OLD_SUPERIOR_DN.instance() ); }
+    | ID_newDN { triggerStoredProcedureParameters.add( StoredProcedureParameter.ModifyDN_NEW_DN.instance() ); }
+    | genericStoredProcedureParameter
+    ;
+
+// -----------------------------------------------------------------------------
+
+genericStoredProcedureParameter
+{
+    log.debug( "entered genericStoredProcedureParameter()" );
+}
+    : ldapContextStoredProcedureParameter
+    | ID_operationPrincipal { triggerStoredProcedureParameters.add( StoredProcedureParameter.Generic_OPERATION_PRINCIPAL.instance() ); }
+    ;
+
+ldapContextStoredProcedureParameter
+{
+    log.debug( "entered ldapContextStoredProcedureParameter()" );
+    Dn ldapContext = null;
+}
+    : ID_ldapContext ( SP )+ ldapContext=distinguishedName
+    { triggerStoredProcedureParameters.add( StoredProcedureParameter.Generic_LDAP_CONTEXT.instance( ldapContext ) ); }
+    ;
+
+// -----------------------------------------------------------------------------
+
+genericStoredProcedureOptionList
+{
+    log.debug( "entered genericStoredProcedureOptionList()" );
+}
+    :
+    OPEN_CURLY ( SP )* ( genericStoredProcedureOption ( SP )*
+        ( SEP ( SP )* genericStoredProcedureOption ( SP )* )* )* CLOSE_CURLY
+    ;
+
+genericStoredProcedureOption
+{
+    log.debug( "entered genericStoredProcedureOption()" );
+    StoredProcedureOption spOption = null;
+}
+    : ( spOption=storedProcedureLanguageSchemeOption | spOption=storedProcedureSearchContextOption )
+    { triggerStoredProcedureOptions.add( spOption ); }
+    ;
+
+storedProcedureLanguageSchemeOption returns [ StoredProcedureLanguageSchemeOption spLanguageSchemeOption ]
+{
+    log.debug( "entered storedProcedureLanguageSchemeOption()" );
+    spLanguageSchemeOption = null;
+}
+    : ID_languageScheme ( SP )+ languageToken:UTF8String
+    { spLanguageSchemeOption = new StoredProcedureLanguageSchemeOption( languageToken.getText() ); }
+    ;
+
+storedProcedureSearchContextOption returns [ StoredProcedureSearchContextOption spSearchContextOption ]
+{
+    log.debug( "entered storedProcedureSearchContextOption()" );
+    spSearchContextOption = null;
+    SearchScope searchScope = SearchScope.OBJECT; // default scope
+    Dn spSearchContext = null;
+}
+    :
+    ID_searchContext ( SP )+ // FIXME: SP should not be mandatory if an OPEN_CURLY follows
+        ( OPEN_CURLY ( SP )*
+            ( ID_search_scope ( SP )+ searchScope=storedProcedureSearchScope ( SP )* )?
+        CLOSE_CURLY ( SP )+ )?
+    spSearchContext=storedProcedureSearchContext
+    { spSearchContextOption = new StoredProcedureSearchContextOption( spSearchContext, searchScope ); }
+    ;
+
+storedProcedureSearchScope returns [ SearchScope scope ]
+{
+    log.debug( "entered storedProcedureSearchScope()" );
+    scope = null;
+}
+    : ID_scope_base { scope = SearchScope.OBJECT; }
+    | ID_scope_one { scope = SearchScope.ONELEVEL; }
+    | ID_scope_subtree { scope = SearchScope.SUBTREE; }
+    ;
+
+storedProcedureSearchContext returns [ Dn spSearchContext ]
+{
+    log.debug( "entered storedProcedureSearchContext()" );
+    spSearchContext = null;
+}
+    : spSearchContext=distinguishedName
+    ;
+
+// -----------------------------------------------------------------------------
+
+fullyQualifiedStoredProcedureName returns [ String spName ] 
+{
+    log.debug( "entered fullyQualifiedStoredProcedureName()" );
+    spName = null;
+}
+    : spNameToken:UTF8String
+    { spName = spNameToken.getText(); }
+    ;
+
+distinguishedName returns [ Dn name ]
+{
+    log.debug( "entered distinguishedName()" );
+    name = null;
+}
+    : nameToken:UTF8String
+    {
+        name = new Dn( nameToken.getText() );
+    }
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "name parse failed for " + nameToken.getText() + " " + e.getMessage() );
+    }
+
+// -----------------------------------------------------------------------------
+//  lexer class definition
+// -----------------------------------------------------------------------------
+
+/**
+  * The parser's primary lexer.
+  *
+  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+  */
+class AntlrTriggerSpecificationLexer extends Lexer;
+
+
+// -----------------------------------------------------------------------------
+//  lexer options
+// -----------------------------------------------------------------------------
+
+options
+{
+    k = 1;
+    defaultErrorHandler = false;
+    charVocabulary = '\3'..'\377';
+    // the grammar is case-insensitive
+    caseSensitive = false;
+    caseSensitiveLiterals = false;
+}
+
+
+// -----------------------------------------------------------------------------
+//  tokens
+// -----------------------------------------------------------------------------
+
+tokens
+{
+    // action time identifiers
+    ID_AFTER = "after";
+    
+    // operation identifiers
+    ID_modify  = "modify";
+    ID_add = "add";
+    ID_delete = "delete";
+    ID_modifyDN = "modifydn";
+    ID_modifyDNRename = "rename";
+    ID_modifyDNExport = "export";
+    ID_modifyDNImport = "import";
+    
+    // modify specific parameters
+    ID_object = "$object";
+    ID_modification = "$modification";
+    ID_oldEntry = "$oldentry";
+    ID_newEntry = "$newentry";
+    
+    // add specific parameters
+    ID_entry = "$entry";
+    ID_attributes = "$attributes";
+    
+    // delete specific parameters
+    ID_name = "$name";
+    ID_deletedEntry = "$deletedentry";
+    
+    // modifyDN specific parameters
+    // ID_entry = "$entry"; // defined before
+    ID_newrdn = "$newrdn";
+    ID_deleteoldrdn = "$deleteoldrdn";
+    ID_newSuperior = "$newSuperior";
+    ID_oldRDN = "$oldRdn";
+    ID_oldSuperiorDN = "$oldSuperiorDn";
+    ID_newDN = "$newDn";
+    
+    // generic parameters
+    ID_ldapContext = "$ldapcontext";
+    ID_operationPrincipal = "$operationprincipal";
+    
+    ID_CALL = "call";
+    
+    ID_languageScheme = "languagescheme";
+    ID_searchContext = "searchcontext";
+    ID_search_scope = "scope";
+    ID_scope_base = "base";
+    ID_scope_one = "one";
+    ID_scope_subtree = "subtree";
+}
+
+
+// -----------------------------------------------------------------------------
+//  lexer initialization
+// -----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrTriggerSpecificationLexer.class );
+}
+
+
+// -----------------------------------------------------------------------------
+//  attribute description lexer rules from models
+// -----------------------------------------------------------------------------
+
+OPEN_PARAN : '(' ;
+
+CLOSE_PARAN : ')' ;
+
+OPEN_CURLY : '{' ;
+
+CLOSE_CURLY : '}' ;
+
+SEMI : ';' ;
+
+SEP : ',' ;
+
+SP
+    : ' '
+    | '\t'
+    | '\n' { newline(); }
+    | '\r' ('\n')? { newline(); }
+    ;
+
+DOT : '.' ;
+
+UTF8String : '"'! ( SAFEUTF8CHAR )* '"'! ;
+
+//  This is all messed up - could not figure out how to get antlr to represent
+//  the safe UTF-8 character set from RFC 3642 for production SafeUTF8Character
+
+protected SAFEUTF8CHAR
+    : '\u0001'..'\u0021'
+    | '\u0023'..'\u007F'
+    | '\u00c0'..'\u00d6'
+    | '\u00d8'..'\u00f6'
+    | '\u00f8'..'\u00ff'
+    | '\u0100'..'\u1fff'
+    | '\u3040'..'\u318f'
+    | '\u3300'..'\u337f'
+    | '\u3400'..'\u3d2d'
+    | '\u4e00'..'\u9fff'
+    | '\uf900'..'\ufaff'
+    ;
+
+COMMENT
+    : '#'
+    (~('\n'|'\r'))* (('\n'|'\r'('\n')?){newline();})?
+    {$setType(Token.SKIP);}
+    ;
+
+IDENTIFIER : ALPHA ( ALPHA )* ; // A MUST HAVE although we do not use explicitly
+
+protected ALPHA : 'a'..'z' | '$' ;
diff --git a/trunk/ldap/extras/trigger/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/extras/trigger/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/extras/trigger/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/extras/trigger/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ActionTime.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ActionTime.java
new file mode 100644
index 0000000..2471d4a
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ActionTime.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+/**
+ * An enumeration that represents action times
+ * for an LDAP trigger specification.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ActionTime
+{
+    /** The AFTER instance. */
+    public static final ActionTime AFTER = new ActionTime( "AFTER" );
+
+    /** The name. */
+    private final String name;
+
+
+    private ActionTime( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Returns the name of this action time.
+     *
+     * @return the name of this action time.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+        h = h * 17 + ( ( name == null ) ? 0 : name.hashCode() );
+
+        return h;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final ActionTime other = ( ActionTime ) obj;
+        if ( name == null )
+        {
+            if ( other.name != null )
+            {
+                return false;
+            }
+        }
+        else if ( !name.equals( other.name ) )
+        {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/LdapOperation.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/LdapOperation.java
new file mode 100644
index 0000000..0d2d4c1
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/LdapOperation.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+/**
+ * An enumeration that represents change inducing LDAP operations.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum LdapOperation
+{
+    MODIFY("Modify"),
+
+    ADD("Add"),
+
+    DELETE("Delete"),
+
+    MODIFYDN("ModifyDN"),
+
+    MODIFYDN_RENAME("ModifyDN.Rename"),
+
+    MODIFYDN_EXPORT("ModifyDN.Export"),
+
+    MODIFYDN_IMPORT("ModifyDN.Import");
+
+    private final String name;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapOperation.
+     *
+     * @param name
+     */
+    LdapOperation( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * @return the name of this LDAP operation
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    public String toString()
+    {
+        return name;
+    }
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ReusableAntlrTriggerSpecificationLexer.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ReusableAntlrTriggerSpecificationLexer.java
new file mode 100644
index 0000000..5c8035c
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ReusableAntlrTriggerSpecificationLexer.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+import java.io.Reader;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+
+
+/**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * Trigger Specification as defined at <a
+ * href="http://docs.safehaus.org/display/APACHEDS/Grammar+for+Triggers">
+ * The ABNF grammar for LDAP Triggers</a>.
+ * 
+ * <p>This class enables the reuse of the antlr lexer without having to recreate
+ * the it every time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * an ANTLR Interest Group mail</a> .
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrTriggerSpecificationLexer extends AntlrTriggerSpecificationLexer
+{
+    private boolean savedCaseSensitive;
+
+    private boolean savedCaseSensitiveLiterals;
+
+
+    /**
+     * Creates a ReusableAntlrTriggerSpecificationLexer instance.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public ReusableAntlrTriggerSpecificationLexer( Reader in )
+    {
+        super( in );
+        savedCaseSensitive = getCaseSensitive();
+        savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+    }
+
+
+    /**
+     * Resets the state of an antlr lexer and initializes it with new input.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public void prepareNextInput( Reader in )
+    {
+        CharBuffer buf = new CharBuffer( in );
+        LexerSharedInputState state = new LexerSharedInputState( buf );
+        this.setInputState( state );
+
+        this.setCaseSensitive( savedCaseSensitive );
+
+        // no set method for this protected field
+        this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+    }
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ReusableAntlrTriggerSpecificationParser.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ReusableAntlrTriggerSpecificationParser.java
new file mode 100644
index 0000000..a9ba80b
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/ReusableAntlrTriggerSpecificationParser.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable lexer class extended from antlr generated parser for an LDAP
+ * Trigger Specification as defined at <a
+ * href="http://docs.safehaus.org/display/APACHEDS/Grammar+for+Triggers">
+ * The ABNF grammar for LDAP Triggers</a>.
+ * 
+ * <p>This class enables the reuse of the antlr lexer without having to recreate
+ * the it every time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * an ANTLR Interest Group mail</a> .
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrTriggerSpecificationParser extends AntlrTriggerSpecificationParser
+{
+    /**
+     * Creates a ReusableAntlrTriggerSpecificationParser instance.
+     */
+    public ReusableAntlrTriggerSpecificationParser( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+
+        this.getInputState().reset();
+    }
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureLanguageSchemeOption.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureLanguageSchemeOption.java
new file mode 100644
index 0000000..bdbc1ed
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureLanguageSchemeOption.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+/**
+ * The language schema option of triggered stored procedure.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureLanguageSchemeOption implements StoredProcedureOption
+{
+
+    private String language;
+
+
+    /**
+     * Instantiates a new stored procedure language scheme option.
+     *
+     * @param language the language
+     */
+    public StoredProcedureLanguageSchemeOption( String language )
+    {
+        this.language = language;
+    }
+
+
+    /**
+     * Gets the language.
+     *
+     * @return the language
+     */
+    public String getLanguage()
+    {
+        return language;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "language " + "\"" + language + "\"";
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + ( ( language == null ) ? 0 : language.hashCode() );
+
+        return h;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final StoredProcedureLanguageSchemeOption other = ( StoredProcedureLanguageSchemeOption ) obj;
+        if ( language == null )
+        {
+            if ( other.language != null )
+            {
+                return false;
+            }
+        }
+        else if ( !language.equals( other.language ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureOption.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureOption.java
new file mode 100644
index 0000000..e5c87ce
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureOption.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+/**
+ * Just a marker interface for Stored Procedure Options.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface StoredProcedureOption
+{
+
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureParameter.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureParameter.java
new file mode 100644
index 0000000..7cb80a0
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureParameter.java
@@ -0,0 +1,410 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.trigger;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * An entity that represents a stored procedure parameter which can be
+ * specified in an LDAP Trigger Specification.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class StoredProcedureParameter
+{
+    public static final class Generic_LDAP_CONTEXT extends StoredProcedureParameter
+    {
+        private Dn ctxName;
+
+
+        private Generic_LDAP_CONTEXT( Dn ctxName )
+        {
+            super( "$ldapContext" );
+            this.ctxName = ctxName;
+        }
+
+
+        public static StoredProcedureParameter instance( Dn ctxName )
+        {
+            return new Generic_LDAP_CONTEXT( ctxName );
+        }
+
+
+        public Dn getCtxName()
+        {
+            return ctxName;
+        }
+
+
+        public String toString()
+        {
+            return name + " \"" + ctxName.getName() + "\"";
+        }
+    }
+
+    public static final class Generic_OPERATION_PRINCIPAL extends StoredProcedureParameter
+    {
+        private static Generic_OPERATION_PRINCIPAL instance = new Generic_OPERATION_PRINCIPAL( "$operationPrincipal" );
+
+
+        private Generic_OPERATION_PRINCIPAL( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    protected final String name;
+
+
+    protected StoredProcedureParameter( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Returns the name of this Stored Procedure Parameter.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    public String toString()
+    {
+        return name;
+    }
+
+
+    /**
+     * @see java.lang.Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + ( ( name == null ) ? 0 : name.hashCode() );
+
+        return h;
+    }
+
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final StoredProcedureParameter other = ( StoredProcedureParameter ) obj;
+        if ( name == null )
+        {
+            if ( other.name != null )
+            {
+                return false;
+            }
+        }
+        else if ( !name.equals( other.name ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public static final class Modify_OBJECT extends StoredProcedureParameter
+    {
+        private static Modify_OBJECT instance = new Modify_OBJECT( "$object" );
+
+
+        private Modify_OBJECT( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class Modify_MODIFICATION extends StoredProcedureParameter
+    {
+        private static Modify_MODIFICATION instance = new Modify_MODIFICATION( "$modification" );
+
+
+        private Modify_MODIFICATION( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class Modify_OLD_ENTRY extends StoredProcedureParameter
+    {
+        private static Modify_OLD_ENTRY instance = new Modify_OLD_ENTRY( "$oldEntry" );
+
+
+        private Modify_OLD_ENTRY( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class Modify_NEW_ENTRY extends StoredProcedureParameter
+    {
+        private static Modify_NEW_ENTRY instance = new Modify_NEW_ENTRY( "$newEntry" );
+
+
+        private Modify_NEW_ENTRY( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class Add_ENTRY extends StoredProcedureParameter
+    {
+        private static Add_ENTRY instance = new Add_ENTRY( "$entry" );
+
+
+        private Add_ENTRY( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class Add_ATTRIBUTES extends StoredProcedureParameter
+    {
+        private static Add_ATTRIBUTES instance = new Add_ATTRIBUTES( "$attributes" );
+
+
+        private Add_ATTRIBUTES( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class Delete_NAME extends StoredProcedureParameter
+    {
+        private static Delete_NAME instance = new Delete_NAME( "$name" );
+
+
+        private Delete_NAME( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class Delete_DELETED_ENTRY extends StoredProcedureParameter
+    {
+        private static Delete_DELETED_ENTRY instance = new Delete_DELETED_ENTRY( "$deletedEntry" );
+
+
+        private Delete_DELETED_ENTRY( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class ModifyDN_ENTRY extends StoredProcedureParameter
+    {
+        private static ModifyDN_ENTRY instance = new ModifyDN_ENTRY( "$entry" );
+
+
+        private ModifyDN_ENTRY( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class ModifyDN_NEW_RDN extends StoredProcedureParameter
+    {
+        private static ModifyDN_NEW_RDN instance = new ModifyDN_NEW_RDN( "$newrdn" );
+
+
+        private ModifyDN_NEW_RDN( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class ModifyDN_DELETE_OLD_RDN extends StoredProcedureParameter
+    {
+        private static ModifyDN_DELETE_OLD_RDN instance = new ModifyDN_DELETE_OLD_RDN( "$deleteoldrdn" );
+
+
+        private ModifyDN_DELETE_OLD_RDN( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class ModifyDN_NEW_SUPERIOR extends StoredProcedureParameter
+    {
+        private static ModifyDN_NEW_SUPERIOR instance = new ModifyDN_NEW_SUPERIOR( "$newSuperior" );
+
+
+        private ModifyDN_NEW_SUPERIOR( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class ModifyDN_OLD_RDN extends StoredProcedureParameter
+    {
+        private static ModifyDN_OLD_RDN instance = new ModifyDN_OLD_RDN( "$oldRDN" );
+
+
+        private ModifyDN_OLD_RDN( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    public static final class ModifyDN_OLD_SUPERIOR_DN extends StoredProcedureParameter
+    {
+        private static ModifyDN_OLD_SUPERIOR_DN instance = new ModifyDN_OLD_SUPERIOR_DN( "$oldRDN" );
+
+
+        private ModifyDN_OLD_SUPERIOR_DN( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+
+    /**
+     * 
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+     */
+    public static final class ModifyDN_NEW_DN extends StoredProcedureParameter
+    {
+        private static ModifyDN_NEW_DN instance = new ModifyDN_NEW_DN( "$oldRDN" );
+
+
+        private ModifyDN_NEW_DN( String identifier )
+        {
+            super( identifier );
+        }
+
+
+        public static StoredProcedureParameter instance()
+        {
+            return instance;
+        }
+    }
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureSearchContextOption.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureSearchContextOption.java
new file mode 100644
index 0000000..365a2d3
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/StoredProcedureSearchContextOption.java
@@ -0,0 +1,156 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * The search context option of the triggered stored procedure.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureSearchContextOption implements StoredProcedureOption
+{
+
+    private final Dn baseObject;
+    private SearchScope searchScope;
+
+
+    /**
+     * Instantiates a new stored procedure search context option.
+     *
+     * @param baseObject the base object
+     */
+    public StoredProcedureSearchContextOption( Dn baseObject )
+    {
+        // the default search scope is "base"
+        this( baseObject, SearchScope.OBJECT );
+    }
+
+
+    /**
+     * Instantiates a new stored procedure search context option.
+     *
+     * @param baseObject the base object
+     * @param searchScope the search scope
+     */
+    public StoredProcedureSearchContextOption( Dn baseObject, SearchScope searchScope )
+    {
+        this.baseObject = baseObject;
+        this.searchScope = searchScope;
+    }
+
+
+    /**
+     * Gets the base object.
+     *
+     * @return the base object
+     */
+    public Dn getBaseObject()
+    {
+        return baseObject;
+    }
+
+
+    /**
+     * Gets the search scope.
+     *
+     * @return the search scope
+     */
+    public SearchScope getSearchScope()
+    {
+        return searchScope;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "searchContext { scope " + searchScope + " } \"" + baseObject + "\"";
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + ( ( baseObject == null ) ? 0 : baseObject.hashCode() );
+        h = h * 17 + ( ( searchScope == null ) ? 0 : searchScope.hashCode() );
+
+        return h;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final StoredProcedureSearchContextOption other = ( StoredProcedureSearchContextOption ) obj;
+        if ( baseObject == null )
+        {
+            if ( other.baseObject != null )
+            {
+                return false;
+            }
+        }
+        else if ( !baseObject.equals( other.baseObject ) )
+        {
+            return false;
+        }
+        if ( searchScope == null )
+        {
+            if ( other.searchScope != null )
+            {
+                return false;
+            }
+        }
+        else if ( !searchScope.equals( other.searchScope ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerSpecification.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerSpecification.java
new file mode 100644
index 0000000..240cde8
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerSpecification.java
@@ -0,0 +1,236 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+import java.util.List;
+
+import org.apache.commons.lang.NullArgumentException;
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * The Trigger Specification Bean.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TriggerSpecification
+{
+
+    private LdapOperation ldapOperation;
+
+    private ActionTime actionTime;
+
+    private List<SPSpec> spSpecs;
+
+
+    /**
+     * Instantiates a new trigger specification.
+     *
+     * @param ldapOperation the LDAP operation
+     * @param actionTime the action time
+     * @param spSpecs the stored procedure specs
+     */
+    public TriggerSpecification( LdapOperation ldapOperation, ActionTime actionTime, List<SPSpec> spSpecs )
+    {
+        super();
+        if ( ldapOperation == null
+            || actionTime == null
+            || spSpecs == null )
+        {
+            throw new NullArgumentException( I18n.err( I18n.ERR_04331 ) );
+        }
+        if ( spSpecs.size() == 0 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04332 ) );
+        }
+        this.ldapOperation = ldapOperation;
+        this.actionTime = actionTime;
+        this.spSpecs = spSpecs;
+    }
+
+
+    /**
+     * Gets the action time.
+     *
+     * @return the action time
+     */
+    public ActionTime getActionTime()
+    {
+        return actionTime;
+    }
+
+
+    /**
+     * Gets the LDAP operation.
+     *
+     * @return the LDAP operation
+     */
+    public LdapOperation getLdapOperation()
+    {
+        return ldapOperation;
+    }
+
+
+    /**
+     * Gets the stored procedure specs.
+     *
+     * @return the stored procedure specs
+     */
+    public List<SPSpec> getSPSpecs()
+    {
+        return spSpecs;
+    }
+
+    /**
+     * The stored procedure spec bean.
+     */
+    public static class SPSpec
+    {
+        private String name;
+
+        private List<StoredProcedureOption> options;
+
+        private List<StoredProcedureParameter> parameters;
+
+
+        /**
+         * Instantiates a new stored procedure spec.
+         *
+         * @param name the name
+         * @param options the options
+         * @param parameters the parameters
+         */
+        public SPSpec( String name, List<StoredProcedureOption> options, List<StoredProcedureParameter> parameters )
+        {
+            super();
+            this.name = name;
+            this.options = options;
+            this.parameters = parameters;
+        }
+
+
+        /**
+         * Gets the name.
+         *
+         * @return the name
+         */
+        public String getName()
+        {
+            return name;
+        }
+
+
+        /**
+         * Gets the options.
+         *
+         * @return the options
+         */
+        public List<StoredProcedureOption> getOptions()
+        {
+            return options;
+        }
+
+
+        /**
+         * Gets the parameters.
+         *
+         * @return the parameters
+         */
+        public List<StoredProcedureParameter> getParameters()
+        {
+            return parameters;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int hashCode()
+        {
+            int h = 37;
+
+            h = h * 17 + ( ( name == null ) ? 0 : name.hashCode() );
+            h = h * 17 + ( ( options == null ) ? 0 : options.hashCode() );
+            h = h * 17 + ( ( parameters == null ) ? 0 : parameters.hashCode() );
+            return h;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean equals( Object obj )
+        {
+            if ( this == obj )
+            {
+                return true;
+            }
+            if ( obj == null )
+            {
+                return false;
+            }
+            if ( getClass() != obj.getClass() )
+            {
+                return false;
+            }
+            final SPSpec other = ( SPSpec ) obj;
+            if ( name == null )
+            {
+                if ( other.name != null )
+                {
+                    return false;
+                }
+            }
+            else if ( !name.equals( other.name ) )
+            {
+                return false;
+            }
+            if ( options == null )
+            {
+                if ( other.options != null )
+                {
+                    return false;
+                }
+            }
+            else if ( !options.equals( other.options ) )
+            {
+                return false;
+            }
+            if ( parameters == null )
+            {
+                if ( other.parameters != null )
+                {
+                    return false;
+                }
+            }
+            else if ( !parameters.equals( other.parameters ) )
+            {
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerSpecificationParser.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerSpecificationParser.java
new file mode 100644
index 0000000..05afd52
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerSpecificationParser.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+import java.io.StringReader;
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.NormalizerMappingResolver;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper around the ANTLR generated parser for a
+ * TriggerSpecification. This class enables the reuse of the antlr parser/lexer
+ * pair without having to recreate them every time.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TriggerSpecificationParser
+{
+    /** the antlr generated parser being wrapped */
+    private ReusableAntlrTriggerSpecificationParser parser;
+
+    /** the antlr generated lexer being wrapped */
+    private ReusableAntlrTriggerSpecificationLexer lexer;
+
+    private final boolean isNormalizing;
+
+
+    /**
+     * Creates a TriggerSpecification parser.
+     */
+    public TriggerSpecificationParser()
+    {
+        this.lexer = new ReusableAntlrTriggerSpecificationLexer( new StringReader( "" ) );
+        this.parser = new ReusableAntlrTriggerSpecificationParser( lexer );
+
+        // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.parser.init();
+        this.isNormalizing = false;
+    }
+
+
+    /**
+     * Creates a normalizing TriggerSpecification parser.
+     *
+     * @param resolver the resolver
+     */
+    public TriggerSpecificationParser( NormalizerMappingResolver<Normalizer> resolver )
+    {
+        this.lexer = new ReusableAntlrTriggerSpecificationLexer( new StringReader( "" ) );
+        this.parser = new ReusableAntlrTriggerSpecificationParser( lexer );
+
+        this.parser.setNormalizerMappingResolver( resolver );
+        // this method MUST be called while we cannot do
+        // constructor overloading for ANTLR generated parser
+        this.parser.init();
+        this.isNormalizing = true;
+    }
+
+
+    /**
+     * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+     * pair with it.
+     * 
+     * @param
+     *          spec the specification to be parsed
+     */
+    private synchronized void reset( String spec )
+    {
+        StringReader in = new StringReader( spec );
+        this.lexer.prepareNextInput( in );
+        this.parser.resetState();
+    }
+
+
+    /**
+     * Parses an TriggerSpecification without exhausting the parser.
+     * 
+     * @param spec
+     *          the specification to be parsed
+     * @return the specification bean
+     * @throws ParseException
+     *          if there are any recognition errors (bad syntax)
+     */
+    public synchronized TriggerSpecification parse( String spec ) throws ParseException
+    {
+        TriggerSpecification triggerSpecification = null;
+
+        if ( spec == null || spec.trim().equals( "" ) )
+        {
+            return null;
+        }
+
+        // reset and initialize the parser / lexer pair
+        reset( spec );
+
+        try
+        {
+            triggerSpecification = this.parser.wrapperEntryPoint();
+        }
+        catch ( TokenStreamException e )
+        {
+            String msg = I18n.err( I18n.ERR_04333, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, 0 );
+        }
+        catch ( RecognitionException e )
+        {
+            String msg = I18n.err( I18n.ERR_04333, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, e.getColumn() );
+        }
+
+        return triggerSpecification;
+
+    }
+
+
+    /**
+     * Tests to see if this parser is normalizing.
+     * 
+     * @return true if it normalizes false otherwise
+     */
+    public boolean isNormizing()
+    {
+        return this.isNormalizing;
+    }
+}
diff --git a/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerUtils.java b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerUtils.java
new file mode 100644
index 0000000..150d40a
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/main/java/org/apache/directory/api/ldap/trigger/TriggerUtils.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.AttributeUtils;
+
+
+/**
+ * A utility class for working with Triggers Execution Administrative Points
+ * Trigger Execution Subentries and Trigger Specifications.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class TriggerUtils
+{
+    public static final String TRIGGER_EXECUTION_SPECIFIC_AREA_VALUE = SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA;
+    public static final String TRIGGER_EXECUTION_SUBENTRY_OC = "triggerExecutionSubentry";
+    public static final String ENTRY_TRIGGER_SPECIFICATION_ATTR = "entryTriggerSpecification";
+    public static final String PRESCRIPTIVE_TRIGGER_SPECIFICATION_ATTR = "prescriptiveTriggerSpecification";
+
+
+    /**
+     * Private constructor.
+     */
+    private TriggerUtils()
+    {
+    }
+
+
+    public static void defineTriggerExecutionSpecificPoint( LdapContext apCtx ) throws NamingException
+    {
+        Attributes ap = apCtx.getAttributes( "", new String[]
+            { SchemaConstants.ADMINISTRATIVE_ROLE_AT } );
+        Attribute administrativeRole = ap.get( SchemaConstants.ADMINISTRATIVE_ROLE_AT );
+        if ( administrativeRole == null
+            || !AttributeUtils.containsValueCaseIgnore( administrativeRole, TRIGGER_EXECUTION_SPECIFIC_AREA_VALUE ) )
+        {
+            Attributes changes = new BasicAttributes( SchemaConstants.ADMINISTRATIVE_ROLE_AT,
+                TRIGGER_EXECUTION_SPECIFIC_AREA_VALUE, true );
+            apCtx.modifyAttributes( "", DirContext.ADD_ATTRIBUTE, changes );
+        }
+    }
+
+
+    public static void createTriggerExecutionSubentry(
+        LdapContext apCtx,
+        String subentryCN,
+        String subtreeSpec,
+        String prescriptiveTriggerSpec ) throws NamingException
+    {
+        Attributes subentry = new BasicAttributes( SchemaConstants.CN_AT, subentryCN, true );
+        Attribute objectClass = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT );
+        subentry.put( objectClass );
+        objectClass.add( SchemaConstants.TOP_OC );
+        objectClass.add( SchemaConstants.SUBENTRY_OC );
+        objectClass.add( TRIGGER_EXECUTION_SUBENTRY_OC );
+        subentry.put( SchemaConstants.SUBTREE_SPECIFICATION_AT, subtreeSpec );
+        subentry.put( PRESCRIPTIVE_TRIGGER_SPECIFICATION_ATTR, prescriptiveTriggerSpec );
+        apCtx.createSubcontext( "cn=" + subentryCN, subentry );
+    }
+
+
+    public static void loadPrescriptiveTriggerSpecification(
+        LdapContext apCtx,
+        String subentryCN,
+        String triggerSpec ) throws NamingException
+    {
+        Attributes changes = new BasicAttributes( PRESCRIPTIVE_TRIGGER_SPECIFICATION_ATTR, triggerSpec, true );
+        apCtx.modifyAttributes( "cn=" + subentryCN, DirContext.ADD_ATTRIBUTE, changes );
+    }
+
+
+    public static void loadEntryTriggerSpecification(
+        LdapContext ctx,
+        String triggerSpec ) throws NamingException
+    {
+        Attributes changes = new BasicAttributes( ENTRY_TRIGGER_SPECIFICATION_ATTR, triggerSpec, true );
+        ctx.modifyAttributes( "", DirContext.ADD_ATTRIBUTE, changes );
+    }
+}
diff --git a/trunk/ldap/extras/trigger/src/site/site.xml b/trunk/ldap/extras/trigger/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/extras/trigger/src/test/java/org/apache/directory/api/ldap/trigger/TriggerSpecificationParserTest.java b/trunk/ldap/extras/trigger/src/test/java/org/apache/directory/api/ldap/trigger/TriggerSpecificationParserTest.java
new file mode 100644
index 0000000..3bdcd9a
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/test/java/org/apache/directory/api/ldap/trigger/TriggerSpecificationParserTest.java
@@ -0,0 +1,247 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.trigger;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.trigger.ActionTime;
+import org.apache.directory.api.ldap.trigger.LdapOperation;
+import org.apache.directory.api.ldap.trigger.StoredProcedureLanguageSchemeOption;
+import org.apache.directory.api.ldap.trigger.StoredProcedureParameter;
+import org.apache.directory.api.ldap.trigger.StoredProcedureSearchContextOption;
+import org.apache.directory.api.ldap.trigger.TriggerSpecification;
+import org.apache.directory.api.ldap.trigger.TriggerSpecificationParser;
+import org.apache.directory.api.ldap.trigger.TriggerSpecification.SPSpec;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests for {@link org.apache.directory.api.ldap.trigger.TriggerSpecificationParser}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TriggerSpecificationParserTest
+{
+
+    /** The Trigger Specification parser */
+    TriggerSpecificationParser parser;
+
+
+    /**
+     * Creates a TriggerSpecificationParserTest instance.
+     */
+    public TriggerSpecificationParserTest()
+    {
+        super();
+        parser = new TriggerSpecificationParser();
+    }
+
+
+    @Test
+    public void testWithOperationParameters() throws Exception
+    {
+        TriggerSpecification triggerSpecification = null;
+
+        String spec = "AFTER Delete CALL \"BackupUtilities.backupDeletedEntry\" ($name, $deletedEntry);";
+
+        triggerSpecification = parser.parse( spec );
+
+        assertNotNull( triggerSpecification );
+        assertEquals( triggerSpecification.getActionTime(), ActionTime.AFTER );
+        assertEquals( triggerSpecification.getLdapOperation(), LdapOperation.DELETE );
+        List<SPSpec> spSpecs = triggerSpecification.getSPSpecs();
+        assertTrue( spSpecs != null );
+        assertTrue( spSpecs.size() == 1 );
+        SPSpec theSpec = spSpecs.get( 0 );
+        assertEquals( theSpec.getName(), "BackupUtilities.backupDeletedEntry" );
+        assertEquals( theSpec.getOptions().size(), 0 );
+        assertEquals( theSpec.getParameters().size(), 2 );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_NAME.instance() ) );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_DELETED_ENTRY.instance() ) );
+    }
+
+
+    @Test
+    public void testWithGenericParameters() throws Exception
+    {
+        TriggerSpecification triggerSpecification = null;
+
+        String spec = "AFTER Add CALL \"Logger.logAddOperation\" ($entry, $attributes, $operationPrincipal);";
+
+        triggerSpecification = parser.parse( spec );
+
+        assertNotNull( triggerSpecification );
+        assertEquals( triggerSpecification.getActionTime(), ActionTime.AFTER );
+        assertEquals( triggerSpecification.getLdapOperation(), LdapOperation.ADD );
+        List<SPSpec> spSpecs = triggerSpecification.getSPSpecs();
+        assertTrue( spSpecs != null );
+        assertTrue( spSpecs.size() == 1 );
+        SPSpec theSpec = spSpecs.get( 0 );
+        assertEquals( theSpec.getName(), "Logger.logAddOperation" );
+        assertEquals( theSpec.getOptions().size(), 0 );
+        assertEquals( theSpec.getParameters().size(), 3 );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Add_ENTRY.instance() ) );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Add_ATTRIBUTES.instance() ) );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Generic_OPERATION_PRINCIPAL.instance() ) );
+    }
+
+
+    @Test
+    public void testWithLanguageSchemeOption() throws Exception
+    {
+        TriggerSpecification triggerSpecification = null;
+
+        String spec = "AFTER Modify CALL \"Logger.logModifyOperation\" {languageScheme \"Java\"}();";
+
+        triggerSpecification = parser.parse( spec );
+
+        assertNotNull( triggerSpecification );
+        assertEquals( triggerSpecification.getActionTime(), ActionTime.AFTER );
+        assertEquals( triggerSpecification.getLdapOperation(), LdapOperation.MODIFY );
+        List<SPSpec> spSpecs = triggerSpecification.getSPSpecs();
+        assertTrue( spSpecs != null );
+        assertTrue( spSpecs.size() == 1 );
+        SPSpec theSpec = spSpecs.get( 0 );
+        assertEquals( theSpec.getName(), "Logger.logModifyOperation" );
+        assertEquals( theSpec.getOptions().size(), 1 );
+        assertTrue( theSpec.getOptions().contains(
+            new StoredProcedureLanguageSchemeOption( "Java" ) ) );
+        assertEquals( theSpec.getParameters().size(), 0 );
+    }
+
+
+    @Test
+    public void testWithSearchContextOption() throws Exception
+    {
+        TriggerSpecification triggerSpecification = null;
+
+        String spec = "AFTER ModifyDN.Rename CALL \"Logger.logModifyDNRenameOperation\" \n" +
+            "{ searchContext { scope one } \"cn=Logger,ou=Stored Procedures,ou=system\" } \n" +
+            "($entry, $newrdn);  # Stored Procedure Parameter(s)";
+
+        triggerSpecification = parser.parse( spec );
+
+        assertNotNull( triggerSpecification );
+        assertEquals( triggerSpecification.getActionTime(), ActionTime.AFTER );
+        assertEquals( triggerSpecification.getLdapOperation(), LdapOperation.MODIFYDN_RENAME );
+        List<SPSpec> spSpecs = triggerSpecification.getSPSpecs();
+        assertTrue( spSpecs != null );
+        assertTrue( spSpecs.size() == 1 );
+        SPSpec theSpec = spSpecs.get( 0 );
+        assertEquals( theSpec.getName(), "Logger.logModifyDNRenameOperation" );
+        assertEquals( theSpec.getOptions().size(), 1 );
+        assertTrue( theSpec.getOptions().contains(
+            new StoredProcedureSearchContextOption(
+                new Dn( "cn=Logger,ou=Stored Procedures,ou=system" ), SearchScope.ONELEVEL ) ) );
+        assertEquals( theSpec.getParameters().size(), 2 );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.ModifyDN_ENTRY.instance() ) );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.ModifyDN_NEW_RDN.instance() ) );
+    }
+
+
+    @Test
+    public void testWithLdapContextParameter() throws Exception
+    {
+        TriggerSpecification triggerSpecification = null;
+
+        String spec = "AFTER Delete CALL \"BackupUtilities.backupDeletedEntry\" ($ldapContext \"ou=Backup,ou=System\", $name, $deletedEntry);";
+
+        triggerSpecification = parser.parse( spec );
+
+        assertNotNull( triggerSpecification );
+        assertEquals( triggerSpecification.getActionTime(), ActionTime.AFTER );
+        assertEquals( triggerSpecification.getLdapOperation(), LdapOperation.DELETE );
+        List<SPSpec> spSpecs = triggerSpecification.getSPSpecs();
+        assertTrue( spSpecs != null );
+        assertTrue( spSpecs.size() == 1 );
+        SPSpec theSpec = spSpecs.get( 0 );
+        assertEquals( theSpec.getName(), "BackupUtilities.backupDeletedEntry" );
+        assertEquals( theSpec.getOptions().size(), 0 );
+        assertEquals( theSpec.getParameters().size(), 3 );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_NAME.instance() ) );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_DELETED_ENTRY.instance() ) );
+        assertTrue( theSpec.getParameters().contains(
+            StoredProcedureParameter.Generic_LDAP_CONTEXT.instance( new Dn( "ou=Backup,ou=System" ) ) ) );
+    }
+
+
+    @Test
+    public void testMultipleSPCalls() throws Exception
+    {
+        TriggerSpecification triggerSpecification = null;
+
+        String spec = "AFTER Delete "
+            +
+            "CALL \"BackupUtilities.backupDeletedEntry\" ($ldapContext \"ou=Backup,ou=System\", $name, $deletedEntry); "
+            +
+            "CALL \"BackupUtilities.recreateDeletedEntry\" ($name, $deletedEntry);";
+
+        triggerSpecification = parser.parse( spec );
+
+        assertNotNull( triggerSpecification );
+        assertEquals( triggerSpecification.getActionTime(), ActionTime.AFTER );
+        assertEquals( triggerSpecification.getLdapOperation(), LdapOperation.DELETE );
+        List<SPSpec> spSpecs = triggerSpecification.getSPSpecs();
+        assertTrue( spSpecs != null );
+        assertTrue( spSpecs.size() == 2 );
+        SPSpec firstSpec = spSpecs.get( 0 );
+        assertEquals( firstSpec.getName(), "BackupUtilities.backupDeletedEntry" );
+        assertEquals( firstSpec.getOptions().size(), 0 );
+        assertEquals( firstSpec.getParameters().size(), 3 );
+        assertTrue( firstSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_NAME.instance() ) );
+        assertTrue( firstSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_DELETED_ENTRY.instance() ) );
+        assertTrue( firstSpec.getParameters().contains(
+            StoredProcedureParameter.Generic_LDAP_CONTEXT.instance( new Dn( "ou=Backup,ou=System" ) ) ) );
+        SPSpec secondSpec = spSpecs.get( 1 );
+        assertEquals( secondSpec.getName(), "BackupUtilities.recreateDeletedEntry" );
+        assertEquals( secondSpec.getOptions().size(), 0 );
+        assertEquals( secondSpec.getParameters().size(), 2 );
+        assertTrue( secondSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_NAME.instance() ) );
+        assertTrue( secondSpec.getParameters().contains(
+            StoredProcedureParameter.Delete_DELETED_ENTRY.instance() ) );
+    }
+
+}
diff --git a/trunk/ldap/extras/trigger/src/test/resources/log4j.properties b/trunk/ldap/extras/trigger/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/extras/trigger/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/extras/util/pom.xml b/trunk/ldap/extras/util/pom.xml
new file mode 100644
index 0000000..affc71b
--- /dev/null
+++ b/trunk/ldap/extras/util/pom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-extras-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-extras-util</artifactId>
+  <name>Apache Directory LDAP API Extras Util</name>
+  <packaging>bundle</packaging>
+  <description>LDAP API Extra utility packages used by clients and servers</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.extras.util</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.util;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.util.tree;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.ldap.codec.api;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              javax.naming,
+              javax.naming.directory,
+              javax.naming.ldap
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/extras/util/src/checkstyle/suppressions.xml b/trunk/ldap/extras/util/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..f1fb9c4
--- /dev/null
+++ b/trunk/ldap/extras/util/src/checkstyle/suppressions.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <!-- UnixCrypt is from external, no formatting is applied -->
+    <suppress files="org.apache.directory.api.util.UnixCrypt" checks="[A-Za-z0-9]" />
+    
+    <!-- hashcode() is final in super class -->
+    <suppress files="org.apache.directory.api.ldap.model.schema.SyntaxChecker" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.Normalizer" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LoadableSchemaObject" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LdapComparator" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.DITStructureRule" checks="EqualsHashCode" />
+    
+    <!-- No Javadoc for schema constants required -->
+    <suppress files="org.apache.directory.api.ldap.model.constants.SchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.MetaSchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.PasswordPolicySchemaConstants" checks="JavadocVariable" />
+
+    <!-- Classes in org.apache.directory.api.asn1.der are forked from Bouncy Castle -->
+    <suppress files="org.apache.directory.api.asn1.der" checks="[A-Za-z0-9]" />
+</suppressions>
diff --git a/trunk/ldap/extras/util/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/extras/util/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/extras/util/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/extras/util/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/extras/util/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/extras/util/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/extras/util/src/main/java/org/apache/directory/api/ldap/util/JndiUtils.java b/trunk/ldap/extras/util/src/main/java/org/apache/directory/api/ldap/util/JndiUtils.java
new file mode 100644
index 0000000..71b10f4
--- /dev/null
+++ b/trunk/ldap/extras/util/src/main/java/org/apache/directory/api/ldap/util/JndiUtils.java
@@ -0,0 +1,427 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.util;
+
+
+import java.util.Hashtable;
+
+import javax.naming.AuthenticationException;
+import javax.naming.AuthenticationNotSupportedException;
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.ContextNotEmptyException;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import javax.naming.NoPermissionException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.PartialResultException;
+import javax.naming.ReferralException;
+import javax.naming.ServiceUnavailableException;
+import javax.naming.TimeLimitExceededException;
+import javax.naming.directory.AttributeInUseException;
+import javax.naming.directory.InvalidAttributeIdentifierException;
+import javax.naming.directory.InvalidAttributeValueException;
+import javax.naming.directory.InvalidSearchFilterException;
+import javax.naming.directory.NoSuchAttributeException;
+import javax.naming.directory.SchemaViolationException;
+import javax.naming.ldap.LdapName;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.model.exception.LdapAffectMultipleDsaException;
+import org.apache.directory.api.ldap.model.exception.LdapAliasDereferencingException;
+import org.apache.directory.api.ldap.model.exception.LdapAliasException;
+import org.apache.directory.api.ldap.model.exception.LdapAttributeInUseException;
+import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
+import org.apache.directory.api.ldap.model.exception.LdapAuthenticationNotSupportedException;
+import org.apache.directory.api.ldap.model.exception.LdapContextNotEmptyException;
+import org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeTypeException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidSearchFilterException;
+import org.apache.directory.api.ldap.model.exception.LdapLoopDetectedException;
+import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchObjectException;
+import org.apache.directory.api.ldap.model.exception.LdapOperationErrorException;
+import org.apache.directory.api.ldap.model.exception.LdapOtherException;
+import org.apache.directory.api.ldap.model.exception.LdapPartialResultException;
+import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
+import org.apache.directory.api.ldap.model.exception.LdapReferralException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
+import org.apache.directory.api.ldap.model.exception.LdapServiceUnavailableException;
+import org.apache.directory.api.ldap.model.exception.LdapTimeLimitExceededException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * An utility class to convert back and forth JNDI classes to ADS classes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class JndiUtils
+{
+    /**
+     * Private constructor.
+     */
+    private JndiUtils()
+    {
+    }
+
+
+    // @TODO not really needed and can be moved out
+    public static javax.naming.ldap.Control toJndiControl( LdapApiService codec, Control control )
+        throws EncoderException
+    {
+        return codec.toJndiControl( control );
+    }
+
+
+    // @TODO not really needed and can be moved out
+    public static javax.naming.ldap.Control[] toJndiControls( LdapApiService codec, Control... controls )
+        throws EncoderException
+    {
+        if ( controls != null )
+        {
+            javax.naming.ldap.Control[] jndiControls = new javax.naming.ldap.Control[controls.length];
+            int i = 0;
+
+            for ( Control control : controls )
+            {
+                jndiControls[i++] = toJndiControl( codec, control );
+            }
+
+            return jndiControls;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    // @TODO not really needed and can be moved out
+    public static Control fromJndiControl( LdapApiService codec, javax.naming.ldap.Control jndiControl )
+        throws DecoderException
+    {
+        return codec.fromJndiControl( jndiControl );
+    }
+
+
+    // @TODO not really needed and can be moved out
+    public static Control[] fromJndiControls( LdapApiService codec, javax.naming.ldap.Control... jndiControls )
+        throws DecoderException
+    {
+        if ( jndiControls != null )
+        {
+            Control[] controls = new Control[jndiControls.length];
+            int i = 0;
+
+            for ( javax.naming.ldap.Control jndiControl : jndiControls )
+            {
+                controls[i++] = fromJndiControl( codec, jndiControl );
+            }
+
+            return controls;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    public static void wrap( Throwable t ) throws NamingException
+    {
+        if ( t instanceof NamingException )
+        {
+            throw ( NamingException ) t;
+        }
+
+        NamingException ne = null;
+
+        if ( t instanceof LdapAffectMultipleDsaException )
+        {
+            ne = new NamingException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapAliasDereferencingException )
+        {
+            ne = new NamingException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapAliasException )
+        {
+            ne = new NamingException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapAttributeInUseException )
+        {
+            ne = new AttributeInUseException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapAuthenticationException )
+        {
+            ne = new AuthenticationException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapAuthenticationNotSupportedException )
+        {
+            ne = new AuthenticationNotSupportedException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapContextNotEmptyException )
+        {
+            ne = new ContextNotEmptyException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapEntryAlreadyExistsException )
+        {
+            ne = new NameAlreadyBoundException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapInvalidAttributeTypeException )
+        {
+            ne = new InvalidAttributeIdentifierException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapInvalidAttributeValueException )
+        {
+            ne = new InvalidAttributeValueException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapInvalidDnException )
+        {
+            ne = new InvalidNameException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapInvalidSearchFilterException )
+        {
+            ne = new InvalidSearchFilterException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapLoopDetectedException )
+        {
+            ne = new NamingException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapNoPermissionException )
+        {
+            ne = new NoPermissionException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapNoSuchAttributeException )
+        {
+            ne = new NoSuchAttributeException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapNoSuchObjectException )
+        {
+            ne = new NameNotFoundException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapOperationErrorException )
+        {
+            ne = new NamingException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapOtherException )
+        {
+            ne = new NamingException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapProtocolErrorException )
+        {
+            ne = new CommunicationException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapReferralException )
+        {
+            ne = new WrappedReferralException( ( LdapReferralException ) t );
+        }
+        else if ( t instanceof LdapPartialResultException )
+        {
+            ne = new WrappedPartialResultException( ( LdapPartialResultException ) t );
+        }
+        else if ( t instanceof LdapSchemaViolationException )
+        {
+            ne = new SchemaViolationException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapServiceUnavailableException )
+        {
+            ne = new ServiceUnavailableException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapTimeLimitExceededException )
+        {
+            ne = new TimeLimitExceededException( t.getLocalizedMessage() );
+        }
+        else if ( t instanceof LdapUnwillingToPerformException )
+        {
+            ne = new OperationNotSupportedException( t.getLocalizedMessage() );
+        }
+        else
+        {
+            ne = new NamingException( t.getLocalizedMessage() );
+        }
+
+        ne.setRootCause( t );
+
+        throw ne;
+    }
+
+
+    /**
+     * Convert a Dn to a {@link javax.naming.Name}
+     *
+     * @param name The Dn to convert
+     * @return A Name
+     */
+    public static Name toName( Dn dn )
+    {
+        try
+        {
+            Name name = new LdapName( dn.toString() );
+
+            return name;
+        }
+        catch ( InvalidNameException ine )
+        {
+            // TODO : check if we must throw an exception.
+            // Logically, the Dn must be valid.
+            return null;
+        }
+    }
+
+
+    /**
+     * Convert a {@link javax.naming.Name} to a Dn
+     *
+     * @param name The Name to convert
+     * @return A Dn
+     */
+    public static Dn fromName( Name name )
+    {
+        try
+        {
+            Dn dn = new Dn( name.toString() );
+
+            return dn;
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            // TODO : check if we must throw an exception.
+            // Logically, the Name must be valid.
+            return null;
+        }
+    }
+}
+
+// a ReferralException around the LdapReferralException to be used in tests
+class WrappedReferralException extends ReferralException
+{
+    private static final long serialVersionUID = 1L;
+
+    private LdapReferralException lre;
+
+
+    public WrappedReferralException( LdapReferralException lre )
+    {
+        this.lre = lre;
+    }
+
+
+    @Override
+    public boolean skipReferral()
+    {
+        return lre.skipReferral();
+    }
+
+
+    @Override
+    public void retryReferral()
+    {
+        lre.retryReferral();
+    }
+
+
+    @Override
+    public Object getReferralInfo()
+    {
+        return lre.getReferralInfo();
+    }
+
+
+    @Override
+    public Context getReferralContext( Hashtable<?, ?> env ) throws NamingException
+    {
+        return lre.getReferralContext( env );
+    }
+
+
+    @Override
+    public Context getReferralContext() throws NamingException
+    {
+        return lre.getReferralContext();
+    }
+
+
+    @Override
+    public Name getRemainingName()
+    {
+        return JndiUtils.toName( lre.getRemainingDn() );
+    }
+
+
+    @Override
+    public Object getResolvedObj()
+    {
+        return lre.getResolvedObject();
+    }
+
+
+    @Override
+    public Name getResolvedName()
+    {
+        return JndiUtils.toName( lre.getResolvedDn() );
+    }
+}
+
+// a PartialResultException around the LdapPartialResultException to be used in tests
+class WrappedPartialResultException extends PartialResultException
+{
+    private static final long serialVersionUID = 1L;
+
+    private LdapPartialResultException lpre;
+
+
+    public WrappedPartialResultException( LdapPartialResultException lpre )
+    {
+        this.lpre = lpre;
+    }
+
+
+    @Override
+    public Name getRemainingName()
+    {
+        return JndiUtils.toName( lpre.getRemainingDn() );
+    }
+
+
+    @Override
+    public Object getResolvedObj()
+    {
+        return lpre.getResolvedObject();
+    }
+
+
+    @Override
+    public Name getResolvedName()
+    {
+        return JndiUtils.toName( lpre.getResolvedDn() );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/extras/util/src/main/java/org/apache/directory/api/ldap/util/tree/DnNode.java b/trunk/ldap/extras/util/src/main/java/org/apache/directory/api/ldap/util/tree/DnNode.java
new file mode 100644
index 0000000..eb4980f
--- /dev/null
+++ b/trunk/ldap/extras/util/src/main/java/org/apache/directory/api/ldap/util/tree/DnNode.java
@@ -0,0 +1,1066 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.util.tree;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class storing nodes in a tree designed to map DNs.<br/>
+ * Branch nodes in this tree refers to child nodes. Leaf nodes in the tree
+ * don't have any children. <br/>
+ * A node may contain a reference to an object whose suffix is the path through the
+ * nodes of the tree from the root. <br/>
+ * A node may also have no attached element.<br/>
+ * Each child node is referenced by a Rdn, and holds the full Dn corresponding to its position<br/>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <N> The type of node we store
+ */
+public class DnNode<N> implements Cloneable
+{
+    /** The logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DnNode.class );
+
+    /** The stored element */
+    private N nodeElement;
+
+    /** The node's key */
+    private Rdn nodeRdn;
+
+    /** The node's Dn */
+    private Dn nodeDn;
+
+    /** The node's depth in the tree */
+    private int depth;
+
+    /** The parent, if any */
+    private DnNode<N> parent;
+
+    /** Stores the list of all the descendant */
+    private Map<Rdn, DnNode<N>> children;
+
+
+    //-------------------------------------------------------------------------
+    // Helper methods
+    //-------------------------------------------------------------------------
+    /**
+     * Check that the Dn is not null
+     */
+    private void checkDn( Dn dn ) throws LdapException
+    {
+        if ( ( dn == null ) || dn.isEmpty() )
+        {
+            String message = "Cannot process an empty Dn";
+            LOG.error( message );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, message );
+        }
+    }
+
+
+    /**
+     * Create a new DnNode, recursively creating all the intermediate nodes.
+     */
+    private DnNode<N> createNode( Dn dn, N element, int nbRdns ) throws LdapException
+    {
+        checkDn( dn );
+
+        DnNode<N> rootNode = null;
+
+        // No parent : add from the current position
+        for ( Rdn rdn : dn.getRdns() )
+        {
+            if ( nbRdns == 0 )
+            {
+                break;
+            }
+
+            if ( rootNode == null )
+            {
+                // Create the new top node
+                DnNode<N> node = new DnNode<N>( element );
+                node.nodeRdn = rdn;
+                node.nodeDn = dn;
+                node.depth = dn.size() + depth;
+
+                rootNode = node;
+            }
+            else
+            {
+                DnNode<N> node = new DnNode<N>();
+                node.nodeRdn = rdn;
+                node.nodeDn = rootNode.nodeDn.getParent();
+                node.depth = node.nodeDn.size() + depth;
+                rootNode.parent = node;
+                node.children.put( rootNode.nodeRdn, rootNode );
+                rootNode = node;
+            }
+
+            nbRdns--;
+        }
+
+        return rootNode;
+    }
+
+
+    /**
+     * Store the given element into the node
+     */
+    private synchronized void setElement( N element )
+    {
+        this.nodeElement = element;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Constructors
+    //-------------------------------------------------------------------------
+    /**
+     * Creates a new instance of DnNode.
+     */
+    public DnNode()
+    {
+        children = new HashMap<Rdn, DnNode<N>>();
+        nodeDn = Dn.EMPTY_DN;
+        nodeRdn = Rdn.EMPTY_RDN;
+    }
+
+
+    /**
+     * Creates a new instance of DnNode.
+     *
+     * @param element the element to store
+     */
+    public DnNode( N element )
+    {
+        this.nodeElement = element;
+        children = new HashMap<Rdn, DnNode<N>>();
+    }
+
+
+    /**
+     * Creates a new instance of DnNode.
+     *
+     * @param dn the node's Dn
+     * @param element the element to store
+     */
+    public DnNode( Dn dn, N element )
+    {
+        if ( ( dn == null ) || ( dn.isEmpty() ) )
+        {
+            children = new HashMap<Rdn, DnNode<N>>();
+            this.nodeDn = Dn.EMPTY_DN;
+
+            return;
+        }
+
+        try
+        {
+            DnNode<N> rootNode = createNode( dn, element, dn.size() );
+
+            // Now copy back the created node into this
+            this.children = rootNode.children;
+            this.depth = rootNode.depth;
+            this.nodeDn = rootNode.nodeDn;
+            this.nodeElement = rootNode.nodeElement;
+            this.nodeRdn = rootNode.nodeRdn;
+            this.parent = null;
+        }
+        catch ( LdapException le )
+        {
+            // Special cas e: the Dn is empty, this is not allowed
+            throw new IllegalArgumentException( le.getMessage(), le );
+        }
+    }
+
+
+    /**
+     * Tells if the implementation is a leaf node. If it's a branch node
+     * then false is returned.
+     *
+     * @return <code>true</code> if the class is a leaf node, false otherwise.
+     */
+    public synchronized boolean isLeaf()
+    {
+        return !hasChildren();
+    }
+
+
+    /**
+     * Tells if the implementation is a leaf node. If it's a branch node
+     * then false is returned.
+     *
+     * @param dn The Dn we want to check
+     * @return <code>true</code> if this is a leaf node, false otherwise.
+     */
+    public synchronized boolean isLeaf( Dn dn )
+    {
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return false;
+        }
+
+        return node.children.size() == 0;
+    }
+
+
+    /**
+     * Returns the number of entries under this node. It includes
+     * the node itself, plus the number of all it children and descendants.
+     *
+     * @return The number of descendents
+     */
+    public synchronized int size()
+    {
+        // The node itself
+        int size = 1;
+
+        // Iterate through the children if any
+        if ( children.size() != 0 )
+        {
+            for ( DnNode<N> node : children.values() )
+            {
+                size += node.size();
+            }
+        }
+
+        return size;
+    }
+
+
+    /**
+     * @return Return the stored element, if any
+     */
+    public synchronized N getElement()
+    {
+        return nodeElement;
+    }
+
+
+    /**
+     * @return Return the stored element, if any
+     * @param dn The Dn we want to get the element for
+     */
+    public synchronized N getElement( Dn dn )
+    {
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return null;
+        }
+
+        return node.nodeElement;
+    }
+
+
+    /**
+     * @return True if the Node stores an element. BranchNode may not hold any
+     * element.
+     */
+    public synchronized boolean hasElement()
+    {
+        return nodeElement != null;
+    }
+
+
+    /**
+     * @return True if the Node stores an element. BranchNode may not hold any
+     * element.
+     * @param dn The Dn we want to get the element for
+     */
+    public synchronized boolean hasElement( Dn dn )
+    {
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return false;
+        }
+
+        return node.nodeElement != null;
+    }
+
+
+    /**
+     * recursively check if the node has a descendant having an element
+     */
+    private synchronized boolean hasDescendantElement( DnNode<N> node )
+    {
+        if ( node == null )
+        {
+            return false;
+        }
+
+        if ( node.hasElement() )
+        {
+            return true;
+        }
+
+        for ( DnNode<N> child : node.getChildren().values() )
+        {
+            if ( hasDescendantElement( child ) )
+            {
+                return true;
+            }
+        }
+
+        // Nothing found ...
+        return false;
+    }
+
+
+    /**
+     * @return True if one of the node below the current node has one element, 
+     * False otherwise
+     * @param dn The Dn we want to get the element for
+     */
+    public synchronized boolean hasDescendantElement( Dn dn )
+    {
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return false;
+        }
+
+        // We must be at the right place in the tree
+        if ( node.getDn().size() != dn.size() )
+        {
+            return false;
+        }
+
+        if ( node.hasChildren() )
+        {
+            for ( DnNode<N> child : node.getChildren().values() )
+            {
+                if ( hasDescendantElement( child ) )
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * recursively get all the elements from nodes having an element
+     */
+    private synchronized void getDescendantElements( DnNode<N> node, List<N> descendants )
+    {
+        if ( node == null )
+        {
+            return;
+        }
+
+        if ( node.hasElement() )
+        {
+            descendants.add( node.getElement() );
+
+            // Stop here
+            return;
+        }
+
+        for ( DnNode<N> child : node.getChildren().values() )
+        {
+            getDescendantElements( child, descendants );
+        }
+    }
+
+
+    /**
+     * @return True if one of the node below the current node has one element, 
+     * False otherwise
+     * @param dn The Dn we want to get the element for
+     */
+    public synchronized List<N> getDescendantElements( Dn dn )
+    {
+        List<N> descendants = new ArrayList<N>();
+
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return descendants;
+        }
+
+        // We must be at the right place in the tree
+        if ( node.getDn().size() != dn.size() )
+        {
+            return descendants;
+        }
+
+        if ( node.hasChildren() )
+        {
+            for ( DnNode<N> child : node.getChildren().values() )
+            {
+                getDescendantElements( child, descendants );
+            }
+        }
+
+        return descendants;
+    }
+
+
+    /**
+     * Tells if the current DnNode has some children or not
+     *
+     * @return <code>true</code> if the node has some children
+     */
+    public synchronized boolean hasChildren()
+    {
+        return ( children != null ) && children.size() != 0;
+    }
+
+
+    /**
+     * Tells if a node has some children or not.
+     *
+     * @param dn the node's Dn
+     * @return <code>true</code> if the node has some children
+     * @throws LdapException if the Dn is null or empty
+     */
+    public synchronized boolean hasChildren( Dn dn ) throws LdapException
+    {
+        checkDn( dn );
+
+        DnNode<N> node = getNode( dn );
+
+        return ( node != null ) && node.hasChildren();
+    }
+
+
+    /**
+     * @return The list of DnNode
+     */
+    public synchronized Map<Rdn, DnNode<N>> getChildren()
+    {
+        return children;
+    }
+
+
+    /**
+     * @return The parent DnNode, if any
+     */
+    public synchronized DnNode<N> getParent()
+    {
+        return parent;
+    }
+
+
+    /**
+     * @return True if the current DnNode has a parent
+     */
+    public synchronized boolean hasParent()
+    {
+        return parent != null;
+    }
+
+
+    /**
+     * Tells if there is a parent for a given Dn,. This parent should be a
+     * subset of the given dn.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the Dn: ou=example, dc=acme, dc=org will have a parent
+     * <br>For the Dn ou=apache, dc=org, there is no parent, so false will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return true if there is a parent associated with the normalized dn
+     */
+    public synchronized boolean hasParent( Dn dn )
+    {
+        List<Rdn> rdns = dn.getRdns();
+
+        DnNode<N> currentNode = this;
+        DnNode<N> parentNode = null;
+
+        // Iterate through all the Rdn until we find the associated element
+        for ( int i = rdns.size() - 1; i >= 0; i-- )
+        {
+            Rdn rdn = rdns.get( i );
+
+            if ( rdn.equals( currentNode.nodeRdn ) )
+            {
+                parentNode = currentNode;
+            }
+            else if ( currentNode.hasChildren() )
+            {
+                currentNode = currentNode.children.get( rdn );
+
+                if ( currentNode == null )
+                {
+                    break;
+                }
+
+                parentNode = currentNode;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        return ( parentNode != null );
+    }
+
+
+    /**
+     * Add a new node in the tree. The added node won't have any element.
+     *
+     * @param dn The node's Dn
+     * @return the corresponding node
+     * @throws LdapException if the Dn is null or empty
+     */
+    public synchronized DnNode<N> add( Dn dn ) throws LdapException
+    {
+        return add( dn, null );
+    }
+
+
+    /**
+     * Add a new node in the tree. We can't add a node if its Dn is empty. The
+     * added element is attached to the node, which is named by the Dn's Rdn.<br/>
+     *
+     * @param dn The node's Dn
+     * @param element The element to associate with this Node. Can be null.
+     * @return the corresponding node
+     * @throws LdapException if the Dn is null or empty
+     */
+    public synchronized DnNode<N> add( Dn dn, N element ) throws LdapException
+    {
+        checkDn( dn );
+
+        // We first have to find the Node which will be the parent
+        DnNode<N> parentNode = getNode( dn );
+
+        if ( parentNode == null )
+        {
+            // No parent : add a new node to the root
+            DnNode<N> childNode = createNode( dn, element, dn.size() );
+            childNode.parent = this;
+            children.put( childNode.nodeRdn, childNode );
+            
+            return childNode;
+        }
+        else
+        {
+            // We have a parent. Add the new node to the found parent
+            int nbRdns = dn.size() - parentNode.depth;
+
+            if ( nbRdns == 0 )
+            {
+                // That means the added Dn is already present. Check if it already has an element
+                if ( parentNode.hasElement() )
+                {
+                    String message = "Cannot add a node to a node already having an element";
+                    LOG.error( message );
+                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, message );
+                }
+                // We may try to add twice the same Dn, without any element
+                else if ( element == null )
+                {
+                    String message = "Cannot add a node with no element if it already exists";
+                    LOG.error( message );
+                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, message );
+                }
+                // All is fine : we are just injecting some data into an existing node
+                else
+                {
+                    parentNode.setElement( element );
+                    
+                    return parentNode;
+                }
+            }
+            else
+            {
+                DnNode<N> childNode = createNode( dn, element, nbRdns );
+
+                // done. now, add the newly created tree to the parent node
+                childNode.parent = parentNode;
+                parentNode.children.put( childNode.nodeRdn, childNode );
+
+                return childNode;
+            }
+        }
+    }
+
+
+    /**
+     * Removes a node from the tree.
+     *
+     * @param dn the node's Dn
+     * @throws LdapException if the Dn is null or empty
+     */
+    public synchronized void remove( Dn dn ) throws LdapException
+    {
+        checkDn( dn );
+
+        // Find the parent first : we won't be able to remove
+        // a node if it's not present in the tree !
+        DnNode<N> parentNode = getNode( dn );
+
+        if ( parentNode == null )
+        {
+            return;
+        }
+
+        // Now, check that this parent has the same Dn than the one
+        // we gave and that there is no children
+        if ( ( dn.size() != parentNode.depth ) || parentNode.hasChildren() )
+        {
+            return;
+        }
+
+        // Ok, no children, same Dn, let's remove what we can.
+        parentNode = parentNode.getParent();
+
+        for ( Rdn rdn : dn.getRdns() )
+        {
+            parentNode.children.remove( rdn );
+
+            if ( parentNode.children.size() > 0 )
+            {
+                // We have to stop here, because the parent's node is shared with other Node.
+                break;
+            }
+
+            parentNode = parentNode.getParent();
+        }
+    }
+
+
+    /**
+     * Tells if the current DnBranchNode contains another node associated
+     * with an rdn.
+     *
+     * @param rdn The name we are looking for
+     * @return <code>true</code> if the tree instance contains this name
+     */
+    public synchronized boolean contains( Rdn rdn )
+    {
+        return children.containsKey( rdn );
+    }
+
+
+    /**
+     * Get's a child using an rdn string.
+     *
+     * @param rdn the rdn to use as the node key
+     * @return the child node corresponding to the rdn.
+     */
+    public synchronized DnNode<N> getChild( Rdn rdn )
+    {
+        if ( children.containsKey( rdn ) )
+        {
+            return children.get( rdn );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * @return The Node's Rdn
+     */
+    public synchronized Rdn getRdn()
+    {
+        return nodeRdn;
+    }
+
+
+    /**
+     * Get the Node for a given Dn, if present in the tree.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the Dn: ou=example, dc=acme, dc=org will have a parent, and
+     * dc=acme, dc=org will be returned.
+     * <br>For the Dn ou=apache, dc=org, there is no parent, so null will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return the Node associated with the normalized dn
+     */
+    public synchronized DnNode<N> getNode( Dn dn )
+    {
+        List<Rdn> rdns = dn.getRdns();
+
+        DnNode<N> currentNode = this;
+        DnNode<N> parentNode = null;
+
+        // Iterate through all the Rdn until we find the associated partition
+        for ( int i = rdns.size() - 1; i >= 0; i-- )
+        {
+            Rdn rdn = rdns.get( i );
+
+            if ( currentNode.hasChildren() )
+            {
+                currentNode = currentNode.children.get( rdn );
+
+                if ( currentNode == null )
+                {
+                    break;
+                }
+
+                parentNode = currentNode;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        return parentNode;
+    }
+
+
+    /**
+     * Get the closest Node for a given Dn which has an element, if present in the tree.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the Dn: ou=example, dc=acme, dc=org will have a parent, and
+     * dc=acme, dc=org will be returned if it has an associated element.
+     * <br>For the Dn ou=apache, dc=org, there is no parent, so null will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return the Node associated with the normalized dn
+     */
+    public synchronized boolean hasParentElement( Dn dn )
+    {
+        List<Rdn> rdns = dn.getRdns();
+
+        DnNode<N> currentNode = this;
+        boolean hasElement = false;
+
+        // Iterate through all the Rdn until we find the associated partition
+        for ( int i = rdns.size() - 1; i >= 0; i-- )
+        {
+            Rdn rdn = rdns.get( i );
+
+            if ( currentNode.hasChildren() )
+            {
+                currentNode = currentNode.children.get( rdn );
+
+                if ( currentNode == null )
+                {
+                    break;
+                }
+
+                if ( currentNode.hasElement() )
+                {
+                    hasElement = true;
+                }
+
+                parent = currentNode;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        return hasElement;
+    }
+
+
+    /**
+     * Get the closest Node for a given Dn which has an element, if present in the tree.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the Dn: ou=example, dc=acme, dc=org will have a parent, and
+     * dc=acme, dc=org will be returned if it has an associated element.
+     * <br>For the Dn ou=apache, dc=org, there is no parent, so null will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return the Node associated with the normalized dn
+     */
+    public synchronized DnNode<N> getParentWithElement( Dn dn )
+    {
+        List<Rdn> rdns = dn.getRdns();
+
+        DnNode<N> currentNode = this;
+        DnNode<N> element = null;
+
+        // Iterate through all the Rdn until we find the associated partition
+        for ( int i = rdns.size() - 1; i >= 1; i-- )
+        {
+            Rdn rdn = rdns.get( i );
+
+            if ( currentNode.hasChildren() )
+            {
+                currentNode = currentNode.children.get( rdn );
+
+                if ( currentNode == null )
+                {
+                    break;
+                }
+
+                if ( currentNode.hasElement() )
+                {
+                    element = currentNode;
+                }
+
+                parent = currentNode;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        return element;
+    }
+
+
+    /**
+     * Get the closest Node for a given Dn which has an element, if present in the tree.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the Dn: ou=example, dc=acme, dc=org will have a parent, and
+     * dc=acme, dc=org will be returned if it has an associated element.
+     * <br>For the Dn ou=apache, dc=org, there is no parent, so null will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return the Node associated with the normalized dn
+     */
+    public synchronized DnNode<N> getParentWithElement()
+    {
+        DnNode<N> currentNode = parent;
+
+        while ( currentNode != null )
+        {
+            if ( currentNode.nodeElement != null )
+            {
+                return currentNode;
+            }
+
+            currentNode = currentNode.parent;
+        }
+
+        return null;
+    }
+
+
+    /**
+     * rename the DnNode's Dn
+     * 
+     * @param newRdn the new Rdn of this node
+     * @throws LdapException
+     */
+    public synchronized void rename( Rdn newRdn ) throws LdapException
+    {
+        Dn temp = nodeDn.getParent();
+        temp = temp.add( newRdn );
+
+        Rdn oldRdn = nodeRdn;
+
+        nodeRdn = temp.getRdn();
+        nodeDn = temp;
+
+        if ( parent != null )
+        {
+            parent.children.remove( oldRdn );
+            parent.children.put( nodeRdn, this );
+        }
+
+        updateAfterModDn( nodeDn );
+    }
+
+
+    /**
+     * move the DnNode's Dn
+     *
+     * @param newParent the new parent Dn
+     * @throws LdapException
+     */
+    public synchronized void move( Dn newParent ) throws LdapException
+    {
+        DnNode<N> tmp = null;
+
+        Dn tmpDn = null;
+
+        // check if the new parent Dn is child of the parent
+        if ( newParent.isDescendantOf( parent.nodeDn ) )
+        {
+            tmp = parent;
+            tmpDn = parent.nodeDn;
+        }
+
+        // if yes, then drill for the new parent node
+        if ( tmpDn != null )
+        {
+            int parentNodeSize = tmpDn.size();
+            int count = newParent.size() - parentNodeSize;
+
+            while ( count-- > 0 )
+            {
+                tmp = tmp.getChild( newParent.getRdn( parentNodeSize++ ) );
+            }
+        }
+
+        // if not, we have to traverse all the way up to the 
+        // root node and then find the new parent node
+        if ( tmp == null )
+        {
+            tmp = this;
+            while ( tmp.parent != null )
+            {
+                tmp = tmp.parent;
+            }
+
+            tmp = tmp.getNode( newParent );
+        }
+
+        nodeDn = newParent.add( nodeRdn );
+        updateAfterModDn( nodeDn );
+
+        if ( parent != null )
+        {
+            parent.children.remove( nodeRdn );
+        }
+
+        parent = tmp;
+        parent.children.put( nodeRdn, this );
+    }
+
+
+    /**
+     * update the children's Dn based on the new parent Dn created
+     * after a rename or move operation
+     * 
+     * @param newParentDn
+     */
+    private synchronized void updateAfterModDn( Dn newParentDn ) throws LdapInvalidDnException
+    {
+        if ( children != null )
+        {
+            for ( DnNode<N> child : children.values() )
+            {
+                child.nodeDn = newParentDn.add( child.nodeRdn );
+                child.updateAfterModDn( child.nodeDn );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized DnNode<N> clone()
+    {
+        DnNode<N> clonedDnNode = new DnNode<N>();
+
+        clonedDnNode.nodeElement = nodeElement;
+        clonedDnNode.depth = depth;
+        clonedDnNode.parent = parent;
+        clonedDnNode.nodeRdn = nodeRdn;
+        clonedDnNode.nodeDn = nodeDn;
+
+        for ( DnNode<N> node : children.values() )
+        {
+            clonedDnNode.children.put( node.getRdn(), node.clone() );
+        }
+
+        return clonedDnNode;
+    }
+
+
+    private String toString( String tabs )
+    {
+        if ( nodeRdn == null )
+        {
+            return tabs;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append( tabs );
+
+        boolean hasChildren = hasChildren();
+
+        if ( isLeaf() )
+        {
+            sb.append( "Leaf[" ).append( nodeDn ).append( "]: " ).append( "'" ).append( nodeElement ).append( "'" );
+            return sb.toString();
+        }
+
+        sb.append( "Branch[" ).append( nodeDn ).append( "]: " );
+
+        if ( nodeElement != null )
+        {
+            sb.append( "'" ).append( nodeElement ).append( "'" );
+        }
+
+        tabs += "    ";
+
+        sb.append( '\n' );
+
+        boolean isFirst = true;
+
+        if ( hasChildren )
+        {
+            for ( Map.Entry<Rdn, DnNode<N>> entry : children.entrySet() )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( "\n" );
+                }
+
+                DnNode<N> child = entry.getValue();
+
+                sb.append( child.toString( tabs ) );
+            }
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return toString( "" );
+    }
+
+
+    /**
+     * @return the dn
+     */
+    public synchronized Dn getDn()
+    {
+        return nodeDn;
+    }
+}
diff --git a/trunk/ldap/extras/util/src/site/site.xml b/trunk/ldap/extras/util/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/extras/util/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/extras/util/src/test/java/org/apache/directory/api/ldap/util/tree/TestDnNode.java b/trunk/ldap/extras/util/src/test/java/org/apache/directory/api/ldap/util/tree/TestDnNode.java
new file mode 100644
index 0000000..777d747
--- /dev/null
+++ b/trunk/ldap/extras/util/src/test/java/org/apache/directory/api/ldap/util/tree/TestDnNode.java
@@ -0,0 +1,942 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.util.tree;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.util.tree.DnNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the Dn Nodes
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TestDnNode
+{
+    //---------------------------------------------------------------------------
+    // Test the Add( Dn ) operation
+    //---------------------------------------------------------------------------
+    /**
+     * Test the addition of a null Dn
+     */
+    @Test(expected = LdapUnwillingToPerformException.class)
+    public void testAddNullDNNoElem() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+
+        tree.add( null );
+    }
+
+
+    /**
+     * Test the addition of a Dn with three Rdn
+     */
+    @Test
+    public void testAdd3LevelDNNoElem() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>( Dn.EMPTY_DN, null );
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+
+        tree.add( dn );
+
+        assertNotNull( tree );
+
+        Map<Rdn, DnNode<Dn>> children = tree.getChildren();
+        assertNotNull( children );
+
+        assertEquals( 1, children.size() );
+        assertNull( tree.getElement() );
+
+        DnNode<Dn> level1 = children.get( new Rdn( "dc=a" ) );
+        DnNode<Dn> level2 = level1.getChildren().get( new Rdn( "dc=b" ) );
+        DnNode<Dn> level3 = level2.getChildren().get( new Rdn( "dc=c" ) );
+
+        assertNotNull( level3 );
+        assertFalse( level3.hasElement() );
+    }
+
+
+    /**
+     * Test the addition of two DNs not overlapping
+     */
+    @Test
+    public void testAdd2DistinctDNsNoElem() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        Dn dn2 = new Dn( "dc=f,dc=e" );
+
+        tree.add( dn1 );
+        tree.add( dn2 );
+
+        assertNotNull( tree );
+
+        Map<Rdn, DnNode<Dn>> children = tree.getChildren();
+        assertNotNull( children );
+
+        assertEquals( 2, children.size() );
+        assertNull( tree.getElement() );
+
+        DnNode<Dn> level1 = children.get( new Rdn( "dc=a" ) );
+        DnNode<Dn> level2 = level1.getChildren().get( new Rdn( "dc=b" ) );
+
+        assertNotNull( level2 );
+        assertFalse( level2.hasElement() );
+
+        level1 = children.get( new Rdn( "dc=e" ) );
+        level2 = level1.getChildren().get( new Rdn( "dc=f" ) );
+
+        assertNotNull( level2 );
+        assertFalse( level2.hasElement() );
+    }
+
+
+    /**
+     * Test the addition of two overlapping DNs
+     */
+    @Test
+    public void testAdd2OverlappingDNsNoElem() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        Dn dn2 = new Dn( "dc=f,dc=a" );
+
+        tree.add( dn1 );
+        tree.add( dn2 );
+
+        assertNotNull( tree );
+
+        Map<Rdn, DnNode<Dn>> children = tree.getChildren();
+        assertNotNull( children );
+
+        assertEquals( 1, children.size() );
+        assertNull( tree.getElement() );
+
+        DnNode<Dn> level1 = children.get( new Rdn( "dc=a" ) );
+        DnNode<Dn> level2 = level1.getChildren().get( new Rdn( "dc=b" ) );
+
+        Map<Rdn, DnNode<Dn>> childrenDn1 = level1.getChildren();
+        assertNotNull( childrenDn1 );
+
+        assertEquals( 2, childrenDn1.size() );
+        assertNull( level1.getElement() );
+
+        assertNotNull( level2 );
+        assertFalse( level2.hasElement() );
+
+        level1 = children.get( new Rdn( "dc=a" ) );
+        level2 = level1.getChildren().get( new Rdn( "dc=f" ) );
+
+        assertNotNull( level2 );
+        assertFalse( level2.hasElement() );
+    }
+
+
+    /**
+     * Test the addition of two equal DNs
+     */
+    @Test(expected = LdapUnwillingToPerformException.class)
+    public void testAdd2EqualDNsNoElem() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        Dn dn2 = new Dn( "dc=b,dc=a" );
+
+        tree.add( dn1 );
+        tree.add( dn2 );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the Add( Dn, N ) operation
+    //---------------------------------------------------------------------------
+    /**
+     * Test the addition of a null Dn
+     */
+    @Test(expected = LdapUnwillingToPerformException.class)
+    public void testAddNullDN() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+
+        tree.add( ( Dn ) null, null );
+    }
+
+
+    /**
+     * Test the addition of a Dn with three Rdn
+     */
+    @Test
+    public void testAdd3LevelDN() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+
+        tree.add( dn, dn );
+
+        assertNotNull( tree );
+
+        Map<Rdn, DnNode<Dn>> children = tree.getChildren();
+        assertNotNull( children );
+
+        assertEquals( 1, children.size() );
+        assertNull( tree.getElement() );
+
+        DnNode<Dn> level1 = children.get( new Rdn( "dc=a" ) );
+        DnNode<Dn> level2 = level1.getChildren().get( new Rdn( "dc=b" ) );
+        DnNode<Dn> level3 = level2.getChildren().get( new Rdn( "dc=c" ) );
+
+        assertNotNull( level3 );
+        assertEquals( dn, level3.getElement() );
+    }
+
+
+    /**
+     * Test the addition of two DNs not overlapping
+     */
+    @Test
+    public void testAdd2DistinctDNs() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        Dn dn2 = new Dn( "dc=f,dc=e" );
+
+        tree.add( dn1, dn1 );
+        tree.add( dn2, dn2 );
+
+        assertNotNull( tree );
+
+        Map<Rdn, DnNode<Dn>> children = tree.getChildren();
+        assertNotNull( children );
+
+        assertEquals( 2, children.size() );
+        assertNull( tree.getElement() );
+
+        DnNode<Dn> level1 = children.get( new Rdn( "dc=a" ) );
+        DnNode<Dn> level2 = level1.getChildren().get( new Rdn( "dc=b" ) );
+
+        assertNotNull( level2 );
+        assertEquals( dn1, level2.getElement() );
+
+        level1 = children.get( new Rdn( "dc=e" ) );
+        level2 = level1.getChildren().get( new Rdn( "dc=f" ) );
+
+        assertNotNull( level2 );
+        assertEquals( dn2, level2.getElement() );
+    }
+
+
+    /**
+     * Test the addition of two overlapping DNs
+     */
+    @Test
+    public void testAdd2OverlappingDNs() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        Dn dn2 = new Dn( "dc=f,dc=a" );
+
+        tree.add( dn1, dn1 );
+        tree.add( dn2, dn2 );
+
+        assertNotNull( tree );
+
+        Map<Rdn, DnNode<Dn>> children = tree.getChildren();
+        assertNotNull( children );
+
+        assertEquals( 1, children.size() );
+        assertNull( tree.getElement() );
+
+        DnNode<Dn> level1 = children.get( new Rdn( "dc=a" ) );
+        DnNode<Dn> level2 = level1.getChildren().get( new Rdn( "dc=b" ) );
+
+        Map<Rdn, DnNode<Dn>> childrenDn1 = level1.getChildren();
+        assertNotNull( childrenDn1 );
+
+        assertEquals( 2, childrenDn1.size() );
+        assertNull( level1.getElement() );
+
+        assertNotNull( level2 );
+        assertEquals( dn1, level2.getElement() );
+
+        level1 = children.get( new Rdn( "dc=a" ) );
+        level2 = level1.getChildren().get( new Rdn( "dc=f" ) );
+
+        assertNotNull( level2 );
+        assertEquals( dn2, level2.getElement() );
+    }
+
+
+    /**
+     * Test the addition of two equal DNs
+     */
+    @Test(expected = LdapUnwillingToPerformException.class)
+    public void testAdd2EqualDNs() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        Dn dn2 = new Dn( "dc=b,dc=a" );
+
+        tree.add( dn1, dn1 );
+        tree.add( dn2, dn2 );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the hasChildren method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testHasChildren() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        tree.add( dn1 );
+
+        assertTrue( tree.hasChildren() );
+        Map<Rdn, DnNode<Dn>> children = tree.getChildren();
+        assertNotNull( children );
+
+        DnNode<Dn> child = children.get( new Rdn( "dc=a" ) );
+        assertTrue( child.hasChildren() );
+
+        children = child.getChildren();
+        child = children.get( new Rdn( "dc=b" ) );
+        assertFalse( child.hasChildren() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the hasChildren(Dn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testHasChildrenDN() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=b,dc=a" );
+        tree.add( dn1 );
+
+        assertTrue( tree.hasChildren( new Dn( "dc=a" ) ) );
+        assertFalse( tree.hasChildren( dn1 ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the isLeaf() method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testIsLeaf() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn );
+
+        assertFalse( tree.isLeaf() );
+
+        DnNode<Dn> child = tree.getChild( new Rdn( "dc=a" ) );
+        assertFalse( child.isLeaf() );
+
+        child = child.getChild( new Rdn( "dc=b" ) );
+        assertFalse( child.isLeaf() );
+
+        child = child.getChild( new Rdn( "dc=c" ) );
+        assertTrue( child.isLeaf() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the isLeaf(Dn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testIsLeafDN() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn1, dn1 );
+
+        Dn dn2 = new Dn( "dc=e,dc=a" );
+        tree.add( dn2 );
+
+        assertFalse( tree.isLeaf( Dn.EMPTY_DN ) );
+        assertFalse( tree.isLeaf( new Dn( "dc=a" ) ) );
+        assertFalse( tree.isLeaf( new Dn( "dc=b,dc=a" ) ) );
+        assertTrue( tree.isLeaf( dn1 ) );
+        assertTrue( tree.isLeaf( dn2 ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the getElement() method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testGetElement() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn, dn );
+
+        assertNull( tree.getElement() );
+
+        DnNode<Dn> child = tree.getChild( new Rdn( "dc=a" ) );
+        assertNull( child.getElement() );
+
+        child = child.getChild( new Rdn( "dc=b" ) );
+        assertNull( child.getElement() );
+
+        child = child.getChild( new Rdn( "dc=c" ) );
+        assertEquals( dn, child.getElement() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the hasElement() method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testHasElement() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn, dn );
+
+        assertFalse( tree.hasElement() );
+
+        DnNode<Dn> child = tree.getChild( new Rdn( "dc=a" ) );
+        assertFalse( child.hasElement() );
+
+        child = child.getChild( new Rdn( "dc=b" ) );
+        assertFalse( child.hasElement() );
+
+        child = child.getChild( new Rdn( "dc=c" ) );
+        assertTrue( child.hasElement() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the getElement(Dn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testGetElementDN() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn1, dn1 );
+
+        Dn dn2 = new Dn( "dc=e,dc=a" );
+        tree.add( dn2, dn2 );
+
+        assertNull( tree.getElement( Dn.EMPTY_DN ) );
+        assertNull( tree.getElement( new Dn( "dc=a" ) ) );
+        assertNull( tree.getElement( new Dn( "dc=b,dc=a" ) ) );
+        assertEquals( dn1, tree.getElement( dn1 ) );
+        assertEquals( dn2, tree.getElement( dn2 ) );
+        assertEquals( dn2, tree.getElement( new Dn( "dc=g,dc=f,dc=e,dc=a" ) ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the hasElement(Dn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testHasElementDN() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn1, dn1 );
+
+        Dn dn2 = new Dn( "dc=e,dc=a" );
+        tree.add( dn2 );
+
+        assertFalse( tree.hasElement( Dn.EMPTY_DN ) );
+        assertFalse( tree.hasElement( new Dn( "dc=a" ) ) );
+        assertFalse( tree.hasElement( new Dn( "dc=b,dc=a" ) ) );
+        assertTrue( tree.hasElement( dn1 ) );
+        assertFalse( tree.hasElement( dn2 ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the size() method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testSize() throws LdapException
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        assertEquals( 1, tree.size() );
+
+        tree.add( new Dn( "dc=b,dc=a" ) );
+        assertEquals( 3, tree.size() );
+
+        tree.add( new Dn( "dc=f,dc=a" ) );
+        assertEquals( 4, tree.size() );
+
+        tree.add( new Dn( "dc=a,dc=f,dc=a" ) );
+        assertEquals( 5, tree.size() );
+
+        tree.add( new Dn( "dc=b,dc=f,dc=a" ) );
+        assertEquals( 6, tree.size() );
+
+        tree.add( new Dn( "dc=z,dc=t" ) );
+        assertEquals( 8, tree.size() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the getParent() method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testGetParent() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn, dn );
+
+        assertNull( tree.getParent() );
+
+        DnNode<Dn> child = tree.getChild( new Rdn( "dc=a" ) );
+        assertEquals( tree, child.getParent() );
+
+        DnNode<Dn> child1 = child.getChild( new Rdn( "dc=b" ) );
+        assertEquals( child, child1.getParent() );
+
+        child = child1.getChild( new Rdn( "dc=c" ) );
+        assertEquals( child1, child.getParent() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the getNode(Dn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testGetNodeDN() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn1, dn1 );
+
+        Dn dn2 = new Dn( "dc=e,dc=a" );
+        tree.add( dn2, dn2 );
+
+        assertNull( tree.getNode( Dn.EMPTY_DN ) );
+
+        DnNode<Dn> child = tree.getChild( new Rdn( "dc=a" ) );
+        assertEquals( child, tree.getNode( new Dn( "dc=a" ) ) );
+
+        child = child.getChild( new Rdn( "dc=b" ) );
+        assertEquals( child, tree.getNode( new Dn( "dc=b,dc=a" ) ) );
+
+        child = child.getChild( new Rdn( "dc=c" ) );
+        assertEquals( child, tree.getNode( new Dn( "dc=c,dc=b,dc=a" ) ) );
+
+        assertEquals( child, tree.getNode( new Dn( "dc=f,dc=e,dc=c,dc=b,dc=a" ) ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the hasParent() method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testHasParent() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn, dn );
+
+        assertFalse( tree.hasParent() );
+
+        DnNode<Dn> child = tree.getChild( new Rdn( "dc=a" ) );
+        assertTrue( child.hasParent() );
+
+        DnNode<Dn> child1 = child.getChild( new Rdn( "dc=b" ) );
+        assertTrue( child1.hasParent() );
+
+        child = child1.getChild( new Rdn( "dc=c" ) );
+        assertTrue( child.hasParent() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the hasParent(Dn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testHasParentDN() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn1, dn1 );
+
+        Dn dn2 = new Dn( "dc=e,dc=a" );
+        tree.add( dn2, dn2 );
+
+        assertFalse( tree.hasParent( Dn.EMPTY_DN ) );
+
+        DnNode<Dn> child = tree.getChild( new Rdn( "dc=a" ) );
+        assertTrue( tree.hasParent( new Dn( "dc=a" ) ) );
+
+        child = child.getChild( new Rdn( "dc=b" ) );
+        assertTrue( tree.hasParent( new Dn( "dc=b,dc=a" ) ) );
+
+        child = child.getChild( new Rdn( "dc=c" ) );
+        assertTrue( tree.hasParent( new Dn( "dc=c,dc=b,dc=a" ) ) );
+
+        assertTrue( tree.hasParent( new Dn( "dc=f,dc=e,dc=c,dc=b,dc=a" ) ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the getChild(Rdn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testGetChildRdn() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn, dn );
+
+        Rdn rdnA = new Rdn( "dc=a" );
+        Rdn rdnB = new Rdn( "dc=b" );
+        Rdn rdnC = new Rdn( "dc=c" );
+
+        DnNode<Dn> child = tree.getChild( rdnA );
+        assertNotNull( child );
+        assertEquals( rdnA, child.getRdn() );
+
+        child = child.getChild( rdnB );
+        assertNotNull( child );
+        assertEquals( rdnB, child.getRdn() );
+
+        child = child.getChild( rdnC );
+        assertNotNull( child );
+        assertEquals( rdnC, child.getRdn() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the contains(Rdn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testContains() throws Exception
+    {
+        DnNode<Dn> tree = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=c,dc=b,dc=a" );
+        tree.add( dn, dn );
+
+        Rdn rdnA = new Rdn( "dc=a" );
+        Rdn rdnB = new Rdn( "dc=b" );
+        Rdn rdnC = new Rdn( "dc=c" );
+
+        assertTrue( tree.contains( rdnA ) );
+        assertFalse( tree.contains( rdnB ) );
+        assertFalse( tree.contains( rdnC ) );
+
+        DnNode<Dn> child = tree.getChild( rdnA );
+
+        assertFalse( child.contains( rdnA ) );
+        assertTrue( child.contains( rdnB ) );
+        assertFalse( child.contains( rdnC ) );
+
+        child = child.getChild( rdnB );
+
+        assertFalse( child.contains( rdnA ) );
+        assertFalse( child.contains( rdnB ) );
+        assertTrue( child.contains( rdnC ) );
+    }
+
+
+    /**
+     * test the deletion of elements in a tree
+     */
+    @Test
+    public void testComplexTreeDeletion() throws LdapException
+    {
+        DnNode<Dn> dnLookupTree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=directory,dc=apache,dc=org" );
+        Dn dn2 = new Dn( "dc=mina,dc=apache,dc=org" );
+        Dn dn3 = new Dn( "dc=test,dc=com" );
+        Dn dn4 = new Dn( "dc=acme,dc=com" );
+        Dn dn5 = new Dn( "dc=acme,c=us,dc=com" );
+        Dn dn6 = new Dn( "dc=empty" );
+
+        dnLookupTree.add( dn1, dn1 );
+        dnLookupTree.add( dn2, dn2 );
+        dnLookupTree.add( dn3, dn3 );
+        dnLookupTree.add( dn4, dn4 );
+        dnLookupTree.add( dn5, dn5 );
+        dnLookupTree.add( dn6, dn6 );
+
+        assertEquals( 11, dnLookupTree.size() );
+
+        dnLookupTree.remove( dn3 );
+        assertEquals( 10, dnLookupTree.size() );
+        assertTrue( dnLookupTree.hasParent( dn1 ) );
+        assertTrue( dnLookupTree.hasParent( dn2 ) );
+        assertTrue( dnLookupTree.hasParent( dn4 ) );
+        assertTrue( dnLookupTree.hasParent( dn5 ) );
+        assertTrue( dnLookupTree.hasParent( dn6 ) );
+        assertTrue( dnLookupTree.hasParent( new Dn( "dc=nothing,dc=empty" ) ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=directory,dc=apache,dc=root" ) ) );
+
+        dnLookupTree.remove( dn6 );
+        assertEquals( 9, dnLookupTree.size() );
+        assertTrue( dnLookupTree.hasParent( dn1 ) );
+        assertTrue( dnLookupTree.hasParent( dn2 ) );
+        assertTrue( dnLookupTree.hasParent( dn4 ) );
+        assertTrue( dnLookupTree.hasParent( dn5 ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=nothing,dc=empty" ) ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=directory,dc=apache,dc=root" ) ) );
+
+        dnLookupTree.remove( dn1 );
+        assertEquals( 8, dnLookupTree.size() );
+        assertTrue( dnLookupTree.hasParent( dn2 ) );
+        assertTrue( dnLookupTree.hasParent( dn4 ) );
+        assertTrue( dnLookupTree.hasParent( dn5 ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=nothing,dc=empty" ) ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=directory,dc=apache,dc=root" ) ) );
+
+        // Should not change anything
+        dnLookupTree.remove( dn3 );
+        assertEquals( 8, dnLookupTree.size() );
+        assertTrue( dnLookupTree.hasParent( dn2 ) );
+        assertTrue( dnLookupTree.hasParent( dn4 ) );
+        assertTrue( dnLookupTree.hasParent( dn5 ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=nothing,dc=empty" ) ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=directory,dc=apache,dc=root" ) ) );
+
+        dnLookupTree.remove( dn5 );
+        assertEquals( 6, dnLookupTree.size() );
+        assertTrue( dnLookupTree.hasParent( dn2 ) );
+        assertTrue( dnLookupTree.hasParent( dn4 ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=nothing,dc=empty" ) ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=directory,dc=apache,dc=root" ) ) );
+
+        dnLookupTree.remove( dn2 );
+        assertEquals( 3, dnLookupTree.size() );
+        assertTrue( dnLookupTree.hasParent( dn4 ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=nothing,dc=empty" ) ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=directory,dc=apache,dc=root" ) ) );
+
+        dnLookupTree.remove( dn4 );
+        assertEquals( 1, dnLookupTree.size() );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=nothing,dc=empty" ) ) );
+        assertFalse( dnLookupTree.hasParent( new Dn( "dc=directory,dc=apache,dc=root" ) ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the hasParentElement(Dn) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testHasParentElement() throws Exception
+    {
+        DnNode<Dn> dnLookupTree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=directory,dc=apache,dc=org" );
+        Dn dn2 = new Dn( "dc=mina,dc=apache,dc=org" );
+        Dn dn3 = new Dn( "dc=test,dc=com" );
+        Dn dn4 = new Dn( "dc=acme,dc=com" );
+        Dn dn5 = new Dn( "dc=acme,c=us,dc=com" );
+        Dn dn6 = new Dn( "dc=empty" );
+
+        Dn org = new Dn( "dc=org" );
+
+        dnLookupTree.add( dn1, dn1 );
+        dnLookupTree.add( dn2, dn2 );
+        dnLookupTree.add( dn3, dn3 );
+        dnLookupTree.add( dn4, dn4 );
+        dnLookupTree.add( dn5 );
+        dnLookupTree.add( dn6, dn6 );
+
+        // Inject some intermediary nodes
+        dnLookupTree.add( org, org );
+
+        assertTrue( dnLookupTree.hasParentElement( new Dn( "dc=apache,dc=org" ) ) );
+
+        // Check that org has at least one descendant containing an element
+        assertTrue( dnLookupTree.hasDescendantElement( org ) );
+
+        // check that for one node which has no children with any element, we get false
+        assertFalse( dnLookupTree.hasDescendantElement( new Dn( "c=us,dc=com" ) ) );
+
+        // Check that we correctly get back all the children
+        Dn dn7 = new Dn( "dc=elem,dc=mina,dc=apache,dc=org" );
+        dnLookupTree.add( dn7, dn7 );
+
+        // With dc=org, we should get back dn1 and dn3
+        List<Dn> dns = dnLookupTree.getDescendantElements( org );
+
+        assertNotNull( dns );
+        assertEquals( 2, dns.size() );
+        assertTrue( dns.contains( dn1 ) );
+        assertTrue( dns.contains( dn2 ) );
+
+        // Same, with a node not having any descendants
+        dns = dnLookupTree.getDescendantElements( dn6 );
+        assertEquals( 0, dns.size() );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the getParentElement(DN) method
+    //---------------------------------------------------------------------------
+    @Test
+    public void testGetParentElement() throws Exception
+    {
+        DnNode<Dn> dnLookupTree = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=directory,dc=apache,dc=org" );
+        Dn dn2 = new Dn( "dc=mina,dc=apache,dc=org" );
+        Dn dn3 = new Dn( "dc=test,dc=com" );
+        Dn dn4 = new Dn( "dc=acme,dc=com" );
+        Dn dn5 = new Dn( "dc=acme,c=us,dc=com" );
+        Dn dn6 = new Dn( "dc=empty" );
+
+        Dn org = new Dn( "dc=org" );
+        Dn apache = new Dn( "dc=apache,dc=org" );
+        Dn test = new Dn( "dc=test,dc=directory,dc=apache,dc=org" );
+
+        dnLookupTree.add( dn1, dn1 );
+        dnLookupTree.add( dn2, dn2 );
+        dnLookupTree.add( dn3, dn3 );
+        dnLookupTree.add( dn4, dn4 );
+        dnLookupTree.add( dn5 );
+        dnLookupTree.add( dn6, dn6 );
+
+        // Inject some intermediary nodes
+        dnLookupTree.add( org, org );
+
+        assertTrue( dnLookupTree.hasParentElement( apache ) );
+        assertEquals( org, dnLookupTree.getParentWithElement( dn1 ).getElement() );
+        assertEquals( org, dnLookupTree.getParentWithElement( apache ).getElement() );
+        assertEquals( dn1, dnLookupTree.getParentWithElement( test ).getElement() );
+        assertNull( dnLookupTree.getParentWithElement( org ) );
+    }
+
+
+    @Test
+    public void testRename() throws Exception
+    {
+        DnNode<Dn> rootNode = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=directory,dc=apache,dc=org" );
+        rootNode.add( dn );
+
+        Rdn childRdn = new Rdn( "dc=org" );
+
+        DnNode<Dn> child = rootNode.getChild( childRdn );
+        assertNotNull( child );
+
+        Rdn newChildRdn = new Rdn( "dc=neworg" );
+
+        child.rename( newChildRdn );
+        assertNull( rootNode.getChild( childRdn ) );
+        assertEquals( new Dn( "dc=neworg" ), child.getDn() );
+
+        DnNode<Dn> child2 = child.getChild( new Rdn( "dc=apache" ) );
+        assertEquals( new Dn( "dc=apache,dc=neworg" ), child2.getDn() );
+
+        assertEquals( new Dn( "dc=directory,dc=apache,dc=neworg" ), child2.getChild( new Rdn( "dc=directory" ) )
+            .getDn() );
+
+        assertNotNull( rootNode.getChild( newChildRdn ) );
+    }
+
+
+    @Test
+    public void testMoveToAnAncestor() throws Exception
+    {
+        DnNode<Dn> rootNode = new DnNode<Dn>();
+        Dn dn = new Dn( "dc=vysper,dc=mina,dc=directory,dc=apache,dc=org" );
+
+        rootNode.add( dn );
+
+        Rdn minaRdn = new Rdn( "dc=mina" );
+        DnNode<Dn> apacheNode = rootNode.getChild( new Rdn( "dc=org" ) ).getChild( new Rdn( "dc=apache" ) );
+        DnNode<Dn> directoryNode = apacheNode.getChild( new Rdn( "dc=directory" ) );
+        DnNode<Dn> minaNode = directoryNode.getChild( minaRdn );
+        assertNotNull( minaNode );
+        assertEquals( directoryNode, minaNode.getParent() );
+        assertTrue( directoryNode.contains( minaRdn ) );
+
+        Dn newParent = new Dn( "dc=apache,dc=org" );
+        minaNode.move( newParent );
+
+        minaNode = apacheNode.getChild( minaRdn );
+        assertNotNull( minaNode );
+        assertNull( directoryNode.getChild( minaRdn ) );
+        assertNotNull( apacheNode.getChild( minaRdn ) );
+        assertFalse( directoryNode.contains( minaRdn ) );
+        assertTrue( apacheNode.contains( minaRdn ) );
+
+        assertEquals( new Dn( "dc=mina,dc=apache,dc=org" ), minaNode.getDn() );
+        assertEquals( new Dn( "dc=vysper,dc=mina,dc=apache,dc=org" ), minaNode.getChild( new Rdn( "dc=vysper" ) )
+            .getDn() );
+    }
+
+
+    @Test
+    public void testMoveToSiblingBranch() throws Exception
+    {
+        DnNode<Dn> rootNode = new DnNode<Dn>();
+        Dn dn1 = new Dn( "dc=vysper,dc=mina,dc=directory,dc=apache,dc=org" );
+
+        Dn dn2 = new Dn( "dc=kayyagari,dc=apache,dc=org" );
+        rootNode.add( dn1 );
+        rootNode.add( dn2 );
+
+        Rdn directoryRdn = new Rdn( "dc=directory" );
+
+        DnNode<Dn> apacheNode = rootNode.getChild( new Rdn( "dc=org" ) ).getChild( new Rdn( "dc=apache" ) );
+        DnNode<Dn> directoryNode = apacheNode.getChild( new Rdn( "dc=directory" ) );
+        assertNotNull( directoryNode );
+        assertEquals( apacheNode, directoryNode.getParent() );
+        assertTrue( apacheNode.contains( directoryRdn ) );
+
+        directoryNode.move( dn2 );
+
+        DnNode<Dn> newParentNode = rootNode.getChild( new Rdn( "dc=org" ) ).getChild( new Rdn( "dc=apache" ) )
+            .getChild( new Rdn( "dc=kayyagari" ) );
+        directoryNode = newParentNode.getChild( directoryRdn );
+        assertNotNull( directoryNode );
+        assertNull( apacheNode.getChild( directoryRdn ) );
+        assertNotNull( newParentNode.getChild( directoryRdn ) );
+        assertFalse( apacheNode.contains( directoryRdn ) );
+        assertTrue( newParentNode.contains( directoryRdn ) );
+
+        assertEquals( new Dn( "dc=directory,dc=kayyagari,dc=apache,dc=org" ), directoryNode.getDn() );
+        assertEquals( new Dn( "dc=mina,dc=directory,dc=kayyagari,dc=apache,dc=org" ),
+            directoryNode.getChild( new Rdn( "dc=mina" ) ).getDn() );
+        assertEquals( new Dn( "dc=vysper,dc=mina,dc=directory,dc=kayyagari,dc=apache,dc=org" ),
+            directoryNode.getChild( new Rdn( "dc=mina" ) ).getChild( new Rdn( "dc=vysper" ) ).getDn() );
+    }
+}
diff --git a/trunk/ldap/extras/util/src/test/resources/log4j.properties b/trunk/ldap/extras/util/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/extras/util/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/model/pom.xml b/trunk/ldap/model/pom.xml
new file mode 100644
index 0000000..9662ef1
--- /dev/null
+++ b/trunk/ldap/model/pom.xml
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-model</artifactId>
+  <name>Apache Directory LDAP API Model</name>
+  <packaging>bundle</packaging>
+  <description>Common LDAP Model used by clients and servers</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-api</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-asn1-ber</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>org.apache.mina</groupId>
+      <artifactId>mina-core</artifactId>
+    </dependency>
+
+  <!-- The original antlr artifact is needed by the antlr-maven-plugin which 
+    checks for its existence within the classpath. Use scope provided to avoid 
+    propagation to dependent projects. Choosen artifact is a valid OSGi bundle 
+    repackaged by ServiceMix team, kudos to them. -->
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.antlr</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>findbugs</groupId>
+      <artifactId>annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>generate-sources</phase>
+            <configuration />
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>antlr-maven-plugin</artifactId>
+        <configuration>
+          <grammars>*.g</grammars>
+        </configuration>
+        <executions>
+           <execution>
+              <goals>
+                 <goal>generate</goal>
+              </goals>
+           </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/Abstract*</exclude>
+            <exclude>**/*RegressionTest*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.model</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.model.constants;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.csn;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.cursor;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.entry;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.exception;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.filter;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.ldif;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.ldif.anonymizer;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.message;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.message.controls;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.message.extended;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.name;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.password;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.schema;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.schema.comparators;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.schema.normalizers;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.schema.parsers;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.schema.registries;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.schema.registries.helper;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.schema.syntaxCheckers;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.subtree;version=${project.version};-noimport:=true,
+              org.apache.directory.api.ldap.model.url;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              antlr;version=${antlr.version},
+              antlr.collections.impl;version=${antlr.version},
+              org.apache.commons.collections;version=${commons.collections.version},
+              org.apache.commons.collections.list;version=${commons.collections.version},
+              org.apache.commons.collections.map;version=${commons.collections.version},
+              org.apache.commons.lang;version=${commons.lang.version},
+              org.apache.commons.lang.exception;version=${commons.lang.version},
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.asn1.util;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.apache.directory.api.util.exception;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              javax.naming,
+              javax.naming.directory,
+              javax.naming.ldap
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/model/src/checkstyle/suppressions.xml b/trunk/ldap/model/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..fd2a7b4
--- /dev/null
+++ b/trunk/ldap/model/src/checkstyle/suppressions.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <!-- hashcode() is final in super class -->
+    <suppress files="org.apache.directory.api.ldap.model.schema.SyntaxChecker" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.Normalizer" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LoadableSchemaObject" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LdapComparator" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.DITStructureRule" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.LdapSyntax" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.NameForm" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.DitContentRule" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.MatchingRule" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.AttributeType" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.DitStructureRule" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.MatchingRuleUse" checks="EqualsHashCode" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.ObjectClass" checks="EqualsHashCode" />
+
+    <!-- No Javadoc for schema constants required -->
+    <suppress files="org.apache.directory.api.ldap.model.constants.SchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.MetaSchemaConstants" checks="JavadocVariable" />
+    <suppress files="org.apache.directory.api.ldap.model.constants.PasswordPolicySchemaConstants" checks="JavadocVariable" />
+
+    <!-- We have some long files -->
+    <suppress files="org.apache.directory.api.ldap.model.constants.SchemaConstants" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.message.ResultCodeEnum" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.PrepareString" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.url.LdapUrl" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.schema.registries.Registries" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.entry.DefaultAttribute" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.entry.DefaultEntry" checks="FileLength" />
+    <suppress files="org.apache.directory.api.ldap.model.ldif.LdifReader" checks="FileLength" />
+
+    <!-- Setter return super type, which is not recognized by Checkstyle -->
+    <suppress files="org.apache.directory.api.ldap.model.message" checks="HiddenField" />
+
+    <!-- Contol inferfaces that don't declare any new method -->
+    <suppress files="org.apache.directory.api.ldap.model.message.controls" checks="InterfaceIsType" />
+
+    <!-- Exclude Antlr generated sources -->
+    <suppress files="[\\/]generated-sources[\\/]" checks="[a-zA-Z0-9]*"/>
+</suppressions>
diff --git a/trunk/ldap/model/src/main/antlr/SubtreeSpecificationChecker.g b/trunk/ldap/model/src/main/antlr/SubtreeSpecificationChecker.g
new file mode 100644
index 0000000..d08861e
--- /dev/null
+++ b/trunk/ldap/model/src/main/antlr/SubtreeSpecificationChecker.g
@@ -0,0 +1,466 @@
+header
+{
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+
+package org.apache.directory.api.ldap.model.subtree;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.LeafNode;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.apache.directory.api.util.ComponentsMonitor;
+import org.apache.directory.api.util.OptionalComponentsMonitor;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The antlr generated subtree specification parser.
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSubtreeSpecificationChecker extends Parser;
+
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 1;
+    defaultErrorHandler = false;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser initialization
+// ----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationChecker.class );
+    
+    private ComponentsMonitor subtreeSpecificationComponentsMonitor = null;
+    
+    /** The SchemaManager */
+    private SchemaManager schemaManager;
+
+    /**
+     * Initiaize the checker
+     */
+    public void init( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+    
+
+    private int token2Integer( Token token ) throws RecognitionException
+    {
+        int i = 0;
+        
+        try
+        {
+            i = Integer.parseInt( token.getText());
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new RecognitionException( "Value of INTEGER token " +
+                                            token.getText() +
+                                            " cannot be converted to an Integer" );
+        }
+        
+        return i;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// parser productions
+// ----------------------------------------------------------------------------
+
+wrapperEntryPoint
+{
+    log.debug( "entered wrapperEntryPoint()" );
+} :
+    subtreeSpecification "end"
+    ;
+
+subtreeSpecification
+{
+    log.debug( "entered subtreeSpecification()" );
+    subtreeSpecificationComponentsMonitor = new OptionalComponentsMonitor( 
+            new String [] { "base", "specificExclusions", "minimum", "maximum", "specificationFilter" } );
+}
+    :
+    OPEN_CURLY ( SP )*
+        ( subtreeSpecificationComponent ( SP )*
+            ( SEP ( SP )* subtreeSpecificationComponent ( SP )* )* )?
+    CLOSE_CURLY
+    ;
+
+subtreeSpecificationComponent
+{
+    log.debug( "entered subtreeSpecification()" );
+}
+    :
+    ss_base
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "base" );
+    }
+    | ss_specificExclusions
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "specificExclusions" );
+    }
+    | ss_minimum
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "minimum" );
+    }
+    | ss_maximum
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "maximum" );
+    }
+    | ss_specificationFilter
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "specificationFilter" );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( e.getMessage() );
+    }
+
+ss_base
+{
+    log.debug( "entered ss_base()" );
+}
+    :
+    ID_base ( SP )+ distinguishedName
+    ;
+
+ss_specificExclusions
+{
+    log.debug( "entered ss_specificExclusions()" );
+}
+    :
+    ID_specificExclusions ( SP )+ specificExclusions
+    ;
+
+specificExclusions
+{
+    log.debug( "entered specificExclusions()" );
+}
+    :
+    OPEN_CURLY ( SP )*
+        ( specificExclusion ( SP )*
+            ( SEP ( SP )* specificExclusion ( SP )* )*
+        )?
+    CLOSE_CURLY
+    ;
+
+specificExclusion
+{
+    log.debug( "entered specificExclusion()" );
+}
+    :
+    chopBefore | chopAfter
+    ;
+
+chopBefore
+{
+    log.debug( "entered chopBefore()" );
+}
+    :
+    ID_chopBefore ( SP )* COLON ( SP )* distinguishedName
+    ;
+
+chopAfter
+{
+    log.debug( "entered chopAfter()" );
+}
+    :
+    ID_chopAfter ( SP )* COLON ( SP )* distinguishedName
+    ;
+
+ss_minimum
+{
+    log.debug( "entered ss_minimum()" );
+}
+    :
+    ID_minimum ( SP )+ baseDistance
+    ;
+
+ss_maximum
+{
+    log.debug( "entered ss_maximum()" );
+}
+    :
+    ID_maximum ( SP )+ baseDistance
+    ;
+
+ss_specificationFilter
+{
+    log.debug( "entered ss_specificationFilter()" );
+}
+    :
+    ID_specificationFilter 
+    ( SP )+ 
+    (
+        ( refinement )
+        |
+        ( filter )
+    )
+    ;
+    
+filter
+{
+    log.debug( "entered filter()" );
+}
+    :
+    ( filterToken:FILTER { FilterParser.parse( filterToken.getText() ); } )
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "filterParser failed. " + e.getMessage() );
+    }
+
+    
+distinguishedName
+{
+    log.debug( "entered distinguishedName()" );
+}
+    :
+    token:SAFEUTF8STRING
+    {
+        new Dn( token.getText() );
+        log.debug( "recognized a DistinguishedName: " + token.getText() );
+    }
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "dnParser failed for " + token.getText() + " " + e.getMessage() );
+    }
+
+baseDistance
+{
+    log.debug( "entered baseDistance()" );
+}
+    :
+    token:INTEGER
+    {
+        token2Integer(token);
+    }
+    ;
+
+oid
+{
+    log.debug( "entered oid()" );
+     Token token = null;
+}
+    :
+    { token = LT( 1 ); } // an interesting trick goes here ;-)
+    ( DESCR | NUMERICOID )
+    {
+        log.debug( "recognized an oid: " + token.getText() );
+    }
+    ;
+
+refinement
+{
+    log.debug( "entered refinement()" );
+}
+    :
+    item | and | or | not
+    ;
+
+item
+{
+    log.debug( "entered item()" );
+}
+    :
+    ID_item ( SP )* COLON ( SP )* oid
+    ;
+
+and
+{
+    log.debug( "entered and()" );
+}
+    :
+    ID_and ( SP )* COLON ( SP )* refinements
+    ;
+
+or
+{
+    log.debug( "entered or()" );
+}
+    :
+    ID_or ( SP )* COLON ( SP )* refinements
+    ;
+
+not
+{
+    log.debug( "entered not()" );
+}
+    :
+    ID_not ( SP )* COLON ( SP )* refinement
+    ;
+
+refinements
+{
+    log.debug( "entered refinements()" );
+}
+    :
+    OPEN_CURLY ( SP )*
+    (
+        refinement ( SP )*
+            ( SEP ( SP )* refinement ( SP )* )*
+    )? CLOSE_CURLY
+    ;
+
+
+// ----------------------------------------------------------------------------
+// lexer class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The parser's primary lexer.
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSubtreeSpecificationCheckerLexer extends Lexer;
+
+
+// ----------------------------------------------------------------------------
+// lexer options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 2;
+
+    charVocabulary = '\u0001'..'\u0127';
+}
+
+tokens
+{
+    ID_base = "base";
+    ID_specificExclusions = "specificExclusions";
+    ID_chopBefore = "chopBefore";
+    ID_chopAfter = "chopAfter";
+    ID_minimum = "minimum";
+    ID_maximum = "maximum";
+    ID_specificationFilter = "specificationFilter";
+    ID_item = "item";
+    ID_and = "and";
+    ID_or = "or";
+    ID_not = "not";
+}
+
+
+//----------------------------------------------------------------------------
+// lexer initialization
+//----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationLexer.class );
+}
+
+
+// ----------------------------------------------------------------------------
+// attribute description lexer rules from models
+// ----------------------------------------------------------------------------
+
+SP : ' ';
+
+COLON : ':' { log.debug( "matched COLON(':')" ); } ;
+
+OPEN_CURLY : '{' { log.debug( "matched LBRACKET('{')" ); } ;
+
+CLOSE_CURLY : '}' { log.debug( "matched RBRACKET('}')" ); } ;
+
+SEP : ',' { log.debug( "matched SEP(',')" ); } ;
+
+SAFEUTF8STRING : '"'! ( SAFEUTF8CHAR )* '"'! { log.debug( "matched SAFEUTF8CHAR: \"" + getText() + "\"" ); } ;
+
+DESCR : ALPHA ( ALPHA | DIGIT | '-' )* { log.debug( "matched DESCR" ); } ;
+
+INTEGER_OR_NUMERICOID
+    :
+    ( INTEGER DOT ) => NUMERICOID
+    {
+        $setType( NUMERICOID );
+    }
+    |
+    INTEGER
+    {
+        $setType( INTEGER );
+    }
+    ;
+
+protected INTEGER: DIGIT | ( LDIGIT ( DIGIT )+ ) { log.debug( "matched INTEGER: " + getText() ); } ;
+
+protected NUMERICOID: INTEGER ( DOT INTEGER )+ { log.debug( "matched NUMERICOID: " + getText() ); } ;
+
+protected DOT: '.' ;
+
+protected DIGIT: '0' | LDIGIT ;
+
+protected LDIGIT: '1'..'9' ;
+
+protected ALPHA: 'A'..'Z' | 'a'..'z' ;
+
+// This is all messed up - could not figure out how to get antlr to represent
+// the safe UTF-8 character set from RFC 3642 for production SafeUTF8Character
+
+protected SAFEUTF8CHAR:
+    '\u0001'..'\u0021' |
+    '\u0023'..'\u007F' |
+    '\u00c0'..'\u00d6' |
+    '\u00d8'..'\u00f6' |
+    '\u00f8'..'\u00ff' |
+    '\u0100'..'\u1fff' |
+    '\u3040'..'\u318f' |
+    '\u3300'..'\u337f' |
+    '\u3400'..'\u3d2d' |
+    '\u4e00'..'\u9fff' |
+    '\uf900'..'\ufaff' ;
+
+FILTER : '(' ( ( '&' (SP)* (FILTER)+ ) | ( '|' (SP)* (FILTER)+ ) | ( '!' (SP)* FILTER ) | FILTER_VALUE ) ')' (SP)* ;
+
+protected FILTER_VALUE : (options{greedy=true;}: ~( ')' | '(' | '&' | '|' | '!' ) ( ~(')') )* ) ;
+    
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/antlr/distinguishedName.g b/trunk/ldap/model/src/main/antlr/distinguishedName.g
new file mode 100644
index 0000000..4830ac7
--- /dev/null
+++ b/trunk/ldap/model/src/main/antlr/distinguishedName.g
@@ -0,0 +1,864 @@
+header {
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import javax.naming.NameParser;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.schema.parsers.ParserMonitor;
+import org.apache.directory.api.util.Strings;
+
+}
+
+/**
+ * An antlr generated Dn lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrDnLexer extends Lexer;
+
+options    {
+    k = 3 ;
+    exportVocab=AntlrDn ;
+    charVocabulary = '\u0000'..'\uFFFE';
+    caseSensitive = false ;
+    defaultErrorHandler = false ;
+}
+
+COMMA : ',' ;
+EQUALS : '=' ;
+PLUS : '+' ;
+HYPHEN : '-' ;
+UNDERSCORE : '_' ;
+DQUOTE : '"' ;
+SEMI : ';' ;
+LANGLE : '<' ;
+RANGLE : '>' ;
+SPACE : ' ' ;
+
+NUMERICOID_OR_ALPHA_OR_DIGIT 
+    : ( NUMERICOID ) => NUMERICOID { $setType(NUMERICOID); }
+    | ( DIGIT ) => DIGIT { $setType(DIGIT); }
+    | ( ALPHA ) => ALPHA { $setType(ALPHA); }
+    ;
+protected NUMERICOID : ( "oid." )? NUMBER ( DOT NUMBER )+ ;
+protected DOT: '.' ;
+protected NUMBER: DIGIT | ( LDIGIT ( DIGIT )+ ) ;
+protected LDIGIT : '1'..'9' ;
+protected DIGIT : '0'..'9' ;
+protected ALPHA : 'a'..'z' ;
+
+HEXPAIR_OR_ESCESC_ESCSHARP_OR_ESC 
+    : (ESC HEX HEX) => HEXPAIR { $setType(HEXPAIR); }
+    | ESCESC { $setType(ESCESC); }
+    | ESCSHARP { $setType(ESCSHARP); }
+    | ESC { $setType(ESC); }
+    ;
+protected HEXPAIR : ESC! HEX HEX ;
+protected ESC : '\\';
+protected ESCESC : ESC ESC;
+protected ESCSHARP : ESC SHARP;
+protected HEX: DIGIT | 'a'..'f' ;
+
+HEXVALUE_OR_SHARP
+    : (SHARP ( HEX HEX )+) => HEXVALUE { $setType(HEXVALUE); }
+    | SHARP { $setType(SHARP); }
+    ;
+protected HEXVALUE : SHARP! ( HEX HEX )+ ;
+protected SHARP: '#' ;
+
+UTFMB : '\u0080'..'\uFFFE' ;
+
+/**
+ * RFC 4514, Section 3:
+ * LUTF1 = %x01-1F / %x21 / %x24-2A / %x2D-3A /
+ *    %x3D / %x3F-5B / %x5D-7F
+ *
+ * To avoid nondeterminism the following 
+ * rules are excluded. These rules are 
+ * explicitly added in the productions.
+ *   EQUALS (0x3D)
+ *   HYPHEN (0x2D)
+ *   UNDERSCORE (0x5F)
+ *   DIGIT (0x30-0x39)
+ *   ALPHA (0x41-0x5A and 0x61-0x7A)
+ */
+LUTF1_REST : 
+    '\u0001'..'\u001F' |
+    '\u0021' |
+    '\u0024'..'\u002A' |
+    '\u002E'..'\u002F' |
+    '\u003A' |
+    '\u003F'..'\u0040' |
+    '\u005B' |
+    '\u005D'..'\u005E' | 
+    '\u0060' | 
+    '\u007B'..'\u007F' 
+    ;
+
+
+/**
+ * An antlr generated Dn parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrDnParser extends Parser;
+options    {
+    k = 3 ;
+    defaultErrorHandler = false ;
+    //buildAST=true ;
+}
+
+{
+    private ParserMonitor monitor = null;
+    public void setParserMonitor( ParserMonitor monitor )
+    {
+        this.monitor = monitor;
+    }
+    private void matchedProduction( String msg )
+    {
+        if ( null != monitor )
+        {
+            monitor.matchedProduction( msg );
+        }
+    }
+    static class UpAndNormValue
+    {
+        Object value = "";
+        String rawValue = "";
+		int lastEscapedSpace = -1;
+    }
+}
+
+    /**
+     * Parses an Dn string.
+     *
+     * RFC 4514, Section 3
+     * distinguishedName = [ relativeDistinguishedName
+     *     *( COMMA relativeDistinguishedName ) ]
+     *
+     * RFC 2253, Section 3
+     * distinguishedName = [name] 
+     * name       = name-component *("," name-component)
+     *
+     * RFC 1779, Section 2.3
+     * <name> ::= <name-component> ( <spaced-separator> )
+     *        | <name-component> <spaced-separator> <name>
+     * <spaced-separator> ::= <optional-space>
+     *             <separator>
+     *             <optional-space>
+     * <separator> ::=  "," | ";"
+     * <optional-space> ::= ( <CR> ) *( " " )
+     *
+     */
+distinguishedName [Dn dn]
+    {
+        matchedProduction( "distinguishedName()" );
+        Rdn rdn = null;
+    }
+    :
+    (
+        rdn = relativeDistinguishedName[new Rdn()] 
+        { 
+            try
+            { 
+                dn.add( rdn ); 
+            }
+            catch ( LdapInvalidDnException lide )
+            {
+                // Do nothing, can't get an exception here
+            } 
+                
+            rdn=null; 
+        }
+        (
+            ( COMMA | SEMI )
+            rdn = relativeDistinguishedName[new Rdn()] 
+            { 
+                try
+                { 
+                    dn.add( rdn ); 
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    // Do nothing, can't get an exception here
+                } 
+
+                rdn=null;
+            }
+        )*
+        EOF
+    )?
+    ;
+
+
+    /**
+     * Parses an Dn string.
+     *
+     * RFC 4514, Section 3
+     * distinguishedName = [ relativeDistinguishedName
+     *     *( COMMA relativeDistinguishedName ) ]
+     *
+     * RFC 2253, Section 3
+     * distinguishedName = [name] 
+     * name       = name-component *("," name-component)
+     *
+     * RFC 1779, Section 2.3
+     * <name> ::= <name-component> ( <spaced-separator> )
+     *        | <name-component> <spaced-separator> <name>
+     * <spaced-separator> ::= <optional-space>
+     *             <separator>
+     *             <optional-space>
+     * <separator> ::=  "," | ";"
+     * <optional-space> ::= ( <CR> ) *( " " )
+     *
+     */
+relativeDistinguishedNames [List<Rdn> rdns]
+    {
+        matchedProduction( "relativeDistinguishedNames()" );
+        Rdn rdn = null;
+    }
+    :
+    (
+        rdn = relativeDistinguishedName[new Rdn()] 
+        { 
+            rdns.add( rdn );
+        }
+        (
+            ( COMMA | SEMI )
+            rdn = relativeDistinguishedName[new Rdn()] 
+            { 
+                rdns.add( rdn ); 
+            }
+        )*
+        EOF
+    )?
+    ;
+
+    /**
+     * Parses an Rdn string.
+     *
+     * RFC 4514, Section 3
+     * relativeDistinguishedName = attributeTypeAndValue
+     *     *( PLUS attributeTypeAndValue )
+     *
+     * RFC 2253, Section 3
+     * name-component = attributeTypeAndValue *("+" attributeTypeAndValue)
+     *
+     * RFC 1779, Section 2.3
+     * <name-component> ::= <attribute>
+     *     | <attribute> <optional-space> "+"
+     *       <optional-space> <name-component>
+     *
+     */
+relativeDistinguishedName [Rdn initialRdn] returns [Rdn rdn]
+    {
+        matchedProduction( "relativeDistinguishedName()" );
+        rdn = initialRdn;
+        String tmp;
+        String upName = "";
+    }
+    :
+    (
+        tmp = attributeTypeAndValue[rdn] 
+        { 
+            upName += tmp;
+        }
+        (
+            PLUS { upName += "+"; }
+            tmp = attributeTypeAndValue[rdn] 
+            { 
+                upName += tmp;
+            }
+        )*
+    )
+    {
+        rdn.normalize();
+        rdn.setUpName( upName );
+    }
+    ;
+    
+
+    /**
+     * RFC 4514, Section 3
+     * attributeTypeAndValue = attributeType EQUALS attributeValue
+     *
+     * RFC 2253, Section 3
+     * attributeTypeAndValue = attributeType "=" attributeValue
+     *
+     */
+attributeTypeAndValue [Rdn rdn] returns [String upName = ""]
+    {
+        matchedProduction( "attributeTypeAndValue()" );
+        String type = null;
+        UpAndNormValue value = new UpAndNormValue();
+        String upValue = null;
+    }
+    :
+    (
+        ( SPACE { upName += " "; } )*
+        type = attributeType { upName += type; }
+        ( SPACE { upName += " "; } )*
+        EQUALS { upName += "="; }
+        ( SPACE 
+        { 
+            upName += " "; 
+            
+            if ( upValue == null )
+            {
+                upValue = " ";
+            }
+            else
+            {
+                upValue += " "; 
+            } 
+        } )*
+        attributeValue[value] 
+        {
+            try
+            {
+                upName += value.rawValue;
+                Ava ava = null;
+            
+                if ( value.value instanceof String )
+                {
+                    if ( upValue != null )
+                    {
+                        value.rawValue = upValue + value.rawValue;
+                    }
+                    
+					int start = 0;
+		
+					for ( int pos = 0; pos < value.rawValue.length(); pos++ )
+					{
+					    if ( value.rawValue.charAt( pos ) == ' ' )
+					    {
+					        start++;
+					    }
+					    else
+					    {
+					        break;
+					    }
+					}
+		
+					boolean escape = false;
+					int lastEscapedSpace = -1;
+					
+					for ( int pos = start; pos< value.rawValue.length(); pos++ )
+					{
+					    if ( escape )
+					    {
+					        escape = false;
+		        
+					        if ( value.rawValue.charAt( pos ) == ' ' )
+					        {
+					            lastEscapedSpace = pos;
+					        }
+					    }
+					    else if ( value.rawValue.charAt( pos ) == '\\' )
+					    {
+					        escape = true;
+					    }
+					}
+		
+					// Remove spaces from the right if needed
+					int pos = value.rawValue.length() - 1;
+		
+					while ( ( value.rawValue.charAt( pos ) == ' ' ) && ( pos > lastEscapedSpace ) )
+					{
+					    pos--;
+					}
+					
+					String trimmedValue = value.rawValue;
+					
+					if ( ( start > 0 ) || ( pos + 1 < value.rawValue.length() ) )
+					{
+						trimmedValue = value.rawValue.substring( start, pos + 1 );
+					}
+					
+					Object unescapedValue = Rdn.unescapeValue( trimmedValue );
+                    
+                    if ( unescapedValue instanceof String )
+                    {
+                        ava = new Ava(
+                            type,
+                            type,
+                            new StringValue( trimmedValue, (String)unescapedValue ),
+                            upName
+                        );
+                    }
+                    else
+                    {
+                        ava = new Ava(
+                            type,
+                            type,
+                            new BinaryValue( (byte[])unescapedValue ),
+                            upName
+                        );
+                    }
+                }
+                else
+                {
+                    ava = new Ava(
+                        type,
+                        type,
+                        new BinaryValue( (byte[])value.value ), 
+                        upName
+                    );
+                }
+           
+                rdn.addAVA( null, ava );
+            }
+            catch ( LdapInvalidDnException e )
+            {
+                throw new SemanticException( e.getMessage() );
+            } 
+        }
+    )
+    ;
+    
+
+    /**
+     * RFC 4514 Section 3
+     *
+     * attributeType = descr / numericoid
+     *
+     */    
+attributeType returns [String attributeType]
+    {
+        matchedProduction( "attributeType()" );
+    }
+    :
+    (
+        attributeType = descr
+        |
+        attributeType = numericoid
+    )
+    ;
+
+
+    /**
+     * RFC 4512 Section 1.4
+     *
+     * descr = keystring
+     * keystring = leadkeychar *keychar
+     * leadkeychar = ALPHA
+     * keychar = ALPHA / DIGIT / HYPHEN
+     *
+     * We additionally add UNDERSCORE because some servers allow them.
+     *
+     */    
+descr returns [String descr]
+    {
+        matchedProduction( "descr()" );
+    }
+    :
+    leadkeychar:ALPHA { descr = leadkeychar.getText(); }
+    (
+        alpha:ALPHA { descr += alpha.getText(); }
+        |
+        digit:DIGIT { descr += digit.getText(); }
+        |
+        hyphen:HYPHEN { descr += hyphen.getText(); }
+        |
+        underscore:UNDERSCORE { descr += underscore.getText(); }
+    )*
+    ;
+
+
+    /**
+     * RFC 4512 Section 1.4
+     *
+     * numericoid = number 1*( DOT number )
+     * number  = DIGIT / ( LDIGIT 1*DIGIT )
+     * DIGIT   = %x30 / LDIGIT       ; "0"-"9"
+     * LDIGIT  = %x31-39             ; "1"-"9"
+     *
+     */   
+numericoid returns [String numericoid = ""]
+    {
+        matchedProduction( "numericoid()" );
+    }
+    :
+    noid:NUMERICOID { numericoid += noid.getText(); }
+    ;
+
+
+    /**
+     * RFC 4514, Section 3
+     * attributeValue = string / hexstring
+     *
+     * RFC 2253, Section 3
+     * attributeValue = string
+     * string     = *( stringchar / pair )
+     *              / "#" hexstring
+     *              / QUOTATION *( quotechar / pair ) QUOTATION ; only from v2
+     * 
+     */    
+attributeValue [UpAndNormValue value]
+    {
+        matchedProduction( "attributeValue()" );
+    }
+    :
+    (
+        (
+            quotestring [value]
+            ( SPACE { value.rawValue += " "; } )*
+        )
+        |
+        string [value]
+        |
+        (
+            hexstring [value]
+            ( SPACE { value.rawValue += " "; } )*
+        )
+    )?
+    ;
+
+
+    /**
+     * RFC 2253, Section 3
+     *              / QUOTATION *( quotechar / pair ) QUOTATION ; only from v2
+     * quotechar     = <any character except "\" or QUOTATION >
+     *
+     */
+quotestring [UpAndNormValue value] 
+    {
+        matchedProduction( "quotestring()" );
+        org.apache.directory.api.util.ByteBuffer bb = new org.apache.directory.api.util.ByteBuffer();
+        byte[] bytes;
+    }
+    :
+    (
+        dq1:DQUOTE { value.rawValue += dq1.getText(); }
+        (
+            (
+                s:~(DQUOTE|ESC|ESCESC|ESCSHARP|HEXPAIR) 
+                {
+                    value.rawValue += s.getText();
+                    bb.append( Strings.getBytesUtf8( s.getText() ) );
+                }
+            )
+            |
+            bytes = pair[value] { bb.append( bytes ); }
+        )*
+        dq2:DQUOTE { value.rawValue += dq2.getText(); }
+    )
+    {
+        String string = Strings.utf8ToString( bb.copyOfUsedBytes() );
+        value.value = string;
+    }
+    ;
+
+
+    /**
+     * RFC 4514 Section 3
+     *
+     * hexstring = SHARP 1*hexpair
+     *
+     * If in <hexstring> form, a BER representation can be obtained from
+     * converting each <hexpair> of the <hexstring> to the octet indicated
+     * by the <hexpair>.
+     *
+     */ 
+hexstring [UpAndNormValue value]
+    {
+        matchedProduction( "hexstring()" );
+    }
+    :
+    hexValue:HEXVALUE
+    {
+        // convert to byte[]
+        value.rawValue = "#" + hexValue.getText();
+        value.value = Strings.toByteArray( hexValue.getText() ); 
+    }
+    ;
+
+
+    /**
+     * RFC 4514 Section 3
+     *
+     * ; The following characters are to be escaped when they appear
+     * ; in the value to be encoded: ESC, one of <escaped>, leading
+     * ; SHARP or SPACE, trailing SPACE, and NULL.
+     * string =   [ ( leadchar / pair ) [ *( stringchar / pair )
+     *    ( trailchar / pair ) ] ]
+     *
+     */ 
+string [UpAndNormValue value]
+    {
+        matchedProduction( "string()" );
+        org.apache.directory.api.util.ByteBuffer bb = new org.apache.directory.api.util.ByteBuffer();
+        String tmp;
+        byte[] bytes;
+    }
+    :
+    (
+        (
+            tmp = lutf1 
+            { 
+                value.rawValue += tmp;
+                bb.append( Strings.getBytesUtf8( tmp ) );
+            }
+            |
+            tmp = utfmb 
+            {
+                value.rawValue += tmp;
+                bb.append( Strings.getBytesUtf8( tmp ) );
+            }
+            |
+            bytes = pair [value] 
+			{ 
+				bb.append( bytes );
+			}
+        )
+        ( 
+            tmp = sutf1
+            {
+                value.rawValue += tmp;
+                bb.append( Strings.getBytesUtf8( tmp ) );
+            }
+            |
+            tmp = utfmb 
+            {
+                value.rawValue += tmp;
+                bb.append( Strings.getBytesUtf8( tmp ) );
+            }
+            |
+            bytes = pair [value] 
+			{ 
+				bb.append( bytes ); 
+			}
+        )*
+    )
+    {
+		/*
+        String string = Strings.utf8ToString( bb.copyOfUsedBytes() );
+        
+        // trim trailing space characters manually
+        // don't know how to tell antlr that the last char mustn't be a space.
+        int rawIndex = value.rawValue.length();
+        while ( string.length() > 0 && rawIndex > 1 
+            && value.rawValue.charAt( rawIndex - 1 ) == ' ' 
+            && value.rawValue.charAt( rawIndex - 2 ) != '\\' )
+        {
+            string = string.substring( 0, string.length() - 1 );
+            rawIndex--;
+        }
+        
+        value.value = string;
+		*/
+    }
+    ;
+
+
+/**
+ * RFC 4514, Section 3:
+ * LUTF1 = %x01-1F / %x21 / %x24-2A / %x2D-3A /
+ *    %x3D / %x3F-5B / %x5D-7F
+ *
+ * The rule LUTF1_REST doesn't contain the following charcters,
+ * so we must check them additionally
+ *   EQUALS (0x3D)
+ *   HYPHEN (0x2D)
+ *   UNDERSCORE (0x5F)
+ *   DIGIT (0x30-0x39)
+ *   ALPHA (0x41-0x5A and 0x61-0x7A)
+ */
+lutf1 returns [String lutf1=""]
+    {
+        matchedProduction( "lutf1()" );
+    }
+    :
+    rest:LUTF1_REST { lutf1 = rest.getText(); }
+    |
+    equals:EQUALS { lutf1 = equals.getText(); }
+    |
+    hyphen:HYPHEN { lutf1 = hyphen.getText(); }
+    |
+    underscore:UNDERSCORE { lutf1 = underscore.getText(); }
+    |
+    digit:DIGIT { lutf1 = digit.getText(); }
+    |
+    alpha:ALPHA { lutf1 = alpha.getText(); }
+    | 
+    numericoid:NUMERICOID  { lutf1 = numericoid.getText(); }    
+    ;
+    
+/**
+ * RFC 4514, Section 3:
+ * SUTF1 = %x01-21 / %x23-2A / %x2D-3A /
+ *    %x3D / %x3F-5B / %x5D-7F
+ *
+ * The rule LUTF1_REST doesn't contain the following charcters,
+ * so we must check them additionally
+ *   EQUALS (0x3D)
+ *   HYPHEN (0x2D)
+ *   UNDERSCORE (0x5F)
+ *   DIGIT (0x30-0x39)
+ *   ALPHA (0x41-0x5A and 0x61-0x7A)
+ *   SHARP
+ *   SPACE
+ */
+sutf1 returns [String sutf1=""]
+    {
+        matchedProduction( "sutf1()" );
+    }
+    :
+    rest:LUTF1_REST { sutf1 = rest.getText(); }
+    |
+    equals:EQUALS { sutf1 = equals.getText(); }
+    |
+    hyphen:HYPHEN { sutf1 = hyphen.getText(); }
+    |
+    underscore:UNDERSCORE { sutf1 = underscore.getText(); }
+    |
+    digit:DIGIT { sutf1 = digit.getText(); }
+    |
+    alpha:ALPHA { sutf1 = alpha.getText(); }
+    |
+    sharp:SHARP { sutf1 = sharp.getText(); }
+    | 
+    space:SPACE  { sutf1 = space.getText(); }
+    | 
+    // This is a hack to deal with #NN included into the value, due to 
+    // some collision with the HEXVALUE token. In this case, we should
+    // consider that a hex value is in fact a String
+    hex:HEXVALUE { sutf1 = "#" + hex.getText(); }
+    |
+    numericoid:NUMERICOID  { sutf1 = numericoid.getText(); }    
+    ;    
+
+
+utfmb returns [String utfmb]
+    {
+        matchedProduction( "utfmb()" );
+    }
+    :
+    s:UTFMB { utfmb = s.getText(); }
+    ;
+
+
+    /**
+     * RFC 4514, Section 3
+     * pair = ESC ( ESC / special / hexpair )
+     * special = escaped / SPACE / SHARP / EQUALS
+     * escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
+     * hexpair = HEX HEX
+     *
+     * If in <string> form, a LDAP string representation asserted value can
+     * be obtained by replacing (left to right, non-recursively) each <pair>
+     * appearing in the <string> as follows:
+     *   replace <ESC><ESC> with <ESC>;
+     *   replace <ESC><special> with <special>;
+     *   replace <ESC><hexpair> with the octet indicated by the <hexpair>.
+     * 
+     * RFC 2253, Section 3
+     * pair       = "\" ( special / "\" / QUOTATION / hexpair )
+     * special    = "," / "=" / "+" / "<" /  ">" / "#" / ";"
+     * 
+     * RFC 1779, Section 2.3
+     * <pair> ::= "\" ( <special> | "\" | '"')
+     * <special> ::= "," | "=" | <CR> | "+" | "<" |  ">"
+     *           | "#" | ";"
+     * 
+     */ 
+pair [UpAndNormValue value] returns [byte[] pair]
+    {
+        matchedProduction( "pair()" );
+        String tmp;
+    }
+    :
+    (
+        ESCESC 
+        { 
+            value.rawValue += "\\\\";
+            pair = Strings.getBytesUtf8( "\\" );
+        } 
+    )
+    |
+    (
+        ESCSHARP 
+        { 
+            value.rawValue += "\\#";
+            pair = Strings.getBytesUtf8( "#" );
+        } 
+    )
+    |
+    ( 
+        ESC
+        tmp = special 
+        { 
+            value.rawValue += "\\" + tmp;
+            pair = Strings.getBytesUtf8( tmp );
+        }
+    )
+    |
+    ( 
+        hexpair:HEXPAIR 
+        { 
+            value.rawValue += "\\" + hexpair.getText();
+            pair = Strings.toByteArray( hexpair.getText() ); 
+        } 
+    )
+    ;
+
+
+    /**
+     * RFC 4514 Section 3
+     * 
+     * special = escaped / SPACE / SHARP / EQUALS
+     * escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
+     *
+     */ 
+special returns [String special]
+    {
+        matchedProduction( "special()" );
+    }
+    :
+    (
+        dquote:DQUOTE { special = dquote.getText(); }
+        |
+        plus:PLUS { special = plus.getText(); }
+        |
+        comma:COMMA { special = comma.getText(); }
+        |
+        semi:SEMI { special = semi.getText(); }
+        |
+        langle:LANGLE { special = langle.getText(); }
+        |
+        rangle:RANGLE { special = rangle.getText(); }
+        |
+        space:SPACE { special = space.getText(); }
+        |
+        sharp:SHARP { special = sharp.getText(); }
+        |
+        equals:EQUALS { special = equals.getText(); }
+    )
+    ;
+
diff --git a/trunk/ldap/model/src/main/antlr/schema-extension.g b/trunk/ldap/model/src/main/antlr/schema-extension.g
new file mode 100644
index 0000000..b6eb96b
--- /dev/null
+++ b/trunk/ldap/model/src/main/antlr/schema-extension.g
@@ -0,0 +1,119 @@
+header {
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+import java.io.StringReader;
+import java.util.List;
+
+}
+
+
+   
+/**
+ * An antlr generated schema lexer. This is a sub-lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaExtensionLexer extends Lexer;
+
+options    {
+    k = 2 ;
+    exportVocab=AntlrSchemaExtension ;
+    charVocabulary = '\u0000'..'\uFFFE'; 
+    caseSensitive = false ;
+    defaultErrorHandler = false ;
+}
+
+protected WHSP
+    :
+    ( options {greedy=true;} :
+    ' '
+    |
+    '\t'
+    |
+    '\r' (options {greedy=true;} : '\n')? { newline(); } 
+    |
+    '\n' { newline(); }
+    )+
+    { $setType(Token.SKIP); } //ignore this token
+    ;
+
+protected QUOTE : '\'' ;
+//protected ESC : '\\' ;
+
+XKEY : xstring:XSTRING { setText(xstring.getText().trim()); }; 
+XVALUES : values:VALUES { setText(values.getText().trim()); };
+
+protected XSTRING : ( "x-" ( 'a'..'z' | '-' | '_' )+ (WHSP)? ) ; 
+protected VALUES : ( VALUE | '('  VALUE ( ('$')? VALUE )* ')' ) ;
+protected VALUE : (WHSP)? ( QUOTED_STRING ) (options {greedy=true;}: WHSP)? ;
+protected QUOTED_STRING : ( QUOTE (~'\'')* QUOTE ) ;
+
+
+
+
+
+
+/**
+ * An antlr generated schema parser. This is a sub-parser used to parse
+ * extensions according to RFC4512.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaExtensionParser extends Parser;
+options    {
+    k = 3 ;
+    defaultErrorHandler = false ;
+    //buildAST=true ;
+}
+
+
+    /**
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )
+     */
+extension returns [AntlrSchemaParser.Extension extension = new AntlrSchemaParser.Extension()]
+    :
+    ( xkey:XKEY { extension.key = xkey.getText(); } )
+    ( xvalues:XVALUES { extension.values = qdstrings(xvalues.getText()); } )
+    ;
+    
+    
+qdstrings [String s] returns [List<String> qdstrings]
+    {
+        try 
+        {
+            AntlrSchemaQdstringLexer lexer = new AntlrSchemaQdstringLexer(new StringReader(s));
+            AntlrSchemaQdstringParser parser = new AntlrSchemaQdstringParser(lexer);
+            qdstrings = parser.qdstrings();
+        }
+        catch (RecognitionException re) {
+            re.printStackTrace();
+            throw re;
+        }
+        catch (TokenStreamException tse) {
+            tse.printStackTrace();
+            throw tse;
+        }
+    }
+    :
+    ;
+
diff --git a/trunk/ldap/model/src/main/antlr/schema-qdstring.g b/trunk/ldap/model/src/main/antlr/schema-qdstring.g
new file mode 100644
index 0000000..03d8f83
--- /dev/null
+++ b/trunk/ldap/model/src/main/antlr/schema-qdstring.g
@@ -0,0 +1,162 @@
+header {
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.schema.parsers.ParserMonitor;
+
+}
+
+   
+/**
+ * An antlr generated schema lexer. This is a sub-lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaQdstringLexer extends Lexer;
+
+options    {
+    k = 2 ;
+    exportVocab=AntlrSchemaQdstring ;
+    charVocabulary = '\u0000'..'\uFFFE'; 
+    caseSensitive = false ;
+    defaultErrorHandler = false ;
+}
+
+WHSP
+    :
+    ( options {greedy=true;} :
+    ' '
+    |
+    '\t'
+    |
+    '\r' (options {greedy=true;} : '\n')? { newline(); } 
+    |
+    '\n' { newline(); }
+    )+
+    { $setType(Token.SKIP); } //ignore this token
+    ;
+
+LPAR : '(' ;
+RPAR : ')' ;
+QUOTE : '\'' ;
+QDSTRING : ( QUOTE (~'\'')* QUOTE ) ;
+
+
+/**
+ * An antlr generated schema parser. This is a sub-parser used to parse
+ * qdstring and qdstrings according to RFC4512.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaQdstringParser extends Parser;
+options    {
+    k = 3 ;
+    defaultErrorHandler = false ;
+    //buildAST=true ;
+}
+
+{
+    private ParserMonitor monitor = null;
+    public void setParserMonitor( ParserMonitor monitor )
+    {
+        this.monitor = monitor;
+    }
+    private void matchedProduction( String msg )
+    {
+        if ( null != monitor )
+        {
+            monitor.matchedProduction( msg );
+        }
+    }
+}
+
+    /**
+     * qdstrings = qdstring / ( LPAREN WSP qdstringlist WSP RPAREN )
+     * qdstringlist = [ qdstring *( SP qdstring ) ]
+     */
+qdstrings returns [List<String> qdstrings]
+    {
+        matchedProduction( "AntlrSchemaQdstringParser.qdstrings()" );
+        qdstrings = new ArrayList<String>();
+        String qdstring = null;
+    }
+    :
+    (
+        ( 
+            q:QDSTRING 
+            { 
+                qdstring = q.getText(); 
+                if(qdstring.startsWith("'")) {
+                    qdstring = qdstring.substring(1, qdstring.length());
+                }
+                if(qdstring.endsWith("'")) {
+                    qdstring = qdstring.substring(0, qdstring.length()-1);
+                }
+                qdstring = qdstring.replaceAll("\\\\5C", "\\\\");
+                qdstring = qdstring.replaceAll("\\\\5c", "\\\\");
+                qdstring = qdstring.replaceAll("\\\\27", "'");
+                qdstrings.add(qdstring);
+            } 
+        )
+    |
+        ( LPAR qdstring=qdstring { qdstrings.add(qdstring); } ( qdstring=qdstring { qdstrings.add(qdstring); } )* RPAR )
+    )
+    ;
+
+    /**
+     * qdstring = SQUOTE dstring SQUOTE
+     * dstring = 1*( QS / QQ / QUTF8 )   ; escaped UTF-8 string
+     *
+     * QQ =  ESC %x32 %x37 ; "\27"
+     * QS =  ESC %x35 ( %x43 / %x63 ) ; "\5C" / "\5c"
+     *
+     * ; Any UTF-8 encoded Unicode character
+     * ; except %x27 ("\'") and %x5C ("\")
+     * QUTF8    = QUTF1 / UTFMB
+     *
+     * ; Any ASCII character except %x27 ("\'") and %x5C ("\")
+     * QUTF1    = %x00-26 / %x28-5B / %x5D-7F
+     */    
+qdstring returns [String qdstring=null]
+    {
+        matchedProduction( "AntlrSchemaQdstringParser.qdstring()" );
+    }
+    : 
+    ( 
+        q:QDSTRING 
+        { 
+            qdstring = q.getText(); 
+            if(qdstring.startsWith("'")) {
+                qdstring = qdstring.substring(1, qdstring.length());
+            }
+            if(qdstring.endsWith("'")) {
+                qdstring = qdstring.substring(0, qdstring.length()-1);
+            }
+            qdstring = qdstring.replaceAll("\\\\5C", "\\\\");
+            qdstring = qdstring.replaceAll("\\\\5c", "\\\\");
+            qdstring = qdstring.replaceAll("\\\\27", "'");
+        } 
+    )
+    ; 
+
diff --git a/trunk/ldap/model/src/main/antlr/schema-value.g b/trunk/ldap/model/src/main/antlr/schema-value.g
new file mode 100644
index 0000000..02992b6
--- /dev/null
+++ b/trunk/ldap/model/src/main/antlr/schema-value.g
@@ -0,0 +1,442 @@
+header {
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.directory.api.ldap.model.schema.parsers.ParserMonitor;
+
+}
+
+
+/**
+ * An antlr generated schema lexer. This is a sub-lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaValueLexer extends Lexer;
+
+options    {
+    k = 3 ;
+    exportVocab=AntlrSchemaValue ;
+    charVocabulary = '\3'..'\377' ;
+    caseSensitive = false ;
+    defaultErrorHandler = false ;
+}
+
+WHSP
+    :
+    ( options {greedy=true;} :
+    ' '
+    |
+    '\t'
+    |
+    '\r' (options {greedy=true;} : '\n')? { newline(); } 
+    |
+    '\n' { newline(); }
+    |
+    '#' (~'\n')* '\n' { newline(); }
+    )+
+    { setText(" "); }
+    //{$setType(Token.SKIP);} //ignore this token
+    ;
+
+LPAR : '(' ;
+RPAR : ')' ;
+protected CHAR : 'a'..'z' ;
+protected LDIGIT : '1'..'9' ;
+protected DIGIT : '0'..'9' ; 
+protected NUMBER : DIGIT | ( LDIGIT (DIGIT)+ ) ;
+protected NUMBER2 : (DIGIT)+ ;
+protected NUMERICOID : NUMBER2 ( '.' NUMBER2 )+ ;
+protected HYPEN : '-';
+protected OTHER : '_' | ';' | '.' | ':' | '#' ;
+protected DESCR: CHAR ( CHAR | DIGIT | HYPEN )* ;
+protected QUIRKS_DESCR: ( CHAR | DIGIT | HYPEN | OTHER )+ ;
+
+QUOTE : '\'' ;
+DOLLAR : '$' ;
+LCURLY : '{' ;
+RCURLY : '}' ;
+LEN : LCURLY n:NUMBER2 RCURLY { setText(n.getText()); } ;
+
+
+DESCR_OR_QUIRKS_DESCR :
+    ( NUMERICOID QUIRKS_DESCR ) => QUIRKS_DESCR { $setType( QUIRKS_DESCR ); }
+    |
+    ( NUMBER QUIRKS_DESCR ) => QUIRKS_DESCR { $setType( QUIRKS_DESCR ); }
+    |
+    ( HYPEN QUIRKS_DESCR ) => QUIRKS_DESCR { $setType( QUIRKS_DESCR ); }
+    |
+    ( OTHER QUIRKS_DESCR ) => QUIRKS_DESCR { $setType( QUIRKS_DESCR ); }
+    |
+    ( DESCR QUIRKS_DESCR ) => QUIRKS_DESCR { $setType( QUIRKS_DESCR ); }
+    |
+    ( DESCR ) { $setType( DESCR ); }
+    |
+    ( NUMBER '.' ) => NUMERICOID { $setType( NUMERICOID ); }
+    |
+    ( NUMBER ) { $setType( NUMBER ); }
+    ;
+
+
+/**
+ * An antlr generated schema parser. This is a sub-parser used to parse
+ * numericoid, oid, oids, qdescr, qdescrs according to RFC4512.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaValueParser extends Parser;
+options    {
+    k = 3 ;
+    defaultErrorHandler = false ;
+    //buildAST=true ;
+}
+
+{
+    private ParserMonitor monitor = null;
+    public void setParserMonitor( ParserMonitor monitor )
+    {
+        this.monitor = monitor;
+    }
+    private void matchedProduction( String msg )
+    {
+        if ( null != monitor )
+        {
+            monitor.matchedProduction( msg );
+        }
+    }
+}
+
+    /**
+     * noidlen = numericoid [ LCURLY len RCURLY ]
+     * len = number
+     */
+noidlen returns [AntlrSchemaParser.NoidLen noidlen = new AntlrSchemaParser.NoidLen()]
+    {
+        matchedProduction( "AntlrSchemaValueParser.noidlen()" );
+    }
+    :
+    ( 
+        (LPAR)?
+        (WHSP)?
+        (QUOTE)?
+        (
+            ( d4:DESCR { noidlen.noid = d4.getText(); } )
+            |
+            ( n2:NUMERICOID { noidlen.noid = n2.getText(); } )
+        )
+        (QUOTE)?
+        (WHSP)?
+        (RPAR)?
+        (
+            l:LEN { noidlen.len = Long.parseLong(l.getText()); }
+            (QUOTE)?
+            (WHSP)?
+            (RPAR)?
+        )?
+    )
+    ;
+
+
+    /**
+     * noidlen = numericoid [ LCURLY len RCURLY ]
+     * len = number
+     */
+quirksNoidlen returns [AntlrSchemaParser.NoidLen noidlen = new AntlrSchemaParser.NoidLen()]
+    {
+        matchedProduction( "AntlrSchemaValueParser.quirksNoidlen()" );
+    }
+    :
+    (
+        (LPAR)?
+        (WHSP)?
+        (QUOTE)?
+        (
+            ( q2:QUIRKS_DESCR { noidlen.noid = q2.getText(); } )
+            |
+            ( d4:DESCR { noidlen.noid = d4.getText(); } )
+            |
+            ( n2:NUMERICOID { noidlen.noid = n2.getText(); } )
+        )
+        (QUOTE)?
+        (WHSP)?
+        (RPAR)?
+        (
+            l:LEN { noidlen.len = Long.parseLong(l.getText()); }
+            (QUOTE)?
+            (WHSP)?
+            (RPAR)?
+        )?    
+    )
+    ;
+
+
+    /**
+     * numericoid = number 1*( DOT number )
+     */
+numericoid returns [String numericoid=null]
+    {
+        matchedProduction( "AntlrSchemaValueParser.numericoid()" );
+    }
+    : 
+    (
+        (WHSP)?
+        (LPAR (WHSP)? )?
+        (
+            ( QUOTE n1:NUMERICOID { numericoid = n1.getText(); } QUOTE )
+            |
+            ( n2:NUMERICOID { numericoid = n2.getText(); } )
+        )
+        (
+        (WHSP)?
+        (RPAR)?
+        )
+    )
+    ;
+
+
+    /**
+     * oid = descr / numericoid
+     * numericoid = number 1*( DOT number )
+     * descr = keystring
+     * keystring = leadkeychar *keychar
+     * leadkeychar = ALPHA
+     * keychar = ALPHA / DIGIT / HYPHEN
+     * number  = DIGIT / ( LDIGIT 1*DIGIT )
+     *
+     */
+oid returns [String oid=null]
+    {
+        matchedProduction( "AntlrSchemaValueParser.oid()" );
+    }
+    : 
+    (
+        (WHSP)?
+        (
+            ( QUOTE n1:NUMERICOID { oid = n1.getText(); } QUOTE  )
+            |
+            ( n2:NUMERICOID { oid = n2.getText(); } )
+            |
+            ( QUOTE d1:DESCR { oid = d1.getText(); } QUOTE )
+            |
+            ( d2:DESCR { oid = d2.getText(); } )
+        )
+        (options {greedy=true;} : WHSP)?
+    )
+    ;
+
+
+    /**
+     * oids = oid / ( LPAREN WSP oidlist WSP RPAREN )
+     * oidlist = oid *( WSP DOLLAR WSP oid )
+     */
+oids returns [List<String> oids]
+    {
+        matchedProduction( "AntlrSchemaValueParser.oids()" );
+        oids = new ArrayList<String>();
+        String oid = null;
+    }
+    :
+    (
+        ( 
+            oid=oid { oids.add(oid); } 
+        )
+    |
+        (
+            LPAR
+            oid=oid { oids.add(oid); } 
+            ( 
+                (DOLLAR)? 
+                oid=oid { oids.add(oid); } 
+            )* 
+            RPAR
+        )
+    )
+    ;
+
+
+    /**
+     * qdescr = SQUOTE descr SQUOTE
+     */
+qdescr returns [String qdescr=null]
+    {
+        matchedProduction( "AntlrSchemaValueParser.qdescr()" );
+    }
+    : 
+    ( 
+        (WHSP)?
+        (
+            ( QUOTE d1:DESCR { qdescr = d1.getText(); } QUOTE )
+            |
+            ( d2:DESCR { qdescr = d2.getText(); } )
+        )
+    )
+    ; 
+
+
+    /**
+     * qdescrs = qdescr / ( LPAREN WSP qdescrlist WSP RPAREN )
+     * qdescrlist = [ qdescr *( SP qdescr ) ]
+     */
+qdescrs returns [List<String> qdescrs]
+    {
+        matchedProduction( "AntlrSchemaValueParser.qdescrs()" );
+        qdescrs = new ArrayList<String>();
+        String qdescr = null;
+    }
+    :
+    (
+        ( 
+            qdescr=qdescr { qdescrs.add(qdescr); } 
+        )
+    |
+        (             
+        
+            LPAR 
+            qdescr=qdescr { qdescrs.add(qdescr); } 
+            (options {greedy=true;} : WHSP)?
+            (DOLLAR)?
+            (options {greedy=true;} : WHSP)?
+            (
+                qdescr=qdescr { qdescrs.add(qdescr); } 
+                (options {greedy=true;} : WHSP)?
+                (DOLLAR)?
+                (options {greedy=true;} : WHSP)?
+            )*
+            RPAR 
+        )
+    )
+    ;
+    
+    
+    
+    /**
+     * qdescr = SQUOTE descr SQUOTE
+     */
+quirksQdescr returns [String qdescr=null]
+    {
+        matchedProduction( "AntlrSchemaValueParser.qdescr()" );
+    }
+    : 
+    ( 
+        (WHSP)?
+        (
+            ( QUOTE d1:QUIRKS_DESCR { qdescr = d1.getText(); } QUOTE )
+            |
+            ( d2:QUIRKS_DESCR { qdescr = d2.getText(); } )
+            |
+            ( QUOTE d3:DESCR { qdescr = d3.getText(); } QUOTE )
+            |
+            ( d4:DESCR { qdescr = d4.getText(); } )
+            |
+            ( QUOTE n1:NUMERICOID { qdescr = n1.getText(); } QUOTE  )
+            |
+            ( n2:NUMERICOID { qdescr = n2.getText(); } )
+        )
+        (options {greedy=true;} : WHSP)?
+    )
+    ; 
+
+
+    /**
+     * qdescrs = qdescr / ( LPAREN WSP qdescrlist WSP RPAREN )
+     * qdescrlist = [ qdescr *( SP qdescr ) ]
+     */
+quirksQdescrs returns [List<String> qdescrs]
+    {
+        matchedProduction( "AntlrSchemaValueParser.qdescrs()" );
+        qdescrs = new ArrayList<String>();
+        String qdescr = null;
+    }
+    :
+    (
+        ( 
+            qdescr=quirksQdescr { qdescrs.add(qdescr); } 
+        )
+    |
+        ( 
+            LPAR 
+            qdescr=quirksQdescr { qdescrs.add(qdescr); } 
+            (options {greedy=true;} : WHSP)?
+            (DOLLAR)?
+            (options {greedy=true;} : WHSP)?
+            (
+                qdescr=quirksQdescr { qdescrs.add(qdescr); } 
+                (options {greedy=true;} : WHSP)?
+                (DOLLAR)?
+                (options {greedy=true;} : WHSP)?
+            )*
+            RPAR 
+        )
+    )
+    ;
+    
+    
+    
+    
+    /**
+     * ruleid = number
+     * number  = DIGIT / ( LDIGIT 1*DIGIT )
+     *
+     */
+ruleid returns [Integer ruleid=null]
+    {
+        matchedProduction( "AntlrSchemaValueParser.ruleid()" );
+    }
+    : 
+    (
+        (WHSP)? 
+        n:NUMBER { ruleid = Integer.parseInt(n.getText()); }
+    )
+    ;
+
+
+    /**
+     * ruleids = ruleid / ( LPAREN WSP ruleidlist WSP RPAREN )
+     * ruleidlist = ruleid *( SP ruleid )
+     */
+ruleids returns [List<Integer> ruleids]
+    {
+        matchedProduction( "AntlrSchemaValueParser.ruleids()" );
+        ruleids = new ArrayList<Integer>();
+        Integer ruleid = null;
+    }
+    :
+    (
+        ( 
+            ruleid=ruleid { ruleids.add(ruleid); } 
+        )
+    |
+        ( 
+            LPAR 
+            ruleid=ruleid { ruleids.add(ruleid); } 
+            ( 
+                WHSP
+                ruleid=ruleid { ruleids.add(ruleid); } 
+            )* 
+            (WHSP)?
+            RPAR 
+        )
+    )
+    ;
+    
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/antlr/schema.g b/trunk/ldap/model/src/main/antlr/schema.g
new file mode 100644
index 0000000..9aa790b
--- /dev/null
+++ b/trunk/ldap/model/src/main/antlr/schema.g
@@ -0,0 +1,1085 @@
+header {
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.api.ldap.model.schema.NameForm;
+import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.ParserMonitor;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.MutableObjectClass;
+import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OpenLdapObjectIdentifierMacro;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+
+}
+
+/**
+ * An antlr generated schema main lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaLexer extends Lexer;
+
+options    {
+    k = 8 ;
+    exportVocab=AntlrSchema ;
+    charVocabulary = '\u0000'..'\uFFFE';
+    caseSensitive = false ;
+    defaultErrorHandler = false ;
+}
+
+WHSP
+    :
+    ( options {greedy=true;} :
+    ' '
+    |
+    '\t'
+    |
+    '\r' (options {greedy=true;} : '\n')? { newline(); } 
+    |
+    '\n' { newline(); }
+    |
+    '#' (~'\n')* '\n' { newline(); }
+    )+
+    {$setType(Token.SKIP);} //ignore this token
+    ;
+
+LPAR : '(' ;
+RPAR : ')' ;
+QUOTE : '\'' ;
+DOLLAR : '$' ;
+LBRACKET : '{' ;
+RBRACKET : '}' ;
+
+LEN : LBRACKET ('0'..'9')+ RBRACKET ;
+
+SINGLE_VALUE : ( "single-value" (WHSP)? ) ;
+COLLECTIVE : ( "collective" (WHSP)? ) ;
+NO_USER_MODIFICATION : ( "no-user-modification" (WHSP)? ) ;
+
+OBSOLETE : ( "obsolete" (WHSP)? ) ;
+ABSTRACT : ( "abstract" (WHSP)? ) ;
+STRUCTURAL : ( "structural" (WHSP)? ) ;
+protected AUXILIARY : ( "auxiliary" (WHSP)? ) ;
+
+OBJECTIDENTIFIER : 
+    ( "objectidentifier" 
+      WHSP
+      ( oiName:UNQUOTED_STRING ) 
+      WHSP
+      ( oiValue:UNQUOTED_STRING ) 
+    ) 
+    { setText( oiName.getText() + " " + oiValue.getText() ); }
+    ;
+
+OBJECTCLASS : ( "objectclass" (WHSP)? ) ;
+ATTRIBUTETYPE : ( "attributetype" (WHSP)? ) ;
+
+STARTNUMERICOID : ( LPAR (options {greedy=true;} : WHSP)? ( numericoid:VALUES ) ) { setText(numericoid.getText()); } ;
+NAME : ( "name" (options {greedy=true;} : WHSP)? qdstrings:VALUES ) { setText(qdstrings.getText().trim()); } ;
+DESC : ( "desc" (options {greedy=true;} : WHSP)? qdstring:VALUES ) { setText(qdstring.getText().trim()); } ;
+SUP : ( "sup" (options {greedy=true;} : WHSP)? sup:VALUES ) { setText(sup.getText().trim()); } ;
+MUST : ( "must" (options {greedy=true;} : WHSP)? must:VALUES ) { setText(must.getText().trim()); } ;
+MAY : ( "may" (options {greedy=true;} : WHSP)? may:VALUES ) { setText(may.getText()); } ;
+protected AUX : ( "aux" (options {greedy=true;} : WHSP)? aux:VALUES ) { setText(aux.getText()); } ;
+NOT : ( "not" (options {greedy=true;} : WHSP)? not:VALUES ) { setText(not.getText()); } ;
+FORM : ( "form" (options {greedy=true;} : WHSP)? form:VALUES ) { setText(form.getText()); } ;
+OC : ( "oc" (options {greedy=true;} : WHSP)? oc:VALUES ) { setText(oc.getText()); } ;
+EQUALITY : ( "equality" (options {greedy=true;} : WHSP)? equality:VALUES ) { setText(equality.getText().trim()); } ;
+ORDERING : ( "ordering" (options {greedy=true;} : WHSP)? ordering:VALUES ) { setText(ordering.getText().trim()); } ;
+SUBSTR : ( "substr" (options {greedy=true;} : WHSP)? substring:VALUES ) { setText(substring.getText().trim()); } ;
+SYNTAX : ( "syntax" (options {greedy=true;} : WHSP)? syntax:VALUES (len:LEN)? ) { setText(syntax.getText().trim() + (len!=null?len.getText().trim():"")); } ;
+APPLIES : ( "applies" (options {greedy=true;} : WHSP)? applies:VALUES ) { setText(applies.getText().trim()); } ;
+EXTENSION : x:( "x-" ( options {greedy=true;} : 'a'..'z' | '-' | '_' )+ (options {greedy=true;} : WHSP)? VALUES ) ; 
+FQCN : ( "fqcn" (options {greedy=true;} : WHSP)? fqcn:FQCN_VALUE ) { setText(fqcn.getText().trim()); } ;
+BYTECODE : ( "bytecode" (options {greedy=true;} : WHSP)? bytecode:BYTECODE_VALUE ) { setText(bytecode.getText().trim()); } ;
+
+AUX_OR_AUXILIARY :
+    ( AUXILIARY ) => AUXILIARY { $setType( AUXILIARY ); }
+    |
+    ( AUX ) { $setType( AUX ); }
+    ;
+
+protected VALUES : ( VALUE | LPAR  VALUE ( (DOLLAR)? VALUE )* RPAR ) ;
+protected VALUE : (WHSP)? ( QUOTED_STRING | UNQUOTED_STRING ) (options {greedy=true;}: WHSP)? ;
+protected UNQUOTED_STRING : (options{greedy=true;}: 'a'..'z' | '0'..'9' | '-' | '_' | ';' | '.' | ':' )+ ;
+protected QUOTED_STRING : ( QUOTE (~'\'')* QUOTE ) ;
+protected FQCN_VALUE : ( FQCN_IDENTIFIER ( '.' FQCN_IDENTIFIER )* ) ;
+protected FQCN_IDENTIFIER : ( FQCN_LETTER ( FQCN_LETTERORDIGIT )* ) ;
+protected FQCN_LETTER : 
+       '\u0024' |
+       '\u005f' |
+       '\u0061'..'\u007a' |
+       '\u00c0'..'\u00d6' |
+       '\u00d8'..'\u00f6' |
+       '\u00f8'..'\u00ff' |
+       '\u0100'..'\u1fff' |
+       '\u3040'..'\u318f' |
+       '\u3300'..'\u337f' |
+       '\u3400'..'\u3d2d' |
+       '\u4e00'..'\u9fff' |
+       '\uf900'..'\ufaff' ;
+protected FQCN_LETTERORDIGIT : 
+       '\u0024' |
+       '\u005f' |
+       '\u0061'..'\u007a' |
+       '\u00c0'..'\u00d6' |
+       '\u00d8'..'\u00f6' |
+       '\u00f8'..'\u00ff' |
+       '\u0100'..'\u1fff' |
+       '\u3040'..'\u318f' |
+       '\u3300'..'\u337f' |
+       '\u3400'..'\u3d2d' |
+       '\u4e00'..'\u9fff' |
+       '\uf900'..'\ufaff' |
+       '\u0030'..'\u0039' ;
+protected BYTECODE_VALUE : ( 'a'..'z' | '0'..'9' | '+' | '/' | '=' )+ ;
+
+
+USAGE : ( "usage" (WHSP)? ) ;
+USER_APPLICATIONS : ( "userapplications" (WHSP)? ) ;
+DIRECTORY_OPERATION : ( "directoryoperation" (WHSP)? ) ;
+DISTRIBUTED_OPERATION : ( "distributedoperation" (WHSP)? ) ;
+DSA_OPERATION : ( "dsaoperation" (WHSP)? ) ;
+
+/**
+ * An antlr generated schema main parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSchemaParser extends Parser;
+options    {
+    k = 3 ;
+    defaultErrorHandler = false ;
+    //buildAST=true ;
+}
+
+{
+    private ParserMonitor monitor = null;
+    private boolean isQuirksModeEnabled = false;
+    public void setParserMonitor( ParserMonitor monitor )
+    {
+        this.monitor = monitor;
+    }
+    private void matchedProduction( String msg )
+    {
+        if ( null != monitor )
+        {
+            monitor.matchedProduction( msg );
+        }
+    }
+    public void setQuirksMode( boolean enabled )
+    {
+        this.isQuirksModeEnabled = enabled;
+    }
+    public boolean isQuirksMode()
+    {
+        return this.isQuirksModeEnabled;
+    }
+    static class Extension
+    {
+        String key = "";
+        List<String> values = new ArrayList<String>();
+        
+        public void addValue( String value )
+        {
+            this.values.add( value );
+        }
+    }
+    static class NoidLen
+    {
+        String noid = "";
+        long len = 0L;
+    }
+    static class ElementTracker
+    {
+        Map<String, Integer> elementMap = new HashMap<String, Integer>();
+        void track(String element, Token token) throws SemanticException 
+        {
+            if(elementMap.containsKey(element))
+            {
+                throw new SemanticException( element + " appears twice.", token.getFilename(), token.getLine() , token.getColumn() );
+            }
+            elementMap.put(element, Integer.valueOf(1));
+        }
+        boolean contains(String element) 
+        {
+            return elementMap.containsKey(element);
+        }
+    }
+
+}
+
+openLdapSchema returns [List<Object> list = new ArrayList<Object>()]
+    {
+        AttributeType attributeType = null;
+        ObjectClass objectClass = null;
+        OpenLdapObjectIdentifierMacro oloid = null;
+    }
+    :
+    (
+        oloid = openLdapObjectIdentifier { list.add( oloid ); }
+        |
+        attributeType = openLdapAttributeType { list.add( attributeType ); }
+        |
+        objectClass = openLdapObjectClass { list.add( objectClass ); }
+    )*
+    ;
+
+openLdapObjectIdentifier returns [OpenLdapObjectIdentifierMacro oloid]
+    {
+        matchedProduction( "openLdapObjectIdentifier()" );
+    }
+    :
+    (
+        oi:OBJECTIDENTIFIER 
+        {
+            String[] nameAndValue = oi.getText().split( " " );
+            oloid = new OpenLdapObjectIdentifierMacro();
+            oloid.setName( nameAndValue[0] );
+            oloid.setRawOidOrNameSuffix( nameAndValue[1] );
+        }
+    )
+    ;
+    
+
+openLdapObjectClass returns [ObjectClass objectClass]
+    {
+        matchedProduction( "openLdapObjectClass()" );
+    }
+    :
+    (
+        OBJECTCLASS
+        ( objectClass=objectClassDescription )
+    )
+    ;
+    
+    
+openLdapAttributeType returns [AttributeType attributeType]
+    {
+        matchedProduction( "openLdapAttributeType()" );
+    }
+    :
+    (
+        ATTRIBUTETYPE
+        ( attributeType=attributeTypeDescription )
+    )
+    ;
+
+
+    /**
+     * Production for matching object class descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * ObjectClassDescription = LPAREN WSP
+     *     numericoid                 ; object identifier
+     *     [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *     [ SP "DESC" SP qdstring ]  ; description
+     *     [ SP "OBSOLETE" ]          ; not active
+     *     [ SP "SUP" SP oids ]       ; superior object classes
+     *     [ SP kind ]                ; kind of class
+     *     [ SP "MUST" SP oids ]      ; attribute types
+     *     [ SP "MAY" SP oids ]       ; attribute types
+     *     extensions WSP RPAREN
+     *
+     * kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+    */
+objectClassDescription returns [MutableObjectClass objectClass]
+    {
+        matchedProduction( "objectClassDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { objectClass = new MutableObjectClass(numericoid(oid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); objectClass.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); objectClass.setDescription(qdstring(desc.getText())); } )
+        |
+        ( obsolete:OBSOLETE { et.track("OBSOLETE", obsolete); objectClass.setObsolete( true ); } )
+        |
+        ( sup:SUP { et.track("SUP", sup); objectClass.setSuperiorOids(oids(sup.getText())); } )
+        |
+        ( kind1:ABSTRACT { et.track("KIND", kind1); objectClass.setType( ObjectClassTypeEnum.ABSTRACT ); }
+          |
+          kind2:STRUCTURAL { et.track("KIND", kind2); objectClass.setType( ObjectClassTypeEnum.STRUCTURAL ); }
+          |
+          kind3:AUXILIARY { et.track("KIND", kind3); objectClass.setType( ObjectClassTypeEnum.AUXILIARY ); } 
+        )
+        |
+        ( must:MUST { et.track("MUST", must); objectClass.setMustAttributeTypeOids(oids(must.getText())); } )
+        |
+        ( may:MAY { et.track("MAY", may); objectClass.setMayAttributeTypeOids(oids(may.getText())); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            objectClass.addExtension(ex.key, ex.values); 
+         } )
+    )*    
+    RPAR
+    ;
+
+
+    /**
+     * Production for matching attribute type descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * AttributeTypeDescription = LPAREN WSP
+     *     numericoid                    ; object identifier
+     *     [ SP "NAME" SP qdescrs ]      ; short names (descriptors)
+     *     [ SP "DESC" SP qdstring ]     ; description
+     *     [ SP "OBSOLETE" ]             ; not active
+     *     [ SP "SUP" SP oid ]           ; supertype
+     *     [ SP "EQUALITY" SP oid ]      ; equality matching rule
+     *     [ SP "ORDERING" SP oid ]      ; ordering matching rule
+     *     [ SP "SUBSTR" SP oid ]        ; substrings matching rule
+     *     [ SP "SYNTAX" SP noidlen ]    ; value syntax
+     *     [ SP "SINGLE-VALUE" ]         ; single-value
+     *     [ SP "COLLECTIVE" ]           ; collective
+     *     [ SP "NO-USER-MODIFICATION" ] ; not user modifiable
+     *     [ SP "USAGE" SP usage ]       ; usage
+     *     extensions WSP RPAREN         ; extensions
+     * 
+     * usage = "userApplications"     /  ; user
+     *         "directoryOperation"   /  ; directory operational
+     *         "distributedOperation" /  ; DSA-shared operational
+     *         "dSAOperation"            ; DSA-specific operational     
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+    */
+attributeTypeDescription returns [MutableAttributeType attributeType]
+    {
+        matchedProduction( "attributeTypeDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { attributeType = new MutableAttributeType(numericoid(oid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); attributeType.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); attributeType.setDescription(qdstring(desc.getText())); } )
+        |
+        ( obsolete:OBSOLETE { et.track("OBSOLETE", obsolete); attributeType.setObsolete( true ); } )
+        |
+        ( superior:SUP { et.track("SUP", superior); attributeType.setSuperiorOid(oid(superior.getText())); } )
+        |
+        ( equality:EQUALITY { et.track("EQUALITY", equality); attributeType.setEqualityOid(oid(equality.getText())); } )
+        |
+        ( ordering:ORDERING { et.track("ORDERING", ordering); attributeType.setOrderingOid(oid(ordering.getText())); } )
+        |
+        ( substring:SUBSTR { et.track("SUBSTR", substring); attributeType.setSubstringOid(oid(substring.getText())); } )
+        |
+        ( syntax:SYNTAX { 
+           et.track("SYNTAX", syntax); 
+            NoidLen noidlen = noidlen(syntax.getText());
+            attributeType.setSyntaxOid(noidlen.noid); 
+            attributeType.setSyntaxLength(noidlen.len);
+          } )
+        |
+        ( singleValued:SINGLE_VALUE { et.track("SINGLE_VALUE", singleValued); attributeType.setSingleValued( true ); } )
+        |
+        ( collective:COLLECTIVE { et.track("COLLECTIVE", collective); attributeType.setCollective( true ); } )
+        |
+        ( noUserModification:NO_USER_MODIFICATION { et.track("NO_USER_MODIFICATION", noUserModification); attributeType.setUserModifiable( false ); } )
+        |
+        ( usage1:USAGE (WHSP)* USER_APPLICATIONS { et.track("USAGE", usage1); attributeType.setUsage( UsageEnum.USER_APPLICATIONS ); }
+          |
+          usage2:USAGE DIRECTORY_OPERATION { et.track("USAGE", usage2); attributeType.setUsage( UsageEnum.DIRECTORY_OPERATION ); }
+          |
+          usage3:USAGE DISTRIBUTED_OPERATION { et.track("USAGE", usage3); attributeType.setUsage( UsageEnum.DISTRIBUTED_OPERATION ); } 
+          |
+          usage4:USAGE DSA_OPERATION { et.track("USAGE", usage4); attributeType.setUsage( UsageEnum.DSA_OPERATION ); } 
+        )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            attributeType.addExtension(ex.key, ex.values); 
+         } )
+    )*    
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {
+            // semantic check: required elements
+            if( !et.contains("SYNTAX") && !et.contains("SUP") ) 
+            {
+                throw new SemanticException( "One of SYNTAX or SUP is required", null, 0, 0 );
+            }
+        
+            // COLLECTIVE requires USAGE userApplications
+            if ( attributeType.isCollective() && ( attributeType.getUsage() != UsageEnum.USER_APPLICATIONS ) )
+            {
+                throw new SemanticException( "COLLECTIVE requires USAGE userApplications", null, 0, 0 );
+            }
+        
+            // NO-USER-MODIFICATION requires an operational USAGE.
+            if ( !attributeType.isUserModifiable() && ( attributeType.getUsage() == UsageEnum.USER_APPLICATIONS ) )
+            {
+                throw new SemanticException( "NO-USER-MODIFICATION requires an operational USAGE", null, 0, 0 );
+            }
+        }
+    }
+    ;
+
+
+    /**
+     * Production for matching ldap syntax descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * SyntaxDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+    */
+ldapSyntaxDescription returns [LdapSyntax ldapSyntax]
+    {
+        matchedProduction( "ldapSyntaxDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { ldapSyntax = new LdapSyntax(numericoid(oid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); ldapSyntax.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); ldapSyntax.setDescription(qdstring(desc.getText())); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            ldapSyntax.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    ;
+
+
+
+    /**
+     * Production for matching rule descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * MatchingRuleDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    SP "SYNTAX" SP numericoid  ; assertion syntax
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+    */
+matchingRuleDescription returns [MutableMatchingRule matchingRule]
+    {
+        matchedProduction( "matchingRuleDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { matchingRule = new MutableMatchingRule(numericoid(oid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); matchingRule.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); matchingRule.setDescription(qdstring(desc.getText())); } )
+        |
+        ( obsolete:OBSOLETE { et.track("OBSOLETE", obsolete); matchingRule.setObsolete( true ); } )
+        |
+        ( syntax:SYNTAX { et.track("SYNTAX", syntax); matchingRule.setSyntaxOid(numericoid(syntax.getText())); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            matchingRule.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {    
+            // semantic check: required elements
+            if( !et.contains("SYNTAX") ) {
+                throw new SemanticException( "SYNTAX is required", null, 0, 0 );
+            }
+        }
+    }
+    ;
+
+
+    /**
+     * Production for matching rule use descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * MatchingRuleUseDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    SP "APPLIES" SP oids       ; attribute types
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+    */
+matchingRuleUseDescription returns [MatchingRuleUse matchingRuleUse]
+    {
+        matchedProduction( "matchingRuleUseDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { matchingRuleUse = new MatchingRuleUse(numericoid(oid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); matchingRuleUse.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); matchingRuleUse.setDescription(qdstring(desc.getText())); } )
+        |
+        ( obsolete:OBSOLETE { et.track("OBSOLETE", obsolete); matchingRuleUse.setObsolete( true ); } )
+        |
+        ( applies:APPLIES { et.track("APPLIES", applies); matchingRuleUse.setApplicableAttributeOids(oids(applies.getText())); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            matchingRuleUse.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {
+            // semantic check: required elements
+            if( !et.contains("APPLIES") ) {
+                throw new SemanticException( "APPLIES is required", null, 0, 0 );
+            }
+        }
+    }
+    ;
+
+
+    /**
+     * Production for DIT content rule descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * DITContentRuleDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    [ SP "AUX" SP oids ]       ; auxiliary object classes
+     *    [ SP "MUST" SP oids ]      ; attribute types
+     *    [ SP "MAY" SP oids ]       ; attribute types
+     *    [ SP "NOT" SP oids ]       ; attribute types
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+    */
+ditContentRuleDescription returns [DitContentRule ditContentRule]
+    {
+        matchedProduction( "ditContentRuleDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { ditContentRule = new DitContentRule(numericoid(oid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); ditContentRule.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); ditContentRule.setDescription(qdstring(desc.getText())); } )
+        |
+        ( obsolete:OBSOLETE { et.track("OBSOLETE", obsolete); ditContentRule.setObsolete( true ); } )
+        |
+        ( aux:AUX { et.track("AUX", aux); ditContentRule.setAuxObjectClassOids(oids(aux.getText())); } )
+        |
+        ( must:MUST { et.track("MUST", must); ditContentRule.setMustAttributeTypeOids(oids(must.getText())); } )
+        |
+        ( may:MAY { et.track("MAY", may); ditContentRule.setMayAttributeTypeOids(oids(may.getText())); } )
+        |
+        ( not:NOT { et.track("NOT", not); ditContentRule.setNotAttributeTypeOids(oids(not.getText())); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            ditContentRule.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    ;
+
+
+    /**
+     * Production for DIT structure rules descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * DITStructureRuleDescription = LPAREN WSP
+     *   ruleid                     ; rule identifier
+     *   [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *   [ SP "DESC" SP qdstring ]  ; description
+     *   [ SP "OBSOLETE" ]          ; not active
+     *   SP "FORM" SP oid           ; NameForm
+     *   [ SP "SUP" ruleids ]       ; superior rules
+     *   extensions WSP RPAREN      ; extensions
+     *
+     * ruleids = ruleid / ( LPAREN WSP ruleidlist WSP RPAREN )
+     * ruleidlist = ruleid *( SP ruleid )
+     * ruleid = number
+     * </pre>
+    */
+ditStructureRuleDescription returns [DitStructureRule ditStructureRule]
+    {
+        matchedProduction( "ditStructureRuleDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( ruleid:STARTNUMERICOID { ditStructureRule = new DitStructureRule(ruleid(ruleid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); ditStructureRule.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); ditStructureRule.setDescription(qdstring(desc.getText())); } )
+        |
+        ( obsolete:OBSOLETE { et.track("OBSOLETE", obsolete); ditStructureRule.setObsolete( true ); } )
+        |
+        ( form:FORM { et.track("FORM", form); ditStructureRule.setForm(oid(form.getText())); } )
+        |
+        ( sup:SUP { et.track("SUP", sup); ditStructureRule.setSuperRules(ruleids(sup.getText())); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            ditStructureRule.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {
+            // semantic check: required elements
+            if( !et.contains("FORM") ) {
+                throw new SemanticException( "FORM is required", null, 0, 0 );
+            }
+        }
+    }
+    ;
+
+
+    /**
+     * Production for name form descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * NameFormDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    SP "OC" SP oid             ; structural object class
+     *    SP "MUST" SP oids          ; attribute types
+     *    [ SP "MAY" SP oids ]       ; attribute types
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+    */
+nameFormDescription returns [NameForm nameForm]
+    {
+        matchedProduction( "nameFormDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { nameForm = new NameForm(numericoid(oid.getText())); } )
+    (
+        ( name:NAME { et.track("NAME", name); nameForm.setNames(qdescrs(name.getText())); } )
+        |
+        ( desc:DESC { et.track("DESC", desc); nameForm.setDescription(qdstring(desc.getText())); } )
+        |
+        ( obsolete:OBSOLETE { et.track("OBSOLETE", obsolete); nameForm.setObsolete( true ); } )
+        |
+        ( oc:OC { et.track("OC", oc); nameForm.setStructuralObjectClassOid(oid(oc.getText())); } )
+        |
+        ( must:MUST { et.track("MUST", must); nameForm.setMustAttributeTypeOids(oids(must.getText())); } )
+        |
+        ( may:MAY { et.track("MAY", may); nameForm.setMayAttributeTypeOids(oids(may.getText())); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            nameForm.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {
+            // semantic check: required elements
+            if( !et.contains("MUST") ) {
+                throw new SemanticException( "MUST is required", null, 0, 0 );
+            }
+            if( !et.contains("OC") ) {
+                throw new SemanticException( "OC is required", null, 0, 0 );
+            }
+        
+            // semantic check: MUST and MAY must be disjoint
+            //List<String> aList = new ArrayList<String>( nfd.getMustAttributeTypes() );
+            //aList.retainAll( nfd.getMayAttributeTypes() );
+            //if( !aList.isEmpty() ) 
+            //{
+            //    throw new SemanticException( "MUST and MAY must be disjoint, "+aList.get( 0 )+" appears in both", null, 0, 0 );
+            //}
+        }
+    }
+    ;
+    
+
+    /**
+     * Production for comparator descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * LdapComparator = LPAREN WSP
+     *       numericoid                           ; object identifier
+     *       [ SP "DESC" SP qdstring ]            ; description
+     *       SP "FQCN" SP fqcn                    ; fully qualified class name
+     *       [ SP "BYTECODE" SP base64 ]          ; optional base64 encoded bytecode
+     *       extensions WSP RPAREN                ; extensions
+     * 
+     * base64          = *(4base64-char)
+     * base64-char     = ALPHA / DIGIT / "+" / "/"
+     * fqcn = fqcnComponent 1*( DOT fqcnComponent )
+     * fqcnComponent = ???
+     * </pre>
+    */
+ldapComparator returns [LdapComparatorDescription lcd]
+    {
+        matchedProduction( "ldapComparator()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { lcd = new LdapComparatorDescription(numericoid(oid.getText())); } )
+    (
+        ( desc:DESC { et.track("DESC", desc); lcd.setDescription(qdstring(desc.getText())); } )
+        |
+        ( fqcn:FQCN { et.track("FQCN", fqcn); lcd.setFqcn(fqcn.getText()); } )
+        |
+        ( bytecode:BYTECODE { et.track("BYTECODE", bytecode); lcd.setBytecode(bytecode.getText()); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            lcd.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {
+            // semantic check: required elements
+            if( !et.contains("FQCN") ) {
+                throw new SemanticException( "FQCN is required", null, 0, 0 );
+            }
+        
+            // semantic check: length should be divisible by 4
+            if( ( lcd.getBytecode() != null ) && ( lcd.getBytecode().length() % 4 != 0 ) ) {
+                throw new SemanticException( "BYTECODE must be divisible by 4", null, 0, 0 );
+            }
+        }
+    }
+    ;
+    
+
+    /**
+     * Production for normalizer descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * NormalizerDescription = LPAREN WSP
+     *       numericoid                           ; object identifier
+     *       [ SP "DESC" SP qdstring ]            ; description
+     *       SP "FQCN" SP fqcn                    ; fully qualified class name
+     *       [ SP "BYTECODE" SP base64 ]          ; optional base64 encoded bytecode
+     *       extensions WSP RPAREN                ; extensions
+     * 
+     * base64          = *(4base64-char)
+     * base64-char     = ALPHA / DIGIT / "+" / "/"
+     * fqcn = fqcnComponent 1*( DOT fqcnComponent )
+     * fqcnComponent = ???
+     * </pre>
+    */
+normalizerDescription returns [NormalizerDescription nd]
+    {
+        matchedProduction( "normalizerDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { nd = new NormalizerDescription(numericoid(oid.getText())); } )
+    (
+        ( desc:DESC { et.track("DESC", desc); nd.setDescription(qdstring(desc.getText())); } )
+        |
+        ( fqcn:FQCN { et.track("FQCN", fqcn); nd.setFqcn(fqcn.getText()); } )
+        |
+        ( bytecode:BYTECODE { et.track("BYTECODE", bytecode); nd.setBytecode(bytecode.getText()); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            nd.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {
+            // semantic check: required elements
+            if( !et.contains("FQCN") ) {
+                throw new SemanticException( "FQCN is required", null, 0, 0 );
+            }
+        
+            // semantic check: length should be divisible by 4
+            if( nd.getBytecode() != null && ( nd.getBytecode().length() % 4 != 0 ) ) {
+                throw new SemanticException( "BYTECODE must be divisible by 4", null, 0, 0 );
+            }     
+        }   
+    }
+    ;
+    
+
+    /**
+     * Production for syntax checker descriptions. It is fault-tolerant
+     * against element ordering.
+     *
+     * <pre>
+     * SyntaxCheckerDescription = LPAREN WSP
+     *       numericoid                           ; object identifier
+     *       [ SP "DESC" SP qdstring ]            ; description
+     *       SP "FQCN" SP fqcn                    ; fully qualified class name
+     *       [ SP "BYTECODE" SP base64 ]          ; optional base64 encoded bytecode
+     *       extensions WSP RPAREN                ; extensions
+     * 
+     * base64          = *(4base64-char)
+     * base64-char     = ALPHA / DIGIT / "+" / "/"
+     * fqcn = fqcnComponent 1*( DOT fqcnComponent )
+     * fqcnComponent = ???
+     * </pre>
+    */
+syntaxCheckerDescription returns [SyntaxCheckerDescription scd]
+    {
+        matchedProduction( "syntaxCheckerDescription()" );
+        ElementTracker et = new ElementTracker();
+    }
+    :
+    ( oid:STARTNUMERICOID { scd = new SyntaxCheckerDescription(numericoid(oid.getText())); } )
+    (
+        ( desc:DESC { et.track("DESC", desc); scd.setDescription(qdstring(desc.getText())); } )
+        |
+        ( fqcn:FQCN { et.track("FQCN", fqcn); scd.setFqcn(fqcn.getText()); } )
+        |
+        ( bytecode:BYTECODE { et.track("BYTECODE", bytecode); scd.setBytecode(bytecode.getText()); } )
+        |
+        ( extension:EXTENSION { 
+            Extension ex = extension(extension.getText());
+            et.track(ex.key, extension); 
+            scd.addExtension(ex.key, ex.values); 
+         } )
+    )*
+    RPAR
+    {
+        if( !isQuirksModeEnabled )
+        {
+            // semantic check: required elements
+            if( !et.contains("FQCN") ) {
+                throw new SemanticException( "FQCN is required", null, 0, 0 );
+            }
+        
+            // semantic check: length should be divisible by 4
+            if( scd.getBytecode() != null && ( scd.getBytecode().length() % 4 != 0 ) ) {
+                throw new SemanticException( "BYTECODE must be divisible by 4", null, 0, 0 );
+            }  
+        }      
+    }
+    ;
+    
+
+
+
+noidlen [String s] returns [NoidLen noidlen]
+    {
+        matchedProduction( "noidlen()" );
+        AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+        AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+        parser.setParserMonitor(monitor);
+        noidlen = isQuirksModeEnabled ? parser.quirksNoidlen() : parser.noidlen();
+    }
+    :
+    ;
+
+
+extension [String s] returns [Extension extension]
+    {
+        matchedProduction( "extension()" );
+        AntlrSchemaExtensionLexer lexer = new AntlrSchemaExtensionLexer(new StringReader(s));
+        AntlrSchemaExtensionParser parser = new AntlrSchemaExtensionParser(lexer);
+        extension = parser.extension();
+    }
+    :
+    ;
+
+
+numericoid [String s] returns [String numericoid]
+    {
+        matchedProduction( "numericoid()");
+        if(isQuirksModeEnabled)
+        {
+             numericoid = oid(s);
+        }
+        else
+        {
+	        AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+	        AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+	        parser.setParserMonitor(monitor);
+	        numericoid = parser.numericoid();
+        }
+    }
+    :
+    ;
+
+oid [String s] returns [String oid]
+    {
+        matchedProduction( "oid()" );
+        List<String> oids = oids(s);
+        if( oids.size() != 1 ) 
+        {
+            throw new SemanticException( "Exactly one OID expected", null, 0, 0 );
+        }
+        oid = oids.get(0);
+    }
+    :
+    ;
+
+oids [String s] returns [List<String> oids]
+    {
+        matchedProduction( "oids()" );
+        if(isQuirksModeEnabled)
+        {
+             oids = qdescrs(s);
+        }
+        else
+        {
+	        AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+	        AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+	        parser.setParserMonitor(monitor);
+	        oids = parser.oids();
+	    }
+    }
+    :
+    ;
+
+qdescr [String s] returns [String qdescr]
+    {
+        matchedProduction( "qdescr()" );
+        List<String> qdescrs = qdescrs(s);
+        if( qdescrs.size() != 1 ) 
+        {
+            throw new SemanticException( "Exactly one qdescrs expected", null, 0, 0 );
+        }
+        qdescr = qdescrs.get(0);
+    }
+    :
+    ;
+
+qdescrs [String s] returns [List<String> qdescrs]
+    {
+        matchedProduction( "qdescrs()" );
+        AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+        AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+        parser.setParserMonitor(monitor);
+        qdescrs = isQuirksModeEnabled ? parser.quirksQdescrs() : parser.qdescrs();
+    }
+    :
+    ;
+
+qdstring [String s] returns [String qdstring]
+    {
+        matchedProduction( "qdstring()" );
+        List<String> qdstrings = qdstrings(s);
+        if( qdstrings.size() != 1 ) 
+        {
+            throw new SemanticException( "Exactly one qdstrings expected", null, 0, 0 );
+        }
+        qdstring = qdstrings.get(0);
+    }
+    :
+    ;
+
+qdstrings [String s] returns [List<String> qdstrings]
+    {
+        matchedProduction( "qdstrings()" );
+        AntlrSchemaQdstringLexer lexer = new AntlrSchemaQdstringLexer(new StringReader(s));
+        AntlrSchemaQdstringParser parser = new AntlrSchemaQdstringParser(lexer);
+        parser.setParserMonitor(monitor);
+        qdstrings = parser.qdstrings();
+    }
+    :
+    ;
+
+ruleid [String s] returns [Integer ruleid]
+    {
+        matchedProduction( "ruleid()" );
+        AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+        AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+        parser.setParserMonitor(monitor);
+        ruleid = parser.ruleid();
+    }
+    :
+    ;
+
+ruleids [String s] returns [List<Integer> ruleids]
+    {
+        matchedProduction( "ruleids()" );
+        AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+        AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+        parser.setParserMonitor(monitor);
+        ruleids = parser.ruleids();
+    }
+    :
+    ;
+
+
+    
diff --git a/trunk/ldap/model/src/main/antlr/subtree-specification.g b/trunk/ldap/model/src/main/antlr/subtree-specification.g
new file mode 100644
index 0000000..346e233
--- /dev/null
+++ b/trunk/ldap/model/src/main/antlr/subtree-specification.g
@@ -0,0 +1,601 @@
+header
+{
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+
+package org.apache.directory.api.ldap.model.subtree;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.LeafNode;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecification;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecificationModifier;
+import org.apache.directory.api.ldap.model.schema.NormalizerMappingResolver;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.util.ComponentsMonitor;
+import org.apache.directory.api.util.OptionalComponentsMonitor;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The antlr generated subtree specification parser.
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSubtreeSpecificationParser extends Parser;
+
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 1;
+    defaultErrorHandler = false;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser initialization
+// ----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationParser.class );
+    
+    private NormalizerMappingResolver resolver;
+    
+    private Set<Dn> chopBeforeExclusions = null;
+    private Set<Dn> chopAfterExclusions = null;
+
+    private SubtreeSpecificationModifier ssModifier = null;
+    
+    /** The schemaManager */
+    private SchemaManager schemaManager;
+    
+    /** The ObjectClass AT */
+    AttributeType OBJECT_CLASS_AT;
+    
+    private ComponentsMonitor subtreeSpecificationComponentsMonitor = null;
+    
+    
+
+    /**
+     * Does nothing.
+     */
+    public void init( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+        
+        if ( schemaManager != null )
+        {
+            OBJECT_CLASS_AT = schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
+        }
+    }
+    
+    
+    public void setNormalizerMappingResolver( NormalizerMappingResolver resolver )
+    {
+        this.resolver = resolver;
+    }
+    
+    
+    public boolean isNormalizing()
+    {
+        return this.resolver != null;
+    }
+    
+
+    private int token2Integer( Token token ) throws RecognitionException
+    {
+        int i = 0;
+        
+        try
+        {
+            i = Integer.parseInt( token.getText());
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new RecognitionException( "Value of INTEGER token " +
+                                            token.getText() +
+                                            " cannot be converted to an Integer" );
+        }
+        
+        return i;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// parser productions
+// ----------------------------------------------------------------------------
+
+wrapperEntryPoint returns [SubtreeSpecification ss]
+{
+    log.debug( "entered wrapperEntryPoint()" );
+    ss = null;
+    SubtreeSpecification tempSs = null;
+} :
+    tempSs=subtreeSpecification "end"
+    {
+        ss = tempSs;
+    }
+    ;
+
+subtreeSpecification returns [SubtreeSpecification ss]
+{
+    log.debug( "entered subtreeSpecification()" );
+    // clear out ss, ssModifier, subtreeSpecificationComponentsMonitor,
+    // chopBeforeExclusions and chopAfterExclusions
+    // in case something is left from the last parse
+    ss = null;
+    ssModifier = new SubtreeSpecificationModifier();
+    subtreeSpecificationComponentsMonitor = new OptionalComponentsMonitor( 
+            new String [] { "base", "specificExclusions", "minimum", "maximum", "specificationFilter" } );
+    chopBeforeExclusions = new HashSet<Dn>();
+    chopAfterExclusions = new HashSet<Dn>();
+    // always create a new filter parser in case we may have some statefulness problems with it
+}
+    :
+    OPEN_CURLY ( SP )*
+        ( subtreeSpecificationComponent ( SP )*
+            ( SEP ( SP )* subtreeSpecificationComponent ( SP )* )* )?
+    CLOSE_CURLY
+    {
+        ss = ssModifier.getSubtreeSpecification();
+    }
+    ;
+
+subtreeSpecificationComponent
+{
+    log.debug( "entered subtreeSpecification()" );
+}
+    :
+    ss_base
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "base" );
+    }
+    | ss_specificExclusions
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "specificExclusions" );
+    }
+    | ss_minimum
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "minimum" );
+    }
+    | ss_maximum
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "maximum" );
+    }
+    | ss_specificationFilter
+    {
+        subtreeSpecificationComponentsMonitor.useComponent( "specificationFilter" );
+    }
+    ;
+    exception
+    catch [IllegalArgumentException e]
+    {
+        throw new RecognitionException( e.getMessage() );
+    }
+
+ss_base
+{
+    log.debug( "entered ss_base()" );
+    Dn base = null;
+}
+    :
+    ID_base ( SP )+ base=distinguishedName
+    {
+        ssModifier.setBase( base );
+    }
+    ;
+
+ss_specificExclusions
+{
+    log.debug( "entered ss_specificExclusions()" );
+}
+    :
+    ID_specificExclusions ( SP )+ specificExclusions
+    {
+        ssModifier.setChopBeforeExclusions( chopBeforeExclusions );
+        ssModifier.setChopAfterExclusions( chopAfterExclusions );
+    }
+    ;
+
+specificExclusions
+{
+    log.debug( "entered specificExclusions()" );
+}
+    :
+    OPEN_CURLY ( SP )*
+        ( specificExclusion ( SP )*
+            ( SEP ( SP )* specificExclusion ( SP )* )*
+        )?
+    CLOSE_CURLY
+    ;
+
+specificExclusion
+{
+    log.debug( "entered specificExclusion()" );
+}
+    :
+    chopBefore | chopAfter
+    ;
+
+chopBefore
+{
+    log.debug( "entered chopBefore()" );
+    Dn chopBeforeExclusion = null;
+}
+    :
+    ID_chopBefore ( SP )* COLON ( SP )* chopBeforeExclusion=distinguishedName
+    {
+        chopBeforeExclusions.add( chopBeforeExclusion );
+    }
+    ;
+
+chopAfter
+{
+    log.debug( "entered chopAfter()" );
+    Dn chopAfterExclusion = null;
+}
+    :
+    ID_chopAfter ( SP )* COLON ( SP )* chopAfterExclusion=distinguishedName
+    {
+        chopAfterExclusions.add( chopAfterExclusion );
+    }
+    ;
+
+ss_minimum
+{
+    log.debug( "entered ss_minimum()" );
+    int minimum = 0;
+}
+    :
+    ID_minimum ( SP )+ minimum=baseDistance
+    {
+        ssModifier.setMinBaseDistance( minimum );
+    }
+    ;
+
+ss_maximum
+{
+    log.debug( "entered ss_maximum()" );
+    int maximum = 0;
+}
+    :
+    ID_maximum ( SP )+ maximum=baseDistance
+    {
+        ssModifier.setMaxBaseDistance( maximum );
+    }
+    ;
+
+ss_specificationFilter
+{
+    log.debug( "entered ss_specificationFilter()" );
+    ExprNode filterExpr = null;
+}
+    :
+    ID_specificationFilter 
+    ( SP )+ 
+    (
+        ( filterExpr=refinement )
+        |
+        ( filterExpr=filter )
+    )
+    { ssModifier.setRefinement( filterExpr ); }
+    ;
+    
+    
+filter returns [ ExprNode filterExpr = null ]
+{
+    log.debug( "entered filter()" );
+}
+    :
+    ( filterToken:FILTER { filterExpr=FilterParser.parse( schemaManager, filterToken.getText() ); } )
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "filterParser failed. " + e.getMessage() );
+    }
+    
+distinguishedName returns [ Dn name ]
+{
+    log.debug( "entered distinguishedName()" );
+    name = null;
+}
+    :
+    token:SAFEUTF8STRING
+    {
+        name = new Dn( token.getText() );
+        name.apply( schemaManager );
+        
+        log.debug( "recognized a DistinguishedName: " + token.getText() );
+    }
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "dnParser failed for " + token.getText() + " " + e.getMessage() );
+    }
+
+baseDistance returns [ int distance ]
+{
+    log.debug( "entered baseDistance()" );
+    distance = 0;
+}
+    :
+    token:INTEGER
+    {
+        distance = token2Integer( token );
+    }
+    ;
+
+oid returns [ String result ]
+{
+    log.debug( "entered oid()" );
+    result = null;
+    Token token = null;
+}
+    :
+    { token = LT( 1 ); } // an interesting trick goes here ;-)
+    ( DESCR | NUMERICOID )
+    {
+        result = token.getText();
+        log.debug( "recognized an oid: " + result );
+    }
+    ;
+
+refinement returns [ ExprNode node ]
+{
+    log.debug( "entered refinement()" );
+    node = null;
+}
+    :
+    node=item | node=and | node=or | node=not
+    ;
+
+item returns [ LeafNode node ]
+{
+    log.debug( "entered item()" );
+    node = null;
+    String oid = null;
+    ObjectClass objectClass;
+}
+    :
+    ID_item ( SP )* COLON ( SP )* oid=oid
+    {
+        try
+        {
+            objectClass = schemaManager.lookupObjectClassRegistry( oid );
+        }
+        catch ( LdapException le )
+        {
+              // The oid does not exist
+              // TODO : deal with such an exception
+        }
+        
+        node = new EqualityNode( OBJECT_CLASS_AT, new StringValue( oid ) );
+    }
+    ;
+
+and returns [ BranchNode node ]
+{
+    log.debug( "entered and()" );
+    node = null;
+    List<ExprNode> children = null; 
+}
+    :
+    ID_and ( SP )* COLON ( SP )* children=refinements
+    {
+        node = new AndNode( children );
+    }
+    ;
+
+or returns [ BranchNode node ]
+{
+    log.debug( "entered or()" );
+    node = null;
+    List<ExprNode> children = null; 
+}
+    :
+    ID_or ( SP )* COLON ( SP )* children=refinements
+    {
+        node = new OrNode( children );
+    }
+    ;
+
+not returns [ BranchNode node ]
+{
+    log.debug( "entered not()" );
+    node = null;
+    ExprNode child = null;
+}
+    :
+    ID_not ( SP )* COLON ( SP )* child=refinement
+    {
+        node = new NotNode( child );
+    }
+    ;
+
+refinements returns [ List<ExprNode> children ]
+{
+    log.debug( "entered refinements()" );
+    children = null;
+    ExprNode child = null;
+    List<ExprNode> tempChildren = new ArrayList<ExprNode>();
+}
+    :
+    OPEN_CURLY ( SP )*
+    (
+        child=refinement ( SP )*
+        {
+            tempChildren.add( child );
+        }
+        ( SEP ( SP )* child=refinement ( SP )*
+        {
+            tempChildren.add( child );
+        } )*
+    )? CLOSE_CURLY
+    {
+        children = tempChildren;
+    }
+    ;
+
+
+// ----------------------------------------------------------------------------
+// lexer class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The parser's primary lexer.
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class AntlrSubtreeSpecificationLexer extends Lexer;
+
+
+// ----------------------------------------------------------------------------
+// lexer options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 5;
+
+    charVocabulary = '\u0001'..'\u0127';
+}
+
+tokens
+{
+    ID_base = "base";
+    ID_specificExclusions = "specificExclusions";
+    ID_chopBefore = "chopBefore";
+    ID_chopAfter = "chopAfter";
+    ID_minimum = "minimum";
+    ID_maximum = "maximum";
+    ID_specificationFilter = "specificationFilter";
+    ID_item = "item";
+    ID_and = "and";
+    ID_or = "or";
+    ID_not = "not";
+}
+
+
+//----------------------------------------------------------------------------
+// lexer initialization
+//----------------------------------------------------------------------------
+
+{
+    private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationLexer.class );
+}
+
+
+// ----------------------------------------------------------------------------
+// attribute description lexer rules from models
+// ----------------------------------------------------------------------------
+
+SP : ' ';
+
+COLON : ':' { log.debug( "matched COLON(':')" ); } ;
+
+OPEN_CURLY : '{' { log.debug( "matched LBRACKET('{')" ); } ;
+
+CLOSE_CURLY : '}' { log.debug( "matched RBRACKET('}')" ); } ;
+
+SEP : ',' { log.debug( "matched SEP(',')" ); } ;
+
+SAFEUTF8STRING : '"'! ( SAFEUTF8CHAR )* '"'! { log.debug( "matched SAFEUTF8CHAR: \"" + getText() + "\"" ); } ;
+
+DESCR : ALPHA ( ALPHA | DIGIT | '-' )* { log.debug( "matched DESCR" ); } ;
+
+INTEGER_OR_NUMERICOID
+    :
+    ( INTEGER DOT ) => NUMERICOID
+    {
+        $setType( NUMERICOID );
+    }
+    |
+    INTEGER
+    {
+        $setType( INTEGER );
+    }
+    ;
+
+protected INTEGER: DIGIT | ( LDIGIT ( DIGIT )+ ) { log.debug( "matched INTEGER: " + getText() ); } ;
+
+protected NUMERICOID: INTEGER ( DOT INTEGER )+ { log.debug( "matched NUMERICOID: " + getText() ); } ;
+
+protected DOT: '.' ;
+
+protected DIGIT: '0' | LDIGIT ;
+
+protected LDIGIT: '1'..'9' ;
+
+protected ALPHA: 'A'..'Z' | 'a'..'z' ;
+
+// This is all messed up - could not figure out how to get antlr to represent
+// the safe UTF-8 character set from RFC 3642 for production SafeUTF8Character
+
+protected SAFEUTF8CHAR:
+    '\u0001'..'\u0021' |
+    '\u0023'..'\u007F' |
+    '\u00c0'..'\u00d6' |
+    '\u00d8'..'\u00f6' |
+    '\u00f8'..'\u00ff' |
+    '\u0100'..'\u1fff' |
+    '\u3040'..'\u318f' |
+    '\u3300'..'\u337f' |
+    '\u3400'..'\u3d2d' |
+    '\u4e00'..'\u9fff' |
+    '\uf900'..'\ufaff' ;
+
+FILTER : '(' ( ( '&' (SP)* (FILTER)+ ) | ( '|' (SP)* (FILTER)+ ) | ( '!' (SP)* FILTER ) | FILTER_VALUE ) ')' (SP)* ;
+
+protected FILTER_VALUE : (options{greedy=true;}: ~( ')' | '(' | '&' | '|' | '!' ) ( ~(')') )* ) ;
diff --git a/trunk/ldap/model/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/model/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/model/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/model/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/model/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/model/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/AuthenticationLevel.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/AuthenticationLevel.java
new file mode 100644
index 0000000..27f3a3d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/AuthenticationLevel.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * An enumeration that represents the level of authentication. We have 4 
+ * different levels :
+ * <ul>
+ * <li>NONE : anonymous</li>
+ * <li>SIMPLE : Simple authentication</li>
+ * <li>STRONG : SASL or external authentication</li>
+ * <li>UNAUTHENT>A special case when just doing some auditing</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum AuthenticationLevel
+{
+    /**
+     * No authentication (anonymous access)
+     */
+    NONE(0, "none"),
+
+    /**
+     * Simple authentication (bound with plain-text credentials)
+     */
+    SIMPLE(1, "simple"),
+
+    /**
+     * Strong authentication (bound with encrypted credentials)
+     */
+    STRONG(2, "strong"),
+
+    /**
+     * Unauthentication, if the BIND contains a Dn but no credentials
+     */
+    UNAUTHENT(3, "unauthent");
+
+    /** The internal numeric value */
+    private int level;
+
+    /** The level name */
+    private final String name;
+
+
+    /**
+     * Creates a new instance of AuthenticationLevel.
+     *
+     * @param level The level
+     * @param name The associated name
+     */
+    private AuthenticationLevel( int level, String name )
+    {
+        this.level = level;
+        this.name = name;
+    }
+
+
+    /**
+     * @return the integer value of this level (greater value, stronger level).
+     */
+    public int getLevel()
+    {
+        return level;
+    }
+
+
+    /**
+     * @return the name of this level.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return name;
+    }
+
+
+    /**
+     * Return the AuthenticationLevel  associated with the given numeric level. This
+     * is used by the serialization process.
+     *
+     * @param val The numeric level we are looking at
+     * @return The associated AuthenticationLevel
+     */
+    public static AuthenticationLevel getLevel( int val )
+    {
+        switch ( val )
+        {
+            case 0:
+                return NONE;
+
+            case 1:
+                return SIMPLE;
+
+            case 2:
+                return STRONG;
+
+            case 3:
+                return UNAUTHENT;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_05001_UNKNOWN_AUTHENT_LEVEL, val ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/JndiPropertyConstants.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/JndiPropertyConstants.java
new file mode 100644
index 0000000..444ab16
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/JndiPropertyConstants.java
@@ -0,0 +1,146 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * This class contains all the Ldap specific properties described in the JNDI API.
+ * See http://java.sun.com/j2se/1.5.0/docs/guide/jndi/jndi-ldap-gl.html
+ * Final reference -> class shouldn't be extended
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class JndiPropertyConstants
+{
+    /**
+     *  Ensures no construction of this class, also ensures there is no need for final keyword above
+     *  (Implicit super constructor is not visible for default constructor),
+     *  but is still self documenting.
+     */
+    private JndiPropertyConstants()
+    {
+    }
+
+    // Pure JNDI properties
+    /** Batch size of search results returned */
+    public static final String JNDI_BATCHSIZE = "java.naming.batchsize";
+
+    /** List of FQCNs of the control factory classes */
+    public static final String JNDI_FACTORY_CONTROL = "java.naming.factory.control";
+
+    /** FQCN of the factory creating the InitialContext */
+    public static final String JNDI_FACTORY_INITIAL = "java.naming.factory.initial";
+
+    /** List of FQCNs of the Object factory */
+    public static final String JNDI_FACTORY_OBJECT = "java.naming.factory.object";
+
+    /** List of FQCNs of the state factory */
+    public static final String JNDI_FACTORY_STATE = "java.naming.factory.state";
+
+    /** The Language to use */
+    public static final String JNDI_LANGUAGE = "java.naming.language";
+
+    /** The list of URL pointing to a LDAP server */
+    public static final String JNDI_PROVIDER_URL = "java.naming.provider.url";
+
+    /** Tells how the referral should be handled */
+    public static final String JNDI_REFERRAL = "java.naming.referral";
+
+    /** The Authentication mechanism */
+    public static final String JNDI_SECURITY_AUTHENTICATION = "java.naming.security.authentication";
+
+    /** The credentials */
+    public static final String JNDI_SECURITY_CREDENTIALS = "java.naming.security.credentials";
+
+    /** The Principal */
+    public static final String JNDI_SECURITY_PRINCIPAL = "java.naming.security.principal";
+
+    /** The security protocol to use */
+    public static final String JNDI_SECURITY_PROTOCOL = "java.naming.security.protocol";
+
+    // Ldap specific properties
+    /** The list of binary attributes */
+    public static final String JNDI_LDAP_ATTRIBUTES_BINARY = "java.naming.ldap.attributes.binary";
+
+    /** The controls to send when connectiong */
+    public static final String JNDI_LDAP_CONTROL_CONNECT = "java.naming.ldap.control.connect";
+
+    /** Tells if the old Rdn must be deleted when doing a MODDN */
+    public static final String JNDI_LDAP_DELETE_RDN = "java.naming.ldap.deleteRDN";
+
+    /** Tells if and how we dereference aliases */
+    public static final String JNDI_LDAP_DAP_DEREF_ALIASES = "java.naming.ldap.derefAliases";
+
+    /** The FQCN of the socket factory to use to connect to the server */
+    public static final String JNDI_FACTORY_SOCKET = "java.naming.ldap.factory.socket";
+
+    /** The separator to use when dealing with RefAddr */
+    public static final String JNDI_LDAP_REF_SEPARATOR = "java.naming.ldap.ref.separator";
+
+    /** The maximum number of referral to follow in a chain of referrals */
+    public static final String JNDI_LDAP_REFERRAL_LIMIT = "java.naming.ldap.referral.limit";
+
+    /** tells that we want the attributeTypes only to be returned */
+    public static final String JNDI_LDAP_TYPES_ONLY = "java.naming.ldap.typesOnly";
+
+    /** Specifies the LDAP version to use */
+    public static final String JNDI_LDAP_VERSION = "java.naming.ldap.version";
+
+    // SASL properties
+    /** The SASL authorization ID */
+    public static final String JNDI_SASL_AUTHORIZATION_ID = "java.naming.security.sasl.authorizationId";
+
+    /** The SASL Realm */
+    public static final String JNDI_SASL_REALM = "java.naming.security.sasl.realm";
+
+    /** An instance of CallbackHandler to use when required */
+    public static final String JNDI_SASL_CALLBACK = "java.naming.security.sasl.callback";
+
+    /** The SASL Quality Of Protection value */
+    public static final String JNDI_SASL_QOP = "javax.security.sasl.qop";
+
+    /** The cipher strength */
+    public static final String JNDI_SASL_STRENGTH = "javax.security.sasl.strength";
+
+    /** The maximum size of the receive buffer */
+    public static final String JNDI_SASL_MAX_BUFFER = "javax.security.sasl.maxbuffer";
+
+    /** Tells if the the server must authenticate the client */
+    public static final String JNDI_SASL_AUTHENTICATION = "javax.security.sasl.server.authentication";
+
+    /** Tells if the server must support forward secrecy */
+    public static final String JNDI_SASL_POLICY_FORWARD = "javax.security.sasl.policy.forward";
+
+    /** Tells if the server must require some credentials */
+    public static final String JNDI_SASL_POLICY_CREDENTIALS = "javax.security.sasl.policy.credentials";
+
+    /** Tells if the server allow Plain text mechanism */
+    public static final String JNDI_SASL_POLICY_NO_PLAIN_TEXT = "javax.security.sasl.policy.noplaintext";
+
+    /** Tells if the SASL mechanism is protected against active attacks */
+    public static final String JNDI_SASL_POLICY_NO_ACTIVE = "javax.security.sasl.policy.noactive";
+
+    /** Tells if the SASL mechanism is protected against dictionary attacks */
+    public static final String JNDI_SASL_POLICY_NO_DICTIONARY = "javax.security.sasl.policy.nodictionary";
+
+    /** Tells if the SASL mechanism accept or not anonymous connections */
+    public static final String JNDI_SASL_POLICY_NO_ANONYMOUS = "javax.security.sasl.policy.noanonymous";
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/LdapConstants.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/LdapConstants.java
new file mode 100644
index 0000000..4d5a971
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/LdapConstants.java
@@ -0,0 +1,38 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * A list of LDAP constants
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LdapConstants
+{
+    /** The default catch-all ObjectClass filter */
+    public static final String OBJECT_CLASS_STAR = "(objectClass=*)";
+
+
+    private LdapConstants()
+    {
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/LdapSecurityConstants.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/LdapSecurityConstants.java
new file mode 100644
index 0000000..1faa8f9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/LdapSecurityConstants.java
@@ -0,0 +1,248 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * An enum to store all the security constants used in the server
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum LdapSecurityConstants
+{
+    /** The SHA encryption method */
+    HASH_METHOD_SHA("SHA", "SHA", "sha"),
+
+    /** The Salted SHA encryption method */
+    HASH_METHOD_SSHA("SSHA", "SHA", "ssha"),
+
+    /** The SHA-256 encryption method */
+    HASH_METHOD_SHA256("SHA-256", "SHA-256", "sha256"),
+
+    /** The salted SHA-256 encryption method */
+    HASH_METHOD_SSHA256("SSHA-256", "SHA-256", "ssha256"),
+
+    /** The SHA-384 encryption method */
+    HASH_METHOD_SHA384("SHA-384", "SHA-384", "sha384"),
+
+    /** The salted SHA-384 encryption method */
+    HASH_METHOD_SSHA384("SSHA-384", "SHA-384", "ssha384"),
+
+    /** The SHA-512 encryption method */
+    HASH_METHOD_SHA512("SHA-512", "SHA-512", "sha512"),
+
+    /** The salted SHA-512 encryption method */
+    HASH_METHOD_SSHA512("SSHA-512", "SHA-512", "ssha512"),
+
+    /** The MD5 encryption method */
+    HASH_METHOD_MD5("MD5", "MD5", "md5"),
+
+    /** The Salter MD5 encryption method */
+    HASH_METHOD_SMD5("SMD5", "MD5", "smd5"),
+
+    /** The crypt encryption method */
+    HASH_METHOD_CRYPT("CRYPT", "CRYPT", "crypt"),
+
+    /** The PBKDF2-based encryption method */
+    HASH_METHOD_PKCS5S2("PKCS5S2", "PBKDF2WithHmacSHA1", "PKCS5S2");
+
+    /* These encryption types are not yet supported 
+    ** The AES encryption method *
+    ENC_METHOD_AES("aes"),
+    
+    ** The 3DES encryption method *
+    ENC_METHOD_3DES("3des"),
+    
+    ** The Blowfish encryption method *
+    ENC_METHOD_BLOWFISH("blowfish"),
+    
+    ** The RC4 encryption method *
+    ENC_METHOD_RC4("rc4");
+    */
+
+    /** The associated name */
+    private String name;
+
+    /** The associated algorithm */
+    private String algorithm;
+
+    /** The associated prefix */
+    private String prefix;
+
+
+    /**
+     * Creates a new instance of LdapSecurityConstants.
+     * 
+     * @param name the associated name
+     * @param algorithm the associated algorithm
+     * @param prefix the associated prefix
+     */
+    private LdapSecurityConstants( String name, String algorithm, String prefix )
+    {
+        this.name = name;
+        this.algorithm = algorithm;
+        this.prefix = prefix;
+    }
+
+
+    /**
+     * @return the name associated with the constant.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * @return the prefix associated with the constant.
+     */
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+
+    /**
+     * @return the prefix associated with the constant.
+     */
+    public String getPrefix()
+    {
+        return prefix;
+    }
+
+
+    /**
+     * Get the associated constant from a string
+     *
+     * @param algorithm The algorithm's name
+     * @return The associated constant
+     */
+    public static LdapSecurityConstants getAlgorithm( String algorithm )
+    {
+        if ( HASH_METHOD_SHA.name.equalsIgnoreCase( algorithm )
+            || HASH_METHOD_SHA.prefix.equalsIgnoreCase( algorithm ) )
+        {
+            return HASH_METHOD_SHA;
+        }
+
+        if ( HASH_METHOD_SSHA.name.equalsIgnoreCase( algorithm )
+            || HASH_METHOD_SSHA.prefix.equalsIgnoreCase( algorithm ) )
+        {
+            return HASH_METHOD_SSHA;
+        }
+
+        if ( HASH_METHOD_MD5.name.equalsIgnoreCase( algorithm )
+            || HASH_METHOD_MD5.prefix.equalsIgnoreCase( algorithm ) )
+        {
+            return HASH_METHOD_MD5;
+        }
+
+        if ( HASH_METHOD_SMD5.name.equalsIgnoreCase( algorithm )
+            || HASH_METHOD_SMD5.prefix.equalsIgnoreCase( algorithm ) )
+        {
+            return HASH_METHOD_SMD5;
+        }
+
+        if ( HASH_METHOD_CRYPT.name.equalsIgnoreCase( algorithm )
+            || HASH_METHOD_CRYPT.prefix.equalsIgnoreCase( algorithm ) )
+        {
+            return HASH_METHOD_CRYPT;
+        }
+
+        if ( ( HASH_METHOD_SHA256.name.equalsIgnoreCase( algorithm ) )
+            || ( HASH_METHOD_SHA256.prefix.equalsIgnoreCase( algorithm ) )
+            // "sha-256" used for backwards compatibility
+            || ( "sha-256".equalsIgnoreCase( algorithm ) ) )
+        {
+            return HASH_METHOD_SHA256;
+        }
+
+        if ( ( HASH_METHOD_SSHA256.name.equalsIgnoreCase( algorithm ) )
+            || ( HASH_METHOD_SSHA256.prefix.equalsIgnoreCase( algorithm ) )
+            // "ssha-256" used for backwards compatibility
+            || ( "ssha-256".equalsIgnoreCase( algorithm ) ) )
+        {
+            return HASH_METHOD_SSHA256;
+        }
+
+        if ( ( HASH_METHOD_SHA384.name.equalsIgnoreCase( algorithm ) )
+            || ( HASH_METHOD_SHA384.prefix.equalsIgnoreCase( algorithm ) )
+            // "sha-384" used for backwards compatibility
+            || ( "sha-384".equalsIgnoreCase( algorithm ) ) )
+        {
+            return HASH_METHOD_SHA384;
+        }
+
+        if ( ( HASH_METHOD_SSHA384.name.equalsIgnoreCase( algorithm ) )
+            || ( HASH_METHOD_SSHA384.prefix.equalsIgnoreCase( algorithm ) )
+            // "ssha-384" used for backwards compatibility
+            || ( "ssha-384".equalsIgnoreCase( algorithm ) ) )
+        {
+            return HASH_METHOD_SSHA384;
+        }
+
+        if ( ( HASH_METHOD_SHA512.name.equalsIgnoreCase( algorithm ) )
+            || ( HASH_METHOD_SHA512.prefix.equalsIgnoreCase( algorithm ) )
+            // "sha-512" used for backwards compatibility
+            || ( "sha-512".equalsIgnoreCase( algorithm ) ) )
+        {
+            return HASH_METHOD_SHA512;
+        }
+
+        if ( ( HASH_METHOD_SSHA512.name.equalsIgnoreCase( algorithm ) )
+            || ( HASH_METHOD_SSHA512.prefix.equalsIgnoreCase( algorithm ) )
+            // "ssha-512" used for backwards compatibility
+            || ( "ssha-512".equalsIgnoreCase( algorithm ) ) )
+        {
+            return HASH_METHOD_SSHA512;
+        }
+
+        if ( HASH_METHOD_PKCS5S2.name.equalsIgnoreCase( algorithm )
+            || HASH_METHOD_PKCS5S2.prefix.equalsIgnoreCase( algorithm ) )
+        {
+            return HASH_METHOD_PKCS5S2;
+        }
+
+        /*
+        if ( ENC_METHOD_AES.name.equalsIgnoreCase( algorithm ) )
+        {
+            return ENC_METHOD_AES;
+        }
+
+        if ( ENC_METHOD_3DES.name.equalsIgnoreCase( algorithm ) )
+        {
+            return ENC_METHOD_3DES;
+        }
+
+        if ( ENC_METHOD_BLOWFISH.name.equalsIgnoreCase( algorithm ) )
+        {
+            return ENC_METHOD_BLOWFISH;
+        }
+
+        if ( ENC_METHOD_RC4.name.equalsIgnoreCase( algorithm ) )
+        {
+            return ENC_METHOD_RC4;
+        }
+        */
+
+        return null;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/Loggers.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/Loggers.java
new file mode 100644
index 0000000..f70649c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/Loggers.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * An enum defining a list of dedicated loggers, used for debugging
+ * purpose :
+ * <ul>
+ * <li>ACI_LOG : Logs on teh ACI processing</li>
+ * <li>CONSUMER_LOG : Logs on the replication consummer</li>
+ * <li>CURSOR_LOG : Logs on search cursors</li>
+ * <li>PROVIDER_LOG : Logs on the replication provider</li>
+ * <li>OPERATION_STAT : Logs on the operations statistics</li>
+ * <li>OPERATION_TIME : Logs on the time it takes to process an operation</li>
+ * <li>KERBEROS_LOG : Logs on Kerberos</li>
+ * <li>CODEC_LOG : Logs on encoder/decoder</li>
+ * <li>OPERATIONS_LOG: Logs on LDAP operations</li>
+ * </ul>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum Loggers
+{
+    /** The dedicated logger for ACIs */
+    ACI_LOG("org.apache.directory.server.ACI_LOG"),
+
+    /** The dedicated logs for the replication consumer */
+    CONSUMER_LOG("org.apache.directory.server.CONSUMER_LOG"),
+
+    /** The dedicated logs for the cursors */
+    CURSOR_LOG("org.apache.directory.CURSOR_LOG"),
+
+    /** The dedicated logs for the replication provider */
+    PROVIDER_LOG("org.apache.directory.server.PROVIDER_LOG"),
+
+    /** The dedicated logs for operation statistics */
+    OPERATION_STAT("org.apache.directory.server.OPERATION_STAT"),
+
+    /** The dedicated logs for operation execution time */
+    OPERATION_TIME("org.apache.directory.server.OPERATION_TIME"),
+
+    /** The dedicated logger for KERBEROS */
+    KERBEROS_LOG("org.apache.directory.server.KERBEROS_LOG"),
+
+    /** The dedicated logger for LDAP operations */
+    OPERATION_LOG("org.apache.directory.server.OPERATION_LOG"),
+
+    /** The dedicated logger for CODEC */
+    CODEC_LOG("org.apache.directory.api.CODEC_LOG");
+
+    /** The associated name */
+    private String name;
+
+
+    /**
+     * Creates a new instance of LdapSecurityConstants.
+     * @param name the associated name
+     */
+    private Loggers( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * @return the name associated with the constant.
+     */
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/MetaSchemaConstants.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/MetaSchemaConstants.java
new file mode 100644
index 0000000..d2d37bb
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/MetaSchemaConstants.java
@@ -0,0 +1,185 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * Apache meta schema specific constants used throughout the server.
+ * Final reference -> class shouldn't be extended
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+//This will suppress PMD.AvoidUsingHardCodedIP warnings in this class
+public final class MetaSchemaConstants
+{
+    /**
+     *  Ensures no construction of this class, also ensures there is no need for final keyword above
+     *  (Implicit super constructor is not visible for default constructor),
+     *  but is still self documenting.
+     */
+    private MetaSchemaConstants()
+    {
+    }
+
+    public static final String SCHEMA_NAME = "apachemeta";
+    public static final String SCHEMA_OTHER = "other";
+
+    // -- objectClass names --
+    public static final String META_TOP_OC = "metaTop";
+    public static final String META_TOP_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.1";
+
+    public static final String META_OBJECT_CLASS_OC = "metaObjectClass";
+    public static final String META_OBJECT_CLASS_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.2";
+
+    public static final String META_ATTRIBUTE_TYPE_OC = "metaAttributeType";
+    public static final String META_ATTRIBUTE_TYPE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.3";
+
+    public static final String META_SYNTAX_OC = "metaSyntax";
+    public static final String META_SYNTAX_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.4";
+
+    public static final String META_MATCHING_RULE_OC = "metaMatchingRule";
+    public static final String META_MATCHING_RULE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.5";
+
+    public static final String META_DIT_STRUCTURE_RULE_OC = "metaDITStructureRule";
+    public static final String META_DIT_STRUCTURE_RULE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.6";
+
+    public static final String META_NAME_FORM_OC = "metaNameForm";
+    public static final String META_NAME_FORM_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.7";
+
+    public static final String META_MATCHING_RULE_USE_OC = "metaMatchingRuleUse";
+    public static final String META_MATCHING_RULE_USE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.8";
+
+    public static final String META_DIT_CONTENT_RULE_OC = "metaDITContentRule";
+    public static final String META_DIT_CONTENT_RULE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.9";
+
+    public static final String META_SYNTAX_CHECKER_OC = "metaSyntaxChecker";
+    public static final String META_SYNTAX_CHECKER_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.10";
+
+    public static final String META_SCHEMA_OC = "metaSchema";
+    public static final String META_SCHEMA_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.11";
+
+    public static final String META_NORMALIZER_OC = "metaNormalizer";
+    public static final String META_NORMALIZER_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.12";
+
+    public static final String META_COMPARATOR_OC = "metaComparator";
+    public static final String META_COMPARATOR_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.13";
+
+    // -- attributeType names --
+    public static final String M_OID_AT = "m-oid";
+    public static final String M_OID_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.1 ";
+
+    public static final String M_NAME_AT = "m-name";
+    public static final String M_NAME_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.2 ";
+
+    public static final String M_DESCRIPTION_AT = "m-description";
+    public static final String M_DESCRIPTION_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.3 ";
+
+    public static final String M_OBSOLETE_AT = "m-obsolete";
+    public static final String M_OBSOLETE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.4 ";
+
+    public static final String M_SUP_OBJECT_CLASS_AT = "m-supObjectClass";
+    public static final String M_SUP_OBJECT_CLASS_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.5 ";
+
+    public static final String M_MUST_AT = "m-must";
+    public static final String M_MUST_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.6 ";
+
+    public static final String M_MAY_AT = "m-may";
+    public static final String M_MAY_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.7 ";
+
+    public static final String M_TYPE_OBJECT_CLASS_AT = "m-typeObjectClass";
+    public static final String M_TYPE_OBJECT_CLASS_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.8 ";
+
+    public static final String M_SUP_ATTRIBUTE_TYPE_AT = "m-supAttributeType";
+    public static final String M_SUP_ATTRIBUTE_TYPE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.10";
+
+    public static final String M_EQUALITY_AT = "m-equality";
+    public static final String M_EQUALITY_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.11";
+
+    public static final String M_ORDERING_AT = "m-ordering";
+    public static final String M_ORDERING_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.12";
+
+    public static final String M_SUBSTR_AT = "m-substr";
+    public static final String M_SUBSTR_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.13";
+
+    public static final String M_SYNTAX_AT = "m-syntax";
+    public static final String M_SYNTAX_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.14";
+
+    public static final String M_SINGLE_VALUE_AT = "m-singleValue";
+    public static final String M_SINGLE_VALUE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.15";
+
+    public static final String M_COLLECTIVE_AT = "m-collective";
+    public static final String M_COLLECTIVE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.16";
+
+    public static final String M_NO_USER_MODIFICATION_AT = "m-noUserModification";
+    public static final String M_NO_USER_MODIFICATION_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.17";
+
+    public static final String M_USAGE_AT = "m-usage";
+    public static final String M_USAGE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.18";
+
+    public static final String M_RULE_ID_AT = "m-ruleId";
+    public static final String M_RULE_ID_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.20";
+
+    public static final String M_FORM_AT = "m-form";
+    public static final String M_FORM_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.21";
+
+    public static final String M_SUP_DIT_STRUCTURE_RULE_AT = "m-supDITStructureRule";
+    public static final String M_SUP_DIT_STRUCTURE_RULE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.22";
+
+    public static final String M_OC_AT = "m-oc";
+    public static final String M_OC_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.24";
+
+    public static final String M_AUX_AT = "m-aux";
+    public static final String M_AUX_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.26";
+
+    public static final String M_NOT_AT = "m-not";
+    public static final String M_NOT_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.27";
+
+    public static final String M_APPLIES_AT = "m-applies";
+    public static final String M_APPLIES_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.29";
+
+    public static final String M_MATCHING_RULE_SYNTAX_AT = "m-matchingRuleSyntax";
+    public static final String M_MATCHING_RULE_SYNTAX_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.31";
+
+    public static final String M_FQCN_AT = "m-fqcn";
+    public static final String M_FQCN_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.32";
+
+    public static final String M_BYTECODE_AT = "m-bytecode";
+    public static final String M_BYTECODE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.33";
+
+    public static final String M_DISABLED_AT = "m-disabled";
+    public static final String M_DISABLED_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.37";
+
+    public static final String M_DEPENDENCIES_AT = "m-dependencies";
+    public static final String M_DEPENDENCIES_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.38";
+
+    public static final String M_LENGTH_AT = "m-length";
+    public static final String M_LENGTH_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.39";
+
+    // -- schema extensions & values --
+    public static final String X_SCHEMA_AT = "X-SCHEMA";
+    public static final String X_SCHEMA_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.35";
+
+    public static final String X_NOT_HUMAN_READABLE_AT = "X-NOT-HUMAN-READABLE";
+    public static final String X_NOT_HUMAN_READABLE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.34";
+
+    // The x-read-only extension
+    public static final String X_READ_ONLY_AT = "X-READ-ONLY";
+    public static final String X_READ_ONLY_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.36";
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/PasswordPolicySchemaConstants.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/PasswordPolicySchemaConstants.java
new file mode 100644
index 0000000..92076de
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/PasswordPolicySchemaConstants.java
@@ -0,0 +1,166 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * The PasswordPolicy schema ObjectClasses and AttributeTypes.
+ * Final reference -> class shouldn't be extended
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PasswordPolicySchemaConstants
+{
+    /**
+     *  Ensures no construction of this class, also ensures there is no need for final keyword above
+     *  (Implicit super constructor is not visible for default constructor),
+     *  but is still self documenting.
+     */
+    private PasswordPolicySchemaConstants()
+    {
+    }
+
+    // ---- ObjectClasses -----------------------------------------------------
+    // pwdPolicy
+    public static final String PWD_POLICY_OC = "pwdPolicy";
+    public static final String PWD_POLICY_OC_OID = "1.3.6.1.4.1.42.2.27.8.2.1";
+
+    // ---- AttributeTypes ----------------------------------------------------
+    // pwdAttribute
+    public static final String PWD_ATTRIBUTE_AT = "pwdAttribute";
+    public static final String PWD_ATTRIBUTE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.1";
+
+    // pwdMinAge
+    public static final String PWD_MIN_AGE_AT = "pwdMinAge";
+    public static final String PWD_MIN_AGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.2";
+
+    // pwdMaxAge
+    public static final String PWD_MAX_AGE_AT = "pwdMaxAge";
+    public static final String PWD_MAX_AGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.3";
+
+    // pwdLockoutDuration
+    public static final String PWD_LOCKOUT_DURATION_AT = "pwdLockoutDuration";
+    public static final String PWD_LOCKOUT_DURATION_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.10";
+
+    // pwdInHistory
+    public static final String PWD_IN_HISTORY_AT = "pwdInHistory";
+    public static final String PWD_IN_HISTORY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.4";
+
+    // pwdCheckQuality
+    public static final String PWD_CHECK_QUALITY_AT = "pwdCheckQuality";
+    public static final String PWD_CHECK_QUALITY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.5";
+
+    // pwdMinLength
+    public static final String PWD_MIN_LENGTH_AT = "pwdMinLength";
+    public static final String PWD_MIN_LENGTH_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.6;";
+
+    // pwdExpireWarning
+    public static final String PWD_EXPIRE_WARNING_AT = "pwdExpireWarning";
+    public static final String PWD_EXPIRE_WARNING_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.7;";
+
+    // pwdGraceAuthNLimit
+    public static final String PWD_GRACE_AUTHN_LIMIT_AT = "pwdGraceAuthNLimit";
+    public static final String PWD_GRACE_AUTHN_LIMIT_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.;";
+
+    // pwdLockout
+    public static final String PWD_LOCKOUT_AT = "pwdLockout";
+    public static final String PWD_LOCKOUT_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.9";
+
+    // pwdMaxFailure
+    public static final String PWD_MAX_FAILURE_AT = "pwdMaxFailure";
+    public static final String PWD_MAX_FAILURE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.11";
+
+    // pwdFailureCountInterval
+    public static final String PWD_FAILURE_COUNT_INTERVAL_AT = "pwdFailureCountInterval";
+    public static final String PWD_FAILURE_COUNT_INTERVAL_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.12";
+
+    // public static final String PWD_MUST_CHANGE_AT = 
+    public static final String PWD_MUST_CHANGE_AT = "pwdMustChange";
+    public static final String PWD_MUST_CHANGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.13";
+
+    // pwdAllowUserChange
+    public static final String PWD_ALLOW_USER_CHANGE_AT = "pwdAllowUserChange";
+    public static final String PWD_ALLOW_USER_CHANGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.14";
+
+    // pwdSafeModify
+    public static final String PWD_SAFE_MODIFY_AT = "pwdSafeModify";
+    public static final String PWD_SAFE_MODIFY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.15";
+
+    // pwdChangedTime
+    public static final String PWD_CHANGED_TIME_AT = "pwdChangedTime";
+    public static final String PWD_CHANGED_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.16";
+
+    // pwdAccountLockedTime
+    public static final String PWD_ACCOUNT_LOCKED_TIME_AT = "pwdAccountLockedTime";
+    public static final String PWD_ACCOUNT_LOCKED_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.17";
+
+    // pwdFailureTime
+    public static final String PWD_FAILURE_TIME_AT = "pwdFailureTime";
+    public static final String PWD_FAILURE_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.19";
+
+    // pwdHistory
+    public static final String PWD_HISTORY_AT = "pwdHistory";
+    public static final String PWD_HISTORY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.20";
+
+    // pwdGraceUseTime
+    public static final String PWD_GRACE_USE_TIME_AT = "pwdGraceUseTime";
+    public static final String PWD_GRACE_USE_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.21";
+
+    // pwdReset
+    public static final String PWD_RESET_AT = "pwdReset";
+    public static final String PWD_RESET_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.22";
+
+    // pwdPolicySubentry
+    public static final String PWD_POLICY_SUBENTRY_AT = "pwdPolicySubentry";
+    public static final String PWD_POLICY_SUBENTRY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.23";
+
+    // pwdMinDelay
+    public static final String PWD_MIN_DELAY_AT = "pwdMinDelay";
+    public static final String PWD_MIN_DELAY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.24";
+
+    // pwdMaxDelay
+    public static final String PWD_MAX_DELAY_AT = "pwdMaxDelay";
+    public static final String PWD_MAX_DELAY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.25";
+
+    // pwdMaxIdle
+    public static final String PWD_MAX_IDLE_AT = "pwdMaxIdle";
+    public static final String PWD_MAX_IDLE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.26";
+
+    // pwdStartTime
+    public static final String PWD_START_TIME_AT = "pwdStartTime";
+    public static final String PWD_START_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.27";
+
+    // pwdEndTime
+    public static final String PWD_END_TIME_AT = "pwdEndTime";
+    public static final String PWD_END_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.28";
+
+    // pwdLastSuccess
+    public static final String PWD_LAST_SUCCESS_AT = "pwdLastSuccess";
+    public static final String PWD_LAST_SUCCESS_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.29";
+
+    // pwdGraceExpire
+    public static final String PWD_GRACE_EXPIRE_AT = "pwdGraceExpire";
+    public static final String PWD_GRACE_EXPIRE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.30";
+
+    // pwdMaxLength
+    public static final String PWD_MAX_LENGTH_AT = "pwdMaxLength";
+    public static final String PWD_MAX_LENGTH_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.31";
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SaslQoP.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SaslQoP.java
new file mode 100644
index 0000000..b5e8ebe
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SaslQoP.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * This enums contains values for SASL QoP (Quality of Protection).
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SaslQoP
+{
+    /** Authentication only */
+    AUTH("auth"),
+
+    /** Authentication with integrity protection */
+    AUTH_INT("auth-int"),
+
+    /** Authentication with integrity and privacy protection */
+    AUTH_CONF("auth-conf");
+
+    /** The equivalent string value */
+    private String value;
+
+
+    /**
+     * Creates a new instance of SaslQoP.
+     *
+     * @param value the equivalent string value
+     */
+    private SaslQoP( String value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * Gets the equivalent string value.
+     *
+     * @return the equivalent string value
+     */
+    public String getValue()
+    {
+        return value;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SaslSecurityStrength.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SaslSecurityStrength.java
new file mode 100644
index 0000000..a8fe4a5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SaslSecurityStrength.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * This enums contains values for SASL Security Strength.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SaslSecurityStrength
+{
+    /** Low SASL Security Strength */
+    LOW("low"),
+
+    /** Medium SASL Security Strength */
+    MEDIUM("medium"),
+
+    /** High SASL Security Strength */
+    HIGH("high");
+
+    /** The equivalent string value */
+    private String value;
+
+
+    /**
+     * Creates a new instance of SaslSecurityStrength.
+     *
+     * @param value
+     *      the equivalent string value
+     */
+    private SaslSecurityStrength( String value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * Gets the equivalent string value.
+     *
+     * @return the equivalent string value
+     */
+    public String getValue()
+    {
+        return value;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SchemaConstants.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SchemaConstants.java
new file mode 100644
index 0000000..2fc0309
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SchemaConstants.java
@@ -0,0 +1,2236 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * A utility class where we declare all the schema objects being used by any
+ * ldap server.
+ * Final reference -> class shouldn't be extended
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SchemaConstants
+{
+    /**
+     *  Ensures no construction of this class, also ensures there is no need for final keyword above
+     *  (Implicit super constructor is not visible for default constructor),
+     *  but is still self documenting.
+     */
+    private SchemaConstants()
+    {
+    }
+
+    // SchemaEntity names
+    public static final String ATTRIBUTE_TYPE = "AttributeType";
+    public static final String COMPARATOR = "Comparator";
+    public static final String DIT_CONTENT_RULE = "DitContentRule";
+    public static final String DIT_STRUCTURE_RULE = "DitStructureRule";
+    public static final String MATCHING_RULE = "MatchingRule";
+    public static final String MATCHING_RULE_USE = "MatchingRuleUse";
+    public static final String NAME_FORM = "NameForm";
+    public static final String NORMALIZER = "Normalizer";
+    public static final String OBJECT_CLASS = "ObjectCLass";
+    public static final String SYNTAX = "Syntax";
+    public static final String SYNTAX_CHECKER = "SyntaxChecker";
+
+    // SchemaEntity paths
+    public static final String ATTRIBUTE_TYPES_PATH = "ou=attributetypes";
+    public static final String COMPARATORS_PATH = "ou=comparators";
+    public static final String DIT_CONTENT_RULES_PATH = "ou=ditcontentrules";
+    public static final String DIT_STRUCTURE_RULES_PATH = "ou=ditstructurerules";
+    public static final String MATCHING_RULES_PATH = "ou=matchingrules";
+    public static final String MATCHING_RULE_USE_PATH = "ou=matchingruleuse";
+    public static final String NAME_FORMS_PATH = "ou=nameforms";
+    public static final String NORMALIZERS_PATH = "ou=normalizers";
+    public static final String OBJECT_CLASSES_PATH = "ou=objectclasses";
+    public static final String SYNTAXES_PATH = "ou=syntaxes";
+    public static final String SYNTAX_CHECKERS_PATH = "ou=syntaxcheckers";
+
+    // Schema root
+    public static final String OU_SCHEMA = "ou=schema";
+
+    // The Dn for the schema modifications
+    public static final String SCHEMA_MODIFICATIONS_DN = "ou=schemaModifications,ou=schema";
+
+    // Special attributes 1.1 , * and + for search operations
+    public static final String NO_ATTRIBUTE = "1.1";
+    public static final String[] NO_ATTRIBUTE_ARRAY = new String[]
+        { NO_ATTRIBUTE };
+
+    public static final String ALL_USER_ATTRIBUTES = "*";
+    public static final String[] ALL_USER_ATTRIBUTES_ARRAY = new String[]
+        { ALL_USER_ATTRIBUTES };
+
+    public static final String ALL_OPERATIONAL_ATTRIBUTES = "+";
+    public static final String[] ALL_OPERATIONAL_ATTRIBUTES_ARRAY = new String[]
+        { ALL_OPERATIONAL_ATTRIBUTES };
+
+    public static final String[] ALL_ATTRIBUTES_ARRAY = new String[]
+        { ALL_OPERATIONAL_ATTRIBUTES, ALL_USER_ATTRIBUTES };
+
+    // ---- ObjectClasses -----------------------------------------------------
+    // We list here all the ObjectClasses from schemas :
+    // o apachemeta
+    // o autofs
+    // o core
+    // o corba
+    // o cosine
+    // o inetorgperson
+    // o nis
+    // o pwdpolicy
+    // o system
+    //
+    // The collectiveAttribute schema has no ObjectClass.
+    // 
+    // We don't list here the complete list of ObjectClasses for the following
+    // schemas :
+    // o adsconfig
+    // o apache
+    // o apachedns
+    // o dhcp
+    // o java
+    // o krb5kdc
+    // o mozilla
+    // o samba
+    //-------------------------------------------------------------------------
+    // o apachemeta
+    //-------------------------------------------------------------------------
+    // MetaTop
+    public static final String META_TOP_OC = "metaTop";
+    public static final String META_TOP_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.1";
+
+    // MetaObjectClass
+    public static final String META_OBJECT_CLASS_OC = "metaObjectClass";
+    public static final String META_OBJECT_CLASS_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.2";
+
+    // MetaAttributeType
+    public static final String META_ATTRIBUTE_TYPE_OC = "metaAttributeType";
+    public static final String META_ATTRIBUTE_TYPE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.3";
+
+    // MetaSyntax
+    public static final String META_SYNTAX_OC = "metaSyntax";
+    public static final String META_SYNTAX_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.4";
+
+    // MetaMatchingRule
+    public static final String META_MATCHING_RULE_OC = "metaMatchingRule";
+    public static final String META_MATCHING_RULE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.5";
+
+    // MetaDITStructureRule
+    public static final String META_DIT_STRUCTURE_RULE_OC = "metaDITStructureRule";
+    public static final String META_DIT_STRUCTURE_RULE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.6";
+
+    // MetaNameForm
+    public static final String META_NAME_FORM_OC = "metaNameForm";
+    public static final String META_NAME_FORM_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.7";
+
+    // MetaMatchingRuleUse
+    public static final String META_MATCHING_RULE_USE_OC = "metaMatchingRuleUse";
+    public static final String META_MATCHING_RULE_USE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.8";
+
+    // MetaDITContentRule
+    public static final String META_DIT_CONTENT_RULE_OC = "metaDITContentRule";
+    public static final String META_DIT_CONTENT_RULE_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.9";
+
+    // MetaSyntaxChecker
+    public static final String META_SYNTAX_CHECKER_OC = "metaSyntaxChecker";
+    public static final String META_SYNTAX_CHECKER_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.10";
+
+    // MetaSchema
+    public static final String META_SCHEMA_OC = "metaSchema";
+    public static final String META_SCHEMA_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.11";
+
+    // MetaNormalizer
+    public static final String META_NORMALIZER_OC = "metaNormalizer";
+    public static final String META_NORMALIZER_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.12";
+
+    // MetaComparator
+    public static final String META_COMPARATOR_OC = "metaComparator";
+    public static final String META_COMPARATOR_OC_OID = "1.3.6.1.4.1.18060.0.4.0.3.13";
+
+    //-------------------------------------------------------------------------
+    // autofs
+    //-------------------------------------------------------------------------
+    // AutomountMap
+    public static final String AUTOMOUNT_MAP_OC = "automountMap";
+    public static final String AUTOMOUNT_MAP_OC_OID = "1.3.6.1.4.1.2312.4.2.2";
+
+    // Automount
+    public static final String AUTOMOUNT_OC = "automount";
+    public static final String AUTOMOUNT_OC_OID = "1.3.6.1.4.1.2312.4.2.3";
+
+    //-------------------------------------------------------------------------
+    // corba
+    //-------------------------------------------------------------------------
+    // CorbaObject
+    public static final String CORBA_OBJECT_OC = "corbaObject";
+    public static final String CORBA_OBJECT_OC_OID = "1.3.6.1.4.1.42.2.27.4.2.9";
+
+    // CorbaContainer
+    public static final String CORBA_CONTAINER_OC = "corbaContainer";
+    public static final String CORBA_CONTAINER_OC_OID = "1.3.6.1.4.1.42.2.27.4.2.10";
+
+    // CorbaReference
+    public static final String CORBA_REFERENCE_OC = "corbaReference";
+    public static final String CORBA_REFERENCE_OC_OID = "1.3.6.1.4.1.42.2.27.4.2.11";
+
+    //-------------------------------------------------------------------------
+    // core
+    //-------------------------------------------------------------------------
+    // SimpleSecurityObject
+    public static final String SIMPLE_SECURITY_OBJECT_OC = "simpleSecurityObject";
+    public static final String SIMPLE_SECURITY_OBJECT_OC_OID = "0.9.2342.19200300.100.4.19";
+
+    // UidObject
+    public static final String UID_OBJECT_OC = "uidObject";
+    public static final String UID_OBJECT_OC_OID = "1.3.6.1.1.3.1";
+
+    // LabeledURIObject
+    public static final String LABELED_URI_OBJECT_OC = "labeledURIObject";
+    public static final String LABELED_URI_OBJECT_OC_OID = "1.3.6.1.4.1.250.3.15";
+
+    // DcObject
+    public static final String DC_OBJECT_OC = "dcObject";
+    public static final String DC_OBJECT_OC_OID = "1.3.6.1.4.1.1466.344";
+
+    // Country
+    public static final String COUNTRY_OC = "country";
+    public static final String COUNTRY_OC_OID = "2.5.6.2";
+
+    // Locality
+    public static final String LOCALITY_OC = "locality";
+    public static final String LOCALITY_OC_OID = "2.5.6.3";
+
+    // Organization
+    public static final String ORGANIZATION_OC = "organization";
+    public static final String ORGANIZATION_OC_OID = "2.5.6.4";
+
+    // OrganizationalUnit
+    public static final String ORGANIZATIONAL_UNIT_OC = "organizationalUnit";
+    public static final String ORGANIZATIONAL_UNIT_OC_OID = "2.5.6.5";
+
+    // Person
+    public static final String PERSON_OC = "person";
+    public static final String PERSON_OC_OID = "2.5.6.6";
+
+    // OrganizationalPerson
+    public static final String ORGANIZATIONAL_PERSON_OC = "organizationalPerson";
+    public static final String ORGANIZATIONAL_PERSON_OC_OID = "2.5.6.7";
+
+    // OrganizationalRole
+    public static final String ORGANIZATIONAL_ROLE_OC = "organizationalRole";
+    public static final String ORGANIZATIONAL_ROLE_OC_OID = "2.5.6.8";
+
+    // GroupOfNames
+    public static final String GROUP_OF_NAMES_OC = "groupOfNames";
+    public static final String GROUP_OF_NAMES_OC_OID = "2.5.6.9";
+
+    // ResidentialPerson
+    public static final String RESIDENTIAL_PERSON_OC = "residentialPerson";
+    public static final String RESIDENTIAL_PERSON_OC_OID = "2.5.6.10";
+
+    // ApplicationProcess
+    public static final String APPLICATION_PROCESS_OC = "applicationProcess";
+    public static final String APPLICATION_PROCESS_OC_OID = "2.5.6.11";
+
+    // ApplicationEntity
+    public static final String APPLICATION_ENTITY_OC = "applicationEntity";
+    public static final String APPLICATION_ENTITY_OC_OID = "2.5.6.12";
+
+    // DSA
+    public static final String DSA_OC = "dSA";
+    public static final String DSA_OC_OID = "2.5.6.13";
+
+    // Device
+    public static final String DEVICE_OC = "device";
+    public static final String DEVICE_OC_OID = "2.5.6.14";
+
+    // StrongAuthenticationUser
+    public static final String STRONG_AUTHENTICATION_USER_OC = "strongAuthenticationUser";
+    public static final String STRONG_AUTHENTICATION_USER_OC_OID = "2.5.6.15";
+
+    // CertificationAuthority
+    public static final String CERTIFICATION_AUTHORITY_OC = "certificationAuthority";
+    public static final String CERTIFICATION_AUTHORITY_OC_OID = "2.5.6.16";
+
+    // CertificationAuthority-V2
+    public static final String CERTIFICATION_AUTHORITY_V2_OC = "certificationAuthority-V2";
+    public static final String CERTIFICATION_AUTHORITY_V2_OC_OID = "2.5.6.16.2";
+
+    // GroupOfUniqueNames
+    public static final String GROUP_OF_UNIQUE_NAMES_OC = "groupOfUniqueNames";
+    public static final String GROUP_OF_UNIQUE_NAMES_OC_OID = "2.5.6.17";
+
+    // UserSecurityInformation
+    public static final String USER_SECURITY_INFORMATION_OC = "userSecurityInformation";
+    public static final String USER_SECURITY_INFORMATION_OC_OID = "2.5.6.18";
+
+    // CRLDistributionPoint
+    public static final String CRL_DISTRIBUTION_POINT_OC = "cRLDistributionPoint";
+    public static final String CRL_DISTRIBUTION_POINT_OC_OID = "2.5.6.19";
+
+    // Dmd
+    public static final String DMD_OC = "dmd";
+    public static final String DMD_OC_OID = "2.5.6.20";
+
+    // PkiUser
+    public static final String PKI_USER_OC = "pkiUser";
+    public static final String PKI_USER_OC_OID = "2.5.6.21";
+
+    // PkiCA
+    public static final String PKI_CA_OC = "pkiCA";
+    public static final String PKI_CA_OC_OID = "2.5.6.22";
+
+    // DeltaCRL
+    public static final String DELTA_CRL_OC = "deltaCRL";
+    public static final String DELTA_CRL_OC_OID = "2.5.6.23";
+
+    //-------------------------------------------------------------------------
+    // cosine
+    //-------------------------------------------------------------------------
+    // PilotPerson
+    public static final String PILOT_PERSON_OC = "pilotPerson";
+    public static final String NEW_PILOT_PERSON_OC = "newPilotPerson";
+    public static final String PILOT_PERSON_OC_OID = "0.9.2342.19200300.100.4.4";
+
+    // Account
+    public static final String ACCOUNT_OC = "account";
+    public static final String ACCOUNT_OC_OID = "0.9.2342.19200300.100.4.5";
+
+    // Document
+    public static final String DOCUMENT_OC = "document";
+    public static final String DOCUMENT_OC_OID = "0.9.2342.19200300.100.4.6";
+
+    // Room
+    public static final String ROOM_OC = "room";
+    public static final String ROOM_OC_OID = "0.9.2342.19200300.100.4.7";
+
+    // DocumentSeries
+    public static final String DOCUMENT_SERIES_OC = "documentSeries";
+    public static final String DOCUMENT_SERIES_OC_OID = "0.9.2342.19200300.100.4.9";
+
+    // Domain
+    public static final String DOMAIN_OC = "domain";
+    public static final String DOMAIN_OC_OID = "0.9.2342.19200300.100.4.13";
+
+    // RFC822LocalPart
+    public static final String RFC822_LOCAL_PART_OC = "RFC822LocalPart";
+    public static final String RFC822_LOCAL_PART_OC_OID = "0.9.2342.19200300.100.4.14";
+
+    // DNSDomain
+    public static final String DNS_DOMAIN_OC = "dNSdomain";
+    public static final String DNS_DOMAIN_OC_OID = "0.9.2342.19200300.100.4.15";
+
+    // DomainRelatedObject
+    public static final String DOMAIN_RELATED_OBJECT_OC = "domainRelatedObject";
+    public static final String DOMAIN_RELATED_OBJECT_OC_OID = "0.9.2342.19200300.100.4.17";
+
+    // FriendlyCountry
+    public static final String FRIENDLY_COUNTRY_OC = "friendlyCountry";
+    public static final String FRIENDLY_COUNTRY_OC_OID = "0.9.2342.19200300.100.4.18";
+
+    // PilotOrganization
+    public static final String PILOT_ORGANIZATION_OC = "pilotOrganization";
+    public static final String PILOT_ORGANIZATION_OC_OID = "0.9.2342.19200300.100.4.20";
+
+    // PilotDSA
+    public static final String PILOT_DSA_OC = "pilotDSA";
+    public static final String PILOT_DSA_OC_OID = "0.9.2342.19200300.100.4.21";
+
+    // QualityLabelledData
+    public static final String QUALITY_LABELLED_DATA_OC = "qualityLabelledData";
+    public static final String QUALITY_LABELLED_DATA_OC_OID = "0.9.2342.19200300.100.4.22";
+
+    //-------------------------------------------------------------------------
+    // inetorgperson
+    //-------------------------------------------------------------------------
+    // InetOrgPerson
+    public static final String INET_ORG_PERSON_OC = "inetOrgPerson";
+    public static final String INET_ORG_PERSON_OC_OID = "2.16.840.1.113730.3.2.2";
+
+    //-------------------------------------------------------------------------
+    // nis
+    //-------------------------------------------------------------------------
+    // PosixAccount
+    public static final String POSIX_ACCOUNT_OC = "posicAccount";
+    public static final String POSIX_ACCOUNT_OC_OID = "1.3.6.1.1.1.2.0";
+
+    // ShadowAccount
+    public static final String SHADOW_ACCOUNT_OC = "shadowAccount";
+    public static final String SHADOW_ACCOUNT_OC_OID = "1.3.6.1.1.1.2.1";
+
+    // PosixGroup
+    public static final String POSIX_GROUP_OC = "posixGroup";
+    public static final String POSIX_GROUP_OC_OID = "1.3.6.1.1.1.2.2";
+
+    // IpService
+    public static final String IP_SERVICE_OC = "ipService";
+    public static final String IP_SERVICE_OC_OID = "1.3.6.1.1.1.2.3";
+
+    // IpProtocol
+    public static final String IP_PROTOCOL_OC = "ipProtocol";
+    public static final String IP_PROTOCOL_OC_OID = "1.3.6.1.1.1.2.4";
+
+    // OncRpc
+    public static final String ONC_RPC_OC = "oncRpc";
+    public static final String ONC_RPC_OC_OID = "1.3.6.1.1.1.2.5";
+
+    // IpHost
+    public static final String IP_HOST_OC = "ipHost";
+    public static final String IP_HOST_OC_OID = "1.3.6.1.1.1.2.6";
+
+    // IpNetwork
+    public static final String IP_NETWORK_OC = "ipNetwork";
+    public static final String IP_NETWORK_OC_OID = "1.3.6.1.1.1.2.7";
+
+    // NisNetgroup
+    public static final String NIS_NETGROUP_OC = "nisNetgroup";
+    public static final String NIS_NETGROUP_OC_OID = "1.3.6.1.1.1.2.8";
+
+    // NisMap
+    public static final String NIS_MAP_OC = "nisMap";
+    public static final String NIS_MAP_OC_OID = "1.3.6.1.1.1.2.9";
+
+    // NisObject
+    public static final String NIS_OBJECT_OC = "nisObject";
+    public static final String NIS_OBJECT_OC_OID = "1.3.6.1.1.1.2.10";
+
+    // Ieee802Device
+    public static final String IEEE_802_DEVICE_OC = "ieee802Device";
+    public static final String IEEE_802_DEVICE_OC_OID = "1.3.6.1.1.1.2.11";
+
+    // BootableDevice
+    public static final String BOOTABLE_DEVICE_OC = "bootableDevice";
+    public static final String BOOTABLE_DEVICE_OC_OID = "1.3.6.1.1.1.2.12";
+
+    //-------------------------------------------------------------------------
+    // pwdpolicy
+    //-------------------------------------------------------------------------
+    // PwdPolicy
+    public static final String PWD_POLICY_OC = "pwdPolicy";
+    public static final String PWD_POLICY_OC_OID = "1.3.6.1.4.1.42.2.27.8.2.1";
+
+    //-------------------------------------------------------------------------
+    // system
+    //-------------------------------------------------------------------------
+    // DynamicObject
+    public static final String DYNAMIC_OBJECT_OC = "dynamicObject";
+    public static final String DYNAMIC_OBJECT_OC_OID = "1.3.6.1.4.1.1466.101.119.2";
+
+    // ExtensibleObject
+    public static final String EXTENSIBLE_OBJECT_OC = "extensibleObject";
+    public static final String EXTENSIBLE_OBJECT_OC_OID = "1.3.6.1.4.1.1466.101.120.111";
+
+    // LDAProotDSE, OpenLDAProotDSE
+    public static final String LDAP_ROOT_DSE_OC = "LDAProotDSE";
+    public static final String OPEN_LDAP_ROOT_DSE_OC = "OpenLDAProotDSE";
+    public static final String LDAP_ROOT_DSE_OC_OID = "1.3.6.1.4.1.4203.1.4.1";
+
+    // Top
+    public static final String TOP_OC = "top";
+    public static final String TOP_OC_OID = "2.5.6.0";
+
+    // Alias
+    public static final String ALIAS_OC = "alias";
+    public static final String ALIAS_OC_OID = "2.5.6.1";
+
+    // Subentry
+    public static final String SUBENTRY_OC = "subentry";
+    public static final String SUBENTRY_OC_OID = "2.5.17.0";
+
+    // CollectiveAttributeSubentry
+    public static final String COLLECTIVE_ATTRIBUTE_SUBENTRY_OC = "collectiveAttributeSubentry";
+    public static final String COLLECTIVE_ATTRIBUTE_SUBENTRY_OC_OID = "2.5.17.2";
+
+    // Subschema
+    public static final String SUBSCHEMA_OC = "subschema";
+    public static final String SUBSCHEMA_OC_OID = "2.5.20.1";
+
+    // Referral
+    public static final String REFERRAL_OC = "referral";
+    public static final String REFERRAL_OC_OID = "2.16.840.1.113730.3.2.6";
+
+    //-------------------------------------------------------------------------
+    // Other schema ObjectClasses
+    //-------------------------------------------------------------------------
+    // Krb5Principal
+    public static final String KRB5_PRINCIPAL_OC = "krb5Principal";
+    public static final String KRB5_PRINCIPAL_OC_OID = "1.3.6.1.4.1.5322.10.2.1";
+
+    // AccessControlSubentry
+    public static final String ACCESS_CONTROL_SUBENTRY_OC = "accessControlSubentry";
+    public static final String ACCESS_CONTROL_SUBENTRY_OC_OID = "2.5.17.1";
+
+    //-------------------------------------------------------------------------
+    // AttributeTypes for standard schemas are listed below. We cover the 
+    // following schemas :
+    // o apachemeta
+    // o autofs
+    // o collective
+    // o corba
+    // o core
+    // o cosine
+    // o inetorgperson
+    // o nis
+    // o passwordpolicy
+    // o system
+    //
+    // We don't cover the following schemas :
+    // o adsconfig
+    // o apache
+    // o apachedns
+    // o dhcp
+    // o java
+    // o krb5kdc
+    // o mozilla
+    // o samba
+    //-------------------------------------------------------------------------
+    // apachemeta AttributeTypes
+    //-------------------------------------------------------------------------
+    // M-oid AT
+    public static final String M_OID_AT = "m-oid";
+    public static final String M_OID_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.1";
+
+    // M-name AT
+    public static final String M_NAME_AT = "m-name";
+    public static final String M_NAME_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.2";
+
+    // M-description AT
+    public static final String M_DESCRIPTION_AT = "m-description";
+    public static final String M_DESCRIPTION_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.3";
+
+    // M-obsolete AT
+    public static final String M_OBSOLETE_AT = "m-obsolete";
+    public static final String M_OBSOLETE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.4";
+
+    // M-supObjectClass AT
+    public static final String M_SUP_OBJECT_CLASS_AT = "m-supObjectClass";
+    public static final String M_SUP_OBJECT_CLASS_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.5";
+
+    // M-must AT
+    public static final String M_MUST_AT = "m-must";
+    public static final String M_MUST_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.6";
+
+    // M-may AT
+    public static final String M_MAY_AT = "m-may";
+    public static final String M_MAY_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.7";
+
+    // M-typeObjectClass AT
+    public static final String M_TYPE_OBJECT_CLASS_AT = "m-typeObjectClass";
+    public static final String M_TYPE_OBJECT_CLASS_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.8";
+
+    // M-supAttributeType AT
+    public static final String M_SUP_ATTRIBUTE_TYPE_AT = "m-supAttributeType";
+    public static final String M_SUP_ATTRIBUTE_TYPE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.10";
+
+    // M-equality AT
+    public static final String M_EQUALITY_AT = "m-equality";
+    public static final String M_EQUALITY_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.11";
+
+    // M-ordering AT
+    public static final String M_ORDERING_AT = "m-ordering";
+    public static final String M_ORDERING_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.12";
+
+    // M-substr AT
+    public static final String M_SUBSTR_AT = "m-substr";
+    public static final String M_SUBSTR_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.13";
+
+    // M-syntax AT
+    public static final String M_SYNTAX_AT = "m-syntax";
+    public static final String M_SYNTAX_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.14";
+
+    // M-singleValue AT
+    public static final String M_SINGLE_VALUE_AT = "m-singleValue";
+    public static final String M_SINGLE_VALUE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.15";
+
+    // M-collective AT
+    public static final String M_COLLECTIVE_AT = "m-collective";
+    public static final String M_COLLECTIVE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.16";
+
+    // M-noUserModification AT
+    public static final String M_NO_USER_MODIFICATION_AT = "m-noUserModification";
+    public static final String M_NO_USER_MODIFICATION_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.17";
+
+    // M-usage AT
+    public static final String M_USAGE_AT = "m-usage";
+    public static final String M_USAGE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.18";
+
+    // M-ruleId AT
+    public static final String M_RULEID_AT = "m-ruleId";
+    public static final String M_RULEID_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.20";
+
+    // M-form AT
+    public static final String M_FORM_AT = "m-form";
+    public static final String M_FORM_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.21";
+
+    // M-supDITStructureRule AT
+    public static final String M_SUP_DIT_STRUCTURE_RULE_AT = "m-supDITStructureRule";
+    public static final String M_SUP_DIT_STRUCTURE_RULE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.22";
+
+    // M-oc AT
+    public static final String M_OC_AT = "m-oc";
+    public static final String M_OC_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.24";
+
+    // M-aux AT
+    public static final String M_AUX_AT = "m-aux";
+    public static final String M_AUX_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.26";
+
+    // M-not AT
+    public static final String M_NOT_AT = "m-not";
+    public static final String M_NOT_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.27";
+
+    // M-applies AT
+    public static final String M_APPLIES_AT = "m-applies";
+    public static final String M_APPLIES_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.29";
+
+    // M-matchingRuleSyntax AT
+    public static final String M_MATCHING_RULE_SYNTAX_AT = "m-matchingRuleSyntax";
+    public static final String M_MATCHING_RULE_SYNTAX_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.31";
+
+    // M-fqcn AT
+    public static final String M_FQCN_AT = "m-fqcn";
+    public static final String M_FQCN_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.32";
+
+    // M-bytecode AT
+    public static final String M_BYTECODE_AT = "m-bytecode";
+    public static final String M_BYTECODE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.33";
+
+    // x-not-human-readable AT
+    public static final String X_NOT_HUMAN_READABLE_AT = "x-not-human-readable";
+    public static final String X_NOT_HUMAN_READABLE_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.34";
+
+    // x-schema AT
+    public static final String X_SCHEMA_AT = "x-schema";
+    public static final String X_SCHEMA_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.35";
+
+    // x-read-only AT
+    public static final String X_READ_ONLY_AT = "x-read-only";
+    public static final String X_READ_ONLY_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.36";
+
+    // M-disabled AT
+    public static final String M_DISABLED_AT = "m-disabled";
+    public static final String M_DISABLED_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.37";
+
+    // M-dependencies AT
+    public static final String M_DEPENDENCIES_AT = "m-dependencies";
+    public static final String M_DEPENDENCIES_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.38";
+
+    // M-length AT
+    public static final String M_LENGTH_AT = "m-length";
+    public static final String M_LENGTH_AT_OID = "1.3.6.1.4.1.18060.0.4.0.2.39";
+
+    //-------------------------------------------------------------------------
+    // autofs AttributeTypes
+    //-------------------------------------------------------------------------
+    // AutomountInformation
+    public static final String AUTOMOUNT_INFORMATION_AT = "automountInformation";
+    public static final String AUTOMOUNT_INFORMATION_AT_OID = "1.3.6.1.4.1.2312.4.1.2";
+
+    //-------------------------------------------------------------------------
+    // collective AttributeTypes
+    //-------------------------------------------------------------------------
+    // C-l
+    public static final String C_L_AT = "c-l";
+    public static final String C_L_AT_OID = "2.5.4.7.1";
+
+    // C-st
+    public static final String C_ST_AT = "c-st";
+    public static final String C_ST_AT_OID = "2.5.4.8.1";
+
+    // C-street
+    public static final String C_STREET_AT = "c-street";
+    public static final String C_STREET_AT_OID = "2.5.4.9.1";
+
+    // C-o
+    public static final String C_O_AT = "c-o";
+    public static final String C_O_AT_OID = "2.5.4.10.1";
+
+    // C-ou
+    public static final String C_OU_AT = "c-ou";
+    public static final String C_OU_AT_OID = "2.5.4.11.1";
+
+    // C-postalAddress
+    public static final String C_POSTAL_ADDRESS_AT = "c-postalAddress";
+    public static final String C_POSTAL_ADDRESS_AT_OID = "2.5.4.16.1";
+
+    // C-postalCode
+    public static final String C_POSTALCODE_AT = "c-postalCode";
+    public static final String C_POSTALCODE_AT_OID = "2.5.4.17.1";
+
+    // C-postOfficeBox
+    public static final String C_POSTOFFICEBOX_AT = "c-postOfficeBox";
+    public static final String C_POSTOFFICEBOX_AT_OID = "2.5.4.18.1";
+
+    // C-physicalDeliveryOfficeName
+    public static final String C_PHYSICAL_DELIVERY_OFFICE_NAME_AT = "c-physicalDeliveryOfficeName";
+    public static final String C_PHYSICAL_DELIVERY_OFFICE_NAME_AT_OID = "2.5.4.19.1";
+
+    // C-telephoneNumber
+    public static final String C_TELEPHONE_NUMBER_AT = "c-telephoneNumber";
+    public static final String C_TELEPHONE_NUMBER_AT_OID = "2.5.4.20.1";
+
+    // C-telexNumber
+    public static final String C_TELEX_NUMBER_AT = "c-telexNumber";
+    public static final String C_TELEX_NUMBER_AT_OID = "2.5.4.21.1";
+
+    // C-fax
+    public static final String C_FACSIMILE_TELEPHONE_NUMBER_AT = "c-facsimileTelephoneNumber";
+    public static final String C_FACSIMILE_TELEPHONE_NUMBER_AT_OID = "2.5.4.23.1";
+
+    // C-internationaliSDNNumber
+    public static final String C_INTERNATIONAL_ISDN_NUMBER_AT = "c-internationaliSDNNumber";
+    public static final String C_INTERNATIONAL_ISDN_NUMBER_AT_OID = "2.5.4.25.1";
+
+    //-------------------------------------------------------------------------
+    // corba AttributeTypes
+    //-------------------------------------------------------------------------
+    // CorbaIor AT
+    public static final String CORBA_IOR_AT = "corbaIor";
+    public static final String CORBA_IOR_AT_OID = "1.3.6.1.4.1.42.2.27.4.1.14";
+
+    // CorbaRepositoryId AT
+    public static final String CORBA_REPOSITORY_ID_AT = "corbaRepositoryId";
+    public static final String CORBA_REPOSITORY_ID_AT_OID = "1.3.6.1.4.1.42.2.27.4.1.15";
+
+    //-------------------------------------------------------------------------
+    // core AttributeTypes
+    //-------------------------------------------------------------------------
+    // Uid
+    public static final String UID_AT = "uid";
+    public static final String USER_ID_AT = "userid";
+    public static final String UID_AT_OID = "0.9.2342.19200300.100.1.1";
+
+    // Mail 
+    public static final String MAIL_AT = "mail";
+    public static final String RFC822_MAILBOX_AT = "rfc822Mailbox";
+    public static final String MAIL_AT_OID = "0.9.2342.19200300.100.1.3";
+
+    // DomainComponent
+    public static final String DC_AT = "dc";
+    public static final String DOMAIN_COMPONENT_AT = "domainComponent";
+    public static final String DOMAIN_COMPONENT_AT_OID = "0.9.2342.19200300.100.1.25";
+
+    // AssociatedDomain
+    public static final String ASSOCIATED_DOMAIN_AT = "associatedDomain";
+    public static final String ASSOCIATED_DOMAIN_AT_OID = "0.9.2342.19200300.100.1.37";
+
+    // Emails
+    public static final String EMAIL_AT = "email";
+    public static final String EMAIL_ADDRESS_AT = "emailAddress";
+    public static final String PKCS9EMAIL_AT = "pkcs9email";
+    public static final String EMAIL_AT_OID = "1.2.840.113549.1.9.1";
+
+    // UidObject
+    public static final String UID_OBJECT_AT = "uidObject";
+    public static final String UID_OBJECT_AT_OID = "1.3.6.1.1.3.1";
+
+    // knowledgeInformation
+    public static final String KNOWLEDGE_INFORMATION_AT = "knowledgeInformation";
+    public static final String KNOWLEDGE_INFORMATION_AT_OID = "2.5.4.2";
+
+    // Sn
+    public static final String SN_AT = "sn";
+    public static final String SURNAME_AT = "surname";
+    public static final String SN_AT_OID = "2.5.4.4";
+
+    // SerialNumber
+    public static final String SERIAL_NUMBER_AT = "serialNumber";
+    public static final String SERIAL_NUMBER_AT_OID = "2.5.4.5";
+
+    // C, CountryName
+    public static final String C_AT = "c";
+    public static final String COUNTRY_NAME_AT = "countryName";
+    public static final String C_AT_OID = "2.5.4.6";
+
+    // L, LocalityName
+    public static final String L_AT = "l";
+    public static final String LOCALITY_NAME_AT = "localityName";
+    public static final String L_AT_OID = "2.5.4.7";
+    public static final String LOCALITY_NAME_AT_OID = "2.5.4.7";
+
+    // St
+    public static final String ST_AT = "st";
+    public static final String STATEORPROVINCE_NAME_AT = "stateOrProvinceName";
+    public static final String ST_AT_OID = "2.5.4.8";
+
+    // Street
+    public static final String STREET_AT = "street";
+    public static final String STREET_ADDRESS_AT = "streetAddress";
+    public static final String STREET_AT_OID = "2.5.4.9";
+
+    // O
+    public static final String O_AT = "o";
+    public static final String ORGANIZATION_NAME_AT = "organizationName";
+    public static final String O_AT_OID = "2.5.4.10";
+    public static final String ORGANIZATION_NAME_AT_OID = "2.5.4.10";
+
+    // Ou
+    public static final String OU_AT = "ou";
+    public static final String ORGANIZATIONAL_UNIT_NAME_AT = "organizationalUnitName";
+    public static final String OU_AT_OID = "2.5.4.11";
+    public static final String ORGANIZATIONAL_UNIT_NAME_AT_OID = "2.5.4.11";
+
+    // Title
+    public static final String TITLE_AT = "title";
+    public static final String TITLE_AT_OID = "2.5.4.12";
+
+    // Description
+    public static final String DESCRIPTION_AT = "description";
+    public static final String DESCRIPTION_AT_OID = "2.5.4.13";
+
+    // SearchGuide
+    public static final String SEARCHGUIDE_AT = "searchguide";
+    public static final String SEARCHGUIDE_AT_OID = "2.5.4.14";
+
+    // BusinessCategory
+    public static final String BUSINESS_CATEGORY_AT = "businessCategory";
+    public static final String BUSINESS_CATEGORY_AT_OID = "2.5.4.15";
+
+    // PostalAddress
+    public static final String POSTAL_ADDRESS_AT = "postalAddress";
+    public static final String POSTAL_ADDRESS_AT_OID = "2.5.4.16";
+
+    // PostalCode
+    public static final String POSTALCODE_AT = "postalCode";
+    public static final String POSTALCODE_AT_OID = "2.5.4.17";
+
+    // PostOfficeBox
+    public static final String POSTOFFICEBOX_AT = "postOfficeBox";
+    public static final String POSTOFFICEBOX_AT_OID = "2.5.4.18";
+
+    // PhysicalDeliveryOfficeName
+    public static final String PHYSICAL_DELIVERY_OFFICE_NAME_AT = "physicalDeliveryOfficeName";
+    public static final String PHYSICAL_DELIVERY_OFFICE_NAME_AT_OID = "2.5.4.19";
+
+    // TelephoneNumber
+    public static final String TELEPHONE_NUMBER_AT = "telephoneNumber";
+    public static final String TELEPHONE_NUMBER_AT_OID = "2.5.4.20";
+
+    // TelexNumber
+    public static final String TELEX_NUMBER_AT = "telexNumber";
+    public static final String TELEX_NUMBER_AT_OID = "2.5.4.21";
+
+    // TeletexTerminalIdentifier
+    public static final String TELETEX_TERMINAL_IDENTIFIER_AT = "teletexTerminalIdentifier";
+    public static final String TELETEX_TERMINAL_IDENTIFIER_AT_OID = "2.5.4.22";
+
+    // Fax
+    public static final String FAX_AT = "fax";
+    public static final String FACSIMILE_TELEPHONE_NUMBER_AT = "facsimileTelephoneNumber";
+    public static final String FACSIMILE_TELEPHONE_NUMBER_AT_OID = "2.5.4.23";
+
+    // X121Address
+    public static final String X12_1ADDRESS_AT = "x121Address";
+    public static final String X121_ADDRESS_AT_OID = "2.5.4.24";
+
+    // InternationaliSDNNumber
+    public static final String INTERNATIONAL_ISDN_NUMBER_AT = "internationaliSDNNumber";
+    public static final String INTERNATIONAL_ISDN_NUMBER_AT_OID = "2.5.4.25";
+
+    // RegisteredAddress
+    public static final String REGISTERED_ADDRESS_AT = "registeredAddress";
+    public static final String REGISTERED_ADDRESS_AT_OID = "2.5.4.26";
+
+    // DestinationIndicator
+    public static final String DESTINATION_INDICATOR_AT = "destinationIndicator";
+    public static final String DESTINATION_INDICATOR_AT_OID = "2.5.4.27";
+
+    // PreferredDeliveryMethod
+    public static final String PREFERRED_DELIVERY_METHOD_AT = "preferredDeliveryMethod";
+    public static final String PREFERRED_DELIVERY_METHOD_AT_OID = "2.5.4.28";
+
+    // PresentationAddress
+    public static final String PRESENTATION_ADDRESS_AT = "presentationAddress";
+    public static final String PRESENTATION_ADDRESS_AT_OID = "2.5.4.29";
+
+    // SupportedApplicationContext
+    public static final String SUPPORTED_APPLICATION_CONTEXT_AT = "supportedApplicationContext";
+    public static final String SUPPORTED_APPLICATION_CONTEXT_AT_OID = "2.5.4.30";
+
+    // Member
+    public static final String MEMBER_AT = "member";
+    public static final String MEMBER_AT_OID = "2.5.4.31";
+
+    // Owner
+    public static final String OWNER_AT = "owner";
+    public static final String OWNER_AT_OID = "2.5.4.32";
+
+    // RoleOccupant
+    public static final String ROLE_OCCUPANT_AT = "roleOccupant";
+    public static final String ROLE_OCCUPANT_AT_OID = "2.5.4.33";
+
+    // SeeAlso
+    public static final String SEE_ALSO_AT = "seeAlso";
+    public static final String SEE_ALSO_AT_OID = "2.5.4.34";
+
+    // UserCertificate
+    public static final String USER_CERTIFICATE_AT = "userCertificate";
+    public static final String USER_CERTIFICATE_AT_OID = "2.5.4.36";
+
+    // CACertificate
+    public static final String CA_CERTIFICATE_AT = "cACertificate";
+    public static final String CA_CERTIFICATE_AT_OID = "2.5.4.37";
+
+    // AuthorityRevocationList
+    public static final String AUTHORITY_REVOCATION_LIST_AT = "authorityRevocationList";
+    public static final String AUTHORITY_REVOCATION_LIST_AT_OID = "2.5.4.38";
+
+    // CertificateRevocationList
+    public static final String CERTIFICATE_REVOCATION_LIST_AT = "certificateRevocationList";
+    public static final String CERTIFICATE_REVOCATION_LIST_AT_OID = "2.5.4.39";
+
+    // CrossCertificatePair
+    public static final String CROSS_CERTIFICATE_PAIR_AT = "crossCertificatePair";
+    public static final String CROSS_CERTIFICATE_PAIR_AT_OID = "2.5.4.40";
+
+    // Gn
+    public static final String GN_AT = "gn";
+    public static final String GIVENNAME_AT = "givenName";
+    public static final String GN_AT_OID = "2.5.4.42";
+    public static final String GIVENNAME_AT_OID = "2.5.4.42";
+
+    // Initials
+    public static final String INITIALS_AT = "initials";
+    public static final String INITIALS_AT_OID = "2.5.4.43";
+
+    // GenerationQualifier
+    public static final String GENERATION_QUALIFIER_AT = "generationQualifier";
+    public static final String GENERATION_QUALIFIER_AT_OID = "2.5.4.44";
+
+    // X500UniqueIdentifier
+    public static final String X500_UNIQUE_IDENTIFIER_AT = "x500UniqueIdentifier";
+    public static final String X500_UNIQUE_IDENTIFIER_AT_OID = "2.5.4.45";
+
+    // DnQualifier
+    public static final String DN_QUALIFIER_AT = "dnQualifier";
+    public static final String DN_QUALIFIER_AT_OID = "2.5.4.46";
+
+    // EnhancedSearchGuide
+    public static final String ENHANCED_SEARCH_GUIDE_AT = "enhancedSearchGuide";
+    public static final String ENHANCED_SEARCH_GUIDE_AT_OID = "2.5.4.47";
+
+    // ProtocolInformation
+    public static final String PROTOCOL_INFORMATION_AT = "protocolInformation";
+    public static final String PROTOCOL_INFORMATION_AT_OID = "2.5.4.48";
+
+    // DistinguishedName
+    public static final String DISTINGUISHED_NAME_AT = "distinguishedName";
+    public static final String DISTINGUISHED_NAME_AT_OID = "2.5.4.49";
+
+    // UniqueMember
+    public static final String UNIQUE_MEMBER_AT = "uniqueMember";
+    public static final String UNIQUE_MEMBER_AT_OID = "2.5.4.50";
+
+    // HouseIdentifier
+    public static final String HOUSE_IDENTIFIER_AT = "houseIdentifier";
+    public static final String HOUSE_IDENTIFIER_AT_OID = "2.5.4.51";
+
+    // SupportedAlgorithms
+    public static final String SUPPORTED_ALGORITHMS_AT = "supportedAlgorithms";
+    public static final String SUPPORTED_ALGORITHMS_AT_OID = "2.5.4.52";
+
+    // DeltaRevocationList
+    public static final String DELTA_REVOCATION_LIST_AT = "deltaRevocationList";
+    public static final String DELTA_REVOCATION_LIST_AT_OID = "2.5.4.53";
+
+    // DmdName
+    public static final String DMD_NAME_AT = "dmdName";
+    public static final String DMD_NAME_AT_OID = "2.5.4.54";
+
+    //-------------------------------------------------------------------------
+    // cosine AttributeTypes
+    //-------------------------------------------------------------------------
+    // TextEncodedORAddress AT
+    public static final String TEXT_ENCODED_OR_ADDRESS_AT = "textEncodedORAddress";
+    public static final String TEXT_ENCODED_OR_ADDRESS_AT_OID = "0.9.2342.19200300.100.1.2";
+
+    // Info AT
+    public static final String INFO_AT = "info";
+    public static final String INFO_AT_OID = "0.9.2342.19200300.100.1.4";
+
+    // Drink AT
+    public static final String DRINK_AT = "drink";
+    public static final String FAVOURITE_DRINK_AT = "favouriteDrink";
+    public static final String DRINK_AT_OID = "0.9.2342.19200300.100.1.5";
+
+    // RoomNumber AT
+    public static final String ROOM_NUMBER_AT = "roomNumber";
+    public static final String ROOM_NUMBER_AT_OID = "0.9.2342.19200300.100.1.6";
+
+    // Photo AT
+    public static final String PHOTO_AT = "photo";
+    public static final String PHOTO_AT_OID = "0.9.2342.19200300.100.1.7";
+
+    // UserClass AT
+    public static final String USER_CLASS_AT = "userClass";
+    public static final String USER_CLASS_AT_OID = "0.9.2342.19200300.100.1.8";
+
+    // Host AT
+    public static final String HOST_AT = "host";
+    public static final String HOST_AT_OID = "0.9.2342.19200300.100.1.9";
+
+    // Manager AT
+    public static final String MANAGER_AT = "manager";
+    public static final String MANAGER_AT_OID = "0.9.2342.19200300.100.1.10";
+
+    // DocumentIdentifier AT
+    public static final String DOCUMENT_IDENTIFIER_AT = "documentIdentifier";
+    public static final String DOCUMENT_IDENTIFIER_AT_OID = "0.9.2342.19200300.100.1.11";
+
+    // DocumentTitle AT
+    public static final String DOCUMENT_TITLE_AT = "documentTitle";
+    public static final String DOCUMENT_TITLE_AT_OID = "0.9.2342.19200300.100.1.12";
+
+    // DocumentVersion AT
+    public static final String DOCUMENT_VERSION_AT = "documentVersion";
+    public static final String DOCUMENT_VERSION_AT_OID = "0.9.2342.19200300.100.1.13";
+
+    // DocumentAuthor AT
+    public static final String DOCUMENT_AUTHOR_AT = "documentAuthor";
+    public static final String DOCUMENT_AUTHOR_AT_OID = "0.9.2342.19200300.100.1.14";
+
+    // DocumentLocation AT
+    public static final String DOCUMENT_LOCATION_AT = "documentLocation";
+    public static final String DOCUMENT_LOCATION_AT_OID = "0.9.2342.19200300.100.1.15";
+
+    // HomePhone AT
+    public static final String HOME_PHONE_AT = "homePhone";
+    public static final String HOME_TELEPHONE_NUMBER_AT = "homeTelephoneNumber";
+    public static final String HOME_PHONE_AT_OID = "0.9.2342.19200300.100.1.20";
+
+    // Secretary AT
+    public static final String SECRETARY_AT = "secretary";
+    public static final String SECRETARY_AT_OID = "0.9.2342.19200300.100.1.21";
+
+    // OtherMailbox AT
+    public static final String OTHER_MAILBOX_AT = "otherMailbox";
+    public static final String OTHER_MAILBOX_AT_OID = "0.9.2342.19200300.100.1.22";
+
+    // ARecord AT
+    public static final String A_RECORD_AT = "aRecord";
+    public static final String A_RECORD_AT_OID = "0.9.2342.19200300.100.1.26";
+
+    // MDRecord AT
+    public static final String MD_RECORD_AT = "mDRecord";
+    public static final String MD_RECORD_AT_OID = "0.9.2342.19200300.100.1.27";
+
+    // MXRecord AT
+    public static final String MX_RECORD_AT = "mXRecord";
+    public static final String MX_RECORD_AT_OID = "0.9.2342.19200300.100.1.28";
+
+    // NSRecord AT
+    public static final String NS_RECORD_AT = "nSRecord";
+    public static final String NS_RECORD_AT_OID = "0.9.2342.19200300.100.1.29";
+
+    // SOARecord AT
+    public static final String SOA_RECORD_AT = "sOARecord";
+    public static final String SOA_RECORD_AT_OID = "0.9.2342.19200300.100.1.30";
+
+    // CNAMERecord AT
+    public static final String CNAME_RECORD_AT = "cNAMERecord";
+    public static final String CNAME_RECORD_AT_OID = "0.9.2342.19200300.100.1.31";
+
+    // AssociatedName AT
+    public static final String ASSOCIATED_NAME_AT = "associatedName";
+    public static final String ASSOCIATED_NAME_AT_OID = "0.9.2342.19200300.100.1.38";
+
+    // HomePostalAddress AT
+    public static final String HOME_POSTAL_ADDRESS_AT = "homePostalAddress";
+    public static final String HOME_POSTAL_ADDRESS_AT_OID = "0.9.2342.19200300.100.1.39";
+
+    // PersonalTitle AT
+    public static final String PERSONAL_TITLE_AT = "personalTitle";
+    public static final String PERSONAL_TITLE_AT_OID = "0.9.2342.19200300.100.1.40";
+
+    // Mobile AT
+    public static final String MOBILE_AT = "mobile";
+    public static final String MOBILE_TELEPHONE_NUMBER_AT = "mobileTelephoneNumber";
+    public static final String MOBILE_AT_OID = "0.9.2342.19200300.100.1.41";
+
+    // Pager AT
+    public static final String PAGER_AT = "pager";
+    public static final String PAGER_TELEPHONE_NUMBER_AT = "pagerTelephoneNumber";
+    public static final String PAGER_AT_OID = "0.9.2342.19200300.100.1.42";
+
+    // Co AT
+    public static final String CO_AT = "co";
+    public static final String FRIENDLY_COUNTRY_NAME_CO_AT = "friendlyCountryName";
+    public static final String CO_AT_OID = "0.9.2342.19200300.100.1.43";
+
+    // UniqueIdentifier AT
+    public static final String UNIQUE_IDENTIFIER_AT = "uniqueIdentifier";
+    public static final String UNIQUE_IDENTIFIER_AT_OID = "0.9.2342.19200300.100.1.44";
+
+    // OrganizationalStatus AT
+    public static final String ORGANIZATIONAL_STATUS_AT = "organizationalStatus";
+    public static final String ORGANIZATIONAL_STATUS_AT_OID = "0.9.2342.19200300.100.1.45";
+
+    // JanetMailbox AT
+    public static final String JANET_MAILBOX_AT = "janetMailbox";
+    public static final String JANET_MAILBOX_AT_OID = "0.9.2342.19200300.100.1.46";
+
+    // MailPreferenceOption AT
+    public static final String MAIL_PREFERENCE_OPTION_AT = "mailPreferenceOption";
+    public static final String MAIL_PREFERENCE_OPTION_AT_OID = "0.9.2342.19200300.100.1.47";
+
+    // BuildingName AT
+    public static final String BUILDING_NAME_AT = "buildingName";
+    public static final String BUILDING_NAME_AT_OID = "0.9.2342.19200300.100.1.48";
+
+    // DSAQuality AT
+    public static final String DSA_QUALITY_AT = "dSAQuality";
+    public static final String DSA_QUALITY_AT_OID = "0.9.2342.19200300.100.1.49";
+
+    // SingleLevelQuality AT
+    public static final String SINGLE_LEVEL_QUALITY_AT = "singleLevelQuality";
+    public static final String SINGLE_LEVEL_QUALITY_AT_OID = "0.9.2342.19200300.100.1.50";
+
+    // SubtreeMinimumQuality AT
+    public static final String SUBTREE_MINIMUM_QUALITY_AT = "subtreeMinimumQuality";
+    public static final String SUBTREE_MINIMUM_QUALITY_AT_OID = "0.9.2342.19200300.100.1.51";
+
+    // SubtreeMaximumQuality AT
+    public static final String SUBTREE_MAXIMUM_QUALITY_AT = "subtreeMaximumQuality";
+    public static final String SUBTREE_MAXIMUM_QUALITY_AT_OID = "0.9.2342.19200300.100.1.52";
+
+    // PersonalSignature AT
+    public static final String PERSONAL_SIGNATURE_AT = "personalSignature";
+    public static final String PERSONAL_SIGNATURE_AT_OID = "0.9.2342.19200300.100.1.53";
+
+    // DITRedirect AT
+    public static final String DIT_REDIRECT_AT = "dITRedirect";
+    public static final String DIT_REDIRECT_AT_OID = "0.9.2342.19200300.100.1.54";
+
+    // Audio AT
+    public static final String AUDIO_AT = "audio";
+    public static final String AUDIO_AT_OID = "0.9.2342.19200300.100.1.55";
+
+    // DocumentPublisher AT
+    public static final String DOCUMENT_PUBLISHER_AT = "documentPublisher";
+    public static final String DOCUMENT_PUBLISHER_AT_OID = "0.9.2342.19200300.100.1.56";
+
+    //-------------------------------------------------------------------------
+    // inetorgperson AttributeTypes
+    //-------------------------------------------------------------------------
+    // JpegPhoto
+    public static final String JPEG_PHOTO_AT = "jpegPhoto";
+    public static final String JPEG_PHOTO_AT_OID = "0.9.2342.19200300.100.1.60";
+
+    // CarLicense
+    public static final String CAR_LICENSE_AT = "carLicense";
+    public static final String CAR_LICENSE_AT_OID = "2.16.840.1.113730.3.1.1";
+
+    // DepartmentNumber
+    public static final String DEPARTMENT_NUMBER_AT = "departmentNumber";
+    public static final String DEPARTMENT_NUMBER_AT_OID = "2.16.840.1.113730.3.1.2";
+
+    // EmployeeNumber
+    public static final String EMPLOYEE_NUMBER_AT = "employeeNumber";
+    public static final String EMPLOYEE_NUMBER_AT_OID = "2.16.840.1.113730.3.1.3";
+
+    // EmployeeType
+    public static final String EMPLOYEE_TYPE_AT = "employeeType";
+    public static final String EMPLOYEE_TYPE_AT_OID = "2.16.840.1.113730.3.1.4";
+
+    // PreferredLanguage
+    public static final String PREFERRED_LANGUAGE_AT = "preferredLanguage";
+    public static final String PREFERRED_LANGUAGE_AT_OID = "2.16.840.1.113730.3.1.39";
+
+    // UserSMIMECertificate
+    public static final String USER_SMIME_CERTIFICATE_AT = "userSMIMECertificate";
+    public static final String USER_SMIME_CERTIFICATE_AT_OID = "2.16.840.1.113730.3.1.40";
+
+    // UserPKCS12
+    public static final String USER_PKCS12_AT = "userPKCS12";
+    public static final String USER_PKCS12_AT_OID = "2.16.840.1.113730.3.1.216";
+
+    // DisplayName
+    public static final String DISPLAY_NAME_AT = "displayName";
+    public static final String DISPLAY_NAME_AT_OID = "2.16.840.1.113730.3.1.241";
+
+    //-------------------------------------------------------------------------
+    // nis AttributeTypes
+    //-------------------------------------------------------------------------
+    // UidNumber AT
+    public static final String UID_NUMBER_AT = "uidNumber";
+    public static final String UID_NUMBER_AT_OID = "1.3.6.1.1.1.1.0";
+
+    // GidNumber AT
+    public static final String GID_NUMBER_AT = "gidNumber";
+    public static final String GID_NUMBER_AT_OID = "1.3.6.1.1.1.1.1";
+
+    // Gecos AT
+    public static final String GECOS_AT = "gecos";
+    public static final String GECOS_AT_OID = "1.3.6.1.1.1.1.2";
+
+    // HomeDirectory AT
+    public static final String HOME_DIRECTORY_AT = "homeDirectory";
+    public static final String HOME_DIRECTORY_AT_OID = "1.3.6.1.1.1.1.3";
+
+    // LoginShell AT
+    public static final String LOGIN_SHELL_AT = "loginShell";
+    public static final String LOGIN_SHELL_AT_OID = "1.3.6.1.1.1.1.4";
+
+    // ShadowLastChange AT
+    public static final String SHADOW_LAST_CHANGE_AT = "shadowLastChange";
+    public static final String SHADOW_LAST_CHANGE_AT_OID = "1.3.6.1.1.1.1.5";
+
+    // ShadowMin AT
+    public static final String SHADOW_MIN_AT = "shadowMin";
+    public static final String SHADOW_MIN_AT_OID = "1.3.6.1.1.1.1.6";
+
+    // ShadowMax AT
+    public static final String SHADOW_MAX_AT = "shadowMax";
+    public static final String SHADOW_MAX_AT_OID = "1.3.6.1.1.1.1.7";
+
+    // ShadowWarning AT
+    public static final String SHADOW_WARNING_AT = "shadowWarning";
+    public static final String SHADOW_WARNING_AT_OID = "1.3.6.1.1.1.1.8";
+
+    // ShadowInactive AT
+    public static final String SHADOW_INACTIVE_AT = "shadowInactive";
+    public static final String SHADOW_INACTIVE_AT_OID = "1.3.6.1.1.1.1.9";
+
+    // ShadowExpire AT
+    public static final String SHADOW_EXPIRE_AT = "shadowExpire";
+    public static final String SHADOW_EXPIRE_AT_OID = "1.3.6.1.1.1.1.10";
+
+    // ShadowFlag AT
+    public static final String SHADOW_FLAG_AT = "shadowFlag";
+    public static final String SHADOW_FLAG_AT_OID = "1.3.6.1.1.1.1.11";
+
+    // MemberUid AT
+    public static final String MEMBER_UID_AT = "memberUid";
+    public static final String MEMBER_UID_AT_OID = "1.3.6.1.1.1.1.12";
+
+    // MemberNisNetgroup AT
+    public static final String MEMBER_NIS_NETGROUP_AT = "memberNisNetgroup";
+    public static final String MEMBER_NIS_NETGROUP_AT_OID = "1.3.6.1.1.1.1.13";
+
+    // NisNetgroupTriple AT
+    public static final String NIS_NETGROUP_TRIPLE_AT = "nisNetgroupTriple";
+    public static final String NIS_NETGROUP_TRIPLE_AT_OID = "1.3.6.1.1.1.1.14";
+
+    // IpServicePort AT
+    public static final String IP_SERVICE_PORT_AT = "ipServicePort";
+    public static final String IP_SERVICE_PORT_AT_OID = "1.3.6.1.1.1.1.15";
+
+    // IpServiceProtocol AT
+    public static final String IP_SERVICE_PROTOCOL_AT = "ipServiceProtocol";
+    public static final String IP_SERVICE_PROTOCOL_AT_OID = "1.3.6.1.1.1.1.16";
+
+    // IpProtocolNumber AT
+    public static final String IP_PROTOCOL_NUMBER_AT = "ipProtocolNumber";
+    public static final String IP_PROTOCOL_NUMBER_AT_OID = "1.3.6.1.1.1.1.17";
+
+    // OncRpcNumber AT
+    public static final String ONC_RPC_NUMBER_AT = "oncRpcNumber";
+    public static final String ONC_RPC_NUMBER_AT_OID = "1.3.6.1.1.1.1.18";
+
+    // IpHostNumber AT
+    public static final String IP_HOST_NUMBER_AT = "ipHostNumber";
+    public static final String IP_HOST_NUMBER_AT_OID = "1.3.6.1.1.1.1.19";
+
+    // IpNetworkNumber AT
+    public static final String IP_NETWORK_NUMBER_AT = "ipNetworkNumber";
+    public static final String IP_NETWORK_NUMBER_AT_OID = "1.3.6.1.1.1.1.20";
+
+    // IpNetmaskNumber AT
+    public static final String IP_NETMASK_NUMBER_AT = "ipNetmaskNumber";
+    public static final String IP_NETMASK_NUMBER_AT_OID = "1.3.6.1.1.1.1.21";
+
+    // MacAddress AT
+    public static final String MAC_ADDRESS_AT = "macAddress";
+    public static final String MAC_ADDRESS_AT_OID = "1.3.6.1.1.1.1.22";
+
+    // BootParameter AT
+    public static final String BOOT_PARAMETER_AT = "bootParameter";
+    public static final String BOOT_PARAMETER_AT_OID = "1.3.6.1.1.1.1.23";
+
+    // BootFile AT
+    public static final String BOOT_FILE_AT = "bootFile";
+    public static final String BOOT_FILE_AT_OID = "1.3.6.1.1.1.1.24";
+
+    // NisMapName AT
+    public static final String NIS_MAP_NAME_AT = "nisMapName";
+    public static final String NIS_MAP_NAME_AT_OID = "1.3.6.1.1.1.1.26";
+
+    // NisMapEntry AT
+    public static final String NIS_MAP_ENTRY_AT = "nisMapEntry";
+    public static final String NIS_MAP_ENTRY_AT_OID = "1.3.6.1.1.1.1.27";
+
+    //-------------------------------------------------------------------------
+    // pwdpolicy AttributeTypes
+    //-------------------------------------------------------------------------
+    // PwdAttribute AT
+    public static final String PWD_ATTRIBUTE_AT = "pwdAttribute";
+    public static final String PWD_ATTRIBUTE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.1";
+
+    // PwdMinAge AT
+    public static final String PWD_MIN_AGE_AT = "pwdMinAge";
+    public static final String PWD_MIN_AGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.2";
+
+    // PwdMaxAge AT
+    public static final String PWD_MAX_AGE_AT = "pwdMaxAge";
+    public static final String PWD_MAX_AGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.3";
+
+    // PwdInHistory AT
+    public static final String PWD_IN_HISTORY_AT = "pwdInHistory";
+    public static final String PWD_IN_HISTORY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.4";
+
+    // PwdCheckQuality AT
+    public static final String PWD_CHECK_QUALITY_AT = "pwdCheckQuality";
+    public static final String PWD_CHECK_QUALITY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.5";
+
+    // PwdMinLength AT
+    public static final String PWD_MIN_LENGTH_AT = "pwdMinLength";
+    public static final String PWD_MIN_LENGTH_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.6";
+
+    // PwdExpireWarning AT
+    public static final String PWD_EXPIRE_WARNING_AT = "pwdExpireWarning";
+    public static final String PWD_EXPIRE_WARNING_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.7";
+
+    // PwdGraceAuthNLimit AT
+    public static final String PWD_GRACE_AUTH_N_LIMIT_AT = "pwdGraceAuthNLimit";
+    public static final String PWD_GRACE_AUTH_N_LIMIT_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.8";
+
+    // PwdLockout AT
+    public static final String PWD_LOCKOUT_AT = "pwdLockout";
+    public static final String PWD_LOCKOUT_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.9";
+
+    // PwdLockoutDuration AT
+    public static final String PWD_LOCKOUT_DURATION_AT = "pwdLockoutDuration";
+    public static final String PWD_LOCKOUT_DURATION_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.10";
+
+    // PwdMaxFailure AT
+    public static final String PWD_MAX_FAILURE_AT = "pwdMaxFailure";
+    public static final String PWD_MAX_FAILURE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.11";
+
+    // PwdFailureCountInterval AT
+    public static final String PWD_FAILURE_COUNT_INTERVAL_AT = "pwdFailureCountInterval";
+    public static final String PWD_FAILURE_COUNT_INTERVAL_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.12";
+
+    // PwdMustChange AT
+    public static final String PWD_MUST_CHANGE_AT = "pwdMustChange";
+    public static final String PWD_MUST_CHANGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.13";
+
+    // PwdAllowUserChange AT
+    public static final String PWD_ALLOW_USER_CHANGE_AT = "pwdAllowUserChange";
+    public static final String PWD_ALLOW_USER_CHANGE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.14";
+
+    // PwdSafeModify AT
+    public static final String PWD_SAFE_MODIFY_AT = "pwdSafeModify";
+    public static final String PWD_SAFE_MODIFY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.15";
+
+    // PwdChangedTime AT
+    public static final String PWD_CHANGED_TIME_AT = "pwdChangedTime";
+    public static final String PWD_CHANGED_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.16";
+
+    // PwdAccountLockedTime AT
+    public static final String PWD_ACCOUNT_LOCKED_TIME_AT = "pwdAccountLockedTime";
+    public static final String PWD_ACCOUNT_LOCKED_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.17";
+
+    // PwdFailureTime AT
+    public static final String PWD_FAILURE_TIME_AT = "pwdFailureTime";
+    public static final String PWD_FAILURE_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.19";
+
+    // PwdHistory AT
+    public static final String PWD_HISTORY_AT = "pwdHistory";
+    public static final String PWD_HISTORY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.20";
+
+    // PwdGraceUseTime AT
+    public static final String PWD_GRACE_USE_TIME_AT = "pwdGraceUseTime";
+    public static final String PWD_GRACE_USE_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.21";
+
+    // PwdReset AT
+    public static final String PWD_RESET_AT = "pwdReset";
+    public static final String PWD_RESET_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.22";
+
+    // PwdPolicySubentry AT
+    public static final String PWD_POLICY_SUBENTRY_AT = "pwdPolicySubentry";
+    public static final String PWD_POLICY_SUBENTRY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.23";
+
+    // PwdMinDelay AT
+    public static final String PWD_MIN_DELAY_AT = "pwdMinDelay";
+    public static final String PWD_MIN_DELAY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.24";
+
+    // PwdMaxDelay AT
+    public static final String PWD_MAX_DELAY_AT = "pwdMaxDelay";
+    public static final String PWD_MAX_DELAY_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.25";
+
+    // PwdMaxIdle AT
+    public static final String PWD_MAX_IDLE_AT = "pwdMaxIdle";
+    public static final String PWD_MAX_IDLE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.26";
+
+    // PwdStartTime AT
+    public static final String PWD_START_TIME_AT = "pwdStartTime";
+    public static final String PWD_START_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.27";
+
+    // PwdEndTime AT
+    public static final String PWD_END_TIME_AT = "pwdEndTime";
+    public static final String PWD_END_TIME_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.28";
+
+    // PwdLastSuccess AT
+    public static final String PWD_LAST_SUCCESS_AT = "pwdLastSuccess";
+    public static final String PWD_LAST_SUCCESS_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.29";
+
+    // PwdGraceExpire AT
+    public static final String PWD_GRACE_EXPIRE_AT = "pwdGraceExpire";
+    public static final String PWD_GRACE_EXPIRE_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.30";
+
+    // PwdMaxLength AT
+    public static final String PWD_MAX_LENGTH_AT = "pwdMaxLength";
+    public static final String PWD_MAX_LENGTH_AT_OID = "1.3.6.1.4.1.42.2.27.8.1.31";
+
+    //-------------------------------------------------------------------------
+    // system AttributeTypes
+    //-------------------------------------------------------------------------
+    // VendorName
+    public static final String VENDOR_NAME_AT = "vendorName";
+    public static final String VENDOR_NAME_AT_OID = "1.3.6.1.1.4";
+
+    // VendorVersion
+    public static final String VENDOR_VERSION_AT = "vendorVersion";
+    public static final String VENDOR_VERSION_AT_OID = "1.3.6.1.1.5";
+
+    // LabeledURI
+    public static final String LABELED_URI_AT = "labeledURI";
+    public static final String LABELED_URI_AT_OID = "1.3.6.1.4.1.250.1.57";
+
+    // EntryTtl
+    public static final String ENTRY_TTL_AT = "entryTtl";
+    public static final String ENTRY_TTL_AT_OID = "1.3.6.1.4.1.1466.101.119.3";
+
+    // DynamicSubtrees
+    public static final String DYNAMIC_SUBTREES_AT = "dynamicSubtrees";
+    public static final String DYNAMIC_SUBTREES_AT_OID = "1.3.6.1.4.1.1466.101.119.4";
+
+    // NamingContexts
+    public static final String NAMING_CONTEXTS_AT = "namingContexts";
+    public static final String NAMING_CONTEXTS_AT_OID = "1.3.6.1.4.1.1466.101.120.5";
+
+    // AltServer
+    public static final String ALT_SERVER_AT = "altServer";
+    public static final String ALT_SERVER_AT_OID = "1.3.6.1.4.1.1466.101.120.6";
+
+    // SupportedExtension
+    public static final String SUPPORTED_EXTENSION_AT = "supportedExtension";
+    public static final String SUPPORTED_EXTENSION_AT_OID = "1.3.6.1.4.1.1466.101.120.7";
+
+    // SupportedControl
+    public static final String SUPPORTED_CONTROL_AT = "supportedControl";
+    public static final String SUPPORTED_CONTROL_AT_OID = "1.3.6.1.4.1.1466.101.120.13";
+
+    // SupportedSASLMechanisms
+    public static final String SUPPORTED_SASL_MECHANISMS_AT = "supportedSASLMechanisms";
+    public static final String SUPPORTED_SASL_MECHANISMS_AT_OID = "1.3.6.1.4.1.1466.101.120.14";
+
+    // SupportedLdapVersion
+    public static final String SUPPORTED_LDAP_VERSION_AT = "supportedLDAPVersion";
+    public static final String SUPPORTED_LDAP_VERSION_AT_OID = "1.3.6.1.4.1.1466.101.120.15";
+
+    // LdapSyntaxes
+    public static final String LDAP_SYNTAXES_AT = "ldapSyntaxes";
+    public static final String LDAP_SYNTAXES_AT_OID = "1.3.6.1.4.1.1466.101.120.16";
+
+    // SupportedFeatures
+    public static final String SUPPORTED_FEATURES_AT = "supportedFeatures";
+    public static final String SUPPORTED_FEATURES_AT_OID = "1.3.6.1.4.1.4203.1.3.5";
+
+    // ObjectClass
+    public static final String OBJECT_CLASS_AT = "objectClass";
+    public static final String OBJECT_CLASS_AT_OID = "2.5.4.0";
+
+    // AliasedObjectName
+    public static final String ALIASED_OBJECT_NAME_AT = "aliasedObjectName";
+    public static final String ALIASED_ENTRY_NAME_AT = "aliasedEntryName";
+    public static final String ALIASED_OBJECT_NAME_AT_OID = "2.5.4.1";
+
+    // Cn
+    public static final String CN_AT = "cn";
+    public static final String COMMON_NAME_AT = "commonName";
+    public static final String CN_AT_OID = "2.5.4.3";
+
+    // UserPassword
+    public static final String USER_PASSWORD_AT = "userPassword";
+    public static final String USER_PASSWORD_AT_OID = "2.5.4.35";
+
+    // Name
+    public static final String NAME_AT = "name";
+    public static final String NAME_AT_OID = "2.5.4.41";
+
+    // CreateTimestamp
+    public static final String CREATE_TIMESTAMP_AT = "createTimestamp";
+    public static final String CREATE_TIMESTAMP_AT_OID = "2.5.18.1";
+
+    // ModifyTimestamp
+    public static final String MODIFY_TIMESTAMP_AT = "modifyTimestamp";
+    public static final String MODIFY_TIMESTAMP_AT_OID = "2.5.18.2";
+
+    // CreatorsName
+    public static final String CREATORS_NAME_AT = "creatorsName";
+    public static final String CREATORS_NAME_AT_OID = "2.5.18.3";
+
+    // ModifiersName
+    public static final String MODIFIERS_NAME_AT = "modifiersName";
+    public static final String MODIFIERS_NAME_AT_OID = "2.5.18.4";
+
+    // AdministrativeRole
+    public static final String ADMINISTRATIVE_ROLE_AT = "administrativeRole";
+    public static final String ADMINISTRATIVE_ROLE_AT_OID = "2.5.18.5";
+
+    // SubtreeSpecification
+    public static final String SUBTREE_SPECIFICATION_AT = "subtreeSpecification";
+    public static final String SUBTREE_SPECIFICATION_AT_OID = "2.5.18.6";
+
+    // CollectiveExclusions
+    public static final String COLLECTIVE_EXCLUSIONS_AT = "collectiveExclusions";
+    public static final String COLLECTIVE_EXCLUSIONS_AT_OID = "2.5.18.7";
+
+    // hasSubordinates
+    public static final String HAS_SUBORDINATES_AT = "hasSubordinates";
+    public static final String HAS_SUBORDINATES_AT_OID = "2.5.18.9";
+
+    // SubschemaSubentry
+    public static final String SUBSCHEMA_SUBENTRY_AT = "subschemaSubentry";
+    public static final String SUBSCHEMA_SUBENTRY_AT_OID = "2.5.18.10";
+
+    // CollectiveAttributeSubentries
+    public static final String COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT = "collectiveAttributeSubentries";
+    public static final String COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT_OID = "2.5.18.12";
+
+    // DitStructureRules
+    public static final String DIT_STRUCTURE_RULES_AT = "ditStructureRules";
+    public static final String DIT_STRUCTURE_RULES_AT_OID = "2.5.21.1";
+
+    // DitContentRules
+    public static final String DIT_CONTENT_RULES_AT = "ditContentRules";
+    public static final String DIT_CONTENT_RULES_AT_OID = "2.5.21.2";
+
+    // MatchingRules
+    public static final String MATCHING_RULES_AT = "matchingRules";
+    public static final String MATCHING_RULES_AT_OID = "2.5.21.4";
+
+    // AttributeTypes
+    public static final String ATTRIBUTE_TYPES_AT = "attributeTypes";
+    public static final String ATTRIBUTE_TYPES_AT_OID = "2.5.21.5";
+
+    // ObjectClasses
+    public static final String OBJECT_CLASSES_AT = "objectClasses";
+    public static final String OBJECT_CLASSES_AT_OID = "2.5.21.6";
+
+    // NameForms
+    public static final String NAME_FORMS_AT = "nameForms";
+    public static final String NAME_FORMS_AT_OID = "2.5.21.7";
+
+    // MatchingRuleUse
+    public static final String MATCHING_RULE_USE_AT = "matchingRuleUse";
+    public static final String MATCHING_RULE_USE_AT_OID = "2.5.21.8";
+
+    // StructuralObjectClass
+    public static final String STRUCTURAL_OBJECT_CLASS_AT = "structuralObjectClass";
+    public static final String STRUCTURAL_OBJECT_CLASS_AT_OID = "2.5.21.9";
+
+    // Ref
+    public static final String REF_AT = "ref";
+    public static final String REF_AT_OID = "2.16.840.1.113730.3.1.34";
+
+    //-------------------------------------------------------------------------
+    // Various other ATtributeTypes
+    //-------------------------------------------------------------------------
+    // apache AttributeTypes
+    //-------------------------------------------------------------------------
+    // EntryUUID
+    public static final String ENTRY_UUID_AT = "entryUUID";
+    public static final String ENTRY_UUID_AT_OID = "1.3.6.1.1.16.4";
+
+    // EntryDN
+    public static final String ENTRY_DN_AT = "entryDN";
+    public static final String ENTRY_DN_AT_OID = "1.3.6.1.1.20";
+
+    // entryCSN
+    public static final String ENTRY_CSN_AT = "entryCSN";
+    public static final String ENTRY_CSN_AT_OID = "1.3.6.1.4.1.4203.666.1.7";
+
+    // contextCSN
+    public static final String CONTEXT_CSN_AT = "contextCSN";
+    public static final String CONTEXT_CSN_AT_OID = "1.3.6.1.4.1.4203.666.1.25";
+
+    // AccessControlSubentries
+    public static final String ACCESS_CONTROL_SUBENTRIES_AT = "accessControlSubentries";
+    public static final String ACCESS_CONTROL_SUBENTRIES_AT_OID = "1.3.6.1.4.1.18060.0.4.1.2.11";
+
+    // TriggerExecutionSubentries
+    public static final String TRIGGER_EXECUTION_SUBENTRIES_AT = "triggerExecutionSubentries";
+    public static final String TRIGGER_EXECUTION_SUBENTRIES_AT_OID = "1.3.6.1.4.1.18060.0.4.1.2.27";
+
+    // Comparators
+    public static final String COMPARATORS_AT = "comparators";
+    public static final String COMPARATORS_AT_OID = "1.3.6.1.4.1.18060.0.4.1.2.32";
+
+    // Normalizers
+    public static final String NORMALIZERS_AT = "normalizers";
+    public static final String NORMALIZERS_AT_OID = "1.3.6.1.4.1.18060.0.4.1.2.33";
+
+    // SyntaxCheckers
+    public static final String SYNTAX_CHECKERS_AT = "syntaxCheckers";
+    public static final String SYNTAX_CHECKERS_AT_OID = "1.3.6.1.4.1.18060.0.4.1.2.34";
+
+    // ChangeLogContext
+    public static final String CHANGELOG_CONTEXT_AT = "changeLogContext";
+    public static final String CHANGELOG_CONTEXT_AT_OID = "1.3.6.1.4.1.18060.0.4.1.2.49";
+
+    // entryParentId
+    public static final String ENTRY_PARENT_ID_AT = "entryParentId";
+    public static final String ENTRY_PARENT_ID_OID = "1.3.6.1.4.1.18060.0.4.1.2.51";
+
+    // PrescriptiveACI
+    public static final String PRESCRIPTIVE_ACI_AT = "prescriptiveACI";
+    public static final String PRESCRIPTIVE_ACI_AT_OID = "2.5.24.4";
+
+    // EntryACI
+    public static final String ENTRY_ACI_AT = "entryACI";
+    public static final String ENTRY_ACI_AT_OID = "2.5.24.5";
+
+    // SubentryACI
+    public static final String SUBENTRY_ACI_AT = "subentryACI";
+    public static final String SUBENTRY_ACI_AT_OID = "2.5.24.6";
+
+    //-------------------------------------------------------------------------
+    // Unkown schema AttributeTypes
+    //-------------------------------------------------------------------------
+    // ExcludeAllCollectiveAttributes
+    public static final String EXCLUDE_ALL_COLLECTIVE_ATTRIBUTES_AT = "excludeAllCollectiveAttributes";
+    public static final String EXCLUDE_ALL_COLLECTIVE_ATTRIBUTES_AT_OID = "2.5.18.0";
+
+    // governingStructureRule
+    public static final String GOVERNING_STRUCTURE_RULE_AT = "governingStructureRule";
+    public static final String GOVERNING_STRUCTURE_RULE_AT_OID = "2.5.21.10";
+
+    // AccessControlScheme
+    public static final String ACCESS_CONTROL_SCHEME_AT = "accessControlScheme";
+    public static final String ACCESS_CONTROL_SCHEME_OID = "2.5.24.1";
+
+    // numSubordinates, by Sun
+    public static final String NUM_SUBORDINATES_AT = "numSubordinates";
+    // no official OID in RFCs
+
+    // subordinateCount, by Novell
+    public static final String SUBORDINATE_COUNT_AT = "subordinateCount";
+    // no official OID in RFCs
+
+    //=========================================================================
+    // LdapServer AT and OC
+    //-------------------------------------------------------------------------
+    // ObjectClasses
+    //-------------------------------------------------------------------------
+
+    //=========================================================================
+    // DirectoryService AT and OC
+    //-------------------------------------------------------------------------
+    // ads-directoryServiceId AT
+    public static final String ADS_DIRECTORY_SERVICE_ID = "ads-directoryServiceId";
+    public static final String ADS_DIRECTORY_SERVICE_ID_OID = "1.3.6.1.4.1.18060.0.4.1.2.100";
+
+    //=========================================================================
+    // Replication AT and OC
+    //-------------------------------------------------------------------------
+    // ObjectClasses
+    //-------------------------------------------------------------------------
+    // ads-replEventLog OC
+    public static final String ADS_REPL_EVENT_LOG = "ads-replEventLog";
+    public static final String ADS_REPL_EVENT_LOG_OID = "1.3.6.1.4.1.18060.0.4.1.3.805";
+
+    // ads-replConsumer OC
+    public static final String ADS_REPL_CONSUMER = "ads-replConsumer";
+    public static final String ADS_REPL_CONSUMER_OID = "1.3.6.1.4.1.18060.0.4.1.3.806";
+
+    // ads-dsReplicaId AT
+    public static final String ADS_DS_REPLICA_ID = "ads-dsReplicaId";
+    public static final String ADS_DS_REPLICA_ID_OID = "1.3.6.1.4.1.18060.0.4.1.2.112";
+
+    // ads-replConsumerImpl AT
+    public static final String ADS_REPL_CONSUMER_IMPL = "ads-replConsumerImpl";
+    public static final String ADS_REPL_CONSUMER_IMPL_OID = "1.3.6.1.4.1.18060.0.4.1.2.310";
+
+    // ads-replSearchFilter AT
+    public static final String ADS_REPL_SEARCH_FILTER = "ads-replSearchFilter";
+    public static final String ADS_REPL_SEARCH_FILTER_OID = "1.3.6.1.4.1.18060.0.4.1.2.817";
+
+    // ads-replLastSentCsn AT
+    public static final String ADS_REPL_LAST_SENT_CSN = "ads-replLastSentCsn";
+    public static final String ADS_REPL_LAST_SENT_CSN_OID = "1.3.6.1.4.1.18060.0.4.1.2.818";
+
+    // ads-replAliasDerefMode AT
+    public static final String ADS_REPL_ALIAS_DEREF_MODE = "ads-replAliasDerefMode";
+    public static final String ADS_REPL_ALIAS_DEREF_MODE_OID = "1.3.6.1.4.1.18060.0.4.1.2.819";
+
+    // ads-searchBaseDN AT
+    public static final String ADS_SEARCH_BASE_DN = "ads-searchBaseDN";
+    public static final String ADS_SEARCH_BASE_DN_OID = "1.3.6.1.4.1.18060.0.4.1.2.820";
+
+    // ads-replSearchScope AT
+    public static final String ADS_REPL_SEARCH_SCOPE = "ads-replSearchScope";
+    public static final String ADS_REPL_SEARCH_SCOPE_OID = "1.3.6.1.4.1.18060.0.4.1.2.821";
+
+    // ads-replRefreshNPersist AT
+    public static final String ADS_REPL_REFRESH_N_PERSIST = "ads-replRefreshNPersist";
+    public static final String ADS_REPL_REFRESH_N_PERSIST_OID = "1.3.6.1.4.1.18060.0.4.1.2.822";
+
+    // ads-replProvHostName AT
+    public static final String ADS_REPL_PROV_HOST_NAME = "ads-replProvHostName";
+    public static final String ADS_REPL_PROV_HOST_NAME_OID = "1.3.6.1.4.1.18060.0.4.1.2.823";
+
+    // ads-replProvPort AT
+    public static final String ADS_REPL_PROV_PORT = "ads-replProvPort";
+    public static final String ADS_REPL_PROV_PORT_OID = "1.3.6.1.4.1.18060.0.4.1.2.824";
+
+    // ads-replUserDn AT
+    public static final String ADS_REPL_USER_DN = "ads-replUserDn";
+    public static final String ADS_REPL_USER_DN_OID = "1.3.6.1.4.1.18060.0.4.1.2.825";
+
+    // ads-replUserPassword AT
+    public static final String ADS_REPL_USER_PASSWORD = "ads-replUserPassword";
+    public static final String ADS_REPL_USER_PASSWORD_OID = "1.3.6.1.4.1.18060.0.4.1.2.826";
+
+    // ads-replRefreshInterval AT
+    public static final String ADS_REPL_REFRESH_INTERVAL = "ads-replRefreshInterval";
+    public static final String ADS_REPL_REFRESH_INTERVAL_OID = "1.3.6.1.4.1.18060.0.4.1.2.827";
+
+    // ads-replAttributes AT
+    public static final String ADS_REPL_ATTRIBUTES = "ads-replAttributes";
+    public static final String ADS_REPL_ATTRIBUTES_OID = "1.3.6.1.4.1.18060.0.4.1.2.828";
+
+    // ads-replSearchSizeLimit AT
+    public static final String ADS_REPL_SEARCH_SIZE_LIMIT = "ads-replSearchSizeLimit";
+    public static final String ADS_REPL_SEARCH_SIZE_LIMIT_OID = "1.3.6.1.4.1.18060.0.4.1.2.829";
+
+    // ads-replSearchTimeOut AT
+    public static final String ADS_REPL_SEARCH_TIMEOUT = "ads-replSearchTimeOut";
+    public static final String ADS_REPL_SEARCH_TIMEOUT_OID = "1.3.6.1.4.1.18060.0.4.1.2.830";
+
+    // ads-replCookie AT
+    public static final String ADS_REPL_COOKIE = "ads-replCookie";
+    public static final String ADS_REPL_COOKIE_OID = "1.3.6.1.4.1.18060.0.4.1.2.831";
+
+    // ads-replReqHandler AT
+    public static final String ADS_REPL_REQ_HANDLER = "ads-replReqHandler";
+    public static final String ADS_REPL_REQ_HANDLER_OID = "1.3.6.1.4.1.18060.0.4.1.2.832";
+
+    // ads-replUseTls AT
+    public static final String ADS_REPL_USE_TLS = "ads-replUseTls";
+    public static final String ADS_REPL_USE_TLS_OID = "1.3.6.1.4.1.18060.0.4.1.2.833";
+
+    // ads-replStrictCertValidation AT
+    public static final String ADS_REPL_STRICT_CERT_VALIDATION = "ads-replStrictCertValidation";
+    public static final String ADS_REPL_STRICT_CERT_VALIDATION_OID = "1.3.6.1.4.1.18060.0.4.1.2.834";
+
+    // ads-replProviderId AT
+    public static final String ADS_REPL_PROVIDER_ID = "ads-replProviderId";
+    public static final String ADS_REPL_PROVIDER_ID_OID = "1.3.6.1.4.1.18060.0.4.1.2.836";
+
+    // ads-replConsumerId AT
+    public static final String ADS_REPL_CONSUMER_ID = "ads-replConsumerId";
+    public static final String ADS_REPL_CONSUMER_ID_OID = "1.3.6.1.4.1.18060.0.4.1.2.837";
+
+    // ads-replEnabled AT
+    public static final String ADS_REPL_ENABLED = "ads-replEnabled";
+    public static final String ADS_REPL_ENABLED_OID = "1.3.6.1.4.1.18060.0.4.1.2.838";
+
+    // ads-replLogMaxIdle AT
+    public static final String ADS_REPL_LOG_MAX_IDLE = "ads-replLogMaxIdle";
+    public static final String ADS_REPL_LOG_MAX_IDLE_OID = "1.3.6.1.4.1.18060.0.4.1.2.920";
+
+    // ads-replLogPurgeThresholdCount AT
+    public static final String ADS_REPL_LOG_PURGE_THRESHOLD_COUNT = "ads-replLogPurgeThresholdCount";
+    public static final String ADS_REPL_LOG_PURGE_THRESHOLD_COUNT_OID = "1.3.6.1.4.1.18060.0.4.1.2.922";
+
+    //-------------------------------------------------------------------------
+    // ---- Syntaxes ----------------------------------------------------------
+    //-------------------------------------------------------------------------
+    public static final String NAME_OR_NUMERIC_ID_SYNTAX = "1.3.6.1.4.1.18060.0.4.0.0.0";
+
+    public static final String OBJECT_CLASS_TYPE_SYNTAX = "1.3.6.1.4.1.18060.0.4.0.0.1";
+
+    public static final String NUMERIC_OID_SYNTAX = "1.3.6.1.4.1.18060.0.4.0.0.2";
+
+    public static final String ATTRIBUTE_TYPE_USAGE_SYNTAX = "1.3.6.1.4.1.18060.0.4.0.0.3";
+
+    // RFC 4517, par. 3.3.23
+    public static final String NUMBER_SYNTAX = "1.3.6.1.4.1.18060.0.4.0.0.4";
+
+    public static final String OID_LEN_SYNTAX = "1.3.6.1.4.1.18060.0.4.0.0.5";
+
+    public static final String OBJECT_NAME_SYNTAX = "1.3.6.1.4.1.18060.0.4.0.0.6";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String ACI_ITEM_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.1";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String ACCESS_POINT_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.2";
+
+    // RFC 4517, chap 3.3.1
+    public static final String ATTRIBUTE_TYPE_DESCRIPTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.3";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String AUDIO_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.4";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String BINARY_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.5";
+
+    // RFC 4517, chap 3.3.2
+    public static final String BIT_STRING_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.6";
+
+    // RFC 4517, chap 3.3.3
+    public static final String BOOLEAN_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.7";
+
+    // RFC 2252, removed in RFC 4517, reintroduced in RFC 4523, chap. 2.1
+    public static final String CERTIFICATE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.8";
+
+    // RFC 2252, removed in RFC 4517, reintroduced in RFC 4523, chap. 2.2
+    public static final String CERTIFICATE_LIST_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.9";
+
+    // RFC 2252, removed in RFC 4517, reintroduced in RFC 4523, chap. 2.3
+    public static final String CERTIFICATE_PAIR_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.10";
+
+    // RFC 4517, chap 3.3.4
+    public static final String COUNTRY_STRING_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.11";
+
+    // RFC 4517, chap 3.3.9
+    public static final String DN_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.12";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String DATA_QUALITY_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.13";
+
+    // RFC 4517, chap 3.3.5
+    public static final String DELIVERY_METHOD_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.14";
+
+    // RFC 4517, chap 3.3.6
+    public static final String DIRECTORY_STRING_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.15";
+
+    // RFC 4517, chap 3.3.7
+    public static final String DIT_CONTENT_RULE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.16";
+
+    // RFC 4517, chap 3.3.8
+    public static final String DIT_STRUCTURE_RULE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.17";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String DL_SUBMIT_PERMISSION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.18";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String DSA_QUALITY_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.19";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String DSE_TYPE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.20";
+
+    // RFC 4517, chap 3.3.10
+    public static final String ENHANCED_GUIDE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.21";
+
+    // RFC 4517, chap 3.3.11
+    public static final String FACSIMILE_TELEPHONE_NUMBER_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.22";
+
+    // RFC 4517, chap 3.3.12
+    public static final String FAX_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.23";
+
+    // RFC 4517, chap 3.3.13
+    public static final String GENERALIZED_TIME_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.24";
+
+    // RFC 4517, chap 3.3.14
+    public static final String GUIDE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.25";
+
+    // RFC 4517, chap 3.3.15
+    public static final String IA5_STRING_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.26";
+
+    // RFC 4517, chap 3.3.16
+    public static final String INTEGER_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.27";
+
+    // RFC 4517, chap 3.3.17
+    public static final String JPEG_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.28";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String MASTER_AND_SHADOW_ACCESS_POINTS_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.29";
+
+    // RFC 4517, chap 3.3.19
+    public static final String MATCHING_RULE_DESCRIPTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.30";
+
+    // RFC 4517, chap 3.3.20
+    public static final String MATCHING_RULE_USE_DESCRIPTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.31";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String MAIL_PREFERENCE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.32";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String MHS_OR_ADDRESS_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.33";
+
+    // RFC 4517, chap 3.3.21
+    public static final String NAME_AND_OPTIONAL_UID_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.34";
+
+    // RFC 4517, chap 3.3.22
+    public static final String NAME_FORM_DESCRIPTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.35";
+
+    // RFC 4517, chap 3.3.23
+    public static final String NUMERIC_STRING_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.36";
+
+    // RFC 4517, chap 3.3.24
+    public static final String OBJECT_CLASS_DESCRIPTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.37";
+
+    // RFC 4517, chap 3.3.26
+    public static final String OID_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.38";
+
+    // RFC 4517, chap 3.3.27
+    public static final String OTHER_MAILBOX_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.39";
+
+    // RFC 4517, chap 3.3.25
+    public static final String OCTET_STRING_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.40";
+
+    // RFC 4517, chap 3.3.28
+    public static final String POSTAL_ADDRESS_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.41";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String PROTOCOL_INFORMATION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.42";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String PRESENTATION_ADDRESS_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.43";
+
+    // RFC 4517, chap 3.3.29
+    public static final String PRINTABLE_STRING_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.44";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String SUBTREE_SPECIFICATION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.45";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String SUPPLIER_INFORMATION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.46";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String SUPPLIER_OR_CONSUMER_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.47";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String SUPPLIER_AND_CONSUMER_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.48";
+
+    // RFC 2252, removed in RFC 4517, reintroduced in RFC 4523, chap. 2.4
+    public static final String SUPPORTED_ALGORITHM_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.49";
+
+    // RFC 4517, chap 3.3.31
+    public static final String TELEPHONE_NUMBER_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.50";
+
+    // RFC 4517, chap 3.3.32
+    public static final String TELETEX_TERMINAL_IDENTIFIER_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.51";
+
+    // RFC 4517, chap 3.3.33
+    public static final String TELEX_NUMBER_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.52";
+
+    // RFC 4517, chap 3.3.34
+    public static final String UTC_TIME_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.53";
+
+    // RFC 4517, chap 3.3.18
+    public static final String LDAP_SYNTAX_DESCRIPTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.54";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String MODIFY_RIGHTS_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.55";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String LDAP_SCHEMA_DEFINITION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.56";
+
+    // RFC 2252, removed in RFC 4517
+    public static final String LDAP_SCHEMA_DESCRIPTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.57";
+
+    // RFC 4517, chap 3.3.30
+    public static final String SUBSTRING_ASSERTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.58";
+
+    // From draft-ietf-pkix-ldap-v3-01.txt. Obsolete.
+    public static final String ATTRIBUTE_CERTIFICATE_ASSERTION_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.59";
+
+    //From RFC 4530, chap. 2.1
+    public static final String UUID_SYNTAX = "1.3.6.1.1.16.1";
+
+    // From http://www.openldap.org/faq/data/cache/1145.html
+    public static final String CSN_SYNTAX = "1.3.6.1.4.1.4203.666.11.2.1";
+
+    // From http://www.openldap.org/faq/data/cache/1145.html
+    public static final String CSN_SID_SYNTAX = "1.3.6.1.4.1.4203.666.11.2.4";
+
+    // ApacheDS
+    public static final String JAVA_BYTE_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.0";
+    public static final String JAVA_CHAR_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.1";
+    public static final String JAVA_SHORT_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.2";
+    public static final String JAVA_LONG_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.3";
+    public static final String JAVA_INT_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.4";
+
+    // Comparator syntax
+    public static final String COMPARATOR_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.5";
+
+    // Normalizer Syntax
+    public static final String NORMALIZER_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.6";
+
+    // SyntaxChecker Syntax
+    public static final String SYNTAX_CHECKER_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.7";
+
+    // SearchScope Syntax
+    public static final String SEARCH_SCOPE_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.10";
+
+    // DerefAlias Syntax
+    public static final String DEREF_ALIAS_SYNTAX = "1.3.6.1.4.1.18060.0.4.1.0.11";
+
+    //-------------------------------------------------------------------------
+    // ---- MatchingRules -----------------------------------------------------
+    //-------------------------------------------------------------------------
+    // caseExactIA5Match (RFC 4517, chap. 4.2.3)
+    public static final String CASE_EXACT_IA5_MATCH_MR = "caseExactIA5Match";
+    public static final String CASE_EXACT_IA5_MATCH_MR_OID = "1.3.6.1.4.1.1466.109.114.1";
+
+    // caseIgnoreIA5Match (RFC 4517, chap. 4.2.7)
+    public static final String CASE_IGNORE_IA5_MATCH_MR = "caseIgnoreIA5Match";
+    public static final String CASE_IGNORE_IA5_MATCH_MR_OID = "1.3.6.1.4.1.1466.109.114.2";
+
+    // caseIgnoreIA5SubstringsMatch (RFC 4517, chap. 4.2.8)
+    public static final String CASE_IGNORE_IA5_SUBSTRINGS_MATCH_MR = "caseIgnoreIA5SubstringsMatch";
+    public static final String CASE_IGNORE_IA5_SUBSTRINGS_MATCH_MR_OID = "1.3.6.1.4.1.1466.109.114.3";
+
+    // objectIdentifierMatch (RFC 4517, chap. 4.2.26)
+    public static final String OBJECT_IDENTIFIER_MATCH_MR = "objectIdentifierMatch";
+    public static final String OBJECT_IDENTIFIER_MATCH_MR_OID = "2.5.13.0";
+
+    // distinguishedNameMatch (RFC 4517, chap. 4.2.15)
+    public static final String DISTINGUISHED_NAME_MATCH_MR = "distinguishedNameMatch";
+    public static final String DISTINGUISHED_NAME_MATCH_MR_OID = "2.5.13.1";
+
+    // caseIgnoreMatch (RFC 4517, chap. 3.3.19)
+    public static final String CASE_IGNORE_MATCH_MR = "caseIgnoreMatch";
+    public static final String CASE_IGNORE_MATCH_MR_OID = "2.5.13.2";
+
+    // caseIgnoreOrderingMatch (RFC 4517, chap. 4.2.12)
+    public static final String CASE_IGNORE_ORDERING_MATCH_MR = "caseIgnoreOrderingMatch";
+    public static final String CASE_IGNORE_ORDERING_MATCH_MR_OID = "2.5.13.3";
+
+    // caseIgnoreSubstringsMatch (RFC 4517, chap. 4.2.13)
+    public static final String CASE_IGNORE_SUBSTRING_MATCH_MR = "caseIgnoreSubstringsMatch";
+    public static final String CASE_IGNORE_SUBSTRING_MATCH_MR_OID = "2.5.13.4";
+
+    // caseExactMatch (RFC 4517, chap. 4.2.4)
+    public static final String CASE_EXACT_MATCH_MR = "caseExactMatch";
+    public static final String CASE_EXACT_MATCH_MR_OID = "2.5.13.5";
+
+    // caseExactOrderingMatch (RFC 4517, chap. 4.2.5)
+    public static final String CASE_EXACT_ORDERING_MATCH_MR = "caseExactOrderingMatch";
+    public static final String CASE_EXACT_ORDERING_MATCH_MR_OID = "2.5.13.6";
+
+    // caseExactSubstringsMatch (RFC 4517, chap. 4.2.6)
+    public static final String CASE_EXACT_SUBSTRING_MATCH_MR = "caseExactSubstringsMatch";
+    public static final String CASE_EXACT_SUBSTRING_MATCH_MR_OID = "2.5.13.7";
+
+    // numericStringMatch (RFC 4517, chap. 4.2.22)
+    public static final String NUMERIC_STRING_MATCH_MR = "numericStringMatch";
+    public static final String NUMERIC_STRING_MATCH_MR_OID = "2.5.13.8";
+
+    // numericStringOrderingMatch (RFC 4517, chap. 4.2.23)
+    public static final String NUMERIC_STRING_ORDERING_MATCH_MR = "numericStringOrderingMatch";
+    public static final String NUMERIC_STRING_ORDERING_MATCH_MR_OID = "2.5.13.9";
+
+    // numericStringSubstringsMatch (RFC 4517, chap. 4.2.24)
+    public static final String NUMERIC_STRING_SUBSTRINGS_MATCH_MR = "numericStringSubstringsMatch";
+    public static final String NUMERIC_STRING_SUBSTRINGS_MATCH_MR_OID = "2.5.13.10";
+
+    // caseIgnoreListMatch (RFC 4517, chap. 4.2.9)
+    public static final String CASE_IGNORE_LIST_MATCH_MR = "caseIgnoreListMatch";
+    public static final String CASE_IGNORE_LIST_MATCH_MR_OID = "2.5.13.11";
+
+    // caseIgnoreListSubstringsMatch (RFC 4517, chap. 4.2.10)
+    public static final String CASE_IGNORE_LIST_SUBSTRINGS_MATCH_MR = "caseIgnoreListSubstringsMatch";
+    public static final String CASE_IGNORE_LIST_SUBSTRINGS_MATCH_MR_OID = "2.5.13.12";
+
+    // booleanMatch (RFC 4517, chap. 4.2.2)
+    public static final String BOOLEAN_MATCH_MR = "booleanMatch";
+    public static final String BOOLEAN_MATCH_MR_OID = "2.5.13.13";
+
+    // integerMatch (RFC 4517, chap. 4.2.19)
+    public static final String INTEGER_MATCH_MR = "integerMatch";
+    public static final String INTEGER_MATCH_MR_OID = "2.5.13.14";
+
+    // integerOrderingMatch (RFC 4517, chap. 4.2.20)
+    public static final String INTEGER_ORDERING_MATCH_MR = "integerOrderingMatch";
+    public static final String INTEGER_ORDERING_MATCH_MR_OID = "2.5.13.15";
+
+    // bitStringMatch (RFC 4517, chap. 4.2.1)
+    public static final String BIT_STRING_MATCH_MR = "bitStringMatch";
+    public static final String BIT_STRING_MATCH_MR_OID = "2.5.13.16";
+
+    // octetStringMatch (RFC 4517, chap. 4.2.27)
+    public static final String OCTET_STRING_MATCH_MR = "octetStringMatch";
+    public static final String OCTET_STRING_MATCH_MR_OID = "2.5.13.17";
+
+    // octetStringMatch (RFC 4517, chap. 4.2.28)
+    public static final String OCTET_STRING_ORDERING_MATCH_MR = "octetStringOrderingMatch";
+    public static final String OCTET_STRING_ORDERING_MATCH_MR_OID = "2.5.13.18";
+
+    // octetStringSubstringsMatch
+    public static final String OCTET_STRING_SUBSTRINGS_MATCH_MR = "octetStringSubstringsMatch";
+    public static final String OCTET_STRING_SUBSTRINGS_MATCH_MR_OID = "2.5.13.19";
+
+    // telephoneNumberMatch (RFC 4517, chap. 4.2.29)
+    public static final String TELEPHONE_NUMBER_MATCH_MR = "telephoneNumberMatch";
+    public static final String TELEPHONE_NUMBER_MATCH_MR_OID = "2.5.13.20";
+
+    // telephoneNumberMatch (RFC 4517, chap. 4.2.30)
+    public static final String TELEPHONE_NUMBER_SUBSTRINGS_MATCH_MR = "telephoneNumberSubstringsMatch";
+    public static final String TELEPHONE_NUMBER_SUBSTRINGS_MATCH_MR_OID = "2.5.13.21";
+
+    // presentationAddressMatch Removed in RFC 4517
+    public static final String PRESENTATION_ADDRESS_MATCH_MATCH_MR = "presentationAddressMatch";
+    public static final String PRESENTATION_ADDRESS_MATCH_MATCH_MR_OID = "2.5.13.22";
+
+    // uniqueMemberMatch (RFC 4517, chap. 4.2.31)
+    public static final String UNIQUE_MEMBER_MATCH_MR = "uniqueMemberMatch";
+    public static final String UNIQUE_MEMBER_MATCH_MR_OID = "2.5.13.23";
+
+    // protocolInformationMatch Removed in RFC 4517
+    public static final String PROTOCOL_INFORMATION_MATCH_MR = "protocolInformationMatch";
+    public static final String PROTOCOL_INFORMATION_MATCH_MR_OID = "2.5.13.24";
+
+    // "2.5.13.25" is not used ...
+    // "2.5.13.26" is not used ...
+
+    // generalizedTimeMatch (RFC 4517, chap. 4.2.16)
+    public static final String GENERALIZED_TIME_MATCH_MR = "generalizedTimeMatch";
+    public static final String GENERALIZED_TIME_MATCH_MR_OID = "2.5.13.27";
+
+    // generalizedTimeOrderingMatch (RFC 4517, chap. 4.2.17)
+    public static final String GENERALIZED_TIME_ORDERING_MATCH_MR = "generalizedTimeOrderingMatch";
+    public static final String GENERALIZED_TIME_ORDERING_MATCH_MR_OID = "2.5.13.28";
+
+    // integerFirstComponentMatch (RFC 4517, chap. 4.2.18)
+    public static final String INTEGER_FIRST_COMPONENT_MATCH_MR = "integerFirstComponentMatch";
+    public static final String INTEGER_FIRST_COMPONENT_MATCH_MR_OID = "2.5.13.29";
+
+    // objectIdentifierFirstComponentMatch (RFC 4517, chap. 4.2.25)
+    public static final String OBJECT_IDENTIFIER_FIRST_COMPONENT_MATCH_MR = "objectIdentifierFirstComponentMatch";
+    public static final String OBJECT_IDENTIFIER_FIRST_COMPONENT_MATCH_MR_OID = "2.5.13.30";
+
+    // directoryStringFirstComponentMatch (RFC 4517, chap. 4.2.14)
+    public static final String DIRECTORY_STRING_FIRST_COMPONENT_MATCH_MR = "directoryStringFirstComponentMatch";
+    public static final String DIRECTORY_STRING_FIRST_COMPONENT_MATCH_MR_OID = "2.5.13.31";
+
+    // wordMatch (RFC 4517, chap. 4.2.32)
+    public static final String WORD_MATCH_MR = "wordMatch";
+    public static final String WORD_MATCH_MR_OID = "2.5.13.32";
+
+    // keywordMatch (RFC 4517, chap. 4.2.21)
+    public static final String KEYWORD_MATCH_MR = "keywordMatch";
+    public static final String KEYWORD_MATCH_MR_OID = "2.5.13.33";
+
+    // uuidMatch
+    public static final String UUID_MATCH_MR = "uuidMatch";
+    public static final String UUID_MATCH_MR_OID = "1.3.6.1.1.16.2";
+
+    // uuidOrderingMatch
+    public static final String UUID_ORDERING_MATCH_MR = "uuidOrderingMatch";
+    public static final String UUID_ORDERING_MATCH_MR_OID = "1.3.6.1.1.16.3";
+
+    // csnMatch
+    public static final String CSN_MATCH_MR = "csnMatch";
+    public static final String CSN_MATCH_MR_OID = "1.3.6.1.4.1.4203.666.11.2.2";
+
+    // csnOrderingMatch
+    public static final String CSN_ORDERING_MATCH_MR = "csnOrderingMatch";
+    public static final String CSN_ORDERING_MATCH_MR_OID = "1.3.6.1.4.1.4203.666.11.2.3";
+
+    // csnSidMatch
+    public static final String CSN_SID_MATCH_MR = "csnSidMatch";
+    public static final String CSN_SID_MATCH_MR_OID = "1.3.6.1.4.1.4203.666.11.2.5";
+
+    // nameOrNumericIdMatch
+    public static final String NAME_OR_NUMERIC_ID_MATCH = "nameOrNumericIdMatch";
+    public static final String NAME_OR_NUMERIC_ID_MATCH_OID = "1.3.6.1.4.1.18060.0.4.0.1.0";
+
+    // objectClassTypeMatch
+    public static final String OBJECT_CLASS_TYPE_MATCH = "objectClassTypeMatch";
+    public static final String OBJECT_CLASS_TYPE_MATCH_OID = "1.3.6.1.4.1.18060.0.4.0.1.1";
+
+    // numericOidMatch
+    public static final String NUMERIC_OID_MATCH = "numericOidMatch";
+    public static final String NUMERIC_OID_MATCH_OID = "1.3.6.1.4.1.18060.0.4.0.1.2";
+
+    // supDITStructureRuleMatch
+    public static final String SUP_DIT_STRUCTURE_RULE_MATCH = "supDITStructureRuleMatch";
+    public static final String SUP_DIT_STRUCTURE_RULE_MATCH_OID = "1.3.6.1.4.1.18060.0.4.0.1.3";
+
+    // ruleIDMatch
+    public static final String RULE_ID_MATCH = "ruleIDMatch";
+    public static final String RULE_ID_MATCH_OID = "1.3.6.1.4.1.18060.0.4.0.1.4";
+
+    // ExactDnAsStringMatch
+    public static final String EXACT_DN_AS_STRING_MATCH_MR = "exactDnAsStringMatch";
+    public static final String EXACT_DN_AS_STRING_MATCH_MR_OID = "1.3.6.1.4.1.18060.0.4.1.1.1";
+
+    // BigIntegerMatch
+    public static final String BIG_INTEGER_MATCH_MR = "bigIntegerMatch";
+    public static final String BIG_INTEGER_MATCH_MR_OID = "1.3.6.1.4.1.18060.0.4.1.1.2";
+
+    // JdbmStringMatch
+    public static final String JDBM_STRING_MATCH_MR = "jdbmStringMatch";
+    public static final String JDBM_STRING_MATCH_MR_OID = "1.3.6.1.4.1.18060.0.4.1.1.3";
+
+    // ComparatorMatch
+    public static final String COMPARATOR_MATCH_MR = "comparatorMatch";
+    public static final String COMPARATOR_MATCH_MR_OID = "1.3.6.1.4.1.18060.0.4.1.1.5";
+
+    // NormalizerMatch
+    public static final String NORMALIZER_MATCH_MR = "normalizerMatch";
+    public static final String NORMALIZER_MATCH_MR_OID = "1.3.6.1.4.1.18060.0.4.1.1.6";
+
+    // SyntaxCheckerMatch
+    public static final String SYNTAX_CHECKER_MATCH_MR = "syntaxCheckerMatch";
+    public static final String SYNTAX_CHECKER_MATCH_MR_OID = "1.3.6.1.4.1.18060.0.4.1.1.7";
+
+    // ---- Features ----------------------------------------------------------
+    public static final String FEATURE_ALL_OPERATIONAL_ATTRIBUTES = "1.3.6.1.4.1.4203.1.5.1";
+
+    // ----Administrative roles -----------------------------------------------
+    // AutonomousArea
+    public static final String AUTONOMOUS_AREA = "autonomousArea";
+    public static final String AUTONOMOUS_AREA_OID = "2.5.23.1";
+
+    // AccessControlSpecificArea
+    public static final String ACCESS_CONTROL_SPECIFIC_AREA = "accessControlSpecificArea";
+    public static final String ACCESS_CONTROL_SPECIFIC_AREA_OID = "2.5.23.2";
+
+    // AccessControlInnerArea
+    public static final String ACCESS_CONTROL_INNER_AREA = "accessControlInnerArea";
+    public static final String ACCESS_CONTROL_INNER_AREA_OID = "2.5.23.3";
+
+    // SubSchemaAdminSpecificArea
+    public static final String SUB_SCHEMA_ADMIN_SPECIFIC_AREA = "subSchemaSpecificArea";
+    public static final String SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID = "2.5.23.4";
+
+    // CollectiveAttributeSpecificArea
+    public static final String COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA = "collectiveAttributeSpecificArea";
+    public static final String COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID = "2.5.23.5";
+
+    // CollectiveAttributeInnerArea
+    public static final String COLLECTIVE_ATTRIBUTE_INNER_AREA = "collectiveAttributeInnerArea";
+    public static final String COLLECTIVE_ATTRIBUTE_INNER_AREA_OID = "2.5.23.6";
+
+    // TriggerExecutionSpecificArea
+    public static final String TRIGGER_EXECUTION_SPECIFIC_AREA = "triggerExecutionSpecificArea";
+    public static final String TRIGGER_EXECUTION_SPECIFIC_AREA_OID = "1.3.6.1.4.1.18060.0.4.1.6.1";
+
+    // TriggerExecutionInnerArea
+    public static final String TRIGGER_EXECUTION_INNER_AREA = "triggerExecutionInnerArea";
+    public static final String TRIGGER_EXECUTION_INNER_AREA_OID = "1.3.6.1.4.1.18060.0.4.1.6.2";
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SupportedSaslMechanisms.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SupportedSaslMechanisms.java
new file mode 100644
index 0000000..48eeed9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/constants/SupportedSaslMechanisms.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.constants;
+
+
+/**
+ * Contains constants used for populating the supportedSASLMechanisms 
+ * in the RootDSE.
+ * Final reference -> class shouldn't be extended
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SupportedSaslMechanisms
+{
+    /**
+     *  Ensures no construction of this class, also ensures there is no need for final keyword above
+     *  (Implicit super constructor is not visible for default constructor),
+     *  but is still self documenting.
+     */
+    private SupportedSaslMechanisms()
+    {
+    }
+
+    /** CRAM-MD5 mechanism */
+    public static final String CRAM_MD5 = "CRAM-MD5";
+
+    /** DIGEST_MD5-MD5 mechanism */
+    public static final String DIGEST_MD5 = "DIGEST-MD5";
+
+    /** GSSAPI mechanism */
+    public static final String GSSAPI = "GSSAPI";
+
+    /** PLAIN mechanism */
+    public static final String PLAIN = "PLAIN";
+
+    /** Not a SASL JDK supported mechanism */
+    public static final String NTLM = "NTLM";
+
+    /** Not a SASL JDK supported mechanism */
+    public static final String GSS_SPNEGO = "GSS-SPNEGO";
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/Csn.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/Csn.java
new file mode 100644
index 0000000..21818f6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/Csn.java
@@ -0,0 +1,745 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.csn;
+
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Represents 'Change Sequence Number' in LDUP specification.
+ * 
+ * A CSN is a composition of a timestamp, a replica ID and a 
+ * operation sequence number.
+ * 
+ * It's described in http://tools.ietf.org/html/draft-ietf-ldup-model-09.
+ * 
+ * The CSN syntax is :
+ * <pre>
+ * <CSN>            ::= <timestamp> # <changeCount> # <replicaId> # <modifierNumber>
+ * <timestamp>      ::= A GMT based time, YYYYmmddHHMMSS.uuuuuuZ
+ * <changeCount>    ::= [000000-ffffff] 
+ * <replicaId>      ::= [000-fff]
+ * <modifierNumber> ::= [000000-ffffff]
+ * </pre>
+ *  
+ * It distinguishes a change made on an object on a server,
+ * and if two operations take place during the same timeStamp,
+ * the operation sequence number makes those operations distinct.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Csn implements Comparable<Csn>
+{
+    /** The logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( Csn.class );
+
+    /** The timeStamp of this operation */
+    private final long timestamp;
+
+    /** The server identification */
+    private final int replicaId;
+
+    /** The operation number in a modification operation */
+    private final int operationNumber;
+
+    /** The changeCount to distinguish operations done in the same second */
+    private final int changeCount;
+
+    /** Stores the String representation of the CSN */
+    private String csnStr;
+
+    /** Stores the byte array representation of the CSN */
+    private byte[] bytes;
+
+    /** The Timestamp syntax. The last 'z' is _not_ the Time Zone */
+    private static final SimpleDateFormat SDF = new SimpleDateFormat( "yyyyMMddHHmmss" );
+
+    private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
+
+    // Initialize the dateFormat with the UTC TZ
+    static
+    {
+        SDF.setTimeZone( UTC_TIME_ZONE );
+    }
+
+    /** Padding used to format number with a fixed size */
+    private static final String[] PADDING_6 = new String[]
+        { "00000", "0000", "000", "00", "0", "" };
+
+    /** Padding used to format number with a fixed size */
+    private static final String[] PADDING_3 = new String[]
+        { "00", "0", "" };
+
+
+    /**
+     * Creates a new instance.
+     * <b>This method should be used only for deserializing a CSN</b> 
+     * 
+     * @param timestamp GMT timestamp of modification
+     * @param changeCount The operation increment
+     * @param replicaId Replica ID where modification occurred (<tt>[-_A-Za-z0-9]{1,16}</tt>)
+     * @param operationNumber Operation number in a modification operation
+     */
+    public Csn( long timestamp, int changeCount, int replicaId, int operationNumber )
+    {
+        this.timestamp = timestamp;
+        this.replicaId = replicaId;
+        this.operationNumber = operationNumber;
+        this.changeCount = changeCount;
+    }
+
+
+    /**
+     * Creates a new instance of SimpleCSN from a String.
+     * 
+     * The string format must be :
+     * &lt;timestamp> # &lt;changeCount> # &lt;replica ID> # &lt;operation number>
+     *
+     * @param value The String containing the CSN
+     * @throws InvalidCSNException if the value doesn't contain a valid CSN
+     */
+    public Csn( String value ) throws InvalidCSNException
+    {
+        if ( Strings.isEmpty( value ) )
+        {
+            String message = I18n.err( I18n.ERR_04114 );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        if ( value.length() != 40 )
+        {
+            String message = I18n.err( I18n.ERR_04115 );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        // Get the Timestamp
+        int sepTS = value.indexOf( '#' );
+
+        if ( sepTS < 0 )
+        {
+            String message = I18n.err( I18n.ERR_04116 );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        String timestampStr = value.substring( 0, sepTS ).trim();
+
+        if ( timestampStr.length() != 22 )
+        {
+            String message = I18n.err( I18n.ERR_04117 );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        // Let's transform the Timestamp by removing the mulliseconds and microseconds
+        String realTimestamp = timestampStr.substring( 0, 14 );
+
+        long tempTimestamp = 0L;
+
+        synchronized ( SDF )
+        {
+            try
+            {
+                tempTimestamp = SDF.parse( realTimestamp ).getTime();
+            }
+            catch ( ParseException pe )
+            {
+                String message = I18n.err( I18n.ERR_04118, timestampStr );
+                LOG.error( message );
+                throw new InvalidCSNException( message, pe );
+            }
+        }
+
+        int millis = 0;
+
+        // And add the milliseconds and microseconds now
+        try
+        {
+            millis = Integer.valueOf( timestampStr.substring( 15, 21 ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            String message = I18n.err( I18n.ERR_04119 );
+            LOG.error( message );
+            throw new InvalidCSNException( message, nfe );
+        }
+
+        tempTimestamp += ( millis / 1000 );
+        timestamp = tempTimestamp;
+
+        // Get the changeCount. It should be an hex number prefixed with '0x'
+        int sepCC = value.indexOf( '#', sepTS + 1 );
+
+        if ( sepCC < 0 )
+        {
+            String message = I18n.err( I18n.ERR_04110, value );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        String changeCountStr = value.substring( sepTS + 1, sepCC ).trim();
+
+        try
+        {
+            changeCount = Integer.parseInt( changeCountStr, 16 );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            String message = I18n.err( I18n.ERR_04121, changeCountStr );
+            LOG.error( message );
+            throw new InvalidCSNException( message, nfe );
+        }
+
+        // Get the replicaID
+        int sepRI = value.indexOf( '#', sepCC + 1 );
+
+        if ( sepRI < 0 )
+        {
+            String message = I18n.err( I18n.ERR_04122, value );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        String replicaIdStr = value.substring( sepCC + 1, sepRI ).trim();
+
+        if ( Strings.isEmpty( replicaIdStr ) )
+        {
+            String message = I18n.err( I18n.ERR_04123 );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        try
+        {
+            replicaId = Integer.parseInt( replicaIdStr, 16 );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            String message = I18n.err( I18n.ERR_04124, replicaIdStr );
+            LOG.error( message );
+            throw new InvalidCSNException( message, nfe );
+        }
+
+        // Get the modification number
+        if ( sepCC == value.length() )
+        {
+            String message = I18n.err( I18n.ERR_04125 );
+            LOG.error( message );
+            throw new InvalidCSNException( message );
+        }
+
+        String operationNumberStr = value.substring( sepRI + 1 ).trim();
+
+        try
+        {
+            operationNumber = Integer.parseInt( operationNumberStr, 16 );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            String message = I18n.err( I18n.ERR_04126, operationNumberStr );
+            LOG.error( message );
+            throw new InvalidCSNException( message, nfe );
+        }
+
+        csnStr = value;
+        bytes = Strings.getBytesUtf8( csnStr );
+    }
+
+    
+    /**
+     * Check if the given String is a valid CSN.
+     * 
+     * @param value The String to check
+     * @return <code>true</code> if the String is a valid CSN
+     */
+    public static boolean isValid( String value )
+    {
+        if ( Strings.isEmpty( value ) )
+        {
+            return false;
+        }
+
+        char[] chars = value.toCharArray();
+        
+        if ( chars.length != 40 )
+        {
+            return false;
+        }
+
+        // Get the Timestamp
+        // Check the timestamp's year
+        for ( int pos = 0; pos < 4; pos++ )
+        {
+            if ( !Chars.isDigit( chars[pos] ) )
+            {
+                return false;
+            }
+        }
+        
+        // Check the timestamp month
+        switch ( chars[4] )
+        {
+            case '0' :
+                if ( !Chars.isDigit( chars[5] ) )
+                {
+                    return false;
+                }
+                
+                if ( chars[5] == '0' )
+                {
+                    return false;
+                }
+                
+                break;
+                
+            case '1' :
+                if ( ( chars[5] != '0' ) && ( chars[5] != '1' ) && ( chars[5] != '2' ) )
+                {
+                    return false;
+                }
+                
+                break;
+                
+            default :
+                return false;
+        }
+
+        // Check the timestamp day
+        switch ( chars[6] )
+        {
+            case '0' :
+                if ( !Chars.isDigit( chars[7] ) )
+                {
+                    return false;
+                }
+                
+                if ( chars[7] == '0' )
+                {
+                    return false;
+                }
+                
+                break;
+                
+            case '1' :
+                if ( !Chars.isDigit( chars[7] ) )
+                {
+                    return false;
+                }
+                
+                break;
+                
+            case '2' :
+                if ( !Chars.isDigit( chars[7] ) )
+                {
+                    return false;
+                }
+                
+                // Special case for february...
+                break;
+                
+            case '3' :
+                // Deal with 30 days months
+                if ( ( chars[7] != '0' ) && ( chars[7] != '1' ) )
+                {
+                    return false;
+                }
+                
+                break;
+                
+            default :
+                return false;
+        }
+
+        // Check the timestamp hour
+        switch ( chars[8] )
+        {
+            case '0' :
+            case '1' :
+                if ( !Chars.isDigit( chars[9] ) )
+                {
+                    return false;
+                }
+
+                break;
+                
+            case '2' :
+                if ( ( chars[9] != '0' ) && ( chars[9] != '1' ) && ( chars[9] != '2' ) && ( chars[9] != '3' ) )
+                {
+                    return false;
+                }
+                
+                break;
+                
+            default :
+                return false;
+        }
+
+        // Check the timestamp minute
+        switch ( chars[10] )
+        {
+            case '0' :
+            case '1' :
+            case '2' :
+            case '3' :
+            case '4' :
+            case '5' :
+                break;
+                
+            default :
+                return false;
+        }
+        
+        if ( !Chars.isDigit( chars[11] ) )
+        {
+            return false;
+        }
+        
+        // Check the timestamp seconds
+        switch ( chars[12] )
+        {
+            case '0' :
+            case '1' :
+            case '2' :
+            case '3' :
+            case '4' :
+            case '5' :
+                break;
+                
+            default :
+                return false;
+        }
+        
+        if ( !Chars.isDigit( chars[13] ) )
+        {
+            return false;
+        }
+
+        // Check the milliseconds
+        if ( chars[14] != '.' )
+        {
+            return false;
+        }
+
+        for ( int i = 0; i < 6; i++ )
+        {
+            if ( !Chars.isDigit( chars[15 + i] ) )
+            {
+                return false;
+            }
+        }
+
+        if ( chars[21] != 'Z' )
+        {
+            return false;
+        }
+
+        if ( chars[22] != '#' )
+        {
+            return false;
+        }
+
+        // Get the changeCount. It should be an 6 digit hex number
+        if ( !Chars.isHex( ( byte ) chars[23] )
+            || !Chars.isHex( ( byte ) chars[24] )
+            || !Chars.isHex( ( byte ) chars[25] )
+            || !Chars.isHex( ( byte ) chars[26] )
+            || !Chars.isHex( ( byte ) chars[27] )
+            || !Chars.isHex( ( byte ) chars[28] ) )
+        {
+            return false;
+        }
+
+        if ( chars[29] != '#' )
+        {
+            return false;
+        }
+        
+        // Get the replicaID, which should be a 3 digits hex number
+        if ( !Chars.isHex( ( byte ) chars[30] )
+            || !Chars.isHex( ( byte ) chars[31] )
+            || !Chars.isHex( ( byte ) chars[32] ) )
+        {
+            return false;
+        }
+
+        if ( chars[33] != '#' )
+        {
+            return false;
+        }
+
+        // Check the modification number, which should be a 6 digits hex number
+        if ( !Chars.isHex( ( byte ) chars[34] )
+            || !Chars.isHex( ( byte ) chars[35] )
+            || !Chars.isHex( ( byte ) chars[36] )
+            || !Chars.isHex( ( byte ) chars[37] )
+            || !Chars.isHex( ( byte ) chars[38] )
+            || !Chars.isHex( ( byte ) chars[39] ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Creates a new instance of SimpleCSN from the serialized data
+     *
+     * @param value The byte array which contains the serialized CSN
+     */
+    Csn( byte[] value )
+    {
+        csnStr = Strings.utf8ToString( value );
+        Csn csn = new Csn( csnStr );
+        timestamp = csn.timestamp;
+        changeCount = csn.changeCount;
+        replicaId = csn.replicaId;
+        operationNumber = csn.operationNumber;
+        bytes = Strings.getBytesUtf8( csnStr );
+    }
+
+
+    /**
+     * Get the CSN as a byte array. The data are stored as :
+     * bytes 1 to 8  : timestamp, big-endian
+     * bytes 9 to 12 : change count, big endian
+     * bytes 13 to ... : ReplicaId 
+     * 
+     * @return A copy of the byte array representing theCSN
+     */
+    public byte[] getBytes()
+    {
+        if ( bytes == null )
+        {
+            bytes = Strings.getBytesUtf8( csnStr );
+        }
+
+        byte[] copy = new byte[bytes.length];
+        System.arraycopy( bytes, 0, copy, 0, bytes.length );
+        return copy;
+    }
+
+
+    /**
+     * @return The timestamp
+     */
+    public long getTimestamp()
+    {
+        return timestamp;
+    }
+
+
+    /**
+     * @return The changeCount
+     */
+    public int getChangeCount()
+    {
+        return changeCount;
+    }
+
+
+    /**
+     * @return The replicaId
+     */
+    public int getReplicaId()
+    {
+        return replicaId;
+    }
+
+
+    /**
+     * @return The operation number
+     */
+    public int getOperationNumber()
+    {
+        return operationNumber;
+    }
+
+
+    /**
+     * @return The CSN as a String
+     */
+    public String toString()
+    {
+        if ( csnStr == null )
+        {
+            StringBuilder buf = new StringBuilder( 40 );
+
+            synchronized ( SDF )
+            {
+                buf.append( SDF.format( new Date( timestamp ) ) );
+            }
+
+            // Add the milliseconds part
+            long millis = ( timestamp % 1000 ) * 1000;
+            String millisStr = Long.toString( millis );
+
+            buf.append( '.' ).append( PADDING_6[millisStr.length() - 1] ).append( millisStr ).append( "Z#" );
+
+            String countStr = Integer.toHexString( changeCount );
+
+            buf.append( PADDING_6[countStr.length() - 1] ).append( countStr );
+            buf.append( '#' );
+
+            String replicaIdStr = Integer.toHexString( replicaId );
+
+            buf.append( PADDING_3[replicaIdStr.length() - 1] ).append( replicaIdStr );
+            buf.append( '#' );
+
+            String operationNumberStr = Integer.toHexString( operationNumber );
+
+            buf.append( PADDING_6[operationNumberStr.length() - 1] ).append( operationNumberStr );
+
+            csnStr = buf.toString();
+        }
+
+        return csnStr;
+    }
+
+
+    /**
+     * Returns a hash code value for the object.
+     * 
+     * @return a hash code value for this object.
+     */
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + ( int ) ( timestamp ^ ( timestamp >>> 32 ) );
+        h = h * 17 + changeCount;
+        h = h * 17 + replicaId;
+        h = h * 17 + operationNumber;
+
+        return h;
+    }
+
+
+    /**
+     * Indicates whether some other object is "equal to" this one
+     * 
+     * @param o the reference object with which to compare.
+     * @return <code>true</code> if this object is the same as the obj argument; 
+     * <code>false</code> otherwise.
+     */
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof Csn ) )
+        {
+            return false;
+        }
+
+        Csn that = ( Csn ) o;
+
+        return ( timestamp == that.timestamp ) && ( changeCount == that.changeCount )
+            && ( replicaId == that.replicaId ) && ( operationNumber == that.operationNumber );
+    }
+
+
+    /**
+     * Compares this object with the specified object for order.  Returns a
+     * negative integer, zero, or a positive integer as this object is less
+     * than, equal to, or greater than the specified object.<p>
+     * 
+     * @param   csn the Object to be compared.
+     * @return  a negative integer, zero, or a positive integer as this object
+     *      is less than, equal to, or greater than the specified object.
+     */
+    public int compareTo( Csn csn )
+    {
+        if ( csn == null )
+        {
+            return 1;
+        }
+
+        // Compares the timestamp first
+        if ( this.timestamp < csn.timestamp )
+        {
+            return -1;
+        }
+        else if ( this.timestamp > csn.timestamp )
+        {
+            return 1;
+        }
+
+        // Then the change count
+        if ( this.changeCount < csn.changeCount )
+        {
+            return -1;
+        }
+        else if ( this.changeCount > csn.changeCount )
+        {
+            return 1;
+        }
+
+        // Then the replicaId
+        int replicaIdCompareResult = getReplicaIdCompareResult( csn );
+
+        if ( replicaIdCompareResult != 0 )
+        {
+            return replicaIdCompareResult;
+        }
+
+        // Last, not least, compares the operation number
+        if ( this.operationNumber < csn.operationNumber )
+        {
+            return -1;
+        }
+        else if ( this.operationNumber > csn.operationNumber )
+        {
+            return 1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+
+
+    private int getReplicaIdCompareResult( Csn csn )
+    {
+        if ( this.replicaId < csn.replicaId )
+        {
+            return -1;
+        }
+        if ( this.replicaId > csn.replicaId )
+        {
+            return 1;
+        }
+        return 0;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/CsnFactory.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/CsnFactory.java
new file mode 100644
index 0000000..dfd9bc2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/CsnFactory.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.csn;
+
+
+/**
+ * Generates a new {@link Csn}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CsnFactory
+{
+    /** The last timestamp */
+    private static volatile long lastTimestamp;
+
+    /** The integer used to disambiguate CSN generated at the same time */
+    private int changeCount;
+
+    /** The replicaId to use for every CSN created by this factory */
+    private int replicaId;
+
+    /** A special instance ID for a purge CSN */
+    private static final int PURGE_INSTANCEID = 0x0FFF;
+
+    /** A lock used during the instance creation */
+    private Object lock = new Object();
+
+
+    public CsnFactory( int replicaId )
+    {
+        changeCount = 0;
+        this.replicaId = replicaId;
+    }
+
+
+    /**
+     * Returns a new {@link Csn}.
+     * Generated CSN can be duplicate if user generates CSNs more than 2G 
+     * times a milliseconds.
+     */
+    public Csn newInstance()
+    {
+        int tmpChangeCount = 0;
+
+        synchronized ( lock )
+        {
+            long newTimestamp = System.currentTimeMillis();
+
+            // We will be able to generate 2 147 483 647 CSNs each 10 ms max
+            if ( lastTimestamp == newTimestamp )
+            {
+                changeCount++;
+            }
+            else
+            {
+                lastTimestamp = newTimestamp;
+                changeCount = 0;
+            }
+
+            tmpChangeCount = changeCount;
+        }
+
+        return new Csn( lastTimestamp, tmpChangeCount, replicaId, 0 );
+    }
+
+
+    /**
+     * Returns a new {@link Csn} created from the given values.
+     * 
+     * This method is <b>not</b> to be used except for test purposes.
+     * 
+     * @param timestamp The timestamp to use
+     * @param changeCount The change count to use
+     */
+    public Csn newInstance( long timestamp, int changeCount )
+    {
+        return new Csn( timestamp, changeCount, replicaId, 0 );
+    }
+
+
+    /**
+     * Generates a CSN used to purge data. Its replicaID is not associated
+     * to a server. 
+     * 
+     * @param expirationDate The time up to the first CSN we want to keep 
+     */
+    public Csn newPurgeCsn( long expirationDate )
+    {
+        return new Csn( expirationDate, Integer.MAX_VALUE, PURGE_INSTANCEID, Integer.MAX_VALUE );
+    }
+
+
+    public void setReplicaId( int replicaId )
+    {
+        this.replicaId = replicaId;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/InvalidCSNException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/InvalidCSNException.java
new file mode 100644
index 0000000..0a5af7a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/csn/InvalidCSNException.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.csn;
+
+
+/**
+ * A {@link RuntimeException} which is thrown when a wrong string
+ * representation is specified to create a new {@link Csn}.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InvalidCSNException extends RuntimeException
+{
+    /**
+     * Declares the Serial Version Uid.
+     *
+     * @see <a
+     *      href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
+     *      Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance.
+     */
+    public InvalidCSNException()
+    {
+        super();
+    }
+
+
+    /**
+     * Creates a new instance with the specified <tt>message</tt> and
+     * <tt>cause</tt>.
+     */
+    public InvalidCSNException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+
+    /**
+     * Creates a new instance with the specified <tt>message</tt>.
+     */
+    public InvalidCSNException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a new instance with the specified <tt>cause</tt>.
+     */
+    public InvalidCSNException( Throwable cause )
+    {
+        super( cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/AbstractCursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/AbstractCursor.java
new file mode 100755
index 0000000..5bebd82
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/AbstractCursor.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Simple class that contains often used Cursor code.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E> The type of element on which this cursor will iterate
+ */
+public abstract class AbstractCursor<E> implements Cursor<E>
+{
+    /** The default associated monitor */
+    private ClosureMonitor monitor = new DefaultClosureMonitor();
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setClosureMonitor( ClosureMonitor monitor )
+    {
+        if ( monitor == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_02001_MONITOR ) );
+        }
+
+        this.monitor = monitor;
+    }
+
+
+    /**
+     * Check that the cursor is not closed before executing an operation.
+     * 
+     * @param operation The operation we try to execute
+     * @throws CursorClosedException If there is a problem during the check
+     */
+    public final void checkNotClosed( String operation ) throws CursorClosedException
+    {
+        monitor.checkNotClosed();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isClosed()
+    {
+        return monitor.isClosed();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close( Exception cause )
+    {
+        monitor.close( cause );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close()
+    {
+        monitor.close();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<E> iterator()
+    {
+        return new CursorIterator<E>( this );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAfterLast()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "isAfterLast()" ) ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isBeforeFirst()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "isBeforeFirst()" ) ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isFirst()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "isFirst()" ) ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isLast()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
+            .concat( "." ).concat( "isLast()" ) ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString( String tabs )
+    {
+        return tabs;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/ClosureMonitor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/ClosureMonitor.java
new file mode 100644
index 0000000..ee6365a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/ClosureMonitor.java
@@ -0,0 +1,80 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * A monitor used by Cursors to detect conditions when they should stop 
+ * performing some work during advance operations such as next(), previous(),
+ * first() etc, and release resources.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ClosureMonitor
+{
+    /**
+     * Sets monitor state to closed, and sets the cause to a 
+     * CursorClosedException without an error message string.
+     */
+    void close();
+
+
+    /**
+     * Sets monitor state to closed, and sets the cause to a 
+     * CursorClosedException with a specific error message string.
+     * 
+     * @param cause error message string
+     */
+    void close( String cause );
+
+
+    /**
+     * Sets monitor state to closed, and sets the cause to a specific 
+     * Exception.
+     * 
+     * @param cause the exception to associate with the closure
+     */
+    void close( Exception cause );
+
+
+    /**
+     * Gets whether the state of this ClosureMonitor is set to closed.
+     *
+     * @return true if state is closed, false if open
+     */
+    boolean isClosed();
+
+
+    /**
+     * Checks if state of this ClosureMonitor is set to closed and if so, 
+     * throws the causing Exception.
+     *
+     * @throws CursorClosedException the cause of the closure
+     */
+    void checkNotClosed() throws CursorClosedException;
+
+
+    /**
+     * Gets the cause of the closure.
+     *
+     * @return the causing Exception
+     */
+    Exception getCause();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/Cursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/Cursor.java
new file mode 100644
index 0000000..66e5924
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/Cursor.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * A Cursor for bidirectional traversal over elements in a dataSet. Cursors
+ * unlike Iterators or Enumerations may advance to an element by calling
+ * next() or previous() which returns true or false if the request succeeds
+ * with a viable element at the new position.  Operations for relative
+ * positioning in larger increments are provided.  If the cursor can not
+ * advance, then the Cursor is either positioned before the first element or
+ * after the last element in which case the user of the Cursor must stop
+ * advancing in the respective direction.  If an advance succeeds a get()
+ * operation retrieves the current object at the Cursors position.
+ *
+ * Although this interface presumes Cursors can advance bidirectionally,
+ * implementations may restrict this by throwing
+ * UnsupportedOperationExceptions.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E> The type of element on which this cursor will iterate
+ */
+public interface Cursor<E> extends Iterable<E>
+{
+    /**
+     * Determines whether or not a call to get() will succeed.
+     *
+     * @return true if a call to the get() method will succeed, false otherwise
+     */
+    boolean available();
+
+
+    /**
+     * Prepares this Cursor, so a subsequent call to Cursor#next() with a
+     * true return value, will have positioned the Cursor on a dataSet 
+     * element equal to or less than the element argument but not greater.  
+     * A call to Cursor#previous() with a true return value will position 
+     * the Cursor on a dataSet element less than the argument.  If 
+     * Cursor#next() returns false then the Cursor is past the last element 
+     * and so all values in the dataSet are less than the argument.  If 
+     * Cursor#previous() returns false then the Cursor is positioned before 
+     * the first element and all elements in the dataSet are greater than 
+     * the argument.
+     *
+     * @param element the element to be positioned before
+     * @throws Exception with problems accessing the underlying btree
+     */
+    void before( E element ) throws LdapException, CursorException;
+
+
+    /**
+     * Prepares this Cursor, so a subsequent call to Cursor#previous() with a
+     * true return value, will have positioned the Cursor on a dataSet element
+     * equal to or less than the element argument but not greater. A call to
+     * Cursor#next() with a true return value will position the Cursor on a
+     * dataSet element greater than the argument.  If Cursor#next() returns
+     * false then the Cursor is past the last element and so all values in the
+     * dataSet are less than or equal to the argument.  If Cursor#previous()
+     * returns false then the Cursor is positioned before the first element
+     * and all elements in the dataSet are greater than the argument.
+     *
+     * @param element the element to be positioned after
+     * @throws Exception if there are problems positioning this cursor or if
+     * this Cursor is closed
+     */
+    void after( E element ) throws LdapException, CursorException;
+
+
+    /**
+     * Positions this Cursor before the first element.
+     *
+     * @throws Exception if there are problems positioning this cursor or if
+     * this Cursor is closed
+     */
+    void beforeFirst() throws LdapException, CursorException;
+
+
+    /**
+     * Positions this Cursor after the last element.
+     *
+     * @throws Exception if there are problems positioning this Cursor or if
+     * this Cursor is closed
+     */
+    void afterLast() throws LdapException, CursorException;
+
+
+    /**
+     * Positions this Cursor at the first element.
+     *
+     * @return true if the position has been successfully changed to the first
+     * element, false otherwise
+     * @throws Exception if there are problems positioning this Cursor or if
+     * this Cursor is closed
+     */
+    boolean first() throws LdapException, CursorException;
+
+
+    /**
+     * Is this Cursor positioned at the first element.
+     *
+     * @return true if this cursor is positioned at the first element, 
+     * false otherwise
+     * @throws Exception if there are problems querying the position of this Cursor
+     * or if this Cursor is closed
+     */
+    boolean isFirst();
+
+
+    /**
+     * Is this Cursor positioned before the first element.
+     *
+     * @return true if this cursor is positioned before the first element, 
+     * false otherwise
+     * @throws Exception if there are problems querying the position of this Cursor
+     * or if this Cursor is closed
+     */
+    boolean isBeforeFirst();
+
+
+    /**
+     * Positions this Cursor at the last element.
+     *
+     * @return true if the position has been successfully changed to the last
+     * element, false otherwise
+     * @throws Exception if there are problems positioning this Cursor or if
+     * this Cursor is closed
+     */
+    boolean last() throws LdapException, CursorException;
+
+
+    /**
+     * Is this Cursor positioned at the last element.
+     *
+     * @return true if this cursor is positioned at the last element, 
+     * false otherwise
+     * @throws Exception if there are problems querying the position of this Cursor
+     * or if this Cursor is closed
+     */
+    boolean isLast();
+
+
+    /**
+     * Is this Cursor positioned after the last element.
+     *
+     * @return true if this cursor is positioned after the last element, 
+     * false otherwise
+     * @throws Exception if there are problems querying the position of this Cursor
+     * or if this Cursor is closed
+     */
+    boolean isAfterLast();
+
+
+    /**
+     * Checks if this Cursor is closed.  Calls to this operation should not
+     * fail with exceptions if and only if the cursor is in the closed state.
+     *
+     * @return true if this Cursor is closed, false otherwise
+     */
+    boolean isClosed();
+
+
+    /**
+     * Advances this Cursor to the previous position.  If called before
+     * explicitly positioning this Cursor, the position is presumed to be
+     * after the last element and this method moves the cursor back to the
+     * last element.
+     *
+     * @return true if the advance succeeded, false otherwise
+     * @throws Exception if there are problems advancing to the next position
+     */
+    boolean previous() throws LdapException, CursorException;
+
+
+    /**
+     * Advances this Cursor to the next position.  If called before
+     * explicitly positioning this Cursor, the position is presumed to be
+     * before the first element and this method moves the cursor forward to
+     * the first element.
+     *
+     * @return true if the advance succeeded, false otherwise
+     * @throws LdapException if we have get any LDAP exception while operating
+     * the cursor
+     * @throws CursorException if there are problems advancing to this Cursor to
+     * the next position, or if this Cursor is closed 
+     * @throws IOException If we have had any IO Exception
+     */
+    boolean next() throws LdapException, CursorException;
+
+
+    /**
+     * Gets the object at the current position.  Cursor implementations may
+     * choose to reuse element objects by re-populating them on advances
+     * instead of creating new objects on each advance.
+     *
+     * @return the object at the current position
+     * @throws CursorException if the object at this Cursor's current position
+     * cannot be retrieved, or if this Cursor is closed
+     * @throws IOException If we have had any IO Exception
+     */
+    E get() throws CursorException;
+
+
+    /**
+     * Closes this Cursor and frees any resources it my have allocated.
+     * Repeated calls to this method after this Cursor has already been
+     * called should not fail with exceptions.
+     */
+    void close();
+
+
+    /**
+     * Closes this Cursor and frees any resources it my have allocated.
+     * Repeated calls to this method after this Cursor has already been
+     * called should not fail with exceptions.  The reason argument is 
+     * the Exception instance thrown instead of the standard 
+     * CursorClosedException.
+     *
+     * @param reason exception thrown when this Cursor is accessed after close
+     */
+    void close( Exception reason );
+
+
+    /**
+     * Sets a non-null closure monitor to associate with this Cursor.
+     *
+     * @param monitor the monitor to use for detecting Cursor close events
+     */
+    void setClosureMonitor( ClosureMonitor monitor );
+
+
+    /**
+     * Pretty-print a cursor and its wrapped cursor.
+     * @param tabs The spaces to add at each level
+     * @return The cursor and all it's wrapped elements, recursively printed
+     */
+    String toString( String tabs );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorClosedException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorClosedException.java
new file mode 100755
index 0000000..475048c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorClosedException.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * A specific form of IOException to note that an operation is being
+ * attempted on a closed Cursor.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CursorClosedException extends CursorException
+{
+    /** The serialVersion UID */
+    private static final long serialVersionUID = -5723233489761854394L;
+
+    /** A static exception to be used by the monitor */
+    public static final CursorClosedException INSTANCE = new CursorClosedException();
+
+
+    /**
+     * Creates a new instance of CursorClosedException.
+     */
+    public CursorClosedException()
+    {
+    }
+
+
+    /**
+     * Creates a new instance of CursorClosedException.
+     *
+     * @param message The associated message
+     */
+    public CursorClosedException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a new instance of CursorClosedException.
+     *
+     * @param message The associated message
+     * @param cause The original cause
+     */
+    public CursorClosedException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorException.java
new file mode 100644
index 0000000..d6439dc
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorException.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * An class for exceptions which add Cursor specific information to
+ * Exceptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CursorException extends Exception
+{
+    /** The serial version UUID */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of CursorException.
+     */
+    public CursorException()
+    {
+    }
+
+
+    /**
+     * Creates a new instance of CursorException.
+     *
+     * @param explanation The message associated with the exception
+     */
+    public CursorException( String explanation )
+    {
+        super( explanation );
+    }
+
+
+    /**
+     * Creates a new instance of LdapException.
+     */
+    public CursorException( Throwable cause )
+    {
+        super( cause );
+    }
+
+
+    /**
+     * Creates a new instance of CursorException.
+     *
+     * @param explanation The message associated with the exception
+     * @param cause The root cause for this exception
+     */
+    public CursorException( String explanation, Throwable cause )
+    {
+        super( explanation, cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorIterator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorIterator.java
new file mode 100644
index 0000000..1cd6b38
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorIterator.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * An Iterator over a Cursor so Cursors can be Iterable for using in foreach
+ * constructs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E> The type of element on which this cursor will iterate
+ */
+public class CursorIterator<E> implements Iterator<E>
+{
+    /** The inner cursor we will iterate */
+    private final Cursor<E> cursor;
+
+    /** A flag used to store the cursor state */
+    private boolean available;
+
+
+    /**
+     * Creates a new instance of CursorIterator.
+     *
+     * @param cursor The inner cursor
+     */
+    public CursorIterator( Cursor<E> cursor )
+    {
+        this.cursor = cursor;
+
+        try
+        {
+            this.available = cursor.next();
+        }
+        catch ( Exception e )
+        {
+            this.available = false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext()
+    {
+        return available;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public E next()
+    {
+        try
+        {
+            E element = cursor.get();
+            available = cursor.next();
+            return element;
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( I18n.err( I18n.ERR_02002_FAILURE_ON_UNDERLYING_CURSOR ), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void remove()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02003_REMOVAL_NOT_SUPPORTED ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorLdapReferralException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorLdapReferralException.java
new file mode 100644
index 0000000..6df995a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorLdapReferralException.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapReferralException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * A specific form of CursorException used when a referral is met
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CursorLdapReferralException extends CursorException
+{
+    /** The serialVersion UID */
+    private static final long serialVersionUID = -5723233489761854394L;
+
+    /** A static exception to be used by the monitor */
+    public static final CursorLdapReferralException INSTANCE = new CursorLdapReferralException( null );
+
+    /** The contained referralException */
+    private LdapReferralException ldapReferralException;
+
+
+    /**
+     * Creates a new instance of CursorClosedException.
+     */
+    public CursorLdapReferralException( LdapReferralException ldapReferralException )
+    {
+        this.ldapReferralException = ldapReferralException;
+    }
+
+
+    /**
+     * Creates a new instance of CursorClosedException.
+     *
+     * @param message The associated message
+     */
+    public CursorLdapReferralException( LdapReferralException ldapReferralException, String message )
+    {
+        super( message );
+
+        this.ldapReferralException = ldapReferralException;
+    }
+
+
+    /**
+     * Creates a new instance of CursorClosedException.
+     *
+     * @param message The associated message
+     * @param cause The original cause
+     */
+    public CursorLdapReferralException( LdapReferralException ldapReferralException, String message, Throwable cause )
+    {
+        super( message, cause );
+
+        this.ldapReferralException = ldapReferralException;
+    }
+
+
+    /**
+     * Always returns {@link ResultCodeEnum#REFERRAL}
+     * 
+     * @see LdapException#getResultCode()
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        if ( ldapReferralException != null )
+        {
+            return ldapReferralException.getResultCode();
+        }
+        else
+        {
+            return ResultCodeEnum.UNKNOWN;
+        }
+    }
+
+
+    /**
+     * @return The current Referral
+     */
+    public String getReferralInfo()
+    {
+        if ( ldapReferralException != null )
+        {
+            return ldapReferralException.getReferralInfo();
+        }
+        else
+        {
+            return "";
+        }
+    }
+
+
+    /**
+     * Move to the next referral
+     * @return true if there is some next referral
+     */
+    public boolean skipReferral()
+    {
+        if ( ldapReferralException != null )
+        {
+            return ldapReferralException.skipReferral();
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * @return the remainingDn
+     */
+    public Dn getRemainingDn()
+    {
+        if ( ldapReferralException != null )
+        {
+            return ldapReferralException.getRemainingDn();
+        }
+        else
+        {
+            return Dn.EMPTY_DN;
+        }
+    }
+
+
+    /**
+     * @return the resolvedObject
+     */
+    public Object getResolvedObject()
+    {
+        if ( ldapReferralException != null )
+        {
+            return ldapReferralException.getResolvedObject();
+        }
+        else
+        {
+            return null;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorStateEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorStateEnum.java
new file mode 100644
index 0000000..9970d2d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/CursorStateEnum.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * An enumeration to represent the various states of a Cursor.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum CursorStateEnum
+{
+    /** the Cursor has been created and so has not been positioned yet */
+    JUST_OPENED,
+
+    /** the Cursor is positioned just before the first element */
+    BEFORE_FIRST,
+
+    /** the Cursor is positioned just after the last element */
+    AFTER_LAST,
+
+    /** the Cursor is positioned just before an element but not on any element */
+    BEFORE_INNER,
+
+    /** the Cursor is positioned just after an element but not on any element */
+    AFTER_INNER,
+
+    /** the Cursor is positioned on the first element */
+    ON_FIRST,
+
+    /** the Cursor is positioned on the last element */
+    ON_LAST,
+
+    /** the Cursor is positioned on an element */
+    ON_INNER,
+
+    /** the Cursor is closed and not operations can be performed on it */
+    CLOSED
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/DefaultClosureMonitor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/DefaultClosureMonitor.java
new file mode 100644
index 0000000..5a8999b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/DefaultClosureMonitor.java
@@ -0,0 +1,126 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * A basic ClosureMonitor that simply uses a boolean for state and a cause
+ * exception.
+ *
+ * Note that we consciously chose not to synchronize close() operations with
+ * checks to see if the monitor state is closed because it costs to
+ * synchronize and it's OK for the Cursor not to stop immediately when close()
+ * is called.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultClosureMonitor implements ClosureMonitor
+{
+    /** Tells if the monitor is closed or not */
+    private boolean closed;
+
+    /** If we get an exception, the cause is stored in this variable */
+    private Exception cause;
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final void close()
+    {
+        // state check needed to "try" not to overwrite exception (lack of
+        // synchronization may still allow overwriting but who cares that much
+        if ( !closed )
+        {
+            // not going to sync because who cares if it takes a little longer
+            // to stop but we need to set cause before toggling closed state
+            // or else check for closure can throw null cause
+            cause = CursorClosedException.INSTANCE;
+            closed = true;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final void close( final String cause )
+    {
+        // state check needed to "try" not to overwrite exception (lack of
+        // synchronization may still allow overwriting but who cares that much
+        if ( !closed )
+        {
+            // not going to sync because who cares if it takes a little longer
+            // to stop but we need to set cause before toggling closed state
+            // or else check for closure can throw null cause
+            this.cause = new CursorClosedException( cause );
+            closed = true;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final void close( final Exception cause )
+    {
+        // state check needed to "try" not to overwrite exception (lack of
+        // synchronization may still allow overwriting but who cares that much
+        if ( !closed )
+        {
+            // not going to sync because who cares if it takes a little longer
+            // to stop but we need to set cause before toggling closed state
+            // or else check for closure can throw null cause
+            this.cause = cause;
+            closed = true;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final Exception getCause()
+    {
+        return cause;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final boolean isClosed()
+    {
+        return closed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void checkNotClosed() throws CursorClosedException
+    {
+        // lack of synchronization may cause pass but eventually it will work
+        if ( closed )
+        {
+            throw new CursorClosedException( cause.getMessage() );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/EmptyCursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/EmptyCursor.java
new file mode 100755
index 0000000..795602c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/EmptyCursor.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An empty Cursor implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E> The type of element on which this cursor will iterate
+ */
+public class EmptyCursor<E> extends AbstractCursor<E>
+{
+    /** A dedicated log for cursors */
+    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
+
+
+    public EmptyCursor()
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Creating EmptyCursor : {}", this );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean available()
+    {
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void before( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "before()" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void after( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "after()" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void beforeFirst() throws LdapException, CursorException
+    {
+        checkNotClosed( "beforeFirst()" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void afterLast() throws LdapException, CursorException
+    {
+        checkNotClosed( "afterLast()" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean first() throws LdapException, CursorException
+    {
+        checkNotClosed( "first()" );
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean last() throws LdapException, CursorException
+    {
+        checkNotClosed( "last()" );
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean previous() throws LdapException, CursorException
+    {
+        checkNotClosed( "previous()" );
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean next() throws LdapException, CursorException
+    {
+        checkNotClosed( "next()" );
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public E get() throws CursorException
+    {
+        checkNotClosed( "get()" );
+        throw new InvalidCursorPositionException( I18n.err( I18n.ERR_02004_EMPTY_CURSOR ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close()
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing EmptyCursor {}", this );
+        }
+
+        super.close();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close( Exception cause )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing EmptyCursor {}", this );
+        }
+
+        super.close( cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/EntryCursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/EntryCursor.java
new file mode 100644
index 0000000..8df789b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/EntryCursor.java
@@ -0,0 +1,47 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+
+
+/**
+ * An extension of Cursor which returns only Entry objects and includes the retrieval of the SearchResultDone. 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface EntryCursor extends Cursor<Entry>
+{
+    /**
+     * gives the SearchResultDone message received at the end of search results
+     * 
+     * @return the SearchResultDone message, null if the search operation fails for any reason 
+     */
+    SearchResultDone getSearchResultDone();
+
+
+    /**
+     * @return the underlying message ID
+     */
+    int getMessageId();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/InconsistentCursorStateException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/InconsistentCursorStateException.java
new file mode 100755
index 0000000..6bf0ab7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/InconsistentCursorStateException.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * Thrown to indicate a condition in the Cursor where the state seems
+ * inconsistent based on internal accounting.  This may indicate the
+ * underlying structure has changed after the Cursor has been created.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InconsistentCursorStateException extends CursorException
+{
+    /** The serialVersion UID */
+    private static final long serialVersionUID = 6222645005251534704L;
+
+
+    /**
+     * Creates a new instance of InconsistentCursorStateException.
+     */
+    public InconsistentCursorStateException()
+    {
+    }
+
+
+    /**
+     * Creates a new instance of CursorClosedException.
+     *
+     * @param message The associated message
+     */
+    public InconsistentCursorStateException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/InvalidCursorPositionException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/InvalidCursorPositionException.java
new file mode 100755
index 0000000..3bbe2e7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/InvalidCursorPositionException.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * Thrown to indicate an illegal position state for a Cursor when a call to
+ * get is made.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InvalidCursorPositionException extends CursorException
+{
+    /** The serialVersion UID */
+    private static final long serialVersionUID = 5730037129071653272L;
+
+
+    /**
+     * Creates a new instance of InvalidCursorPositionException.
+     */
+    public InvalidCursorPositionException()
+    {
+    }
+
+
+    /**
+     * Creates a new instance of InvalidCursorPositionException.
+     *
+     * @param message The associated message
+     */
+    public InvalidCursorPositionException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/ListCursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/ListCursor.java
new file mode 100644
index 0000000..1c1241a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/ListCursor.java
@@ -0,0 +1,530 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A simple implementation of a Cursor on a {@link List}.  Optionally, the
+ * Cursor may be limited to a specific range within the list.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E> The element on which this cursor will iterate
+ */
+public class ListCursor<E> extends AbstractCursor<E>
+{
+    /** A dedicated log for cursors */
+    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
+
+    /** The inner List */
+    private final List<E> list;
+
+    /** The associated comparator */
+    private final Comparator<E> comparator;
+
+    /** The starting position for the cursor in the list. It can be > 0 */
+    private final int start;
+
+    /** The ending position for the cursor in the list. It can be < List.size() */
+    private final int end;
+    /** The current position in the list */
+
+    private int index = -1;
+
+
+    /**
+     * Creates a new ListCursor with lower (inclusive) and upper (exclusive)
+     * bounds.
+     *
+     * As with all Cursors, this ListCursor requires a successful return from
+     * advance operations (next() or previous()) to properly return values
+     * using the get() operation.
+     *
+     * @param comparator an optional comparator to use for ordering
+     * @param start the lower bound index
+     * @param list the list this ListCursor operates on
+     * @param end the upper bound index
+     */
+    public ListCursor( Comparator<E> comparator, int start, List<E> list, int end )
+    {
+        if ( list == null )
+        {
+            list = Collections.emptyList();
+        }
+
+        if ( ( start < 0 ) || ( start > list.size() ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_02005_START_INDEX_OUT_OF_RANGE, start ) );
+        }
+
+        if ( ( end < 0 ) || ( end > list.size() ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_02006_END_INDEX_OUT_OF_RANGE, end ) );
+        }
+
+        // check list is not empty list since the empty list is the only situation
+        // where we allow for start to equal the end: in other cases it makes no sense
+        if ( ( list.size() > 0 ) && ( start >= end ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_02007_START_INDEX_ABOVE_END_INDEX, start, end ) );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Creating ListCursor {}", this );
+        }
+
+        this.comparator = comparator;
+        this.list = list;
+        this.start = start;
+        this.end = end;
+    }
+
+
+    /**
+     * Creates a new ListCursor with lower (inclusive) and upper (exclusive)
+     * bounds.
+     *
+     * As with all Cursors, this ListCursor requires a successful return from
+     * advance operations (next() or previous()) to properly return values
+     * using the get() operation.
+     *
+     * @param start the lower bound index
+     * @param list the list this ListCursor operates on
+     * @param end the upper bound index
+     */
+    public ListCursor( int start, List<E> list, int end )
+    {
+        this( null, start, list, end );
+    }
+
+
+    /**
+     * Creates a new ListCursor with a specific upper (exclusive) bound: the
+     * lower (inclusive) bound defaults to 0.
+     *
+     * @param list the backing for this ListCursor
+     * @param end the upper bound index representing the position after the
+     * last element
+     */
+    public ListCursor( List<E> list, int end )
+    {
+        this( null, 0, list, end );
+    }
+
+
+    /**
+     * Creates a new ListCursor with a specific upper (exclusive) bound: the
+     * lower (inclusive) bound defaults to 0. We also provide a comparator.
+     *
+     * @param comparator The comparator to use for the <E> elements
+     * @param list the backing for this ListCursor
+     * @param end the upper bound index representing the position after the
+     * last element
+     */
+    public ListCursor( Comparator<E> comparator, List<E> list, int end )
+    {
+        this( comparator, 0, list, end );
+    }
+
+
+    /**
+     * Creates a new ListCursor with a lower (inclusive) bound: the upper
+     * (exclusive) bound is the size of the list.
+     *
+     * @param start the lower (inclusive) bound index: the position of the
+     * first entry
+     * @param list the backing for this ListCursor
+     */
+    public ListCursor( int start, List<E> list )
+    {
+        this( null, start, list, list.size() );
+    }
+
+
+    /**
+     * Creates a new ListCursor with a lower (inclusive) bound: the upper
+     * (exclusive) bound is the size of the list. We also provide a comparator.
+     *
+     * @param comparator The comparator to use for the <E> elements
+     * @param start the lower (inclusive) bound index: the position of the
+     * first entry
+     * @param list the backing for this ListCursor
+     */
+    public ListCursor( Comparator<E> comparator, int start, List<E> list )
+    {
+        this( comparator, start, list, list.size() );
+    }
+
+
+    /**
+     * Creates a new ListCursor without specific bounds: the bounds are
+     * acquired from the size of the list.
+     *
+     * @param list the backing for this ListCursor
+     */
+    public ListCursor( List<E> list )
+    {
+        this( null, 0, list, list.size() );
+    }
+
+
+    /**
+     * Creates a new ListCursor without specific bounds: the bounds are
+     * acquired from the size of the list. We also provide a comparator.
+     *
+     * @param comparator The comparator to use for the <E> elements
+     * @param list the backing for this ListCursor
+     */
+    public ListCursor( Comparator<E> comparator, List<E> list )
+    {
+        this( comparator, 0, list, list.size() );
+    }
+
+
+    /**
+     * Creates a new ListCursor without any elements.
+     */
+    @SuppressWarnings("unchecked")
+    public ListCursor()
+    {
+        this( null, 0, Collections.EMPTY_LIST, 0 );
+    }
+
+
+    /**
+     * Creates a new ListCursor without any elements. We also provide 
+     * a comparator.
+     * 
+     * @param comparator The comparator to use for the <E> elements
+     */
+    @SuppressWarnings("unchecked")
+    public ListCursor( Comparator<E> comparator )
+    {
+        this( comparator, 0, Collections.EMPTY_LIST, 0 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean available()
+    {
+        return index >= 0 && index < end;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void before( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "before()" );
+
+        if ( comparator == null )
+        {
+            throw new IllegalStateException();
+        }
+
+        // handle some special cases
+        if ( list.size() == 0 )
+        {
+            return;
+        }
+        else if ( list.size() == 1 )
+        {
+            if ( comparator.compare( element, list.get( 0 ) ) <= 0 )
+            {
+                beforeFirst();
+            }
+            else
+            {
+                afterLast();
+            }
+        }
+
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008_LIST_MAY_BE_SORTED ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void after( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "after()" );
+
+        if ( comparator == null )
+        {
+            throw new IllegalStateException();
+        }
+
+        // handle some special cases
+        if ( list.size() == 0 )
+        {
+            return;
+        }
+        else if ( list.size() == 1 )
+        {
+            if ( comparator.compare( element, list.get( 0 ) ) >= 0 )
+            {
+                afterLast();
+            }
+            else
+            {
+                beforeFirst();
+            }
+        }
+
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008_LIST_MAY_BE_SORTED ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void beforeFirst() throws LdapException, CursorException
+    {
+        checkNotClosed( "beforeFirst()" );
+        this.index = -1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void afterLast() throws LdapException, CursorException
+    {
+        checkNotClosed( "afterLast()" );
+        this.index = end;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean first() throws LdapException, CursorException
+    {
+        checkNotClosed( "first()" );
+
+        if ( list.size() > 0 )
+        {
+            index = start;
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean last() throws LdapException, CursorException
+    {
+        checkNotClosed( "last()" );
+
+        if ( list.size() > 0 )
+        {
+            index = end - 1;
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isFirst()
+    {
+        return list.size() > 0 && index == start;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isLast()
+    {
+        return list.size() > 0 && index == end - 1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAfterLast()
+    {
+        return index == end;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isBeforeFirst()
+    {
+        return index == -1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean previous() throws LdapException, CursorException
+    {
+        checkNotClosed( "previous()" );
+
+        // if parked at -1 we cannot go backwards
+        if ( index == -1 )
+        {
+            return false;
+        }
+
+        // if the index moved back is still greater than or eq to start then OK
+        if ( index - 1 >= start )
+        {
+            index--;
+
+            return true;
+        }
+
+        // if the index currently less than or equal to start we need to park it at -1 and return false
+        if ( index <= start )
+        {
+            index = -1;
+
+            return false;
+        }
+
+        if ( list.size() <= 0 )
+        {
+            index = -1;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean next() throws LdapException, CursorException
+    {
+        checkNotClosed( "next()" );
+
+        // if parked at -1 we advance to the start index and return true
+        if ( ( list.size() > 0 ) && ( index == -1 ) )
+        {
+            index = start;
+
+            return true;
+        }
+
+        // if the index plus one is less than the end then increment and return true
+        if ( ( list.size() > 0 ) && ( index + 1 < end ) )
+        {
+            index++;
+
+            return true;
+        }
+
+        // if the index plus one is equal to the end then increment and return false
+        if ( ( list.size() > 0 ) && ( index + 1 == end ) )
+        {
+            index++;
+
+            return false;
+        }
+
+        if ( list.size() <= 0 )
+        {
+            index = end;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public E get() throws CursorException
+    {
+        checkNotClosed( "get()" );
+
+        if ( ( index < start ) || ( index >= end ) )
+        {
+            throw new CursorException( I18n.err( I18n.ERR_02009_CURSOR_NOT_POSITIONED ) );
+        }
+
+        return list.get( index );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close()
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing ListCursor {}", this );
+        }
+
+        super.close();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close( Exception cause )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing ListCursor {}", this );
+        }
+
+        super.close( cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SearchCursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SearchCursor.java
new file mode 100644
index 0000000..1981548
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SearchCursor.java
@@ -0,0 +1,90 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.IntermediateResponse;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.SearchResultDone;
+
+
+/**
+ * An extension of Cursor which includes the retrieval of the SearchResultDone. 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SearchCursor extends Cursor<Response>
+{
+    /**
+     * @return true if the cursor has processed all the elements we were searching
+     */
+    boolean isDone();
+
+
+    /**
+     * gives the SearchResultDone message received at the end of search results
+     * 
+     * @return the SearchResultDone message, null if the search operation fails for any reason 
+     */
+    SearchResultDone getSearchResultDone();
+
+
+    /**
+     * @return true if the next element in the cursor is a referral 
+     */
+    boolean isReferral();
+
+
+    /**
+     * @return The next referral element, if it's a referral 
+     * @throws LdapException If the 
+     */
+    Referral getReferral() throws LdapException;
+
+
+    /**
+     * @return true if the next element in the cursor is an entry 
+     */
+    boolean isEntry();
+
+
+    /**
+     * @return The next entry element, if it's an entry 
+     * @throws LdapException If the 
+     */
+    Entry getEntry() throws LdapException;
+
+
+    /**
+     * @return true if the next element in the cursor is an intermediate response 
+     */
+    boolean isIntermediate();
+
+
+    /**
+     * @return The next intermediate response element, if it's an intermediate response 
+     * @throws LdapException If the 
+     */
+    IntermediateResponse getIntermediate() throws LdapException;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SetCursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SetCursor.java
new file mode 100644
index 0000000..1999623
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SetCursor.java
@@ -0,0 +1,462 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A simple implementation of a Cursor on a {@link Set}.  Optionally, the
+ * Cursor may be limited to a specific range within the list.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E> The element on which this cursor will iterate
+ */
+public class SetCursor<E> extends AbstractCursor<E>
+{
+    /** A dedicated log for cursors */
+    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
+
+    /** The inner Set */
+    private final E[] set;
+
+    /** The associated comparator */
+    private final Comparator<E> comparator;
+
+    /** The current position in the list */
+    private int index = -1;
+
+    /** A limit to what we can print */
+    private static final int MAX_PRINTED_ELEMENT = 100;
+
+
+    /**
+     * Creates a new SetCursor.
+     *
+     * As with all Cursors, this SetCursor requires a successful return from
+     * advance operations (next() or previous()) to properly return values
+     * using the get() operation.
+     *
+     * @param comparator an optional comparator to use for ordering
+     * @param set the Set this StCursor operates on
+     */
+    @SuppressWarnings("unchecked")
+    public SetCursor( Comparator<E> comparator, Set<E> set )
+    {
+        if ( set == null )
+        {
+            set = Collections.EMPTY_SET;
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Creating SetCursor {}", this );
+        }
+
+        this.comparator = comparator;
+        this.set = ( E[] ) set.toArray();
+    }
+
+
+    /**
+     * Creates a new SetCursor
+     *
+     * As with all Cursors, this SetCursor requires a successful return from
+     * advance operations (next() or previous()) to properly return values
+     * using the get() operation.
+     *
+     * @param set the Set this SetCursor operates on
+     */
+    public SetCursor( Set<E> set )
+    {
+        this( null, set );
+    }
+
+
+    /**
+     * Creates a new SetCursor without any elements.
+     */
+    @SuppressWarnings("unchecked")
+    public SetCursor()
+    {
+        this( null, Collections.EMPTY_SET );
+    }
+
+
+    /**
+     * Creates a new SetCursor without any elements. We also provide 
+     * a comparator.
+     * 
+     * @param comparator The comparator to use for the <E> elements
+     */
+    @SuppressWarnings("unchecked")
+    public SetCursor( Comparator<E> comparator )
+    {
+        this( comparator, Collections.EMPTY_SET );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean available()
+    {
+        return ( index >= 0 ) && ( index < set.length );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void before( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "before()" );
+
+        if ( comparator == null )
+        {
+            throw new IllegalStateException();
+        }
+
+        // handle some special cases
+        if ( set.length == 0 )
+        {
+            return;
+        }
+        else if ( set.length == 1 )
+        {
+            if ( comparator.compare( element, set[0] ) <= 0 )
+            {
+                beforeFirst();
+            }
+            else
+            {
+                afterLast();
+            }
+        }
+
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008_LIST_MAY_BE_SORTED ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void after( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "after()" );
+
+        if ( comparator == null )
+        {
+            throw new IllegalStateException();
+        }
+
+        // handle some special cases
+        if ( set.length == 0 )
+        {
+            return;
+        }
+        else if ( set.length == 1 )
+        {
+            if ( comparator.compare( element, set[0] ) >= 0 )
+            {
+                afterLast();
+            }
+            else
+            {
+                beforeFirst();
+            }
+        }
+
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008_LIST_MAY_BE_SORTED ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void beforeFirst() throws LdapException, CursorException
+    {
+        checkNotClosed( "beforeFirst()" );
+        this.index = -1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void afterLast() throws LdapException, CursorException
+    {
+        checkNotClosed( "afterLast()" );
+        this.index = set.length;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean first() throws LdapException, CursorException
+    {
+        checkNotClosed( "first()" );
+
+        if ( set.length > 0 )
+        {
+            index = 0;
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean last() throws LdapException, CursorException
+    {
+        checkNotClosed( "last()" );
+
+        if ( set.length > 0 )
+        {
+            index = set.length - 1;
+
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isFirst()
+    {
+        return ( set.length > 0 ) && ( index == 0 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isLast()
+    {
+        return ( set.length > 0 ) && ( index == set.length - 1 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAfterLast()
+    {
+        return index == set.length;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isBeforeFirst()
+    {
+        return index == -1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean previous() throws LdapException, CursorException
+    {
+        checkNotClosed( "previous()" );
+
+        // if parked at -1 we cannot go backwards
+        if ( index == -1 )
+        {
+            return false;
+        }
+
+        // if the index moved back is still greater than or eq to start then OK
+        if ( index - 1 >= 0 )
+        {
+            index--;
+
+            return true;
+        }
+
+        // if the index currently less than or equal to start we need to park it at -1 and return false
+        if ( index <= 0 )
+        {
+            index = -1;
+
+            return false;
+        }
+
+        if ( set.length <= 0 )
+        {
+            index = -1;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean next() throws LdapException, CursorException
+    {
+        checkNotClosed( "next()" );
+
+        // if parked at -1 we advance to the start index and return true
+        if ( ( set.length > 0 ) && ( index == -1 ) )
+        {
+            index = 0;
+
+            return true;
+        }
+
+        // if the index plus one is less than the end then increment and return true
+        if ( ( set.length > 0 ) && ( index + 1 < set.length ) )
+        {
+            index++;
+
+            return true;
+        }
+
+        // if the index plus one is equal to the end then increment and return false
+        if ( ( set.length > 0 ) && ( index + 1 == set.length ) )
+        {
+            index++;
+
+            return false;
+        }
+
+        if ( set.length <= 0 )
+        {
+            index = set.length;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public E get() throws CursorException
+    {
+        checkNotClosed( "get()" );
+
+        if ( ( index < 0 ) || ( index >= set.length ) )
+        {
+            throw new CursorException( I18n.err( I18n.ERR_02009_CURSOR_NOT_POSITIONED ) );
+        }
+
+        return set[index];
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close()
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing ListCursor {}", this );
+        }
+
+        super.close();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close( Exception cause )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing ListCursor {}", this );
+        }
+
+        super.close( cause );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString( String tabs )
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( tabs ).append( "SetCursor :\n" );
+        sb.append( tabs ).append( "    Index : " ).append( index ).append( "\n" );
+
+        if ( ( set != null ) && ( set.length > 0 ) )
+        {
+            sb.append( tabs ).append( "    Size : " ).append( set.length ).append( "\n" );
+
+            // Don't print more than 100 elements...
+            int counter = 0;
+
+            for ( E e : set )
+            {
+                sb.append( tabs ).append( "    " ).append( e ).append( "\n" );
+                counter++;
+
+                if ( counter == MAX_PRINTED_ELEMENT )
+                {
+                    break;
+                }
+            }
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return toString( "" );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SingletonCursor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SingletonCursor.java
new file mode 100755
index 0000000..4fb0243
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/SingletonCursor.java
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import java.util.Comparator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Cursor over a single element.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <E> The type of element on which this cursor will iterate
+ */
+public class SingletonCursor<E> extends AbstractCursor<E>
+{
+    /** A dedicated log for cursors */
+    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
+
+    /** A flag to tell if the cursor is set before the first element */
+    private boolean beforeFirst = true;
+
+    /** A flag to tell if the cursor is set after the last element */
+    private boolean afterLast;
+
+    /** A flag to tell if the cursor is on the element */
+    private boolean onSingleton;
+
+    /** The comparator used for this cursor. */
+    private final Comparator<E> comparator;
+
+    /** The unique element stored in the cursor */
+    private final E singleton;
+
+
+    /**
+     * Creates a new instance of SingletonCursor.
+     *
+     * @param singleton The unique element to store into this cursor
+     */
+    public SingletonCursor( E singleton )
+    {
+        this( singleton, null );
+    }
+
+
+    /**
+     * Creates a new instance of SingletonCursor, with its associated
+     * comparator
+     *
+     * @param singleton The unique element to store into this cursor
+     * @param comparator The associated comparator
+     */
+    public SingletonCursor( E singleton, Comparator<E> comparator )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Creating SingletonCursor {}", this );
+        }
+
+        this.singleton = singleton;
+        this.comparator = comparator;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean available()
+    {
+        return onSingleton;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void before( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "before()" );
+
+        if ( comparator == null )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_02010_NO_COMPARATOR_CANT_MOVE_BEFORE ) );
+        }
+
+        int comparison = comparator.compare( singleton, element );
+
+        if ( comparison < 0 )
+        {
+            first();
+        }
+        else
+        {
+            beforeFirst();
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void after( E element ) throws LdapException, CursorException
+    {
+        checkNotClosed( "after()" );
+
+        if ( comparator == null )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_02011_NO_COMPARATOR_CANT_MOVE_AFTER ) );
+        }
+
+        int comparison = comparator.compare( singleton, element );
+
+        if ( comparison > 0 )
+        {
+            first();
+        }
+        else
+        {
+            afterLast();
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void beforeFirst() throws LdapException, CursorException
+    {
+        checkNotClosed( "beforeFirst" );
+        beforeFirst = true;
+        afterLast = false;
+        onSingleton = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void afterLast() throws LdapException, CursorException
+    {
+        checkNotClosed( "afterLast" );
+        beforeFirst = false;
+        afterLast = true;
+        onSingleton = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean first() throws LdapException, CursorException
+    {
+        checkNotClosed( "first" );
+        beforeFirst = false;
+        onSingleton = true;
+        afterLast = false;
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean last() throws LdapException, CursorException
+    {
+        checkNotClosed( "last" );
+        beforeFirst = false;
+        onSingleton = true;
+        afterLast = false;
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isFirst()
+    {
+        return onSingleton;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isLast()
+    {
+        return onSingleton;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAfterLast()
+    {
+        return afterLast;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isBeforeFirst()
+    {
+        return beforeFirst;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean previous() throws LdapException, CursorException
+    {
+        checkNotClosed( "previous" );
+
+        if ( beforeFirst )
+        {
+            return false;
+        }
+
+        if ( afterLast )
+        {
+            beforeFirst = false;
+            onSingleton = true;
+            afterLast = false;
+
+            return true;
+        }
+
+        // must be on the singleton
+        beforeFirst = true;
+        onSingleton = false;
+        afterLast = false;
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean next() throws LdapException, CursorException
+    {
+        checkNotClosed( "next" );
+
+        if ( beforeFirst )
+        {
+            beforeFirst = false;
+            onSingleton = true;
+            afterLast = false;
+
+            return true;
+        }
+
+        if ( afterLast )
+        {
+            return false;
+        }
+
+        // must be on the singleton
+        beforeFirst = false;
+        onSingleton = false;
+        afterLast = true;
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public E get() throws CursorException
+    {
+        checkNotClosed( "get" );
+
+        if ( onSingleton )
+        {
+            return singleton;
+        }
+
+        if ( beforeFirst )
+        {
+            throw new InvalidCursorPositionException( I18n.err( I18n.ERR_02012_CANNOT_ACCESS_IF_BEFORE_FIRST ) );
+        }
+        else
+        {
+            throw new InvalidCursorPositionException( I18n.err( I18n.ERR_02013_CANNOT_ACCESS_IF_AFTER_LAST ) );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close()
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing SingletonCursor {}", this );
+        }
+
+        super.close();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void close( Exception cause )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG_CURSOR.debug( "Closing SingletonCursor {}", this );
+        }
+
+        super.close( cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/Tuple.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/Tuple.java
new file mode 100644
index 0000000..218e7bc
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/Tuple.java
@@ -0,0 +1,243 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * A key/value tuple for simple two column persistent Tables with sorted keys.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <K> The key type for the Tuple
+ * @param <V> The associated Value type
+ */
+public class Tuple<K, V>
+{
+    /** the key for this Tuple */
+    private K key;
+
+    /** the value for this Tuple */
+    private V value;
+
+
+    /**
+     * Do nothing default that has a null key and null value.
+     */
+    public Tuple()
+    {
+        // does nothing!
+    }
+
+
+    /**
+     * Creates a Tuple using a key and a value.
+     * 
+     * @param key the key to set
+     * @param value the value to set
+     */
+    public Tuple( K key, V value )
+    {
+        this.key = key;
+        this.value = value;
+    }
+
+
+    /**
+     * Gets the key for this Tuple.
+     *
+     * @return the Tuple's key
+     */
+    public K getKey()
+    {
+        return key;
+    }
+
+
+    /**
+     * Sets the key for this Tuple.
+     *
+     * @param key the new key to set
+     * @return this Tuple itself to set and return
+     */
+    public Tuple<K, V> setKey( K key )
+    {
+        this.key = key;
+
+        return this;
+    }
+
+
+    /**
+     * Gets the value for this Tuple.
+     *
+     * @return the Tuple's value
+     */
+    public V getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Sets the value for this Tuple.
+     *
+     * @param value the new value to set
+     * @return this Tuple itself to set and return
+     */
+    public Tuple<K, V> setValue( V value )
+    {
+        this.value = value;
+
+        return this;
+    }
+
+
+    /**
+     * Sets both the key and the value for this Tuple in one call and returns
+     * this Tuple object.  This is useful for setting the tuples key and value
+     * then returning it.
+     *
+     * @param key the new key to set
+     * @param value the new value to set
+     * @return this Tuple itself to set and return
+     */
+    public Tuple<K, V> setBoth( K key, V value )
+    {
+        this.key = key;
+        this.value = value;
+
+        return this;
+    }
+
+
+    /**
+     * Sets both the key and the value for this Tuple in one call and returns
+     * this Tuple object.  This is useful for setting the tuples key and value
+     * then returning it.
+     *
+     * @param tupleToCopy the tuple to copy
+     * @return this Tuple itself to set and return
+     */
+    public Tuple<K, V> setBoth( Tuple<K, V> tupleToCopy )
+    {
+        this.key = tupleToCopy.key;
+        this.value = tupleToCopy.value;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int prime = 31;
+        int result = 1;
+
+        if ( key == null )
+        {
+            result = prime * result;
+        }
+        else
+        {
+            result = prime * result + key.hashCode();
+        }
+
+        if ( value == null )
+        {
+            result = prime * result;
+        }
+        else
+        {
+            result = prime * result + value.hashCode();
+        }
+
+        return result;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( obj == null )
+        {
+            return false;
+        }
+
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+
+        Tuple<?, ?> other = ( Tuple<?, ?> ) obj;
+
+        if ( key == null )
+        {
+            if ( other.key != null )
+            {
+                return false;
+            }
+        }
+        else if ( !key.equals( other.key ) )
+        {
+            return false;
+        }
+
+        if ( value == null )
+        {
+            if ( other.value != null )
+            {
+                return false;
+            }
+        }
+        else if ( !value.equals( other.value ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "Tuple( '" );
+        buf.append( key );
+        buf.append( "', '" );
+        buf.append( value );
+        buf.append( "' )" );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/TupleRenderer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/TupleRenderer.java
new file mode 100644
index 0000000..cbd3aa6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/cursor/TupleRenderer.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+/**
+ * A table key/value String renderer for the display or logging of
+ * human readable potentially binary data.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface TupleRenderer
+{
+    /**
+     * Gets the key Object rendered as a String.
+     *
+     * @param key the key Object
+     * @return the String representation of the key Object
+     */
+    String getKeyString( Object key );
+
+
+    /**
+     * Gets the value Object rendered as a String.
+     *
+     * @param value the value Object
+     * @return the String representation of the value Object
+     */
+    String getValueString( Object value );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/AbstractValue.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/AbstractValue.java
new file mode 100644
index 0000000..f7d375d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/AbstractValue.java
@@ -0,0 +1,320 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A wrapper around byte[] values in entries.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractValue<T> implements Value<T>
+{
+    /** logger for reporting errors that might not be handled properly upstream */
+    protected static final Logger LOG = LoggerFactory.getLogger( AbstractValue.class );
+
+    /** reference to the attributeType zssociated with the value */
+    protected transient AttributeType attributeType;
+
+    /** the User Provided value */
+    protected T upValue;
+
+    /** the canonical representation of the user provided value */
+    protected T normalizedValue;
+
+    /** The computed hashcode. We don't want to compute it each time the hashcode() method is called */
+    protected volatile int h;
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public Value<T> clone()
+    {
+        try
+        {
+            return ( Value<T> ) super.clone();
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            // Do nothing
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public T getReference()
+    {
+        return upValue;
+    }
+
+
+    /**
+     * Get the wrapped value as a String.
+     *
+     * @return the wrapped value as a String
+     */
+    public String getString()
+    {
+        throw new UnsupportedOperationException( "Cannot call this method on a binary value" );
+    }
+
+
+    /**
+     * Get the wrapped value as a byte[].
+     *
+     * @return the wrapped value as a byte[]
+     */
+    public byte[] getBytes()
+    {
+        throw new UnsupportedOperationException( "Cannot call this method on a String value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    /**
+     * Apply an AttributeType to the current Value, normalizing it.
+     *
+     * @param attributeType The AttributeType to apply
+     * @throws LdapInvalidAttributeValueException If the value is not valid accordingly
+     * to the schema
+     */
+    @SuppressWarnings("unchecked")
+    public void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException
+    {
+        if ( this.attributeType != null )
+        {
+            // We already have applied an AttributeType, get out
+            LOG.warn( "AttributeType {0} already applied", attributeType.getName() );
+            return;
+        }
+        
+        if ( attributeType == null )
+        {
+            // No attributeType : the normalized value and the user provided value are the same
+            normalizedValue = upValue;
+            return;
+        }
+
+        this.attributeType = attributeType;
+
+        // We first have to normalize the value before we can check its syntax
+        // Get the equality matchingRule, if we have one
+        MatchingRule equality = attributeType.getEquality();
+
+        if ( equality != null )
+        {
+            // If we have an Equality MR, we *must* have a normalizer
+            Normalizer normalizer = equality.getNormalizer();
+
+            if ( normalizer != null )
+            {
+                if ( upValue != null )
+                {
+                    boolean isHR = attributeType.getSyntax().isHumanReadable();
+                    
+
+                    if ( isHR != isHumanReadable() )
+                    {
+                        
+                        String message = "The '" + attributeType.getName() + "' AttributeType and values must "
+                            + "both be String or binary";
+                        LOG.error( message );
+                        throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, message );
+                    }
+
+                    try
+                    {
+                        if ( isHumanReadable() )
+                        {
+                            if ( normalizedValue != null )
+                            {    
+                                normalizedValue = ( T ) normalizer.normalize( ( String ) normalizedValue );
+                            }
+                            else
+                            {
+                                normalizedValue = ( T ) normalizer.normalize( ( String ) upValue );
+                            }
+                        }
+                        else
+                        {
+                            normalizedValue = ( T ) normalizer.normalize( new BinaryValue( ( byte[] ) upValue ) )
+                                .getNormReference();
+                        }
+                    }
+                    catch ( LdapException ne )
+                    {
+                        String message = I18n.err( I18n.ERR_04447_CANNOT_NORMALIZE_VALUE, ne.getLocalizedMessage() );
+                        LOG.info( message );
+                    }
+                }
+            }
+            else
+            {
+                String message = "The '" + attributeType.getName() + "' AttributeType does not have" + " a normalizer";
+                LOG.error( message );
+                throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, message );
+            }
+        }
+        else
+        {
+            // No MatchingRule, there is nothing we can do but make the normalized value
+            // to be a reference on the user provided value
+            normalizedValue = upValue;
+        }
+
+        // and checks that the value syntax is valid
+        try
+        {
+            LdapSyntax syntax = attributeType.getSyntax();
+
+            // Check the syntax
+            if ( ( syntax != null ) && ( !isValid( syntax.getSyntaxChecker() ) ) )
+            {
+                String message = I18n.err( I18n.ERR_04473_NOT_VALID_VALUE, upValue, attributeType );
+                LOG.info( message );
+                throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, message );
+            }
+        }
+        catch ( LdapException le )
+        {
+            String message = I18n.err( I18n.ERR_04447_CANNOT_NORMALIZE_VALUE, le.getLocalizedMessage() );
+            LOG.info( message );
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, message, le );
+        }
+
+        // Rehash the Value now
+        h = 0;
+        hashCode();
+    }
+
+
+    /**
+     * Gets a comparator using getMatchingRule() to resolve the matching
+     * that the comparator is extracted from.
+     *
+     * @return a comparator associated with the attributeType or null if one cannot be found
+     * @throws LdapException if resolution of schema entities fail
+     */
+    @SuppressWarnings("unchecked")
+    protected final LdapComparator<T> getLdapComparator() throws LdapException
+    {
+        if ( attributeType != null )
+        {
+            MatchingRule mr = attributeType.getEquality();
+
+            if ( mr != null )
+            {
+                return ( LdapComparator<T> ) mr.getLdapComparator();
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInstanceOf( AttributeType attributeType )
+    {
+        return ( attributeType != null )
+            && ( this.attributeType.equals( attributeType ) || this.attributeType.isDescendantOf( attributeType ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public T getNormReference()
+    {
+        if ( isNull() )
+        {
+            return null;
+        }
+
+        if ( normalizedValue == null )
+        {
+            return upValue;
+        }
+
+        return normalizedValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final boolean isNull()
+    {
+        return upValue == null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final boolean isValid( SyntaxChecker syntaxChecker ) throws LdapInvalidAttributeValueException
+    {
+        if ( syntaxChecker == null )
+        {
+            String message = I18n.err( I18n.ERR_04139, toString() );
+            LOG.error( message );
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, message );
+        }
+
+        return syntaxChecker.isValidSyntax( normalizedValue );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final boolean isSchemaAware()
+    {
+        return attributeType != null;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Attribute.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Attribute.java
new file mode 100644
index 0000000..cb3f296
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Attribute.java
@@ -0,0 +1,433 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.Externalizable;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * A generic interface used to store the LDAP Attributes.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Attribute extends Iterable<Value<?>>, Externalizable
+{
+    /**
+     * Adds some values to this attribute. If the new values are already present in
+     * the attribute values, the method has no effect.
+     * <p>
+     * The new values are added at the end of list of values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were added.
+     * </p>
+     * <p>
+     * If the value's type is different from the attribute's type,
+     * a conversion is done. For instance, if we try to set some String
+     * into a Binary attribute, we just store the UTF-8 byte array 
+     * encoding for this String.
+     * </p>
+     * <p>
+     * If we try to store some byte[] in a HR attribute, we try to 
+     * convert those byte[] assuming they represent an UTF-8 encoded
+     * String. Of course, if it's not the case, the stored value will
+     * be incorrect.
+     * </p>
+     * <p>
+     * It's the responsibility of the caller to check if the stored
+     * values are consistent with the attribute's type.
+     * </p>
+     * <p>
+     * The caller can set the HR flag in order to enforce a type for 
+     * the current attribute, otherwise this type will be set while
+     * adding the first value, using the value's type to set the flag.
+     * </p>
+     *
+     * @param vals some new values to be added which may be null
+     * @return the number of added values, or 0 if none has been added
+     * @throws LdapInvalidAttributeValueException if some of the added values are not valid
+     */
+    int add( String... vals ) throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * Adds some values to this attribute. If the new values are already present in
+     * the attribute values, the method has no effect.
+     * <p>
+     * The new values are added at the end of list of values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were added.
+     * </p>
+     * If the value's type is different from the attribute's type,
+     * a conversion is done. For instance, if we try to set some String
+     * into a Binary attribute, we just store the UTF-8 byte array 
+     * encoding for this String.
+     * If we try to store some byte[] in a HR attribute, we try to 
+     * convert those byte[] assuming they represent an UTF-8 encoded
+     * String. Of course, if it's not the case, the stored value will
+     * be incorrect.
+     * <br>
+     * It's the responsibility of the caller to check if the stored
+     * values are consistent with the attribute's type.
+     * <br>
+     * The caller can set the HR flag in order to enforce a type for 
+     * the current attribute, otherwise this type will be set while
+     * adding the first value, using the value's type to set the flag.
+     *
+     * @param vals some new values to be added which may be null
+     * @return the number of added values, or 0 if none has been added
+     * @throws LdapInvalidAttributeValueException if some of the added values are not valid
+     */
+    int add( byte[]... vals ) throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * Adds some values to this attribute. If the new values are already present in
+     * the attribute values, the method has no effect.
+     * <p>
+     * The new values are added at the end of list of values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were added.
+     * </p>
+     * <p>
+     * If the value's type is different from the attribute's type,
+     * a conversion is done. For instance, if we try to set some 
+     * StringValue into a Binary attribute, we just store the UTF-8 
+     * byte array encoding for this StringValue.
+     * </p>
+     * <p>
+     * If we try to store some BinaryValue in a HR attribute, we try to 
+     * convert those BinaryValue assuming they represent an UTF-8 encoded
+     * String. Of course, if it's not the case, the stored value will
+     * be incorrect.
+     * </p>
+     * <p>
+     * It's the responsibility of the caller to check if the stored
+     * values are consistent with the attribute's type.
+     * </p>
+     * <p>
+     * The caller can set the HR flag in order to enforce a type for 
+     * the current attribute, otherwise this type will be set while
+     * adding the first value, using the value's type to set the flag.
+     * </p>
+     * <p>
+     * <b>Note : </b>If the entry contains no value, and the unique added value
+     * is a null length value, then this value will be considered as
+     * a binary value.
+     * </p>
+     * @param val some new values to be added which may be null
+     * @return the number of added values, or 0 if none has been added
+     * @throws LdapInvalidAttributeValueException if some of the added values are not valid
+     */
+    int add( Value<?>... val ) throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * Remove all the values from this attribute.
+     */
+    void clear();
+
+
+    /**
+     * @return A clone of the current object
+     */
+    Attribute clone();
+
+
+    /**
+     * <p>
+     * Indicates whether the specified values are some of the attribute's values.
+     * </p>
+     * <p>
+     * If the Attribute is not HR, the values will be converted to byte[]
+     * </p>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the given values, otherwise false
+     */
+    boolean contains( String... vals );
+
+
+    /**
+     * <p>
+     * Indicates whether the specified values are some of the attribute's values.
+     * </p>
+     * <p>
+     * If the Attribute is HR, the values will be converted to String
+     * </p>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the given values, otherwise false
+     */
+    boolean contains( byte[]... vals );
+
+
+    /**
+     * <p>
+     * Indicates whether the specified values are some of the attribute's values.
+     * </p>
+     * <p>
+     * If the Attribute is HR, the binary values will be converted to String before
+     * being checked.
+     * </p>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the given values, otherwise false
+     */
+    boolean contains( Value<?>... vals );
+
+
+    /**
+     * Get the attribute type associated with this EntryAttribute.
+     *
+     * @return the attributeType associated with this entry attribute
+     */
+    AttributeType getAttributeType();
+
+
+    /**
+     * <p>
+     * Set the attribute type associated with this EntryAttribute.
+     * </p>
+     * <p>
+     * The current attributeType will be replaced. It is the responsibility of
+     * the caller to insure that the existing values are compatible with the new
+     * AttributeType
+     * </p>
+     *
+     * @param attributeType the attributeType associated with this entry attribute
+     * @throws LdapInvalidAttributeValueException if the contained values are not valid accordingly
+     * to the added AttributeType
+     */
+    void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * <p>
+     * Check if the current attribute type has the same type (or is a descendant of)
+     * than the given attributeType
+     *
+     * @param attributeType The AttributeType to check
+     * @return true if the current attribute is of the expected attributeType or a descendant of it
+     * @throws LdapInvalidAttributeValueException If there is no AttributeType
+     */
+    boolean isInstanceOf( AttributeType attributeType ) throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * <p>
+     * Get the first value of this attribute. If there is none, 
+     * null is returned.
+     * </p>
+     * <p> 
+     * This method is meant to be used if the attribute hold only one value.
+     * </p>
+     * 
+     *  @return The first value for this attribute.
+     */
+    Value<?> get();
+
+
+    /**
+     * <p>
+     * Get the byte[] value, if and only if the value is known to be Binary,
+     * otherwise a InvalidAttributeValueException will be thrown
+     * </p>
+     * <p>
+     * Note that this method returns the first value only.
+     * </p>
+     *
+     * @return The value as a byte[]
+     * @throws LdapInvalidAttributeValueException If the value is a String
+     */
+    byte[] getBytes() throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * Get's the attribute identifier for this entry. This is the value
+     * that will be used as the identifier for the attribute within the
+     * entry.
+     *
+     * @return the identifier for this attribute
+     */
+    String getId();
+
+
+    /**
+     * Get's the user provided identifier for this entry.  This is the value
+     * that will be used as the identifier for the attribute within the
+     * entry.  If this is a commonName attribute for example and the user
+     * provides "COMMONname" instead when adding the entry then this is
+     * the format the user will have that entry returned by the directory
+     * server.  To do so we store this value as it was given and track it
+     * in the attribute using this property.
+     *
+     * @return the user provided identifier for this attribute
+     */
+    String getUpId();
+
+
+    /**
+     * <p>
+     * Tells if the attribute is human readable. 
+     * </p>
+     * <p>This flag is set by the caller, or implicitly when adding String 
+     * values into an attribute which is not yet declared as Binary.
+     * </p> 
+     * @return true if the attribute is human readable
+     */
+    boolean isHumanReadable();
+
+
+    /**
+     * <p>
+     * Get the String value, if and only if the value is known to be a String,
+     * otherwise a InvalidAttributeValueException will be thrown
+     * </p>
+     * <p>
+     * Note that this method returns the first value only.
+     * </p>
+     *
+     * @return The value as a String
+     * @throws LdapInvalidAttributeValueException If the value is a byte[]
+     */
+    String getString() throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * <p>
+     * Removes all the  values that are equal to the given values.
+     * </p>
+     * <p>
+     * Returns true if all the values are removed.
+     * </p>
+     * <p>
+     * If the attribute type is not HR, then the values will be first converted
+     * to byte[]
+     * </p>
+     *
+     * @param vals the values to be removed
+     * @return true if all the values are removed, otherwise false
+     */
+    boolean remove( String... vals );
+
+
+    /**
+     * <p>
+     * Removes all the  values that are equal to the given values.
+     * </p>
+     * <p>
+     * Returns true if all the values are removed. 
+     * </p>
+     * <p>
+     * If the attribute type is HR, then the values will be first converted
+     * to String
+     * </p>
+     *
+     * @param val the values to be removed
+     * @return true if all the values are removed, otherwise false
+     */
+    boolean remove( byte[]... val );
+
+
+    /**
+     * <p>
+     * Removes all the  values that are equal to the given values.
+     * </p>
+     * <p>
+     * Returns true if all the values are removed.
+     * </p>
+     * <p>
+     * If the attribute type is HR and some value which are not String, we
+     * will convert the values first (same thing for a non-HR attribute).
+     * </p>
+     *
+     * @param vals the values to be removed
+     * @return true if all the values are removed, otherwise false
+     */
+    boolean remove( Value<?>... vals );
+
+
+    /**
+     * Set the user provided ID. It will also set the ID, normalizing
+     * the upId (removing spaces before and after, and lower casing it)
+     *
+     * @param upId The attribute ID
+     * @throws IllegalArgumentException If the ID is empty or null or
+     * resolve to an empty value after being trimmed
+     */
+    void setUpId( String upId ) throws IllegalArgumentException;
+
+
+    /**
+     * <p>
+     * Set the user provided ID. If we have none, the upId is assigned
+     * the attributetype's name. If it does not have any name, we will
+     * use the OID.
+     * </p>
+     * <p>
+     * If we have an upId and an AttributeType, they must be compatible. :
+     *  - if the upId is an OID, it must be the AttributeType's OID
+     *  - otherwise, its normalized form must be equals to ones of
+     *  the attributeType's names.
+     * </p>
+     * <p>
+     * In any case, the ATtributeType will be changed. The caller is responsible for
+     * the present values to be compatible with the new AttributeType.
+     * </p>
+     * 
+     * @param upId The attribute ID
+     * @param attributeType The associated attributeType
+     */
+    void setUpId( String upId, AttributeType attributeType );
+
+
+    /**
+      * Retrieves the number of values in this attribute.
+      *
+      * @return the number of values in this attribute, including any values
+      * wrapping a null value if there is one
+      */
+    int size();
+
+
+    /**
+     * Checks to see if this attribute is valid along with the values it contains.
+     *
+     * @param attributeType The AttributeType
+     * @return true if the attribute and it's values are valid, false otherwise
+     * @throws LdapInvalidAttributeValueException if there is a failure to check syntaxes of values
+     */
+    boolean isValid( AttributeType attributeType ) throws LdapInvalidAttributeValueException;
+    
+    
+    /**
+     * A pretty-pinter for Attribute
+     * 
+     * @param tabs The tabs to add before any output
+     * @return The pretty-printed entry
+     */
+    String toString( String tabs );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/AttributeUtils.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/AttributeUtils.java
new file mode 100644
index 0000000..1ffbfd6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/AttributeUtils.java
@@ -0,0 +1,594 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeTypeException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Position;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A set of utility fuctions for working with Attributes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class AttributeUtils
+{
+    private AttributeUtils()
+    {
+    }
+
+
+    /**
+     * Check if an attribute contains a value. The test is case insensitive,
+     * and the value is supposed to be a String. If the value is a byte[],
+     * then the case sensitivity is useless.
+     *
+     * @param attr The attribute to check
+     * @param value The value to look for
+     * @return true if the value is present in the attribute
+     */
+    public static boolean containsValueCaseIgnore( javax.naming.directory.Attribute attr, Object value )
+    {
+        // quick bypass test
+        if ( attr.contains( value ) )
+        {
+            return true;
+        }
+
+        try
+        {
+            if ( value instanceof String )
+            {
+                String strVal = ( String ) value;
+
+                NamingEnumeration<?> attrVals = attr.getAll();
+
+                while ( attrVals.hasMoreElements() )
+                {
+                    Object attrVal = attrVals.nextElement();
+
+                    if ( attrVal instanceof String && strVal.equalsIgnoreCase( ( String ) attrVal ) )
+                    {
+                        return true;
+                    }
+                }
+            }
+            else
+            {
+                byte[] valueBytes = ( byte[] ) value;
+
+                NamingEnumeration<?> attrVals = attr.getAll();
+
+                while ( attrVals.hasMoreElements() )
+                {
+                    Object attrVal = attrVals.nextElement();
+
+                    if ( attrVal instanceof byte[] && Arrays.equals( ( byte[] ) attrVal, valueBytes ) )
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+        catch ( NamingException ne )
+        {
+            return false;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Check if the attributes is a BasicAttributes, and if so, switch
+     * the case sensitivity to false to avoid tricky problems in the server.
+     * (Ldap attributeTypes are *always* case insensitive)
+     * 
+     * @param attributes The Attributes to check
+     */
+    public static Attributes toCaseInsensitive( Attributes attributes )
+    {
+        if ( attributes == null )
+        {
+            return attributes;
+        }
+
+        if ( attributes instanceof BasicAttributes )
+        {
+            if ( attributes.isCaseIgnored() )
+            {
+                // Just do nothing if the Attributes is already case insensitive
+                return attributes;
+            }
+            else
+            {
+                // Ok, bad news : we have to create a new BasicAttributes
+                // which will be case insensitive
+                Attributes newAttrs = new BasicAttributes( true );
+
+                NamingEnumeration<?> attrs = attributes.getAll();
+
+                if ( attrs != null )
+                {
+                    // Iterate through the attributes now
+                    while ( attrs.hasMoreElements() )
+                    {
+                        newAttrs.put( ( javax.naming.directory.Attribute ) attrs.nextElement() );
+                    }
+                }
+
+                return newAttrs;
+            }
+        }
+        else
+        {
+            // we can safely return the attributes if it's not a BasicAttributes
+            return attributes;
+        }
+    }
+
+
+    /**
+     * Parse attribute's options :
+     * 
+     * options = *( ';' option )
+     * option = 1*keychar
+     * keychar = 'a'-z' | 'A'-'Z' / '0'-'9' / '-'
+     */
+    private static void parseOptions( byte[] str, Position pos ) throws ParseException
+    {
+        while ( Strings.isCharASCII( str, pos.start, ';' ) )
+        {
+            pos.start++;
+
+            // We have an option
+            if ( !Chars.isAlphaDigitMinus( str, pos.start ) )
+            {
+                // We must have at least one keychar
+                throw new ParseException( I18n.err( I18n.ERR_04343 ), pos.start );
+            }
+
+            pos.start++;
+
+            while ( Chars.isAlphaDigitMinus( str, pos.start ) )
+            {
+                pos.start++;
+            }
+        }
+    }
+
+
+    /**
+     * Parse a number :
+     * 
+     * number = '0' | '1'..'9' digits
+     * digits = '0'..'9'*
+     * 
+     * @return true if a number has been found
+     */
+    private static boolean parseNumber( byte[] filter, Position pos )
+    {
+        byte b = Strings.byteAt( filter, pos.start );
+
+        switch ( b )
+        {
+            case '0':
+                // If we get a starting '0', we should get out
+                pos.start++;
+                return true;
+
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                pos.start++;
+                break;
+
+            default:
+                // Not a number.
+                return false;
+        }
+
+        while ( Chars.isDigit( filter, pos.start ) )
+        {
+            pos.start++;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * 
+     * Parse an OID.
+     *
+     * numericoid = number 1*( '.' number )
+     * number = '0'-'9' / ( '1'-'9' 1*'0'-'9' )
+     *
+     * @param str The OID to parse
+     * @param pos The current position in the string
+     * @throws ParseException If we don't have a valid OID
+     */
+    private static void parseOID( byte[] str, Position pos ) throws ParseException
+    {
+        // We have an OID
+        parseNumber( str, pos );
+
+        // We must have at least one '.' number
+        if ( !Strings.isCharASCII( str, pos.start, '.' ) )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04344 ), pos.start );
+        }
+
+        pos.start++;
+
+        if ( !parseNumber( str, pos ) )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04345 ), pos.start );
+        }
+
+        while ( true )
+        {
+            // Break if we get something which is not a '.'
+            if ( !Strings.isCharASCII( str, pos.start, '.' ) )
+            {
+                break;
+            }
+
+            pos.start++;
+
+            if ( !parseNumber( str, pos ) )
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04345 ), pos.start );
+            }
+        }
+    }
+
+
+    /**
+     * Parse an attribute. The grammar is :
+     * attributedescription = attributetype options
+     * attributetype = oid
+     * oid = descr / numericoid
+     * descr = keystring
+     * numericoid = number 1*( '.' number )
+     * options = *( ';' option )
+     * option = 1*keychar
+     * keystring = leadkeychar *keychar
+     * leadkeychar = 'a'-z' | 'A'-'Z'
+     * keychar = 'a'-z' | 'A'-'Z' / '0'-'9' / '-'
+     * number = '0'-'9' / ( '1'-'9' 1*'0'-'9' )
+     *
+     * @param str The parsed attribute,
+     * @param pos The position of the attribute in the current string
+     * @return The parsed attribute if valid
+     */
+    public static String parseAttribute( byte[] str, Position pos, boolean withOption, boolean relaxed )
+        throws ParseException
+    {
+        // We must have an OID or an DESCR first
+        byte b = Strings.byteAt( str, pos.start );
+
+        if ( b == '\0' )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04346 ), pos.start );
+        }
+
+        int start = pos.start;
+
+        if ( Chars.isAlpha( b ) )
+        {
+            // A DESCR
+            pos.start++;
+
+            while ( Chars.isAlphaDigitMinus( str, pos.start ) || ( relaxed && Chars.isUnderscore( str, pos.start ) ) )
+            {
+                pos.start++;
+            }
+
+            // Parse the options if needed
+            if ( withOption )
+            {
+                parseOptions( str, pos );
+            }
+
+            return Strings.getString( str, start, pos.start - start, "UTF-8" );
+        }
+        else if ( Chars.isDigit( b ) )
+        {
+            // An OID
+            pos.start++;
+
+            // Parse the OID
+            parseOID( str, pos );
+
+            // Parse the options
+            if ( withOption )
+            {
+                parseOptions( str, pos );
+            }
+
+            return Strings.getString( str,  start, pos.start - start, "UTF-8" );
+        }
+        else
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04347 ), pos.start );
+        }
+    }
+
+
+    /**
+     * A method to apply a modification to an existing entry.
+     * 
+     * @param entry The entry on which we want to apply a modification
+     * @param modification the Modification to be applied
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if some operation fails.
+     */
+    public static void applyModification( Entry entry, Modification modification ) throws LdapException
+    {
+        Attribute modAttr = modification.getAttribute();
+        String modificationId = modAttr.getUpId();
+
+        switch ( modification.getOperation() )
+        {
+            case ADD_ATTRIBUTE:
+                Attribute modifiedAttr = entry.get( modificationId );
+
+                if ( modifiedAttr == null )
+                {
+                    // The attribute should be added.
+                    entry.put( modAttr );
+                }
+                else
+                {
+                    // The attribute exists : the values can be different,
+                    // so we will just add the new values to the existing ones.
+                    for ( Value<?> value : modAttr )
+                    {
+                        // If the value already exist, nothing is done.
+                        // Note that the attribute *must* have been
+                        // normalized before.
+                        modifiedAttr.add( value );
+                    }
+                }
+
+                break;
+
+            case REMOVE_ATTRIBUTE:
+                if ( modAttr.get() == null )
+                {
+                    // We have no value in the ModificationItem attribute :
+                    // we have to remove the whole attribute from the initial
+                    // entry
+                    entry.removeAttributes( modificationId );
+                }
+                else
+                {
+                    // We just have to remove the values from the original
+                    // entry, if they exist.
+                    modifiedAttr = entry.get( modificationId );
+
+                    if ( modifiedAttr == null )
+                    {
+                        break;
+                    }
+
+                    for ( Value<?> value : modAttr )
+                    {
+                        // If the value does not exist, nothing is done.
+                        // Note that the attribute *must* have been
+                        // normalized before.
+                        modifiedAttr.remove( value );
+                    }
+
+                    if ( modifiedAttr.size() == 0 )
+                    {
+                        // If this was the last value, remove the attribute
+                        entry.removeAttributes( modifiedAttr.getUpId() );
+                    }
+                }
+
+                break;
+
+            case REPLACE_ATTRIBUTE:
+                if ( modAttr.get() == null )
+                {
+                    // If the modification does not have any value, we have
+                    // to delete the attribute from the entry.
+                    entry.removeAttributes( modificationId );
+                }
+                else
+                {
+                    // otherwise, just substitute the existing attribute.
+                    entry.put( modAttr );
+                }
+
+                break;
+            default:
+                break;
+        }
+    }
+
+
+    /**
+     * Convert a BasicAttributes or a AttributesImpl to an Entry
+     *
+     * @param attributes the BasicAttributes or AttributesImpl instance to convert
+     * @param dn The Dn which is needed by the Entry
+     * @return An instance of a Entry object
+     * 
+     * @throws LdapException If we get an invalid attribute
+     */
+    public static Entry toEntry( Attributes attributes, Dn dn ) throws LdapException
+    {
+        if ( attributes instanceof BasicAttributes )
+        {
+            try
+            {
+                Entry entry = new DefaultEntry( dn );
+
+                for ( NamingEnumeration<? extends javax.naming.directory.Attribute> attrs = attributes.getAll(); attrs
+                    .hasMoreElements(); )
+                {
+                    javax.naming.directory.Attribute attr = attrs.nextElement();
+
+                    Attribute entryAttribute = toApiAttribute( attr );
+
+                    if ( entryAttribute != null )
+                    {
+                        entry.put( entryAttribute );
+                    }
+                }
+
+                return entry;
+            }
+            catch ( LdapException ne )
+            {
+                throw new LdapInvalidAttributeTypeException( ne.getMessage(), ne );
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Converts an {@link Entry} to an {@link Attributes}.
+     *
+     * @param entry
+     *      the {@link Entry} to convert
+     * @return
+     *      the equivalent {@link Attributes}
+     */
+    public static Attributes toAttributes( Entry entry )
+    {
+        if ( entry != null )
+        {
+            Attributes attributes = new BasicAttributes( true );
+
+            // Looping on attributes
+            for ( Iterator<Attribute> attributeIterator = entry.iterator(); attributeIterator.hasNext(); )
+            {
+                Attribute entryAttribute = attributeIterator.next();
+
+                attributes.put( toJndiAttribute( entryAttribute ) );
+            }
+
+            return attributes;
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Converts an {@link Attribute} to a JNDI Attribute.
+     *
+     * @param attribute the {@link Attribute} to convert
+     * @return the equivalent JNDI Attribute
+     */
+    public static javax.naming.directory.Attribute toJndiAttribute( Attribute attribute )
+    {
+        if ( attribute != null )
+        {
+            javax.naming.directory.Attribute jndiAttribute = new BasicAttribute( attribute.getUpId() );
+
+            // Looping on values
+            for ( Iterator<Value<?>> valueIterator = attribute.iterator(); valueIterator.hasNext(); )
+            {
+                Value<?> value = valueIterator.next();
+                jndiAttribute.add( value.getValue() );
+            }
+
+            return jndiAttribute;
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Convert a JNDI Attribute to an LDAP API Attribute
+     *
+     * @param jndiAttribute the JNDI Attribute instance to convert
+     * @return An instance of a LDAP API Attribute object
+     */
+    public static Attribute toApiAttribute( javax.naming.directory.Attribute jndiAttribute )
+        throws LdapInvalidAttributeValueException
+    {
+        if ( jndiAttribute == null )
+        {
+            return null;
+        }
+
+        try
+        {
+            Attribute attribute = new DefaultAttribute( jndiAttribute.getID() );
+
+            for ( NamingEnumeration<?> values = jndiAttribute.getAll(); values.hasMoreElements(); )
+            {
+                Object value = values.nextElement();
+
+                if ( value instanceof String )
+                {
+                    attribute.add( ( String ) value );
+                }
+                else if ( value instanceof byte[] )
+                {
+                    attribute.add( ( byte[] ) value );
+                }
+                else
+                {
+                    attribute.add( ( String ) null );
+                }
+            }
+
+            return attribute;
+        }
+        catch ( NamingException ne )
+        {
+            return null;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/BinaryValue.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/BinaryValue.java
new file mode 100644
index 0000000..2623a93
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/BinaryValue.java
@@ -0,0 +1,699 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A server side schema aware wrapper around a binary attribute value.
+ * This value wrapper uses schema information to syntax check values,
+ * and to compare them for equality and ordering.  It caches results
+ * and invalidates them when the user provided value changes.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BinaryValue extends AbstractValue<byte[]>
+{
+    /** Used for serialization */
+    public static final long serialVersionUID = 2L;
+
+
+    /**
+     * Creates a BinaryValue without an initial user provided value.
+     *
+     * @param attributeType the schema type associated with this BinaryValue
+     */
+    /* No protection */BinaryValue( AttributeType attributeType )
+    {
+        if ( attributeType != null )
+        {
+            // We must have a Syntax
+            if ( attributeType.getSyntax() == null )
+            {
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04445 ) );
+            }
+
+            if ( attributeType.getSyntax().isHumanReadable() )
+            {
+                LOG.warn( "Treating a value of a human readible attribute {} as binary: ", attributeType.getName() );
+            }
+
+            this.attributeType = attributeType;
+        }
+    }
+
+
+    /**
+     * Creates a BinaryValue with an initial user provided binary value.
+     *
+     * @param value the binary value to wrap which may be null, or a zero length byte array
+     */
+    public BinaryValue( byte[] value )
+    {
+        if ( value != null )
+        {
+            this.upValue = new byte[value.length];
+            this.normalizedValue = new byte[value.length];
+            System.arraycopy( value, 0, this.upValue, 0, value.length );
+            System.arraycopy( value, 0, this.normalizedValue, 0, value.length );
+        }
+        else
+        {
+            this.upValue = null;
+            this.normalizedValue = null;
+        }
+    }
+
+
+    /**
+     * Creates a BinaryValue with an initial user provided binary value.
+     *
+     * @param attributeType the schema type associated with this BinaryValue
+     * @param value the binary value to wrap which may be null, or a zero length byte array
+     * @throws LdapInvalidAttributeValueException If the added value is invalid accordingly 
+     * to the schema
+     */
+    public BinaryValue( AttributeType attributeType, byte[] value ) throws LdapInvalidAttributeValueException
+    {
+        this( value );
+        apply( attributeType );
+    }
+
+
+    /**
+     * Gets a direct reference to the normalized representation for the
+     * user provided value of this ServerValue wrapper. Implementations will most
+     * likely leverage the attributeType this value is associated with to
+     * determine how to properly normalize the user provided value.
+     *
+     * @return the normalized version of the user provided value
+     */
+    public byte[] getNormValue()
+    {
+        if ( isNull() )
+        {
+            return null;
+        }
+
+        byte[] copy = new byte[normalizedValue.length];
+        System.arraycopy( normalizedValue, 0, copy, 0, normalizedValue.length );
+        return copy;
+    }
+
+
+    /**
+     *
+     * @see ServerValue#compareTo(Value)
+     */
+    public int compareTo( Value<byte[]> value )
+    {
+        if ( isNull() )
+        {
+            if ( ( value == null ) || value.isNull() )
+            {
+                return 0;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+        else
+        {
+            if ( ( value == null ) || value.isNull() )
+            {
+                return 1;
+            }
+        }
+
+        BinaryValue binaryValue = ( BinaryValue ) value;
+
+        if ( attributeType != null )
+        {
+            try
+            {
+                LdapComparator<byte[]> comparator = getLdapComparator();
+
+                if ( comparator != null )
+                {
+                    return comparator
+                        .compare( getNormReference(), binaryValue.getNormReference() );
+                }
+                else
+                {
+                    return new ByteArrayComparator( null ).compare( getNormReference(), binaryValue
+                        .getNormReference() );
+                }
+            }
+            catch ( LdapException e )
+            {
+                String msg = I18n.err( I18n.ERR_04443, Arrays.toString( getReference() ), value );
+                LOG.error( msg, e );
+                throw new IllegalStateException( msg, e );
+            }
+        }
+        else
+        {
+            return new ByteArrayComparator( null ).compare( getNormValue(), binaryValue.getNormValue() );
+        }
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Object Methods
+    // -----------------------------------------------------------------------
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hashcode 
+     */
+    public int hashCode()
+    {
+        if ( h == 0 )
+        {
+            // return zero if the value is null so only one null value can be
+            // stored in an attribute - the string version does the same
+            if ( isNull() )
+            {
+                return 0;
+            }
+
+            byte[] normalizedValue = getNormReference();
+            h = Arrays.hashCode( normalizedValue );
+        }
+
+        return h;
+    }
+
+
+    /**
+     * Checks to see if this BinaryValue equals the supplied object.
+     *
+     * This equals implementation overrides the BinaryValue implementation which
+     * is not schema aware.
+     */
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( !( obj instanceof BinaryValue ) )
+        {
+            return false;
+        }
+
+        BinaryValue other = ( BinaryValue ) obj;
+
+        // First check if we have an attrbuteType.
+        if ( attributeType != null )
+        {
+            // yes : check for the other value
+            if ( other.attributeType != null )
+            {
+                if ( attributeType.getOid().equals( other.getAttributeType().getOid() ) )
+                {
+                    // Both AttributeType have the same OID, we can assume they are 
+                    // equals. We don't check any further, because the unicity of OID
+                    // makes it unlikely that the two AT are different.
+                    // The values may be both null
+                    if ( isNull() )
+                    {
+                        return other.isNull();
+                    }
+
+                    // Shortcut : if we have an AT for both the values, check the 
+                    // already normalized values
+                    if ( Arrays.equals( upValue, other.upValue ) )
+                    {
+                        return true;
+                    }
+
+                    // We have an AttributeType, we use the associated comparator
+                    try
+                    {
+                        Comparator<byte[]> comparator = getLdapComparator();
+
+                        // Compare normalized values
+                        if ( comparator == null )
+                        {
+                            return Arrays.equals( getNormReference(), other.getNormReference() );
+                        }
+                        else
+                        {
+                            return comparator.compare( getNormReference(), other.getNormReference() ) == 0;
+                        }
+                    }
+                    catch ( LdapException ne )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    // We can't compare two values when the two ATs are different
+                    return false;
+                }
+            }
+            else
+            {
+                // We only have one AT : we will assume that both values are for the 
+                // same AT.
+                // The values may be both null
+                if ( isNull() )
+                {
+                    return other.isNull();
+                }
+
+                // We have an AttributeType on the base value, we need to use its comparator
+                try
+                {
+                    Comparator<byte[]> comparator = getLdapComparator();
+
+                    // Compare normalized values. We have to normalized the other value,
+                    // as it has no AT
+                    MatchingRule equality = getAttributeType().getEquality();
+
+                    if ( equality == null )
+                    {
+                        // No matching rule : compare the raw values
+                        return Arrays.equals( getNormReference(), other.getNormReference() );
+                    }
+
+                    Normalizer normalizer = equality.getNormalizer();
+
+                    BinaryValue otherValue = ( BinaryValue ) normalizer.normalize( other );
+
+                    if ( comparator == null )
+                    {
+                        return Arrays.equals( getNormReference(), otherValue.getNormReference() );
+                    }
+                    else
+                    {
+                        return comparator.compare( getNormReference(), otherValue.getNormReference() ) == 0;
+                    }
+                }
+                catch ( LdapException ne )
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            // No : check for the other value
+            if ( other.attributeType != null )
+            {
+                // We only have one AT : we will assume that both values are for the 
+                // same AT.
+                // The values may be both null
+                if ( isNull() )
+                {
+                    return other.isNull();
+                }
+
+                try
+                {
+                    Comparator<byte[]> comparator = other.getLdapComparator();
+
+                    // Compare normalized values. We have to normalized the other value,
+                    // as it has no AT
+                    MatchingRule equality = other.getAttributeType().getEquality();
+
+                    if ( equality == null )
+                    {
+                        // No matching rule : compare the raw values
+                        return Arrays.equals( getNormReference(), other.getNormReference() );
+                    }
+
+                    Normalizer normalizer = equality.getNormalizer();
+
+                    BinaryValue thisValue = ( BinaryValue ) normalizer.normalize( this );
+
+                    if ( comparator == null )
+                    {
+                        return Arrays.equals( thisValue.getNormReference(), other.getNormReference() );
+                    }
+                    else
+                    {
+                        return comparator.compare( thisValue.getNormReference(), other.getNormReference() ) == 0;
+                    }
+                }
+                catch ( LdapException ne )
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                // The values may be both null
+                if ( isNull() )
+                {
+                    return other.isNull();
+                }
+
+                // Now check the normalized values
+                return Arrays.equals( getNormReference(), other.getNormReference() );
+            }
+        }
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Cloneable methods
+    // -----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public BinaryValue clone()
+    {
+        BinaryValue clone = ( BinaryValue ) super.clone();
+
+        // We have to copy the byte[], they are just referenced by suoer.clone()
+        if ( normalizedValue != null )
+        {
+            clone.normalizedValue = new byte[normalizedValue.length];
+            System.arraycopy( normalizedValue, 0, clone.normalizedValue, 0, normalizedValue.length );
+        }
+
+        if ( upValue != null )
+        {
+            clone.upValue = new byte[upValue.length];
+            System.arraycopy( upValue, 0, clone.upValue, 0, upValue.length );
+        }
+
+        return clone;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        if ( upValue == null )
+        {
+            return null;
+        }
+
+        final byte[] copy = new byte[upValue.length];
+        System.arraycopy( upValue, 0, copy, 0, upValue.length );
+
+        return copy;
+    }
+
+
+    /**
+     * Tells if the current value is Human Readable
+     * 
+     * @return <code>true</code> if the value is HR, <code>false</code> otherwise
+     */
+    public boolean isHumanReadable()
+    {
+        return false;
+    }
+
+
+    /**
+     * @return The length of the interned value
+     */
+    public int length()
+    {
+        return upValue != null ? upValue.length : 0;
+    }
+
+
+    /**
+     * Get the user provided value as a byte[]. This method returns a copy of 
+     * the user provided byte[].
+     * 
+     * @return the user provided value as a byte[]
+     */
+    public byte[] getBytes()
+    {
+        return getValue();
+    }
+
+
+    /**
+     * Get the user provided value as a String.
+     *
+     * @return the user provided value as a String
+     */
+    public String getString()
+    {
+        return Strings.utf8ToString( upValue );
+    }
+
+
+    /**
+     * Deserialize a BinaryValue. It will return a new BinaryValue instance.
+     * 
+     * @param attributeType The AttributeType associated with the Value. Can be null
+     * @param in The input stream
+     * @return A new StringValue instance
+     * @throws IOException If the stream can't be read
+     * @throws ClassNotFoundException If we can't instanciate a BinaryValue
+     */
+    public static BinaryValue deserialize( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        BinaryValue value = new BinaryValue( ( AttributeType ) null );
+        value.readExternal( in );
+
+        return value;
+    }
+
+
+    /**
+     * Deserialize a schema aware BinaryValue. It will return a new BinaryValue instance.
+     * 
+     * @param attributeType The AttributeType associated with the Value. Can be null
+     * @param in The input stream
+     * @return A new StringValue instance
+     * @throws IOException If the stream can't be read
+     * @throws ClassNotFoundException If we can't instanciate a BinaryValue
+     */
+    public static BinaryValue deserialize( AttributeType attributeType, ObjectInput in ) throws IOException,
+        ClassNotFoundException
+    {
+        BinaryValue value = new BinaryValue( attributeType );
+        value.readExternal( in );
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the BINARY flag
+        boolean isHR = in.readBoolean();
+
+        if ( isHR )
+        {
+            throw new IOException( "The serialized value is not a Binary value" );
+        }
+        // Read the user provided value, if it's not null
+        int upLength = in.readInt();
+
+        if ( upLength >= 0 )
+        {
+            upValue = new byte[upLength];
+
+            in.readFully( upValue );
+        }
+
+        // Read the isNormalized flag
+        boolean normalized = in.readBoolean();
+
+        if ( normalized )
+        {
+            int normalizedLength = in.readInt();
+
+            if ( normalizedLength >= 0 )
+            {
+                normalizedValue = new byte[normalizedLength];
+
+                in.readFully( normalizedValue );
+            }
+        }
+        else
+        {
+            if ( attributeType != null )
+            {
+                try
+                {
+                    normalizedValue = attributeType.getEquality().getNormalizer().normalize( this ).getBytes();
+                    MatchingRule equality = attributeType.getEquality();
+
+                    if ( equality == null )
+                    {
+                        if ( upLength >= 0 )
+                        {
+                            normalizedValue = new byte[upLength];
+
+                            System.arraycopy( upValue, 0, normalizedValue, 0, upLength );
+                        }
+                    }
+                    else
+                    {
+                        Normalizer normalizer = equality.getNormalizer();
+
+                        if ( normalizer != null )
+                        {
+                            normalizedValue = normalizer.normalize( this ).getBytes();
+                        }
+                        else
+                        {
+                            if ( upLength >= 0 )
+                            {
+                                normalizedValue = new byte[upLength];
+
+                                System.arraycopy( upValue, 0, normalizedValue, 0, upLength );
+                            }
+                        }
+                    }
+                }
+                catch ( LdapException le )
+                {
+                    // Copy the upValue into the normalizedValue
+                    if ( upLength >= 0 )
+                    {
+                        normalizedValue = new byte[upLength];
+
+                        System.arraycopy( upValue, 0, normalizedValue, 0, upLength );
+                    }
+                }
+            }
+            else
+            {
+                // Copy the upValue into the normalizedValue
+                if ( upLength >= 0 )
+                {
+                    normalizedValue = new byte[upLength];
+
+                    System.arraycopy( upValue, 0, normalizedValue, 0, upLength );
+                }
+            }
+        }
+
+        // The hashCoe
+        h = in.readInt();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        // Write the BINARY flag
+        out.writeBoolean( BINARY );
+
+        // Write the user provided value, if it's not null
+        if ( upValue != null )
+        {
+            out.writeInt( upValue.length );
+
+            if ( upValue.length > 0 )
+            {
+                out.write( upValue, 0, upValue.length );
+            }
+        }
+        else
+        {
+            out.writeInt( -1 );
+        }
+
+        // Write the isNormalized flag
+        if ( attributeType != null )
+        {
+            out.writeBoolean( true );
+
+            // Write the normalized value, if not null
+            if ( normalizedValue != null )
+            {
+                out.writeInt( normalizedValue.length );
+
+                if ( normalizedValue.length > 0 )
+                {
+                    out.write( normalizedValue, 0, normalizedValue.length );
+                }
+            }
+            else
+            {
+                out.writeInt( -1 );
+            }
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        // The hashCode
+        out.writeInt( h );
+
+        out.flush();
+    }
+
+
+    /**
+     * Dumps binary in hex with label.
+     *
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        if ( upValue == null )
+        {
+            return "null";
+        }
+        else if ( upValue.length > 16 )
+        {
+            // Just dump the first 16 bytes...
+            byte[] copy = new byte[16];
+
+            System.arraycopy( upValue, 0, copy, 0, 16 );
+
+            return Strings.dumpBytes( copy ) + "...";
+        }
+        else
+        {
+            return Strings.dumpBytes( upValue );
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultAttribute.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultAttribute.java
new file mode 100644
index 0000000..2515cc7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultAttribute.java
@@ -0,0 +1,2132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An LDAP attribute.<p>
+ * To define the kind of data stored, the client must set the isHR flag, or inject an AttributeType.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultAttribute implements Attribute, Cloneable
+{
+    /** logger for reporting errors that might not be handled properly upstream */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultAttribute.class );
+
+    /** The associated AttributeType */
+    private AttributeType attributeType;
+
+    /** The set of contained values */
+    private Set<Value<?>> values = new LinkedHashSet<Value<?>>();
+
+    /** The User provided ID */
+    private String upId;
+
+    /** The normalized ID (will be the OID if we have a AttributeType) */
+    private String id;
+
+    /** Tells if the attribute is Human Readable or not. When not set,
+     * this flag is null. */
+    private Boolean isHR;
+
+    /** The computed hashcode. We don't want to compute it each time the hashcode() method is called */
+    private volatile int h;
+
+
+    //-------------------------------------------------------------------------
+    // Helper methods
+    //-------------------------------------------------------------------------
+    private Value<String> createStringValue( AttributeType attributeType, String value )
+    {
+        Value<String> stringValue = null;
+
+        if ( attributeType != null )
+        {
+            try
+            {
+                stringValue = new StringValue( attributeType, value );
+            }
+            catch ( LdapInvalidAttributeValueException iae )
+            {
+                return null;
+            }
+        }
+        else
+        {
+            stringValue = new StringValue( value );
+        }
+
+        return stringValue;
+    }
+
+
+    private Value<byte[]> createBinaryValue( AttributeType attributeType, byte[] value )
+        throws LdapInvalidAttributeValueException
+    {
+        Value<byte[]> binaryValue = null;
+
+        if ( attributeType != null )
+        {
+            binaryValue = new BinaryValue( attributeType, value );
+        }
+        else
+        {
+            binaryValue = new BinaryValue( value );
+        }
+
+        return binaryValue;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Constructors
+    //-------------------------------------------------------------------------
+    // maybe have some additional convenience constructors which take
+    // an initial value as a string or a byte[]
+    /**
+     * Create a new instance of a Attribute, without ID nor value.
+     * Used by the serializer
+     */
+    /* No protection*/DefaultAttribute()
+    {
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, without ID nor value.
+     * Used by the serializer
+     */
+    /* No protection*/DefaultAttribute( AttributeType attributeType, String upId, String normId, boolean isHR,
+        int hashCode, Value<?>... values )
+    {
+        this.attributeType = attributeType;
+        this.upId = upId;
+        this.id = normId;
+        this.isHR = isHR;
+        this.h = hashCode;
+
+        if ( values != null )
+        {
+            for ( Value<?> value : values )
+            {
+                this.values.add( value );
+            }
+        }
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, without ID nor value.
+     * 
+     * @param attributeType the attributeType for the empty attribute added into the entry
+     */
+    public DefaultAttribute( AttributeType attributeType )
+    {
+        if ( attributeType != null )
+        {
+            try
+            {
+                apply( attributeType );
+            }
+            catch ( LdapInvalidAttributeValueException liave )
+            {
+                // Do nothing, it can't happen, there is no value
+            }
+        }
+    }
+
+
+    /**
+     * Create a new instance of an Attribute, without value.
+     * @param upId The user provided ID
+     */
+    public DefaultAttribute( String upId )
+    {
+        setUpId( upId );
+    }
+
+
+    /**
+     * Create a new instance of an Attribute, without value.
+     * @param upId The user provided ID
+     */
+    public DefaultAttribute( byte[] upId )
+    {
+        setUpId( upId );
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, without value.
+     * 
+     * @param upId the ID for the added attributeType
+     * @param attributeType the added AttributeType
+     */
+    public DefaultAttribute( String upId, AttributeType attributeType )
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        try
+        {
+            apply( attributeType );
+        }
+        catch ( LdapInvalidAttributeValueException liave )
+        {
+            // Do nothing, it can't happen, there is no value
+        }
+
+        setUpId( upId, attributeType );
+    }
+
+
+    /**
+     * Create a new instance of an Attribute, with some values, and a user provided ID.<br>
+     * If the value does not correspond to the same attributeType, then it's
+     * wrapped value is copied into a new ClientValue which uses the specified
+     * attributeType.
+     * <p>
+     * Otherwise, the value is stored, but as a reference. It's not a copy.
+     * </p>
+     * @param upId the attributeType ID
+     * @param vals an initial set of values for this attribute
+     */
+    public DefaultAttribute( String upId, Value<?>... vals )
+    {
+        // The value can be null, this is a valid value.
+        if ( vals[0] == null )
+        {
+            add( new StringValue( ( String ) null ) );
+        }
+        else
+        {
+            for ( Value<?> val : vals )
+            {
+                if ( ( val instanceof StringValue ) || ( !val.isHumanReadable() ) )
+                {
+                    add( val );
+                }
+                else
+                {
+                    String message = I18n.err( I18n.ERR_04129, val.getClass().getName() );
+                    LOG.error( message );
+                    throw new IllegalStateException( message );
+                }
+            }
+        }
+
+        setUpId( upId );
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, without ID but with some values.
+     * 
+     * @param attributeType The attributeType added on creation
+     * @param vals The added value for this attribute
+     * @throws LdapInvalidAttributeValueException If any of the
+     * added values is not valid
+     */
+    public DefaultAttribute( AttributeType attributeType, String... vals ) throws LdapInvalidAttributeValueException
+    {
+        this( null, attributeType, vals );
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, with some values, and a user provided ID.
+     * 
+     * @param upId the ID for the created attribute
+     * @param attributeType The attributeType added on creation
+     * @param vals the added values for this attribute
+     * @throws LdapInvalidAttributeValueException If any of the
+     * added values is not valid
+     */
+    public DefaultAttribute( String upId, AttributeType attributeType, String... vals )
+        throws LdapInvalidAttributeValueException
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        apply( attributeType );
+
+        if ( ( vals != null ) && ( vals.length > 0 ) )
+        {
+            add( vals );
+        }
+
+        setUpId( upId, attributeType );
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, with some values, and a user provided ID.<br>
+     * If the value does not correspond to the same attributeType, then it's
+     * wrapped value is copied into a new Value which uses the specified
+     * attributeType.
+     * <p>
+     * Otherwise, the value is stored, but as a reference. It's not a copy.
+     * </p>
+     * @param upId the ID of the created attribute
+     * @param attributeType the attribute type according to the schema
+     * @param vals an initial set of values for this attribute
+     * @throws LdapInvalidAttributeValueException If any of the
+     * added values is not valid
+     */
+    public DefaultAttribute( String upId, AttributeType attributeType, Value<?>... vals )
+        throws LdapInvalidAttributeValueException
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        apply( attributeType );
+        setUpId( upId, attributeType );
+        add( vals );
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, with some values.
+     * <p>
+     * If the value does not correspond to the same attributeType, then it's
+     * wrapped value is copied into a new Value which uses the specified
+     * attributeType.
+     * </p>
+     * @param attributeType the attribute type according to the schema
+     * @param vals an initial set of values for this attribute
+     */
+    public DefaultAttribute( AttributeType attributeType, Value<?>... vals ) throws LdapInvalidAttributeValueException
+    {
+        this( null, attributeType, vals );
+    }
+
+
+    /**
+     * Create a new instance of an Attribute, with some String values, and a user provided ID.
+     * 
+     * @param upId the ID of the created attribute
+     * @param vals an initial set of String values for this attribute
+     */
+    public DefaultAttribute( String upId, String... vals )
+    {
+        try
+        {
+            add( vals );
+        }
+        catch ( LdapInvalidAttributeValueException liave )
+        {
+            // Do nothing, it can't happen
+        }
+
+        setUpId( upId );
+    }
+
+
+    /**
+     * Create a new instance of an Attribute, with some binary values, and a user provided ID.
+     * 
+     * @param upId the ID of the created attribute
+     * @param vals an initial set of binary values for this attribute
+     */
+    public DefaultAttribute( String upId, byte[]... vals )
+    {
+        try
+        {
+            add( vals );
+        }
+        catch ( LdapInvalidAttributeValueException liave )
+        {
+            // Do nothing, this can't happen
+        }
+
+        setUpId( upId );
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, with some byte[] values.
+     * 
+     * @param attributeType The attributeType added on creation
+     * @param vals The added binary values
+     * @throws LdapInvalidAttributeValueException If any of the
+     * added values is not valid
+     */
+    public DefaultAttribute( AttributeType attributeType, byte[]... vals ) throws LdapInvalidAttributeValueException
+    {
+        this( null, attributeType, vals );
+    }
+
+
+    /**
+     * Create a new instance of a schema aware Attribute, with some byte[] values, and
+     * a user provided ID.
+     * 
+     * @param upId the ID for the added attribute
+     * @param attributeType the AttributeType to be added
+     * @param vals the binary values for the added attribute
+     * @throws LdapInvalidAttributeValueException If any of the
+     * added values is not valid
+     */
+    public DefaultAttribute( String upId, AttributeType attributeType, byte[]... vals )
+        throws LdapInvalidAttributeValueException
+    {
+        if ( attributeType == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED ) );
+        }
+
+        apply( attributeType );
+        add( vals );
+        setUpId( upId, attributeType );
+    }
+
+
+    /**
+     * Creates a new instance of schema aware Attribute, by copying another attribute.
+     * If the initial Attribute is not schema aware, the copy will be if the attributeType
+     * argument is not null.
+     *
+     * @param attributeType The attribute's type
+     * @param attribute The attribute to be copied
+     */
+    public DefaultAttribute( AttributeType attributeType, Attribute attribute ) throws LdapException
+    {
+        // Copy the common values. isHR is only available on a ServerAttribute
+        this.attributeType = attributeType;
+        this.id = attribute.getId();
+        this.upId = attribute.getUpId();
+
+        if ( attributeType == null )
+        {
+            isHR = attribute.isHumanReadable();
+
+            // Copy all the values
+            for ( Value<?> value : attribute )
+            {
+                add( value.clone() );
+            }
+
+            if ( attribute.getAttributeType() != null )
+            {
+                apply( attribute.getAttributeType() );
+            }
+        }
+        else
+        {
+
+            isHR = attributeType.getSyntax().isHumanReadable();
+
+            // Copy all the values
+            for ( Value<?> clientValue : attribute )
+            {
+                Value<?> serverValue = null;
+
+                // We have to convert the value first
+                if ( clientValue instanceof StringValue )
+                {
+                    if ( isHR )
+                    {
+                        serverValue = new StringValue( attributeType, clientValue.getString() );
+                    }
+                    else
+                    {
+                        // We have to convert the value to a binary value first
+                        serverValue = new BinaryValue( attributeType,
+                            clientValue.getBytes() );
+                    }
+                }
+                else if ( clientValue instanceof BinaryValue )
+                {
+                    if ( isHR )
+                    {
+                        // We have to convert the value to a String value first
+                        serverValue = new StringValue( attributeType,
+                            clientValue.getString() );
+                    }
+                    else
+                    {
+                        serverValue = new BinaryValue( attributeType, clientValue.getBytes() );
+                    }
+                }
+
+                add( serverValue );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getBytes() throws LdapInvalidAttributeValueException
+    {
+        Value<?> value = get();
+
+        if ( !isHR && ( value != null ) )
+        {
+            return value.getBytes();
+        }
+
+        String message = I18n.err( I18n.ERR_04130 );
+        LOG.error( message );
+        throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, message );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getString() throws LdapInvalidAttributeValueException
+    {
+        Value<?> value = get();
+
+        if ( isHR && ( value != null ) )
+        {
+            return value.getString();
+        }
+
+        String message = I18n.err( I18n.ERR_04131 );
+        LOG.error( message );
+        throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, message );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getId()
+    {
+        return id;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getUpId()
+    {
+        return upId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setUpId( String upId )
+    {
+        setUpId( upId, attributeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setUpId( byte[] upId )
+    {
+        setUpId( upId, attributeType );
+    }
+
+
+    /**
+     * Check that the upId is either a name or the OID of a given AT
+     */
+    private boolean areCompatible( String id, AttributeType attributeType )
+    {
+        // First, get rid of the options, if any
+        int optPos = id.indexOf( ';' );
+        String idNoOption = id;
+
+        if ( optPos != -1 )
+        {
+            idNoOption = id.substring( 0, optPos );
+        }
+
+        // Check that we find the ID in the AT names
+        for ( String name : attributeType.getNames() )
+        {
+            if ( name.equalsIgnoreCase( idNoOption ) )
+            {
+                return true;
+            }
+        }
+
+        // Not found in names, check the OID
+        return Oid.isOid( id ) && attributeType.getOid().equals( id );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setUpId( String upId, AttributeType attributeType )
+    {
+        String trimmed = Strings.trim( upId );
+
+        if ( Strings.isEmpty( trimmed ) && ( attributeType == null ) )
+        {
+            throw new IllegalArgumentException( "Cannot set a null ID with a null AttributeType" );
+        }
+
+        String newId = Strings.toLowerCase( trimmed );
+
+        setUpIdInternal( upId, newId, attributeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setUpId( byte[] upId, AttributeType attributeType )
+    {
+        byte[] trimmed = Strings.trim( upId );
+
+        if ( Strings.isEmpty( trimmed ) && ( attributeType == null ) )
+        {
+            throw new IllegalArgumentException( "Cannot set a null ID with a null AttributeType" );
+        }
+
+        String newId = Strings.toLowerCase( trimmed );
+
+        setUpIdInternal( Strings.utf8ToString( upId ), newId, attributeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private void setUpIdInternal( String upId, String newId, AttributeType attributeType )
+    {
+        if ( attributeType == null )
+        {
+            if ( this.attributeType == null )
+            {
+                this.upId = upId;
+                this.id = newId;
+
+                // Compute the hashCode
+                rehash();
+
+                return;
+            }
+            else
+            {
+                if ( areCompatible( newId, this.attributeType ) )
+                {
+                    this.upId = upId;
+                    this.id = this.attributeType.getOid();
+
+                    // Compute the hashCode
+                    rehash();
+
+                    return;
+                }
+                else
+                {
+                    return;
+                }
+            }
+        }
+
+        if ( Strings.isEmpty( newId ) )
+        {
+            this.attributeType = attributeType;
+            this.upId = attributeType.getName();
+            this.id = attributeType.getOid();
+
+            // Compute the hashCode
+            rehash();
+
+            return;
+        }
+
+        if ( areCompatible( newId, attributeType ) )
+        {
+            this.upId = upId;
+            this.id = attributeType.getOid();
+            this.attributeType = attributeType;
+
+            // Compute the hashCode
+            rehash();
+
+            return;
+        }
+
+        throw new IllegalArgumentException( "ID '" + id + "' and AttributeType '" + attributeType.getName()
+            + "' are not compatible " );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isHumanReadable()
+    {
+        return isHR != null ? isHR : false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValid( AttributeType attributeType ) throws LdapInvalidAttributeValueException
+    {
+        LdapSyntax syntax = attributeType.getSyntax();
+
+        if ( syntax == null )
+        {
+            return false;
+        }
+
+        SyntaxChecker syntaxChecker = syntax.getSyntaxChecker();
+
+        if ( syntaxChecker == null )
+        {
+            return false;
+        }
+
+        // Check that we can have no value for this attributeType
+        if ( values.size() == 0 )
+        {
+            return syntaxChecker.isValidSyntax( null );
+        }
+
+        // Check that we can't have more than one value if the AT is single-value
+        if ( ( attributeType.isSingleValued() ) && ( values.size() > 1 ) )
+        {
+            return false;
+        }
+
+        // Now check the values
+        for ( Value<?> value : values )
+        {
+            try
+            {
+                if ( !value.isValid( syntaxChecker ) )
+                {
+                    return false;
+                }
+            }
+            catch ( LdapException le )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int add( Value<?>... vals )
+    {
+        int nbAdded = 0;
+        BinaryValue nullBinaryValue = null;
+        StringValue nullStringValue = null;
+        boolean nullValueAdded = false;
+        Value<?>[] valArray = vals;
+
+        if ( vals == null )
+        {
+            valArray = new Value[0];
+        }
+
+        if ( attributeType != null )
+        {
+            for ( Value<?> val : valArray )
+            {
+                if ( attributeType.getSyntax().isHumanReadable() )
+                {
+                    if ( ( val == null ) || val.isNull() )
+                    {
+                        try
+                        {
+                            Value<String> nullSV = new StringValue( attributeType, ( String ) null );
+
+                            if ( values.add( nullSV ) )
+                            {
+                                nbAdded++;
+                            }
+                        }
+                        catch ( LdapInvalidAttributeValueException iae )
+                        {
+                            continue;
+                        }
+                    }
+                    else if ( val instanceof StringValue )
+                    {
+                        StringValue stringValue = ( StringValue ) val;
+
+                        try
+                        {
+                            if ( stringValue.getAttributeType() == null )
+                            {
+                                stringValue.apply( attributeType );
+                            }
+
+                            if ( values.contains( val ) )
+                            {
+                                // Replace the value
+                                values.remove( val );
+                                values.add( val );
+                            }
+                            else if ( values.add( val ) )
+                            {
+                                nbAdded++;
+                            }
+                        }
+                        catch ( LdapInvalidAttributeValueException iae )
+                        {
+                            continue;
+                        }
+                    }
+                    else
+                    {
+                        String message = I18n.err( I18n.ERR_04451 );
+                        LOG.error( message );
+                    }
+                }
+                else
+                {
+                    if ( val == null )
+                    {
+                        if ( attributeType.getSyntax().getSyntaxChecker().isValidSyntax( val ) )
+                        {
+                            try
+                            {
+                                Value<byte[]> nullSV = new BinaryValue( attributeType, ( byte[] ) null );
+
+                                if ( values.add( nullSV ) )
+                                {
+                                    nbAdded++;
+                                }
+                            }
+                            catch ( LdapInvalidAttributeValueException iae )
+                            {
+                                continue;
+                            }
+                        }
+                        else
+                        {
+                            String message = I18n.err( I18n.ERR_04452 );
+                            LOG.error( message );
+                        }
+                    }
+                    else
+                    {
+                        if ( val instanceof BinaryValue )
+                        {
+                            BinaryValue binaryValue = ( BinaryValue ) val;
+
+                            try
+                            {
+                                if ( binaryValue.getAttributeType() == null )
+                                {
+                                    binaryValue = new BinaryValue( attributeType, val.getBytes() );
+                                }
+
+                                if ( values.add( binaryValue ) )
+                                {
+                                    nbAdded++;
+                                }
+                            }
+                            catch ( LdapInvalidAttributeValueException iae )
+                            {
+                                continue;
+                            }
+                        }
+                        else
+                        {
+                            String message = I18n.err( I18n.ERR_04452 );
+                            LOG.error( message );
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            for ( Value<?> val : valArray )
+            {
+                if ( val == null )
+                {
+                    // We have a null value. If the HR flag is not set, we will consider
+                    // that the attribute is not HR. We may change this later
+                    if ( isHR == null )
+                    {
+                        // This is the first value. Add both types, as we
+                        // don't know yet the attribute type's, but we may
+                        // know later if we add some new value.
+                        // We have to do that because we are using a Set,
+                        // and we can't remove the first element of the Set.
+                        nullBinaryValue = new BinaryValue( ( byte[] ) null );
+                        nullStringValue = new StringValue( ( String ) null );
+
+                        values.add( nullBinaryValue );
+                        values.add( nullStringValue );
+                        nullValueAdded = true;
+                        nbAdded++;
+                    }
+                    else if ( !isHR )
+                    {
+                        // The attribute type is binary.
+                        nullBinaryValue = new BinaryValue( ( byte[] ) null );
+
+                        // Don't add a value if it already exists.
+                        if ( !values.contains( nullBinaryValue ) )
+                        {
+                            values.add( nullBinaryValue );
+                            nbAdded++;
+                        }
+
+                    }
+                    else
+                    {
+                        // The attribute is HR
+                        nullStringValue = new StringValue( ( String ) null );
+
+                        // Don't add a value if it already exists.
+                        if ( !values.contains( nullStringValue ) )
+                        {
+                            values.add( nullStringValue );
+                        }
+                    }
+                }
+                else
+                {
+                    // Let's check the value type.
+                    if ( val instanceof StringValue )
+                    {
+                        // We have a String value
+                        if ( isHR == null )
+                        {
+                            // The attribute type will be set to HR
+                            isHR = true;
+                            values.add( val );
+                            nbAdded++;
+                        }
+                        else if ( !isHR )
+                        {
+                            // The attributeType is binary, convert the
+                            // value to a BinaryValue
+                            BinaryValue bv = new BinaryValue( val.getBytes() );
+
+                            if ( !contains( bv ) )
+                            {
+                                values.add( bv );
+                                nbAdded++;
+                            }
+                        }
+                        else
+                        {
+                            // The attributeType is HR, simply add the value
+                            if ( !contains( val ) )
+                            {
+                                values.add( val );
+                                nbAdded++;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // We have a Binary value
+                        if ( isHR == null )
+                        {
+                            // The attribute type will be set to binary
+                            isHR = false;
+                            values.add( val );
+                            nbAdded++;
+                        }
+                        else if ( !isHR )
+                        {
+                            // The attributeType is not HR, simply add the value if it does not already exist
+                            if ( !contains( val ) )
+                            {
+                                values.add( val );
+                                nbAdded++;
+                            }
+                        }
+                        else
+                        {
+                            // The attribute Type is HR, convert the
+                            // value to a StringValue
+                            StringValue sv = new StringValue( val.getString() );
+
+                            if ( !contains( sv ) )
+                            {
+                                values.add( sv );
+                                nbAdded++;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Last, not least, if a nullValue has been added, and if other
+        // values are all String, we have to keep the correct nullValue,
+        // and to remove the other
+        if ( nullValueAdded )
+        {
+            if ( isHR )
+            {
+                // Remove the Binary value
+                values.remove( nullBinaryValue );
+            }
+            else
+            {
+                // Remove the String value
+                values.remove( nullStringValue );
+            }
+        }
+
+        return nbAdded;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int add( String... vals ) throws LdapInvalidAttributeValueException
+    {
+        int nbAdded = 0;
+        String[] valArray = vals;
+
+        if ( vals == null )
+        {
+            valArray = new String[0];
+        }
+
+        // First, if the isHR flag is not set, we assume that the
+        // attribute is HR, because we are asked to add some strings.
+        if ( isHR == null )
+        {
+            isHR = true;
+        }
+
+        // Check the attribute type.
+        if ( attributeType == null )
+        {
+            if ( isHR )
+            {
+                for ( String val : valArray )
+                {
+                    Value<String> value = createStringValue( attributeType, val );
+
+                    if ( value == null )
+                    {
+                        // The value can't be normalized : we don't add it.
+                        LOG.error( I18n.err( I18n.ERR_04449, val ) );
+                        continue;
+                    }
+
+                    // Call the add(Value) method, if not already present
+                    if ( add( value ) == 1 )
+                    {
+                        nbAdded++;
+                    }
+                    else
+                    {
+                        LOG.warn( I18n.err( I18n.ERR_04486_VALUE_ALREADY_EXISTS, val, upId ) );
+                    }
+                }
+            }
+            else
+            {
+                // The attribute is binary. Transform the String to byte[]
+                for ( String val : valArray )
+                {
+                    byte[] valBytes = null;
+
+                    if ( val != null )
+                    {
+                        valBytes = Strings.getBytesUtf8( val );
+                    }
+
+                    Value<byte[]> value = createBinaryValue( attributeType, valBytes );
+
+                    // Now call the add(Value) method
+                    if ( add( value ) == 1 )
+                    {
+                        nbAdded++;
+                    }
+                }
+            }
+        }
+        else
+        {
+            if ( attributeType.isSingleValued() && ( values.size() + valArray.length > 1 ) )
+            {
+                LOG.error( I18n.err( I18n.ERR_04487_ATTRIBUTE_IS_SINGLE_VALUED, attributeType.getName() ) );
+                return 0;
+            }
+
+            if ( isHR )
+            {
+                for ( String val : valArray )
+                {
+                    Value<String> value = createStringValue( attributeType, val );
+
+                    if ( value == null )
+                    {
+                        // The value can't be normalized : we don't add it.
+                        LOG.error( I18n.err( I18n.ERR_04449, val ) );
+                        continue;
+                    }
+
+                    // Call the add(Value) method, if not already present
+                    if ( add( value ) == 1 )
+                    {
+                        nbAdded++;
+                    }
+                    else
+                    {
+                        LOG.warn( I18n.err( I18n.ERR_04486_VALUE_ALREADY_EXISTS, val, upId ) );
+                    }
+                }
+            }
+            else
+            {
+                // The attribute is binary. Transform the String to byte[]
+                for ( String val : valArray )
+                {
+                    byte[] valBytes = null;
+
+                    if ( val != null )
+                    {
+                        valBytes = Strings.getBytesUtf8( val );
+                    }
+
+                    Value<byte[]> value = createBinaryValue( attributeType, valBytes );
+
+                    // Now call the add(Value) method
+                    if ( add( value ) == 1 )
+                    {
+                        nbAdded++;
+                    }
+                }
+            }
+        }
+
+        return nbAdded;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int add( byte[]... vals ) throws LdapInvalidAttributeValueException
+    {
+        int nbAdded = 0;
+        byte[][] valArray = vals;
+
+        if ( vals == null )
+        {
+            valArray = new byte[0][];
+        }
+
+        // First, if the isHR flag is not set, we assume that the
+        // attribute is not HR, because we are asked to add some byte[].
+        if ( isHR == null )
+        {
+            isHR = false;
+        }
+
+        if ( !isHR )
+        {
+            for ( byte[] val : valArray )
+            {
+                Value<byte[]> value = null;
+
+                if ( attributeType == null )
+                {
+                    value = new BinaryValue( val );
+                }
+                else
+                {
+                    value = createBinaryValue( attributeType, val );
+                }
+
+                if ( add( value ) != 0 )
+                {
+                    nbAdded++;
+                }
+                else
+                {
+                    LOG.warn( I18n.err( I18n.ERR_04486_VALUE_ALREADY_EXISTS, Strings.dumpBytes( val ), upId ) );
+                }
+            }
+        }
+        else
+        {
+            // We can't add Binary values into a String Attribute
+            LOG.info( I18n.err( I18n.ERR_04451 ) );
+            return 0;
+        }
+
+        return nbAdded;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        values.clear();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( Value<?>... vals )
+    {
+        if ( isHR == null )
+        {
+            // If this flag is null, then there is no values.
+            return false;
+        }
+
+        if ( attributeType == null )
+        {
+            if ( isHR )
+            {
+                // Iterate through all the values, convert the Binary values
+                // to String values, and quit id any of the values is not
+                // contained in the object
+                for ( Value<?> val : vals )
+                {
+                    if ( val instanceof StringValue )
+                    {
+                        if ( !values.contains( val ) )
+                        {
+                            return false;
+                        }
+                    }
+                    else
+                    {
+                        byte[] binaryVal = val.getBytes();
+
+                        // We have to convert the binary value to a String
+                        if ( !values.contains( new StringValue( Strings.utf8ToString( binaryVal ) ) ) )
+                        {
+                            return false;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                // Iterate through all the values, convert the String values
+                // to binary values, and quit id any of the values is not
+                // contained in the object
+                for ( Value<?> val : vals )
+                {
+                    if ( val.isHumanReadable() )
+                    {
+                        String stringVal = val.getString();
+
+                        // We have to convert the binary value to a String
+                        if ( !values.contains( new BinaryValue( Strings.getBytesUtf8( stringVal ) ) ) )
+                        {
+                            return false;
+                        }
+                    }
+                    else
+                    {
+                        if ( !values.contains( val ) )
+                        {
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            // Iterate through all the values, and quit if we
+            // don't find one in the values. We have to separate the check
+            // depending on the isHR flag value.
+            if ( isHR )
+            {
+                for ( Value<?> val : vals )
+                {
+                    if ( val instanceof StringValue )
+                    {
+                        StringValue stringValue = ( StringValue ) val;
+
+                        try
+                        {
+                            if ( stringValue.getAttributeType() == null )
+                            {
+                                stringValue.apply( attributeType );
+                            }
+                        }
+                        catch ( LdapInvalidAttributeValueException liave )
+                        {
+                            return false;
+                        }
+
+                        if ( !values.contains( val ) )
+                        {
+                            return false;
+                        }
+                    }
+                    else
+                    {
+                        // Not a String value
+                        return false;
+                    }
+                }
+            }
+            else
+            {
+                for ( Value<?> val : vals )
+                {
+                    if ( val instanceof BinaryValue )
+                    {
+                        if ( !values.contains( val ) )
+                        {
+                            return false;
+                        }
+                    }
+                    else
+                    {
+                        // Not a Binary value
+                        return false;
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String... vals )
+    {
+        if ( isHR == null )
+        {
+            // If this flag is null, then there is no values.
+            return false;
+        }
+
+        if ( attributeType == null )
+        {
+            if ( isHR )
+            {
+                for ( String val : vals )
+                {
+                    try
+                    {
+                        if ( !contains( new StringValue( val ) ) )
+                        {
+                            return false;
+                        }
+                    }
+                    catch ( IllegalArgumentException iae )
+                    {
+                        return false;
+                    }
+                }
+            }
+            else
+            {
+                // As the attribute type is binary, we have to convert
+                // the values before checking for them in the values
+                // Iterate through all the values, and quit if we
+                // don't find one in the values
+                for ( String val : vals )
+                {
+                    byte[] binaryVal = Strings.getBytesUtf8( val );
+
+                    if ( !contains( new BinaryValue( binaryVal ) ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+        else
+        {
+            if ( isHR )
+            {
+                // Iterate through all the values, and quit if we
+                // don't find one in the values
+                for ( String val : vals )
+                {
+                    try
+                    {
+                        StringValue value = new StringValue( attributeType, val );
+
+                        if ( !values.contains( value ) )
+                        {
+                            return false;
+                        }
+                    }
+                    catch ( LdapInvalidAttributeValueException liave )
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( byte[]... vals )
+    {
+        if ( isHR == null )
+        {
+            // If this flag is null, then there is no values.
+            return false;
+        }
+
+        if ( attributeType == null )
+        {
+            if ( !isHR )
+            {
+                // Iterate through all the values, and quit if we
+                // don't find one in the values
+                for ( byte[] val : vals )
+                {
+                    if ( !contains( new BinaryValue( val ) ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+            else
+            {
+                // As the attribute type is String, we have to convert
+                // the values before checking for them in the values
+                // Iterate through all the values, and quit if we
+                // don't find one in the values
+                for ( byte[] val : vals )
+                {
+                    String stringVal = Strings.utf8ToString( val );
+
+                    if ( !contains( new StringValue( stringVal ) ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+        else
+        {
+            if ( !isHR )
+            {
+                // Iterate through all the values, and quit if we
+                // don't find one in the values
+                for ( byte[] val : vals )
+                {
+                    try
+                    {
+                        BinaryValue value = new BinaryValue( attributeType, val );
+
+                        if ( !values.contains( value ) )
+                        {
+                            return false;
+                        }
+                    }
+                    catch ( LdapInvalidAttributeValueException liave )
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> get()
+    {
+        if ( values.isEmpty() )
+        {
+            return null;
+        }
+
+        return values.iterator().next();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return values.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( Value<?>... vals )
+    {
+        if ( ( isHR == null ) || ( values.size() == 0 ) )
+        {
+            // Trying to remove a value from an empty list will fail
+            return false;
+        }
+
+        boolean removed = true;
+
+        if ( attributeType == null )
+        {
+            if ( isHR )
+            {
+                for ( Value<?> val : vals )
+                {
+                    if ( val instanceof StringValue )
+                    {
+                        removed &= values.remove( val );
+                    }
+                    else
+                    {
+                        // Convert the binary value to a string value
+                        byte[] binaryVal = val.getBytes();
+                        removed &= values.remove( new StringValue( Strings.utf8ToString( binaryVal ) ) );
+                    }
+                }
+            }
+            else
+            {
+                for ( Value<?> val : vals )
+                {
+                    removed &= values.remove( val );
+                }
+            }
+        }
+        else
+        {
+            // Loop through all the values to remove. If one of
+            // them is not present, the method will return false.
+            // As the attribute may be HR or not, we have two separated treatments
+            if ( isHR )
+            {
+                for ( Value<?> val : vals )
+                {
+                    if ( val instanceof StringValue )
+                    {
+                        StringValue stringValue = ( StringValue ) val;
+
+                        try
+                        {
+                            if ( stringValue.getAttributeType() == null )
+                            {
+                                stringValue.apply( attributeType );
+                            }
+
+                            removed &= values.remove( stringValue );
+                        }
+                        catch ( LdapInvalidAttributeValueException liave )
+                        {
+                            removed = false;
+                        }
+                    }
+                    else
+                    {
+                        removed = false;
+                    }
+                }
+            }
+            else
+            {
+                for ( Value<?> val : vals )
+                {
+                    if ( val instanceof BinaryValue )
+                    {
+                        try
+                        {
+                            BinaryValue binaryValue = ( BinaryValue ) val;
+
+                            if ( binaryValue.getAttributeType() == null )
+                            {
+                                binaryValue.apply( attributeType );
+                            }
+
+                            removed &= values.remove( binaryValue );
+                        }
+                        catch ( LdapInvalidAttributeValueException liave )
+                        {
+                            removed = false;
+                        }
+                    }
+                    else
+                    {
+                        removed = false;
+                    }
+                }
+            }
+        }
+
+        return removed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( byte[]... vals )
+    {
+        if ( ( isHR == null ) || ( values.size() == 0 ) )
+        {
+            // Trying to remove a value from an empty list will fail
+            return false;
+        }
+
+        boolean removed = true;
+
+        if ( attributeType == null )
+        {
+            if ( !isHR )
+            {
+                // The attribute type is not HR, we can directly process the values
+                for ( byte[] val : vals )
+                {
+                    BinaryValue value = new BinaryValue( val );
+                    removed &= values.remove( value );
+                }
+            }
+            else
+            {
+                // The attribute type is String, we have to convert the values
+                // to String before removing them
+                for ( byte[] val : vals )
+                {
+                    StringValue value = new StringValue( Strings.utf8ToString( val ) );
+                    removed &= values.remove( value );
+                }
+            }
+        }
+        else
+        {
+            if ( !isHR )
+            {
+                try
+                {
+                    for ( byte[] val : vals )
+                    {
+                        BinaryValue value = new BinaryValue( attributeType, val );
+                        removed &= values.remove( value );
+                    }
+                }
+                catch ( LdapInvalidAttributeValueException liave )
+                {
+                    removed = false;
+                }
+            }
+            else
+            {
+                removed = false;
+            }
+        }
+
+        return removed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( String... vals )
+    {
+        if ( ( isHR == null ) || ( values.size() == 0 ) )
+        {
+            // Trying to remove a value from an empty list will fail
+            return false;
+        }
+
+        boolean removed = true;
+
+        if ( attributeType == null )
+        {
+            if ( isHR )
+            {
+                // The attribute type is HR, we can directly process the values
+                for ( String val : vals )
+                {
+                    StringValue value = new StringValue( val );
+                    removed &= values.remove( value );
+                }
+            }
+            else
+            {
+                // The attribute type is binary, we have to convert the values
+                // to byte[] before removing them
+                for ( String val : vals )
+                {
+                    BinaryValue value = new BinaryValue( Strings.getBytesUtf8( val ) );
+                    removed &= values.remove( value );
+                }
+            }
+        }
+        else
+        {
+            if ( isHR )
+            {
+                for ( String val : vals )
+                {
+                    try
+                    {
+                        StringValue value = new StringValue( attributeType, val );
+                        removed &= values.remove( value );
+                    }
+                    catch ( LdapInvalidAttributeValueException liave )
+                    {
+                        removed = false;
+                    }
+                }
+            }
+            else
+            {
+                removed = false;
+            }
+        }
+
+        return removed;
+    }
+
+
+    /**
+     * An iterator on top of the stored values.
+     * 
+     * @return an iterator over the stored values.
+     */
+    public Iterator<Value<?>> iterator()
+    {
+        return values.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException
+    {
+        if ( attributeType == null )
+        {
+            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
+        }
+
+        this.attributeType = attributeType;
+        this.id = attributeType.getOid();
+
+        if ( Strings.isEmpty( this.upId ) )
+        {
+            this.upId = attributeType.getName();
+        }
+        else
+        {
+            if ( !areCompatible( this.upId, attributeType ) )
+            {
+                this.upId = attributeType.getName();
+            }
+        }
+
+        if ( values != null )
+        {
+            Set<Value<?>> newValues = new LinkedHashSet<Value<?>>( values.size() );
+
+            for ( Value<?> value : values )
+            {
+                if ( value instanceof StringValue )
+                {
+                    newValues.add( new StringValue( attributeType, value.getString() ) );
+                }
+                else
+                {
+                    newValues.add( new BinaryValue( attributeType, value.getBytes() ) );
+                }
+            }
+
+            values = newValues;
+        }
+
+        isHR = attributeType.getSyntax().isHumanReadable();
+
+        // Compute the hashCode
+        rehash();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInstanceOf( AttributeType attributeType ) throws LdapInvalidAttributeValueException
+    {
+        return ( attributeType != null )
+            && ( this.attributeType.equals( attributeType ) || this.attributeType.isDescendantOf( attributeType ) );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Overloaded Object classes
+    //-------------------------------------------------------------------------
+    /**
+     * A helper method to rehash the hashCode
+     */
+    private void rehash()
+    {
+        h = 37;
+
+        if ( isHR != null )
+        {
+            h = h * 17 + isHR.hashCode();
+        }
+
+        if ( id != null )
+        {
+            h = h * 17 + id.hashCode();
+        }
+
+        if ( attributeType != null )
+        {
+            h = h * 17 + attributeType.hashCode();
+        }
+    }
+
+
+    /**
+     * The hashCode is based on the id, the isHR flag and
+     * on the internal values.
+     * 
+     * @see Object#hashCode()
+     * @return the instance's hashcode
+     */
+    public int hashCode()
+    {
+        if ( h == 0 )
+        {
+            rehash();
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !( obj instanceof Attribute ) )
+        {
+            return false;
+        }
+
+        Attribute other = ( Attribute ) obj;
+
+        if ( id == null )
+        {
+            if ( other.getId() != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( other.getId() == null )
+            {
+                return false;
+            }
+            else
+            {
+                if ( attributeType != null )
+                {
+                    if ( !attributeType.equals( other.getAttributeType() ) )
+                    {
+                        return false;
+                    }
+                }
+                else if ( !id.equals( other.getId() ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        if ( isHumanReadable() != other.isHumanReadable() )
+        {
+            return false;
+        }
+
+        if ( values.size() != other.size() )
+        {
+            return false;
+        }
+
+        for ( Value<?> val : values )
+        {
+            if ( !other.contains( val ) )
+            {
+                return false;
+            }
+        }
+
+        if ( attributeType == null )
+        {
+            return other.getAttributeType() == null;
+        }
+
+        return attributeType.equals( other.getAttributeType() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute clone()
+    {
+        try
+        {
+            DefaultAttribute attribute = ( DefaultAttribute ) super.clone();
+
+            if ( this.attributeType != null )
+            {
+                attribute.id = attributeType.getOid();
+                attribute.attributeType = attributeType;
+            }
+
+            attribute.values = new LinkedHashSet<Value<?>>( values.size() );
+
+            for ( Value<?> value : values )
+            {
+                // No need to clone the value, it will never be changed
+                attribute.values.add( value );
+            }
+
+            return attribute;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * This is the place where we serialize attributes, and all theirs
+     * elements.
+     * 
+     * {@inheritDoc}
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        // Write the UPId (the id will be deduced from the upID)
+        out.writeUTF( upId );
+
+        // Write the HR flag, if not null
+        if ( isHR != null )
+        {
+            out.writeBoolean( true );
+            out.writeBoolean( isHR );
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        // Write the number of values
+        out.writeInt( size() );
+
+        if ( size() > 0 )
+        {
+            // Write each value
+            for ( Value<?> value : values )
+            {
+                // Write the value
+                value.writeExternal( out );
+            }
+        }
+
+        out.flush();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the ID and the UPId
+        upId = in.readUTF();
+
+        // Compute the id
+        setUpId( upId );
+
+        // Read the HR flag, if not null
+        if ( in.readBoolean() )
+        {
+            isHR = in.readBoolean();
+        }
+
+        // Read the number of values
+        int nbValues = in.readInt();
+
+        if ( nbValues > 0 )
+        {
+            for ( int i = 0; i < nbValues; i++ )
+            {
+                Value<?> value = null;
+
+                if ( isHR )
+                {
+                    value = new StringValue( attributeType );
+                }
+                else
+                {
+                    value = new BinaryValue( attributeType );
+                }
+
+                value.readExternal( in );
+
+                values.add( value );
+            }
+        }
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return toString( "" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString( String tabs )
+    {
+        StringBuilder sb = new StringBuilder();
+
+        if ( ( values != null ) && ( values.size() != 0 ) )
+        {
+            boolean isFirst = true;
+
+            for ( Value<?> value : values )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( '\n' );
+                }
+
+                sb.append( tabs ).append( upId ).append( ": " );
+
+                if ( value.isNull() )
+                {
+                    sb.append( "''" );
+                }
+                else
+                {
+                    sb.append( value );
+                }
+            }
+        }
+        else
+        {
+            sb.append( tabs ).append( upId ).append( ": (null)" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultEntry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultEntry.java
new file mode 100644
index 0000000..b272f08
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultEntry.java
@@ -0,0 +1,2668 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.ldif.LdapLdifException;
+import org.apache.directory.api.ldap.model.ldif.LdifAttributesReader;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A default implementation of a ServerEntry which should suite most
+ * use cases.<br/>
+ * <br/>
+ * This class is final, it should not be extended.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DefaultEntry implements Entry
+{
+    /** Used for serialization */
+    private static final long serialVersionUID = 2L;
+
+    /** The logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultEntry.class );
+
+    /** The Dn for this entry */
+    private Dn dn;
+
+    /** A map containing all the attributes for this entry */
+    private Map<String, Attribute> attributes = new HashMap<String, Attribute>();
+
+    /** A speedup to get the ObjectClass attribute */
+    private static AttributeType objectClassAttributeType;
+
+    /** The SchemaManager */
+    private SchemaManager schemaManager;
+
+    /** The computed hashcode. We don't want to compute it each time the hashcode() method is called */
+    private volatile int h;
+
+    /** A mutex to manage synchronization*/
+    private static final Object MUTEX = new Object();
+
+
+    //-------------------------------------------------------------------------
+    // Constructors
+    //-------------------------------------------------------------------------
+    /**
+     * Creates a new instance of DefaultEntry.
+     * <p>
+     * This entry <b>must</b> be initialized before being used !
+     */
+    public DefaultEntry()
+    {
+        this( ( SchemaManager ) null );
+    }
+
+
+    /**
+     * <p>
+     * Creates a new instance of DefaultEntry, schema aware.
+     * </p>
+     * <p>
+     * No attributes will be created.
+     * </p>
+     *
+     * @param schemaManager The reference to the schemaManager
+     */
+    public DefaultEntry( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+        dn = Dn.EMPTY_DN;
+
+        // Initialize the ObjectClass object
+        if ( schemaManager != null )
+        {
+            initObjectClassAT();
+        }
+    }
+
+
+    /**
+     * Creates a new instance of DefaultEntry, with a Dn.
+     *
+     * @param dn The String Dn for this serverEntry. Can be null.
+     * @throws LdapInvalidDnException If the Dn is invalid
+     */
+    public DefaultEntry( String dn ) throws LdapInvalidDnException
+    {
+        this.dn = new Dn( dn );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultEntry, with a Dn.
+     *
+     * @param dn The Dn for this serverEntry. Can be null.
+     */
+    public DefaultEntry( Dn dn )
+    {
+        this.dn = dn;
+    }
+
+
+    /**
+     * <p>
+     * Creates a new instance of DefaultEntry, schema aware.
+     * </p>
+     * <p>
+     * No attributes will be created.
+     * </p>
+     *
+     * @param schemaManager The reference to the schemaManager
+     * @param dn The String Dn for this serverEntry. Can be null.
+     * @throws LdapInvalidDnException If the Dn is invalid
+     */
+    public DefaultEntry( SchemaManager schemaManager, String dn ) throws LdapInvalidDnException
+    {
+        this.schemaManager = schemaManager;
+
+        if ( Strings.isEmpty( dn ) )
+        {
+            this.dn = Dn.EMPTY_DN;
+        }
+        else
+        {
+            this.dn = new Dn( dn );
+            normalizeDN( this.dn );
+        }
+
+        // Initialize the ObjectClass object
+        initObjectClassAT();
+    }
+
+
+    /**
+     * <p>
+     * Creates a new instance of DefaultEntry, schema aware.
+     * </p>
+     * <p>
+     * No attributes will be created.
+     * </p>
+     *
+     * @param schemaManager The reference to the schemaManager
+     * @param dn The Dn for this serverEntry. Can be null.
+     */
+    public DefaultEntry( SchemaManager schemaManager, Dn dn )
+    {
+        this.schemaManager = schemaManager;
+
+        if ( dn == null )
+        {
+            this.dn = Dn.EMPTY_DN;
+        }
+        else
+        {
+            this.dn = dn;
+            normalizeDN( this.dn );
+        }
+
+        // Initialize the ObjectClass object
+        initObjectClassAT();
+    }
+
+
+    /**
+     * Creates a new instance of DefaultEntry, with a
+     * Dn and a list of IDs.
+     *
+     * @param dn The Dn for this serverEntry. Can be null.
+     * @param upIds The list of attributes to create.
+     */
+    public DefaultEntry( String dn, Object... elements ) throws LdapException
+    {
+        this( null, dn, elements );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultEntry, with a
+     * Dn and a list of IDs.
+     *
+     * @param dn The Dn for this serverEntry. Can be null.
+     * @param upIds The list of attributes to create.
+     */
+    public DefaultEntry( Dn dn, Object... elements ) throws LdapException
+    {
+        this( null, dn, elements );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultEntry, with a
+     * Dn and a list of IDs.
+     *
+     * @param dn The Dn for this serverEntry. Can be null.
+     * @param upIds The list of attributes to create.
+     */
+    public DefaultEntry( SchemaManager schemaManager, String dn, Object... elements ) throws LdapException
+    {
+        this( schemaManager, new Dn( schemaManager, dn ), elements );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultEntry, with a
+     * Dn and a list of IDs.
+     *
+     * @param dn The Dn for this serverEntry. Can be null.
+     * @param upIds The list of attributes to create.
+     */
+    public DefaultEntry( SchemaManager schemaManager, Dn dn, Object... elements ) throws LdapException
+    {
+        DefaultEntry entry = ( DefaultEntry ) createEntry( schemaManager, elements );
+
+        this.dn = dn;
+        this.attributes = entry.attributes;
+        this.schemaManager = schemaManager;
+
+        if ( schemaManager != null )
+        {
+            this.dn.apply( schemaManager );
+            initObjectClassAT();
+        }
+    }
+
+
+    /**
+     * <p>
+     * Creates a new instance of DefaultEntry, copying
+     * another entry.
+     * </p>
+     * <p>
+     * No attributes will be created.
+     * </p>
+     *
+     * @param schemaManager The reference to the schemaManager
+     * @param entry the entry to copy
+     */
+    public DefaultEntry( SchemaManager schemaManager, Entry entry ) throws LdapException
+    {
+        this.schemaManager = schemaManager;
+
+        // Initialize the ObjectClass object
+        initObjectClassAT();
+
+        // We will clone the existing entry, because it may be normalized
+        if ( entry.getDn() != null )
+        {
+            dn = entry.getDn();
+            normalizeDN( dn );
+        }
+        else
+        {
+            dn = Dn.EMPTY_DN;
+        }
+
+        // Init the attributes map
+        attributes = new HashMap<String, Attribute>( entry.size() );
+
+        // and copy all the attributes
+        for ( Attribute attribute : entry )
+        {
+            try
+            {
+                // First get the AttributeType
+                AttributeType attributeType = attribute.getAttributeType();
+
+                if ( attributeType == null )
+                {
+                    attributeType = schemaManager.lookupAttributeTypeRegistry( attribute.getId() );
+                }
+
+                // Create a new ServerAttribute.
+                Attribute serverAttribute = new DefaultAttribute( attributeType, attribute );
+
+                // And store it
+                add( serverAttribute );
+            }
+            catch ( LdapException ne )
+            {
+                // Just log a warning
+                LOG.warn( "The attribute '" + attribute.getId() + "' cannot be stored" );
+                throw ne;
+            }
+        }
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Helper methods
+    //-------------------------------------------------------------------------
+    private Entry createEntry( SchemaManager schemaManager, Object... elements )
+        throws LdapInvalidAttributeValueException, LdapLdifException
+    {
+        StringBuilder sb = new StringBuilder();
+        int pos = 0;
+        boolean valueExpected = false;
+
+        for ( Object element : elements )
+        {
+            if ( !valueExpected )
+            {
+                if ( !( element instanceof String ) )
+                {
+                    throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                        I18n.ERR_12085, ( pos + 1 ) ) );
+                }
+
+                String attribute = ( String ) element;
+                sb.append( attribute );
+
+                if ( attribute.indexOf( ':' ) != -1 )
+                {
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    valueExpected = true;
+                }
+            }
+            else
+            {
+                if ( element instanceof String )
+                {
+                    sb.append( ": " ).append( ( String ) element ).append( '\n' );
+                }
+                else if ( element instanceof byte[] )
+                {
+                    sb.append( ":: " );
+                    sb.append( new String( Base64.encode( ( byte[] ) element ) ) );
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                        I18n.ERR_12086, ( pos + 1 ) ) );
+                }
+
+                valueExpected = false;
+            }
+        }
+
+        if ( valueExpected )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n
+                .err( I18n.ERR_12087 ) );
+        }
+
+        LdifAttributesReader reader = null;
+
+        try
+        {
+            reader = new LdifAttributesReader();
+            Entry entry = reader.parseEntry( schemaManager, sb.toString() );
+
+            return entry;
+        }
+        finally
+        {
+            try
+            {
+                if ( reader != null )
+                {
+                    reader.close();
+                }
+            }
+            catch ( IOException e )
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+
+
+    /**
+     * Get the trimmed and lower cased entry ID
+     */
+    private String getId( String upId )
+    {
+        String id = Strings.trim( Strings.toLowerCase( upId ) );
+
+        // If empty, throw an error
+        if ( Strings.isEmpty( id ) )
+        {
+            String message = I18n.err( I18n.ERR_04133 );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        return id;
+    }
+
+
+    /**
+     * Get the UpId if it is null.
+     * 
+     * @param upId The ID
+     */
+    private String getUpId( String upId, AttributeType attributeType )
+    {
+        String normUpId = Strings.trim( upId );
+
+        if ( ( attributeType == null ) )
+        {
+            if ( Strings.isEmpty( normUpId ) )
+            {
+                String message = I18n.err( I18n.ERR_04458 );
+                LOG.error( message );
+                throw new IllegalArgumentException( message );
+            }
+
+            return upId;
+        }
+        else if ( Strings.isEmpty( normUpId ) )
+        {
+            String id = attributeType.getName();
+
+            if ( Strings.isEmpty( id ) )
+            {
+                id = attributeType.getOid();
+            }
+
+            return id;
+        }
+        else
+        {
+            return upId;
+        }
+    }
+
+
+    /**
+     * This method is used to initialize the OBJECT_CLASS_AT attributeType.
+     *
+     * We want to do it only once, so it's a synchronized method. Note that
+     * the alternative would be to call the lookup() every time, but this won't
+     * be very efficient, as it will get the AT from a map, which is also
+     * synchronized, so here, we have a very minimal cost.
+     *
+     * We can't do it once as a static part in the body of this class, because
+     * the access to the registries is mandatory to get back the AttributeType.
+     */
+    private void initObjectClassAT()
+    {
+        if ( schemaManager == null )
+        {
+            return;
+        }
+
+        try
+        {
+            synchronized ( MUTEX )
+            {
+                if ( objectClassAttributeType == null )
+                {
+                    objectClassAttributeType = schemaManager
+                        .lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT );
+                }
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // do nothing...
+        }
+    }
+
+
+    /**
+     * normalizes the given Dn if it was not already normalized
+     *
+     * @param dn the Dn to be normalized
+     */
+    private void normalizeDN( Dn dn )
+    {
+        if ( !dn.isSchemaAware() )
+        {
+            try
+            {
+                // The dn must be normalized
+                dn.apply( schemaManager );
+            }
+            catch ( LdapException ne )
+            {
+                LOG.warn( "The Dn '{}' cannot be normalized", dn );
+            }
+        }
+    }
+
+
+    /**
+     * A helper method to recompute the hash code
+     */
+    private void rehash()
+    {
+        h = 37;
+        h = h * 17 + dn.hashCode();
+    }
+
+
+    /**
+     * Add a new EntryAttribute, with its upId. If the upId is null,
+     * default to the AttributeType name.
+     *
+     * Updates the AttributeMap.
+     */
+    protected void createAttribute( String upId, AttributeType attributeType, byte[]... values )
+        throws LdapInvalidAttributeValueException
+    {
+        Attribute attribute = new DefaultAttribute( attributeType, values );
+        attribute.setUpId( upId, attributeType );
+        attributes.put( attributeType.getOid(), attribute );
+    }
+
+
+    /**
+     * Add a new EntryAttribute, with its upId. If the upId is null,
+     * default to the AttributeType name.
+     *
+     * Updates the AttributeMap.
+     */
+    protected void createAttribute( String upId, AttributeType attributeType, String... values )
+        throws LdapInvalidAttributeValueException
+    {
+        Attribute attribute = new DefaultAttribute( attributeType, values );
+        attribute.setUpId( upId, attributeType );
+        attributes.put( attributeType.getOid(), attribute );
+    }
+
+
+    /**
+     * Add a new EntryAttribute, with its upId. If the upId is null,
+     * default to the AttributeType name.
+     *
+     * Updates the AttributeMap.
+     */
+    protected void createAttribute( String upId, AttributeType attributeType, Value<?>... values )
+        throws LdapInvalidAttributeValueException
+    {
+        Attribute attribute = new DefaultAttribute( attributeType, values );
+        attribute.setUpId( upId, attributeType );
+        attributes.put( attributeType.getOid(), attribute );
+    }
+
+
+    /**
+     * Returns the attributeType from an Attribute ID.
+     */
+    protected AttributeType getAttributeType( String upId ) throws LdapException
+    {
+        if ( Strings.isEmpty( Strings.trim( upId ) ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        return schemaManager.lookupAttributeTypeRegistry( upId );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Entry methods
+    //-------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        if ( ( values == null ) || ( values.length == 0 ) )
+        {
+            String message = I18n.err( I18n.ERR_04478_NO_VALUE_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        // ObjectClass with binary values are not allowed
+        if ( attributeType.equals( objectClassAttributeType ) )
+        {
+            String message = I18n.err( I18n.ERR_04461 );
+            LOG.error( message );
+            throw new UnsupportedOperationException( message );
+        }
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values
+            // into it
+            attribute.add( values );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values.
+            // The upId, which is set to null, will be setup by the
+            // createAttribute method
+            createAttribute( null, attributeType, values );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( AttributeType attributeType, String... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values
+            // into it
+            attribute.add( values );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values.
+            // The upId, which is set to null, will be setup by the
+            // createAttribute method
+            createAttribute( null, attributeType, values );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values
+            // into it
+            attribute.add( values );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values.
+            // The upId, which is set to null, will be setup by the
+            // createAttribute method
+            createAttribute( null, attributeType, values );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        // ObjectClass with binary values are not allowed
+        if ( attributeType.equals( objectClassAttributeType ) )
+        {
+            String message = I18n.err( I18n.ERR_04461 );
+            LOG.error( message );
+            throw new UnsupportedOperationException( message );
+        }
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        String id = getUpId( upId, attributeType );
+
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values
+            // into it
+            attribute.add( values );
+            attribute.setUpId( id, attributeType );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values
+            // and the upId
+            createAttribute( id, attributeType, values );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        String id = getUpId( upId, attributeType );
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values
+            // into it
+            attribute.add( values );
+            attribute.setUpId( id, attributeType );
+        }
+        else
+        {
+            createAttribute( id, attributeType, values );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, AttributeType attributeType, String... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        String id = getUpId( upId, attributeType );
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values
+            // into it
+            attribute.add( values );
+            attribute.setUpId( id, attributeType );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values
+            // and the upId
+            createAttribute( id, attributeType, values );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( Attribute... attributes ) throws LdapException
+    {
+        // Loop on all the added attributes
+        for ( Attribute attribute : attributes )
+        {
+            AttributeType attributeType = attribute.getAttributeType();
+
+            if ( attributeType != null )
+            {
+                String oid = attributeType.getOid();
+
+                if ( this.attributes.containsKey( oid ) )
+                {
+                    // We already have an attribute with the same AttributeType
+                    // Just add the new values into it.
+                    Attribute existingAttribute = this.attributes.get( oid );
+
+                    for ( Value<?> value : attribute )
+                    {
+                        existingAttribute.add( value );
+                    }
+
+                    // And update the upId
+                    existingAttribute.setUpId( attribute.getUpId() );
+                }
+                else
+                {
+                    // The attributeType does not exist, add it
+                    this.attributes.put( oid, attribute );
+                }
+            }
+            else
+            {
+                // If the attribute already exist, we will add the new values.
+                if ( contains( attribute ) )
+                {
+                    Attribute existingAttribute = get( attribute.getId() );
+
+                    // Loop on all the values, and add them to the existing attribute
+                    for ( Value<?> value : attribute )
+                    {
+                        existingAttribute.add( value );
+                    }
+                }
+                else
+                {
+                    // Stores the attribute into the entry
+                    this.attributes.put( attribute.getId(), attribute );
+                }
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, byte[]... values ) throws LdapException
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        // First, transform the upID to a valid ID
+        String id = getId( upId );
+
+        if ( schemaManager != null )
+        {
+            add( upId, schemaManager.lookupAttributeTypeRegistry( id ), values );
+        }
+        else
+        {
+            // Now, check to see if we already have such an attribute
+            Attribute attribute = attributes.get( id );
+
+            if ( attribute != null )
+            {
+                // This Attribute already exist, we add the values
+                // into it. (If the values already exists, they will
+                // not be added, but this is done in the add() method)
+                attribute.add( values );
+                attribute.setUpId( upId );
+            }
+            else
+            {
+                // We have to create a new Attribute and set the values
+                // and the upId
+                attributes.put( id, new DefaultAttribute( upId, values ) );
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, String... values ) throws LdapException
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        // First, transform the upID to a valid ID
+        String id = getId( upId );
+
+        if ( schemaManager != null )
+        {
+            add( upId, schemaManager.lookupAttributeTypeRegistry( upId ), values );
+        }
+        else
+        {
+            // Now, check to see if we already have such an attribute
+            Attribute attribute = attributes.get( id );
+
+            if ( attribute != null )
+            {
+                // This Attribute already exist, we add the values
+                // into it. (If the values already exists, they will
+                // not be added, but this is done in the add() method)
+                attribute.add( values );
+                attribute.setUpId( upId );
+            }
+            else
+            {
+                // We have to create a new Attribute and set the values
+                // and the upId
+                attributes.put( id, new DefaultAttribute( upId, values ) );
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, Value<?>... values ) throws LdapException
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        // First, transform the upID to a valid ID
+        String id = getId( upId );
+
+        if ( schemaManager != null )
+        {
+            add( upId, schemaManager.lookupAttributeTypeRegistry( upId ), values );
+        }
+        else
+        {
+            // Now, check to see if we already have such an attribute
+            Attribute attribute = attributes.get( id );
+
+            if ( attribute != null )
+            {
+                // This Attribute already exist, we add the values
+                // into it. (If the values already exists, they will
+                // not be added, but this is done in the add() method)
+                attribute.add( values );
+                attribute.setUpId( upId );
+            }
+            else
+            {
+                // We have to create a new Attribute and set the values
+                // and the upId
+                attributes.put( id, new DefaultAttribute( upId, values ) );
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * Clone an entry. All the element are duplicated, so a modification on
+     * the original object won't affect the cloned object, as a modification
+     * on the cloned object has no impact on the original object
+     */
+    public Entry clone()
+    {
+        // First, clone the structure
+        DefaultEntry clone = ( DefaultEntry ) shallowClone();
+
+        // now clone all the attributes
+        clone.attributes.clear();
+
+        if ( schemaManager != null )
+        {
+            for ( Attribute attribute : attributes.values() )
+            {
+                String oid = attribute.getAttributeType().getOid();
+                clone.attributes.put( oid, attribute.clone() );
+            }
+        }
+        else
+        {
+            for ( Attribute attribute : attributes.values() )
+            {
+                clone.attributes.put( attribute.getId(), attribute.clone() );
+            }
+
+        }
+
+        // We are done !
+        return clone;
+    }
+
+
+    /**
+     * Shallow clone an entry. We don't clone the Attributes
+     */
+    @SuppressWarnings("unchecked")
+    public Entry shallowClone()
+    {
+        try
+        {
+            // First, clone the structure
+            DefaultEntry clone = ( DefaultEntry ) super.clone();
+
+            // An Entry has a Dn and many attributes.
+            // note that Dn is immutable now
+            clone.dn = dn;
+
+            // then clone the ClientAttribute Map.
+            clone.attributes = ( Map<String, Attribute> ) ( ( ( HashMap<String, Attribute> ) attributes )
+                .clone() );
+
+            // We are done !
+            return clone;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( Attribute... attributes )
+    {
+        if ( schemaManager == null )
+        {
+            for ( Attribute attribute : attributes )
+            {
+                if ( attribute == null )
+                {
+                    return this.attributes.size() == 0;
+                }
+
+                if ( !this.attributes.containsKey( attribute.getId() ) )
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            for ( Attribute entryAttribute : attributes )
+            {
+                if ( entryAttribute == null )
+                {
+                    return this.attributes.size() == 0;
+                }
+
+                AttributeType attributeType = entryAttribute.getAttributeType();
+
+                if ( ( attributeType == null ) || !this.attributes.containsKey( attributeType.getOid() ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsAttribute( String... attributes )
+    {
+        if ( schemaManager == null )
+        {
+            for ( String attribute : attributes )
+            {
+                String id = getId( attribute );
+
+                if ( !this.attributes.containsKey( id ) )
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        else
+        {
+            for ( String attribute : attributes )
+            {
+                try
+                {
+                    if ( !containsAttribute( schemaManager.lookupAttributeTypeRegistry( attribute ) ) )
+                    {
+                        return false;
+                    }
+                }
+                catch ( LdapException ne )
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsAttribute( AttributeType attributeType )
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        return attributes.containsKey( attributeType.getOid() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( AttributeType attributeType, byte[]... values )
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            return attribute.contains( values );
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( AttributeType attributeType, String... values )
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            return attribute.contains( values );
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( AttributeType attributeType, Value<?>... values )
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        Attribute attribute = attributes.get( attributeType.getOid() );
+
+        if ( attribute != null )
+        {
+            return attribute.contains( values );
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String upId, byte[]... values )
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            return false;
+        }
+
+        String id = getId( upId );
+
+        if ( schemaManager != null )
+        {
+            try
+            {
+                return contains( schemaManager.lookupAttributeTypeRegistry( id ), values );
+            }
+            catch ( LdapException le )
+            {
+                return false;
+            }
+        }
+
+        Attribute attribute = attributes.get( id );
+
+        if ( attribute == null )
+        {
+            return false;
+        }
+
+        return attribute.contains( values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String upId, String... values )
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            return false;
+        }
+
+        String id = getId( upId );
+
+        if ( schemaManager != null )
+        {
+            try
+            {
+                return contains( schemaManager.lookupAttributeTypeRegistry( id ), values );
+            }
+            catch ( LdapException le )
+            {
+                return false;
+            }
+        }
+
+        Attribute attribute = attributes.get( id );
+
+        if ( attribute == null )
+        {
+            return false;
+        }
+
+        return attribute.contains( values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String upId, Value<?>... values )
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            return false;
+        }
+
+        String id = getId( upId );
+
+        if ( schemaManager != null )
+        {
+            try
+            {
+                return contains( schemaManager.lookupAttributeTypeRegistry( id ), values );
+            }
+            catch ( LdapException le )
+            {
+                return false;
+            }
+        }
+
+        Attribute attribute = attributes.get( id );
+
+        if ( attribute == null )
+        {
+            return false;
+        }
+
+        return attribute.contains( values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute get( String alias )
+    {
+        try
+        {
+            String id = getId( alias );
+
+            if ( schemaManager != null )
+            {
+                try
+                {
+                    AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( id );
+
+                    return attributes.get( attributeType.getOid() );
+                }
+                catch ( LdapException ne )
+                {
+                    String message = ne.getLocalizedMessage();
+                    LOG.error( message );
+                    return null;
+                }
+            }
+            else
+            {
+                return attributes.get( id );
+            }
+        }
+        catch ( IllegalArgumentException iea )
+        {
+            LOG.error( I18n.err( I18n.ERR_04134, alias ) );
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute get( AttributeType attributeType )
+    {
+        if ( attributeType != null )
+        {
+            return attributes.get( attributeType.getOid() );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<Attribute> getAttributes()
+    {
+        return Collections.unmodifiableMap( attributes ).values();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, byte[]... values )
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        if ( schemaManager == null )
+        {
+            // Get the normalized form of the ID
+            String id = getId( upId );
+
+            // Create a new attribute
+            Attribute clientAttribute = new DefaultAttribute( upId, values );
+
+            // Replace the previous one, and return it back
+            return attributes.put( id, clientAttribute );
+        }
+        else
+        {
+            try
+            {
+                return put( upId, getAttributeType( upId ), values );
+            }
+            catch ( LdapException ne )
+            {
+                String message = I18n.err( I18n.ERR_04464, upId, ne.getLocalizedMessage() );
+                LOG.error( message );
+                throw new IllegalArgumentException( message, ne );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, String... values )
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        if ( schemaManager == null )
+        {
+            // Get the normalized form of the ID
+            String id = getId( upId );
+
+            // Create a new attribute
+            Attribute clientAttribute = new DefaultAttribute( upId, values );
+
+            // Replace the previous one, and return it back
+            return attributes.put( id, clientAttribute );
+        }
+        else
+        {
+            try
+            {
+                return put( upId, getAttributeType( upId ), values );
+            }
+            catch ( LdapException ne )
+            {
+                String message = I18n.err( I18n.ERR_04464, upId, ne.getLocalizedMessage() );
+                LOG.error( message );
+                throw new IllegalArgumentException( message, ne );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, Value<?>... values )
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+
+        if ( schemaManager == null )
+        {
+            // Get the normalized form of the ID
+            String id = getId( upId );
+
+            // Create a new attribute
+            Attribute clientAttribute = new DefaultAttribute( upId, values );
+
+            // Replace the previous one, and return it back
+            return attributes.put( id, clientAttribute );
+        }
+        else
+        {
+            try
+            {
+                return put( upId, getAttributeType( upId ), values );
+            }
+            catch ( LdapException ne )
+            {
+                String message = I18n.err( I18n.ERR_04464, upId, ne.getLocalizedMessage() );
+                LOG.error( message );
+                throw new IllegalArgumentException( message, ne );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     **
+    public List<Attribute> set( AttributeType... attributeTypes )
+    {
+        List<Attribute> removed = new ArrayList<Attribute>();
+
+        // Now, loop on all the attributeType to add
+        for ( AttributeType attributeType : attributeTypes )
+        {
+            if ( attributeType == null )
+            {
+                String message = I18n.err( I18n.ERR_04467 );
+                LOG.error( message );
+                continue;
+            }
+
+            Attribute attribute = attributes.put( attributeType.getOid(),
+                new DefaultAttribute( attributeType ) );
+
+            if ( attribute != null )
+            {
+                removed.add( attribute );
+            }
+        }
+
+        if ( removed.size() == 0 )
+        {
+            return null;
+        }
+        else
+        {
+            return removed;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Attribute> put( Attribute... attributes ) throws LdapException
+    {
+        // First, get the existing attributes
+        List<Attribute> previous = new ArrayList<Attribute>();
+
+        if ( schemaManager == null )
+        {
+            for ( Attribute attribute : attributes )
+            {
+                String id = attribute.getId();
+
+                if ( containsAttribute( id ) )
+                {
+                    // Store the attribute and remove it from the list
+                    previous.add( get( id ) );
+                    this.attributes.remove( id );
+                }
+
+                // add the new one
+                this.attributes.put( id, attribute );
+            }
+        }
+        else
+        {
+            for ( Attribute attribute : attributes )
+            {
+                if ( attribute == null )
+                {
+                    String message = I18n.err( I18n.ERR_04462 );
+                    LOG.error( message );
+                    throw new IllegalArgumentException( message );
+                }
+
+                if ( attribute.getAttributeType() == null )
+                {
+                    AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute.getId() );
+                    attribute.apply( attributeType );
+                }
+
+                Attribute removed = this.attributes.put( attribute.getAttributeType().getOid(), attribute );
+
+                if ( removed != null )
+                {
+                    previous.add( removed );
+                }
+            }
+        }
+
+        // return the previous attributes
+        return previous;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        return put( null, attributeType, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( AttributeType attributeType, String... values ) throws LdapException
+    {
+        return put( null, attributeType, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        return put( null, attributeType, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            try
+            {
+                attributeType = getAttributeType( upId );
+            }
+            catch ( Exception e )
+            {
+                String message = I18n.err( I18n.ERR_04477_NO_VALID_AT_FOR_THIS_ID );
+                LOG.error( message );
+                throw new IllegalArgumentException( message, e );
+            }
+        }
+        else
+        {
+            if ( !Strings.isEmpty( upId ) )
+            {
+                AttributeType tempAT = getAttributeType( upId );
+
+                if ( !tempAT.equals( attributeType ) )
+                {
+                    String message = I18n.err( I18n.ERR_04463, upId, attributeType );
+                    LOG.error( message );
+                    throw new IllegalArgumentException( message );
+                }
+            }
+            else
+            {
+                upId = getUpId( upId, attributeType );
+            }
+        }
+
+        if ( attributeType.equals( objectClassAttributeType ) )
+        {
+            String message = I18n.err( I18n.ERR_04461 );
+            LOG.error( message );
+            throw new UnsupportedOperationException( message );
+        }
+
+        Attribute attribute = new DefaultAttribute( upId, attributeType, values );
+
+        return attributes.put( attributeType.getOid(), attribute );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, AttributeType attributeType, String... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            try
+            {
+                attributeType = getAttributeType( upId );
+            }
+            catch ( Exception e )
+            {
+                String message = I18n.err( I18n.ERR_04477_NO_VALID_AT_FOR_THIS_ID );
+                LOG.error( message );
+                throw new IllegalArgumentException( message, e );
+            }
+        }
+        else
+        {
+            if ( !Strings.isEmpty( upId ) )
+            {
+                AttributeType tempAT = getAttributeType( upId );
+
+                if ( !tempAT.equals( attributeType ) )
+                {
+                    String message = I18n.err( I18n.ERR_04463, upId, attributeType );
+                    LOG.error( message );
+                    throw new IllegalArgumentException( message );
+                }
+            }
+            else
+            {
+                upId = getUpId( upId, attributeType );
+            }
+        }
+
+        Attribute attribute = new DefaultAttribute( upId, attributeType, values );
+
+        return attributes.put( attributeType.getOid(), attribute );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            try
+            {
+                attributeType = getAttributeType( upId );
+            }
+            catch ( Exception e )
+            {
+                String message = I18n.err( I18n.ERR_04477_NO_VALID_AT_FOR_THIS_ID );
+                LOG.error( message );
+                throw new IllegalArgumentException( message, e );
+            }
+        }
+        else
+        {
+            if ( !Strings.isEmpty( upId ) )
+            {
+                AttributeType tempAT = getAttributeType( upId );
+
+                if ( !tempAT.equals( attributeType ) )
+                {
+                    String message = I18n.err( I18n.ERR_04463, upId, attributeType );
+                    LOG.error( message );
+                    throw new IllegalArgumentException( message );
+                }
+            }
+            else
+            {
+                upId = getUpId( upId, attributeType );
+            }
+        }
+
+        Attribute attribute = new DefaultAttribute( upId, attributeType, values );
+
+        return attributes.put( attributeType.getOid(), attribute );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Attribute> remove( Attribute... attributes ) throws LdapException
+    {
+        List<Attribute> removedAttributes = new ArrayList<Attribute>();
+
+        if ( schemaManager == null )
+        {
+            for ( Attribute attribute : attributes )
+            {
+                if ( containsAttribute( attribute.getId() ) )
+                {
+                    this.attributes.remove( attribute.getId() );
+                    removedAttributes.add( attribute );
+                }
+            }
+        }
+        else
+        {
+            for ( Attribute attribute : attributes )
+            {
+                AttributeType attributeType = attribute.getAttributeType();
+
+                if ( attributeType == null )
+                {
+                    String message = I18n.err( I18n.ERR_04460_ATTRIBUTE_TYPE_NULL_NOT_ALLOWED );
+                    LOG.error( message );
+                    throw new IllegalArgumentException( message );
+                }
+
+                if ( this.attributes.containsKey( attributeType.getOid() ) )
+                {
+                    this.attributes.remove( attributeType.getOid() );
+                    removedAttributes.add( attribute );
+                }
+            }
+        }
+
+        return removedAttributes;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        try
+        {
+            Attribute attribute = attributes.get( attributeType.getOid() );
+
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+
+            int nbOldValues = attribute.size();
+
+            // Remove the values
+            attribute.remove( values );
+
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( attributeType.getOid() );
+
+                return true;
+            }
+
+            return nbOldValues != attribute.size();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            LOG.error( I18n.err( I18n.ERR_04465, attributeType ) );
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( AttributeType attributeType, String... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        try
+        {
+            Attribute attribute = attributes.get( attributeType.getOid() );
+
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+
+            int nbOldValues = attribute.size();
+
+            // Remove the values
+            attribute.remove( values );
+
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( attributeType.getOid() );
+
+                return true;
+            }
+
+            return nbOldValues != attribute.size();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            LOG.error( I18n.err( I18n.ERR_04465, attributeType ) );
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        try
+        {
+            Attribute attribute = attributes.get( attributeType.getOid() );
+
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+
+            int nbOldValues = attribute.size();
+
+            // Remove the values
+            attribute.remove( values );
+
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( attributeType.getOid() );
+
+                return true;
+            }
+
+            return nbOldValues != attribute.size();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            LOG.error( I18n.err( I18n.ERR_04465, attributeType ) );
+            return false;
+        }
+    }
+
+
+    /**
+     * <p>
+     * Removes the attribute with the specified AttributeTypes.
+     * </p>
+     * <p>
+     * The removed attribute are returned by this method.
+     * </p>
+     * <p>
+     * If there is no attribute with the specified AttributeTypes,
+     * the return value is <code>null</code>.
+     * </p>
+     *
+     * @param attributes the AttributeTypes to be removed
+     * @return the removed attributes, if any, as a list; otherwise <code>null</code>
+     */
+    public void removeAttributes( AttributeType... attributes )
+    {
+        if ( ( attributes == null ) || ( attributes.length == 0 ) || ( schemaManager == null ) )
+        {
+            return;
+        }
+
+        for ( AttributeType attributeType : attributes )
+        {
+            if ( attributeType == null )
+            {
+                continue;
+            }
+
+            this.attributes.remove( attributeType.getOid() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeAttributes( String... attributes )
+    {
+        if ( attributes.length == 0 )
+        {
+            return;
+        }
+
+        if ( schemaManager == null )
+        {
+            for ( String attribute : attributes )
+            {
+                Attribute attr = get( attribute );
+
+                if ( attr != null )
+                {
+                    this.attributes.remove( attr.getId() );
+                }
+                else
+                {
+                    String message = I18n.err( I18n.ERR_04137, attribute );
+                    LOG.warn( message );
+                    continue;
+                }
+            }
+        }
+        else
+        {
+            for ( String attribute : attributes )
+            {
+                AttributeType attributeType = null;
+
+                try
+                {
+                    attributeType = schemaManager.lookupAttributeTypeRegistry( attribute );
+                }
+                catch ( LdapException ne )
+                {
+                    String message = "The attribute '" + attribute + "' does not exist in the entry";
+                    LOG.warn( message );
+                    continue;
+                }
+
+                this.attributes.remove( attributeType.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified binary values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns
+     * <code>false</code>
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist.
+     */
+    public boolean remove( String upId, byte[]... values ) throws LdapException
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.info( message );
+            return false;
+        }
+
+        if ( schemaManager == null )
+        {
+            String id = getId( upId );
+
+            Attribute attribute = get( id );
+
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+
+            int nbOldValues = attribute.size();
+
+            // Remove the values
+            attribute.remove( values );
+
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( id );
+
+                return true;
+            }
+
+            return nbOldValues != attribute.size();
+        }
+        else
+        {
+            try
+            {
+                AttributeType attributeType = getAttributeType( upId );
+
+                return remove( attributeType, values );
+            }
+            catch ( LdapException ne )
+            {
+                LOG.error( I18n.err( I18n.ERR_04465, upId ) );
+                return false;
+            }
+            catch ( IllegalArgumentException iae )
+            {
+                LOG.error( I18n.err( I18n.ERR_04466, upId ) );
+                return false;
+            }
+        }
+
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified String values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns
+     * <code>false</code>
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param values the attributes to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist.
+     */
+    public boolean remove( String upId, String... values ) throws LdapException
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.info( message );
+            return false;
+        }
+
+        if ( schemaManager == null )
+        {
+            String id = getId( upId );
+
+            Attribute attribute = get( id );
+
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+
+            int nbOldValues = attribute.size();
+
+            // Remove the values
+            attribute.remove( values );
+
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( id );
+
+                return true;
+            }
+
+            return nbOldValues != attribute.size();
+        }
+        else
+        {
+            try
+            {
+                AttributeType attributeType = getAttributeType( upId );
+
+                return remove( attributeType, values );
+            }
+            catch ( LdapException ne )
+            {
+                LOG.error( I18n.err( I18n.ERR_04465, upId ) );
+                return false;
+            }
+            catch ( IllegalArgumentException iae )
+            {
+                LOG.error( I18n.err( I18n.ERR_04466, upId ) );
+                return false;
+            }
+        }
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns
+     * <code>false</code>
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param values the attributes to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist.
+     */
+    public boolean remove( String upId, Value<?>... values ) throws LdapException
+    {
+        if ( Strings.isEmpty( upId ) )
+        {
+            String message = I18n.err( I18n.ERR_04457_NULL_ATTRIBUTE_ID );
+            LOG.info( message );
+            return false;
+        }
+
+        if ( schemaManager == null )
+        {
+            String id = getId( upId );
+
+            Attribute attribute = get( id );
+
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+
+            int nbOldValues = attribute.size();
+
+            // Remove the values
+            attribute.remove( values );
+
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( id );
+
+                return true;
+            }
+
+            return nbOldValues != attribute.size();
+        }
+        else
+        {
+            try
+            {
+                AttributeType attributeType = getAttributeType( upId );
+
+                return remove( attributeType, values );
+            }
+            catch ( LdapException ne )
+            {
+                LOG.error( I18n.err( I18n.ERR_04465, upId ) );
+                return false;
+            }
+            catch ( IllegalArgumentException iae )
+            {
+                LOG.error( I18n.err( I18n.ERR_04466, upId ) );
+                return false;
+            }
+        }
+    }
+
+
+    /**
+     * Get this entry's Dn.
+     *
+     * @return The entry's Dn
+     */
+    public Dn getDn()
+    {
+        return dn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDn( Dn dn )
+    {
+        this.dn = dn;
+
+        // Rehash the object
+        rehash();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDn( String dn ) throws LdapInvalidDnException
+    {
+        setDn( new Dn( dn ) );
+    }
+
+
+    /**
+     * Remove all the attributes for this entry. The Dn is not reset
+     */
+    public void clear()
+    {
+        attributes.clear();
+    }
+
+
+    /**
+     * Returns an enumeration containing the zero or more attributes in the
+     * collection. The behavior of the enumeration is not specified if the
+     * attribute collection is changed.
+     *
+     * @return an enumeration of all contained attributes
+     */
+    public Iterator<Attribute> iterator()
+    {
+        return Collections.unmodifiableMap( attributes ).values().iterator();
+    }
+
+
+    /**
+     * Returns the number of attributes.
+     *
+     * @return the number of attributes
+     */
+    public int size()
+    {
+        return attributes.size();
+    }
+
+
+    /**
+     * This is the place where we serialize entries, and all theirs
+     * elements.
+     * <br/>
+     * The structure used to store the entry is the following :
+     * <ul>
+     *   <li>
+     *     <b>[Dn]</b> : If it's null, stores an empty Dn
+     *   </li>
+     *   <li>
+     *     <b>[attributes number]</b> : the number of attributes.
+     *   </li>
+     *   <li>
+     *     <b>[attribute]*</b> : each attribute, if we have some
+     *   </li>
+     * </ul>
+     * 
+     * {@inheritDoc}
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        // First, the Dn
+        if ( dn == null )
+        {
+            // Write an empty Dn
+            Dn.EMPTY_DN.writeExternal( out );
+        }
+        else
+        {
+            // Write the Dn
+            dn.writeExternal( out );
+        }
+
+        // Then the attributes.
+        // Store the attributes' nulber first
+        out.writeInt( attributes.size() );
+
+        // Iterate through the keys.
+        for ( Attribute attribute : attributes.values() )
+        {
+            // Store the attribute
+            attribute.writeExternal( out );
+        }
+
+        out.flush();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the Dn
+        dn = new Dn( schemaManager );
+        dn.readExternal( in );
+
+        // Read the number of attributes
+        int nbAttributes = in.readInt();
+
+        // Read the attributes
+        for ( int i = 0; i < nbAttributes; i++ )
+        {
+            // Read each attribute
+            Attribute attribute = new DefaultAttribute();
+            attribute.readExternal( in );
+
+            if ( schemaManager != null )
+            {
+                try
+                {
+                    AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute.getId() );
+                    attribute.apply( attributeType );
+
+                    attributes.put( attributeType.getOid(), attribute );
+                }
+                catch ( LdapException le )
+                {
+                    String message = le.getLocalizedMessage();
+                    LOG.error( message );
+                    throw new IOException( message, le );
+                }
+            }
+            else
+            {
+                attributes.put( attribute.getId(), attribute );
+            }
+        }
+    }
+
+
+    /**
+     * Get the hash code of this ClientEntry. The Attributes will be sorted
+     * before the comparison can be done.
+     *
+     * @see java.lang.Object#hashCode()
+     * @return the instance's hash code
+     */
+    public int hashCode()
+    {
+        if ( h == 0 )
+        {
+            rehash();
+        }
+
+        return h;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasObjectClass( String... objectClasses )
+    {
+        if ( ( objectClasses == null ) || ( objectClasses.length == 0 ) || ( objectClasses[0] == null ) )
+        {
+            return false;
+        }
+
+        for ( String objectClass : objectClasses )
+        {
+            if ( schemaManager != null )
+            {
+                if ( !contains( objectClassAttributeType, objectClass ) )
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if ( !contains( "objectclass", objectClass ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasObjectClass( Attribute... objectClasses )
+    {
+        if ( ( objectClasses == null ) || ( objectClasses.length == 0 ) || ( objectClasses[0] == null ) )
+        {
+            return false;
+        }
+
+        for ( Attribute objectClass : objectClasses )
+        {
+            // We have to check that we are checking the ObjectClass attributeType
+            if ( !objectClass.getAttributeType().equals( objectClassAttributeType ) )
+            {
+                return false;
+            }
+
+            Attribute attribute = attributes.get( objectClassAttributeType.getOid() );
+
+            if ( attribute == null )
+            {
+                // The entry does not have an ObjectClass attribute
+                return false;
+            }
+
+            for ( Value<?> value : objectClass )
+            {
+                // Loop on all the values, and check if they are present
+                if ( !attribute.contains( value.getString() ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSchemaAware()
+    {
+        return schemaManager != null;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        // Short circuit
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof Entry ) )
+        {
+            return false;
+        }
+
+        Entry other = ( Entry ) o;
+
+        // Both Dn must be equal
+        if ( dn == null )
+        {
+            if ( other.getDn() != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !dn.equals( other.getDn() ) )
+            {
+                return false;
+            }
+        }
+
+        // They must have the same number of attributes
+        if ( size() != other.size() )
+        {
+            return false;
+        }
+
+        // Each attribute must be equal
+        for ( Attribute attribute : other )
+        {
+            if ( !attribute.equals( this.get( attribute.getId() ) ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return toString( "" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString( String tabs )
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( tabs ).append( "Entry\n" );
+        sb.append( tabs ).append( "    dn" );
+
+        if ( dn.isSchemaAware() )
+        {
+            sb.append( "[n]" );
+        }
+
+        sb.append( ": " );
+        sb.append( dn.getName() );
+        sb.append( '\n' );
+
+        // First dump the ObjectClass attribute
+        if ( schemaManager != null )
+        {
+            // First dump the ObjectClass attribute
+            if ( containsAttribute( objectClassAttributeType.getOid() ) )
+            {
+                Attribute objectClass = get( objectClassAttributeType );
+
+                sb.append( objectClass.toString( tabs + "    " ) );
+            }
+        }
+        else
+        {
+            if ( containsAttribute( "objectClass" ) )
+            {
+                Attribute objectClass = get( "objectclass" );
+
+                sb.append( objectClass.toString( tabs + "    " ) );
+            }
+        }
+
+        sb.append( '\n' );
+
+        if ( attributes.size() != 0 )
+        {
+            for ( Attribute attribute : attributes.values() )
+            {
+                String id = attribute.getId();
+
+                if ( schemaManager != null )
+                {
+                    AttributeType attributeType = schemaManager.getAttributeType( id );
+
+                    if ( attributeType == null )
+                    {
+                        sb.append( tabs + "id: " + id );
+                    }
+                    else if ( !attributeType.equals( objectClassAttributeType ) )
+                    {
+                        sb.append( attribute.toString( tabs + "    " ) );
+                        sb.append( '\n' );
+                        continue;
+                    }
+                }
+                else
+                {
+                    if ( !id.equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT )
+                        && !id.equals( SchemaConstants.OBJECT_CLASS_AT_OID ) )
+                    {
+                        sb.append( attribute.toString( tabs + "    " ) );
+                        sb.append( '\n' );
+                        continue;
+                    }
+                }
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultModification.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultModification.java
new file mode 100644
index 0000000..6b43dc0
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/DefaultModification.java
@@ -0,0 +1,417 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An internal implementation for a ModificationItem. The name has been
+ * chosen so that it does not conflict with @see ModificationItem
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultModification implements Modification
+{
+    /** The modification operation */
+    private ModificationOperation operation;
+
+    /** The attribute which contains the modification */
+    private Attribute attribute;
+
+    /** The AtributeType */
+    private AttributeType attributeType;
+
+    /** logger for reporting errors that might not be handled properly upstream */
+    protected static final Logger LOG = LoggerFactory.getLogger( Modification.class );
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     */
+    public DefaultModification()
+    {
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param operation The modification operation
+     * @param attribute The associated attribute 
+     */
+    public DefaultModification( ModificationOperation operation, Attribute attribute )
+    {
+        this.operation = operation;
+        this.attribute = attribute;
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param operation The modification operation
+     * @param attributeId The associated attribute ID
+     * @param values the associated values
+     */
+    public DefaultModification( ModificationOperation operation, String attributeId, String... values )
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeId, values );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param operation The modification operation
+     * @param attributeId The associated attribute ID
+     * @param values the associated values
+     */
+    public DefaultModification( ModificationOperation operation, String attributeId, byte[]... values )
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeId, values );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param operation The modification operation
+     * @param attributeId The associated attribute ID
+     * @param values the associated values
+     */
+    public DefaultModification( ModificationOperation operation, String attributeId, Value<?>... values )
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeId, values );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification with no value
+     *
+     * @param operation The modification operation
+     * @param attributeId The associated attribute ID
+     */
+    public DefaultModification( ModificationOperation operation, String attributeId )
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeId );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param operation The modification operation
+     * @param attributeType The associated attributeType
+     * @param values the associated values
+     */
+    public DefaultModification( ModificationOperation operation, AttributeType attributeType, String... values )
+        throws LdapInvalidAttributeValueException
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeType, values );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param operation The modification operation
+     * @param attributeType The associated attributeType
+     * @param values the associated values
+     */
+    public DefaultModification( ModificationOperation operation, AttributeType attributeType, byte[]... values )
+        throws LdapInvalidAttributeValueException
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeType, values );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param operation The modification operation
+     * @param attributeType The associated attributeType
+     * @param values the associated values
+     */
+    public DefaultModification( ModificationOperation operation, AttributeType attributeType, Value<?>... values )
+        throws LdapInvalidAttributeValueException
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeType, values );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification with no value.
+     *
+     * @param operation The modification operation
+     * @param attributeType The associated attributeType
+     */
+    public DefaultModification( ModificationOperation operation, AttributeType attributeType )
+        throws LdapInvalidAttributeValueException
+    {
+        this.operation = operation;
+        this.attribute = new DefaultAttribute( attributeType );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultModification.
+     *
+     * @param schemaManager The schema manager 
+     * @param modification The modification
+     */
+    public DefaultModification( SchemaManager schemaManager, Modification modification )
+    {
+        operation = modification.getOperation();
+
+        Attribute modAttribute = modification.getAttribute();
+
+        try
+        {
+            AttributeType at = modAttribute.getAttributeType();
+
+            if ( at == null )
+            {
+                at = schemaManager.lookupAttributeTypeRegistry( modAttribute.getId() );
+            }
+
+            attribute = new DefaultAttribute( at, modAttribute );
+        }
+        catch ( LdapException ne )
+        {
+            // The attributeType is incorrect. Log, but do nothing otherwise.
+            LOG.error( I18n.err( I18n.ERR_04472, modAttribute.getId() ) );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModificationOperation getOperation()
+    {
+        return operation;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setOperation( int operation )
+    {
+        this.operation = ModificationOperation.getOperation( operation );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setOperation( ModificationOperation operation )
+    {
+        this.operation = operation;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute getAttribute()
+    {
+        return attribute;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setAttribute( Attribute attribute )
+    {
+        this.attribute = attribute;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException
+    {
+        this.attributeType = attributeType;
+
+        if ( attribute != null )
+        {
+            attribute.apply( attributeType );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     * @return <code>true</code> if both values are equal
+     */
+    public boolean equals( Object that )
+    {
+        // Basic equals checks
+        if ( this == that )
+        {
+            return true;
+        }
+
+        if ( !( that instanceof Modification ) )
+        {
+            return false;
+        }
+
+        Modification otherModification = ( Modification ) that;
+
+        // Check the operation
+        if ( operation != otherModification.getOperation() )
+        {
+            return false;
+        }
+
+        // Check the attribute
+        if ( attribute == null )
+        {
+            return otherModification.getAttribute() == null;
+        }
+
+        return attribute.equals( otherModification.getAttribute() );
+    }
+
+
+    /**
+     * Compute the modification @see Object#hashCode
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int h = 37;
+
+        h += h * 17 + operation.getValue();
+        h += h * 17 + attribute.hashCode();
+
+        return h;
+    }
+
+
+    /**
+     * @see java.io.Externalizable#readExternal(ObjectInput)
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // The operation
+        operation = ModificationOperation.getOperation( in.readInt() );
+
+        // The EntryAttribute if we have some
+        boolean hasAttribute = in.readBoolean();
+
+        if ( hasAttribute )
+        {
+            attribute = new DefaultAttribute();
+            attribute.readExternal( in );
+        }
+    }
+
+
+    /**
+     * @see java.io.Externalizable#writeExternal(ObjectOutput)
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        // The operation
+        out.writeInt( operation.getValue() );
+
+        // The EntryAttribute if not null
+        if ( attribute != null )
+        {
+            out.writeBoolean( true );
+            attribute.writeExternal( out );
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        out.flush();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultModification clone()
+    {
+        try
+        {
+            DefaultModification clone = ( DefaultModification ) super.clone();
+
+            clone.attribute = this.attribute.clone();
+            return clone;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "Modification: " ).
+            append( operation ).
+            append( "\n" ).
+            append( ", attribute : " ).
+            append( attribute );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Entry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Entry.java
new file mode 100644
index 0000000..41d9a30
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Entry.java
@@ -0,0 +1,859 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.Externalizable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * <p>
+ * This interface represent a LDAP entry. An LDAP entry contains :
+ * <li> A distinguished name (Dn)</li>
+ * <li> A list of attributes</li>
+ * </p>
+ * <p>
+ * The available methods on this object are described in this interface.
+ * </p>
+ * <p>
+ * This interface is used by the serverEntry and clientEntry interfaces.
+ *</p>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Entry extends Cloneable, Iterable<Attribute>, Externalizable
+{
+    /**
+     * Remove all the attributes for this entry. The Dn is not reset
+     */
+    void clear();
+
+
+    /**
+     * Clone the current entry
+     */
+    Entry clone();
+
+
+    /**
+     * Shallow Clone the current entry. We don't deep clone the attributes
+     */
+    Entry shallowClone();
+
+
+    /**
+     * Get this entry's Dn.
+     *
+     * @return The entry's Dn
+     */
+    Dn getDn();
+
+
+    /**
+     * Tells if an entry as some specific ObjectClasses values
+     * 
+     * @param objectClasses The ObjectClasses we want to check
+     * @return <code>true</code> if all the ObjectClasses value are present 
+     * in the ObjectClass attribute
+     */
+    boolean hasObjectClass( String... objectClasses );
+
+
+    /**
+     * Tells if an entry has some specific ObjectClasses Attributes
+     * 
+     * @param objectClasses The ObjectClasses we want to check
+     * @return <code>true</code> if the ObjectClasses Attribute are present 
+     * in the ObjectClass attribute
+     */
+    boolean hasObjectClass( Attribute... objectClasses );
+
+
+    /**
+     * <p>
+     * Returns the attribute with the specified alias. The return value
+     * is <code>null</code> if no match is found.  
+     * </p>
+     * <p>An Attribute with an id different from the supplied alias may 
+     * be returned: for example a call with 'cn' may in some implementations 
+     * return an Attribute whose getId() field returns 'commonName'.
+     * </p>
+     *
+     * @param alias an aliased name of the attribute identifier
+     * @return the attribute associated with the alias
+     */
+    Attribute get( String alias );
+
+
+    /**
+     * Returns the attribute associated with an AttributeType
+     * 
+     * @param attributeType the AttributeType we are looking for
+     * @return the associated attribute
+     */
+    Attribute get( AttributeType attributeType );
+
+
+    /**
+     * Gets all the attributes
+     *
+     * @return The combined set of all the attributes.
+     */
+    Collection<Attribute> getAttributes();
+
+
+    /**
+     * Set this entry's Dn.
+     *
+     * @param dn The Dn associated with this entry
+     */
+    void setDn( Dn dn );
+
+
+    /**
+     * Set this entry's Dn.
+     *
+     * @param dn The String Dn associated with this entry
+     * @throws LdapInvalidDnException if the provided Dn is invalid
+     */
+    void setDn( String dn ) throws LdapInvalidDnException;
+
+
+    /**
+     * Returns an iterator on the attributes for this entry.
+     *
+     * @return an iterator on top of all contained attributes
+     */
+    Iterator<Attribute> iterator();
+
+
+    /**
+     * Add some Attributes to the current Entry.
+     *
+     * @param attributes The attributes to add
+     * @return the modified entry
+     * @throws LdapException If we can't add any of the attributes
+     */
+    Entry add( Attribute... attributes ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some binary values) into an 
+     * entry.
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, the duplicated values 
+     * are not added (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a LdapException is thrown.
+     * </p>
+     *
+     * @param attributeType The attribute Type.
+     * @param values The list of binary values to inject. It can be empty.
+     * @return the modified entry
+     * @throws LdapException If the attribute does not exist
+     */
+    Entry add( AttributeType attributeType, byte[]... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some String values) into an 
+     * entry.
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, the duplicated values 
+     * are not added (duplicated values are not allowed)
+     * </p>
+     * <p> 
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a LdapException is thrown.
+     * </p>
+     * 
+     * @param attributeType The attribute Type
+     * @param values The list of binary values to inject. It can be empty
+     * @return the modified entry
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If the attribute does not exist
+     */
+    Entry add( AttributeType attributeType, String... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some values) into an 
+     * entry.
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, the duplicated values 
+     * are not added (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a LdapException is thrown.
+     * </p>
+     *
+     * @param attributeType The attribute Type
+     * @param values The list of binary values to inject. It can be empty
+     * @return the modified entry
+     * @throws LdapException If the attribute does not exist
+     */
+    Entry add( AttributeType attributeType, Value<?>... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some binary values) into an 
+     * entry. Set the User Provider ID at the same time
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, the duplicated values 
+     * are not added (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a LdapException is thrown.
+     * </p>
+     *
+     * @param upId The user provided ID for the added AttributeType
+     * @param attributeType The attribute Type.
+     * @param values The list of binary values to add. It can be empty.
+     * @return the modified entry
+     * @throws LdapException If the attribute does not exist
+     */
+    Entry add( String upId, AttributeType attributeType, byte[]... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some String values) into an 
+     * entry. Set the User Provider ID at the same time
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, the duplicated values 
+     * are not added (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a LdapException is thrown.
+     * </p>
+     *
+     * @param upId The user provided ID for the added AttributeType
+     * @param attributeType The attribute Type.
+     * @param values The list of String values to add. It can be empty.
+     * @return the modified entry
+     * @throws LdapException If the attribute does not exist
+     */
+    Entry add( String upId, AttributeType attributeType, String... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some values) into an 
+     * entry. Set the User Provider ID at the same time
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, nothing is done 
+     * (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a LdapException is thrown.
+     * </p>
+     *
+     * @param upId The user provided ID for the added AttributeType
+     * @param attributeType The attribute Type.
+     * @param values The list of values to add. It can be empty.
+     * @return the modified entry
+     * @throws LdapException If the attribute does not exist
+     */
+    Entry add( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException;
+
+
+    /**
+     * Add some String values to the current Entry.
+     *
+     * @param upId The user provided ID of the attribute we want to add 
+     * some values to
+     * @param values The list of String values to add
+     * @return the modified entry
+     * @throws LdapException If we can't add any of the values
+     */
+    Entry add( String upId, String... values ) throws LdapException;
+
+
+    /**
+     * Add some binary values to the current Entry.
+     *
+     * @param upId The user provided ID of the attribute we want to add 
+     * some values to
+     * @param values The list of binary values to add
+     * @return the modified entry
+     * @throws LdapException If we can't add any of the values
+     */
+    Entry add( String upId, byte[]... values ) throws LdapException;
+
+
+    /**
+     * Add some Values to the current Entry.
+     *
+     * @param upId The user provided ID of the attribute we want to add 
+     * some values to
+     * @param values The list of Values to add
+     * @return the modified entry
+     * @throws LdapException If we can't add any of the values
+     */
+    Entry add( String upId, Value<?>... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Places attributes in the attribute collection. 
+     * </p>
+     * <p>If there is already an attribute with the same ID as any of the 
+     * new attributes, the old ones are removed from the collection and 
+     * are returned by this method. If there was no attribute with the 
+     * same ID the return value is <code>null</code>.
+     *</p>
+     *
+     * @param attributes the attributes to be put
+     * @return the old attributes with the same OID, if exist; otherwise <code>null</code>
+     * @exception LdapException if the operation fails
+     */
+    List<Attribute> put( Attribute... attributes ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and binary values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param attributeType the type of the new attribute to be put
+     * @param values the binary values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if there are failures
+     */
+    Attribute put( AttributeType attributeType, byte[]... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and String values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param attributeType the type of the new attribute to be put
+     * @param values the String values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if there are failures
+     */
+    Attribute put( AttributeType attributeType, String... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param attributeType the type of the new attribute to be put
+     * @param values the values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws LdapException if there are failures
+     */
+    Attribute put( AttributeType attributeType, Value<?>... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some binary values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * The given User provided ID will be used for this new AttributeEntry.
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param upId The User Provided ID to be stored into the AttributeEntry
+     * @param values the binary values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws LdapException if there are failures.
+     */
+    Attribute put( String upId, AttributeType attributeType, byte[]... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some String values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * The given User provided ID will be used for this new AttributeEntry.
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param upId The User Provided ID to be stored into the AttributeEntry
+     * @param attributeType the type of the new attribute to be put
+     * @param values the String values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if there are failures.
+     */
+    Attribute put( String upId, AttributeType attributeType, String... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * The given User provided ID will be used for this new AttributeEntry.
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param upId The User Provided ID to be stored into the AttributeEntry
+     * @param attributeType the type of the new attribute to be put
+     * @param values the values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws LdapException if there are failures.
+     */
+    Attribute put( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Put an attribute (represented by its ID and some binary values) into an entry. 
+     * </p>
+     * <p> 
+     * If the attribute already exists, the previous attribute will be 
+     * replaced and returned.
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param values The list of binary values to put. It can be empty.
+     * @return The replaced attribute
+     */
+    Attribute put( String upId, byte[]... values );
+
+
+    /**
+     * <p>
+     * Put an attribute (represented by its ID and some String values) into an entry. 
+     * </p>
+     * <p> 
+     * If the attribute already exists, the previous attribute will be 
+     * replaced and returned.
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param values The list of String values to put. It can be empty.
+     * @return The replaced attribute
+     */
+    Attribute put( String upId, String... values );
+
+
+    /**
+     * <p>
+     * Put an attribute (represented by its ID and some values) into an entry. 
+     * </p>
+     * <p> 
+     * If the attribute already exists, the previous attribute will be 
+     * replaced and returned.
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param values The list of values to put. It can be empty.
+     * @return The replaced attribute
+     */
+    Attribute put( String upId, Value<?>... values );
+
+
+    /**
+     * <p>
+     * Removes the specified binary values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param attributeType The attribute type  
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    boolean remove( AttributeType attributeType, byte[]... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Removes the specified String values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param attributeType The attribute type  
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    boolean remove( AttributeType attributeType, String... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Removes the specified values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param attributeType The attribute type  
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    boolean remove( AttributeType attributeType, Value<?>... values ) throws LdapException;
+
+
+    /**
+     * Removes the specified attributes. The removed attributes are
+     * returned by this method. If there were no attribute the return value
+     * is <code>null</code>.
+     *
+     * @param attributes the attributes to be removed
+     * @return the removed attribute, if exists; otherwise <code>null</code>
+     */
+    List<Attribute> remove( Attribute... attributes ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Removes the attribute with the specified AttributeTypes. 
+     * </p>
+     * <p>
+     * The removed attribute are returned by this method. 
+     * </p>
+     * <p>
+     * If there is no attribute with the specified AttributeTypes,
+     * the return value is <code>null</code>.
+     * </p>
+     *
+     * @param attributes the AttributeTypes to be removed
+     * @return the removed attributes, if any, as a list; otherwise <code>null</code>
+     */
+    void removeAttributes( AttributeType... attributes );
+
+
+    /**
+     * <p>
+     * Removes the specified binary values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID  
+     * @param values the attribute's values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    boolean remove( String upId, byte[]... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Removes the specified String values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after havong removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID  
+     * @param values the attribute's values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if no values have been removed or if the attribute does not exist. 
+     */
+    boolean remove( String upId, String... values ) throws LdapException;
+
+
+    /**
+     * <p>
+     * Removes the specified values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID  
+     * @param values the attribute's values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     * @throws LdapException if the attribute does not exists
+     */
+    boolean remove( String upId, Value<?>... values ) throws LdapException;
+
+
+    /**
+      * <p>
+      * Removes the attribute with the specified alias. 
+      * </p>
+      * <p>
+      * The removed attribute are returned by this method. 
+      * </p>
+      * <p>
+      * If there is no attribute with the specified alias,
+      * the return value is <code>null</code>.
+      * </p>
+      *
+      * @param attributes an aliased name of the attribute to be removed
+      * @return the removed attributes, if any, as a list; otherwise <code>null</code>
+      */
+    void removeAttributes( String... attributes );
+
+
+    // -----------------------------------------------------------------------
+    // Container (contains/get/put/remove) Methods
+    // -----------------------------------------------------------------------
+    /**
+     * Checks if an entry contains an attribute with some given binary values.
+     *
+     * @param attributeType The Attribute we are looking for.
+     * @param values The searched binary values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * <code>false</code> otherwise, or if the attributes does not exist.
+     */
+    boolean contains( AttributeType attributeType, byte[]... values );
+
+
+    /**
+     * Checks if an entry contains an attribute with some given String values.
+     *
+     * @param attributeType The Attribute we are looking for.
+     * @param values The searched String values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * <code>false</code> otherwise, or if the attributes does not exist.
+     */
+    boolean contains( AttributeType attributeType, String... values );
+
+
+    /**
+     * Checks if an entry contains an attribute with some given binary values.
+     *
+     * @param attributeType The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * <code>false</code> otherwise, or if the attributes does not exist.
+     */
+    boolean contains( AttributeType attributeType, Value<?>... values );
+
+
+    /**
+     * Checks if an entry contains a specific AttributeType.
+     *
+     * @param attributeType The AttributeType to look for.
+     * @return <code>true</code> if the attribute is found within the entry.
+     */
+    boolean containsAttribute( AttributeType attributeType );
+
+
+    /**
+     * <p>
+     * Checks if an entry contains a list of attributes.
+     * </p>
+     * <p>
+     * If the list is null or empty, this method will return <code>true</code>
+     * if the entry has no attribute, <code>false</code> otherwise.
+     * </p>
+     *
+     * @param attributes The Attributes to look for
+     * @return <code>true</code> if all the attributes are found within 
+     * the entry, <code>false</code> if at least one of them is not present.
+     */
+    boolean contains( Attribute... attributes );
+
+
+    /**
+     * Checks if an entry contains an attribute with some binary values.
+     *
+     * @param upId The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * false if at least one value is not present or if the ID is not valid. 
+     */
+    boolean contains( String upId, byte[]... values );
+
+
+    /**
+     * Checks if an entry contains an attribute with some String values.
+     *
+     * @param upId The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * false if at least one value is not present or if the ID is not valid. 
+     */
+    boolean contains( String upId, String... values );
+
+
+    /**
+     * Checks if an entry contains an attribute with some values.
+     *
+     * @param upId The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * false if at least one value is not present or if the ID is not valid. 
+     */
+    boolean contains( String upId, Value<?>... values );
+
+
+    /**
+     * Checks if an entry contains some specific attributes.
+     *
+     * @param attributes The Attributes to look for.
+     * @return <code>true</code> if the attributes are all found within the entry.
+     */
+    boolean containsAttribute( String... attributes );
+
+
+    /**
+     * Returns the number of attributes.
+     *
+     * @return the number of attributes
+     */
+    int size();
+
+
+    /**
+     * Tells if the Entry is schema aware
+     * @return true if the Entry is schema aware
+     */
+    boolean isSchemaAware();
+
+
+    /**
+     * A pretty-pinter for Entries
+     * 
+     * @param tabs The tabs to add before any output
+     * @return The pretty-printed entry
+     */
+    String toString( String tabs );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ImmutableEntry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ImmutableEntry.java
new file mode 100644
index 0000000..473175c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ImmutableEntry.java
@@ -0,0 +1,754 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.util.exception.NotImplementedException;
+
+
+/**
+ * A default implementation of a ServerEntry which should suite most
+ * use cases.
+ * 
+ * This class is final, it should not be extended.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableEntry implements Entry
+{
+    /** Used for serialization */
+    private static final long serialVersionUID = 2L;
+
+    /** The wrapped Entry for this entry */
+    private Entry entry;
+
+
+    //-------------------------------------------------------------------------
+    // Constructors
+    //-------------------------------------------------------------------------
+    /**
+     * Creates a new instance of DefaultEntry. 
+     * <p>
+     * This entry <b>must</b> be initialized before being used !
+     */
+    public ImmutableEntry( Entry entry )
+    {
+        this.entry = entry;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Entry methods
+    //-------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( AttributeType attributeType, String... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, AttributeType attributeType, String... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( Attribute... attributes ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, byte[]... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, String... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry add( String upId, Value<?>... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot add an attribute : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * Clone an entry. All the element are duplicated, so a modification on
+     * the original object won't affect the cloned object, as a modification
+     * on the cloned object has no impact on the original object
+     */
+    public Entry clone()
+    {
+        return entry.clone();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry shallowClone()
+    {
+        return entry.shallowClone();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( Attribute... attributes )
+    {
+        return entry.contains( attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsAttribute( String... attributes )
+    {
+        return entry.containsAttribute( attributes );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsAttribute( AttributeType attributeType )
+    {
+        return entry.containsAttribute( attributeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( AttributeType attributeType, byte[]... values )
+    {
+        return entry.contains( attributeType, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( AttributeType attributeType, String... values )
+    {
+        return entry.contains( attributeType, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( AttributeType attributeType, Value<?>... values )
+    {
+        return entry.contains( attributeType, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String upId, byte[]... values )
+    {
+        return entry.contains( upId, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String upId, String... values )
+    {
+        return entry.contains( upId, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String upId, Value<?>... values )
+    {
+        return entry.contains( upId, values );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute get( String alias )
+    {
+        return entry.get( alias );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute get( AttributeType attributeType )
+    {
+        return entry.get( attributeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<Attribute> getAttributes()
+    {
+        return entry.getAttributes();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, byte[]... values )
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, String... values )
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, Value<?>... values )
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Attribute> put( Attribute... attributes ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( AttributeType attributeType, String... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, AttributeType attributeType, String... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Attribute put( String upId, AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot put a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Attribute> remove( Attribute... attributes ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( AttributeType attributeType, byte[]... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( AttributeType attributeType, String... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove( AttributeType attributeType, Value<?>... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * <p>
+     * Removes the attribute with the specified AttributeTypes. 
+     * </p>
+     * <p>
+     * The removed attribute are returned by this method. 
+     * </p>
+     * <p>
+     * If there is no attribute with the specified AttributeTypes,
+     * the return value is <code>null</code>.
+     * </p>
+     *
+     * @param attributes the AttributeTypes to be removed
+     * @return the removed attributes, if any, as a list; otherwise <code>null</code>
+     */
+    public void removeAttributes( AttributeType... attributes )
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeAttributes( String... attributes )
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified binary values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID  
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    public boolean remove( String upId, byte[]... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified String values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID  
+     * @param values the attributes to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    public boolean remove( String upId, String... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID  
+     * @param values the attributes to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    public boolean remove( String upId, Value<?>... values ) throws LdapException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot remove a value : the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * Get this entry's Dn.
+     *
+     * @return The entry's Dn
+     */
+    public Dn getDn()
+    {
+        return entry.getDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDn( Dn dn )
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot rename the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDn( String dn ) throws LdapInvalidDnException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot rename the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * Remove all the attributes for this entry. The Dn is not reset
+     */
+    public void clear()
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot clear the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * Returns an enumeration containing the zero or more attributes in the
+     * collection. The behavior of the enumeration is not specified if the
+     * attribute collection is changed.
+     *
+     * @return an enumeration of all contained attributes
+     */
+    public Iterator<Attribute> iterator()
+    {
+        return entry.iterator();
+    }
+
+
+    /**
+     * Returns the number of attributes.
+     *
+     * @return the number of attributes
+     */
+    public int size()
+    {
+        return entry.size();
+    }
+
+
+    /**
+     * This is the place where we serialize entries, and all theirs
+     * elements.
+     * <br/>
+     * The structure used to store the entry is the following :
+     * <ul>
+     *   <li>
+     *     <b>[Dn]</b> : If it's null, stores an empty Dn
+     *   </li>
+     *   <li>
+     *     <b>[attributes number]</b> : the number of attributes.
+     *   </li>
+     *   <li>
+     *     <b>[attribute]*</b> : each attribute, if we have some
+     *   </li>
+     * </ul>
+     * 
+     * {@inheritDoc} 
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        entry.writeExternal( out );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot read the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * Serialize an Entry.
+     * 
+     * The structure is the following :
+     * <b>[a byte]</b> : if the Dn is empty 0 will be written else 1
+     * <b>[Rdn]</b> : The entry's Rdn.
+     * <b>[numberAttr]</b> : the bumber of attributes. Can be 0 
+     * <b>[attribute's oid]*</b> : The attribute's OID to get back 
+     * the attributeType on deserialization
+     * <b>[Attribute]*</b> The attribute
+     * 
+     * @param out the buffer in which the data will be serialized
+     * @throws IOException if the serialization failed
+     */
+    public void serialize( ObjectOutput out ) throws IOException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot serialize the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * Deserialize an entry. 
+     * 
+     * @param in The buffer containing the serialized serverEntry
+     * @throws IOException if there was a problem when deserializing
+     * @throws ClassNotFoundException if we can't deserialize an expected object
+     */
+    public void deserialize( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        new Exception().printStackTrace();
+        throw new NotImplementedException( "Cannot deserialize the entry " + entry.getDn() + " is immutable." );
+    }
+
+
+    /**
+     * Get the hash code of this ClientEntry. The Attributes will be sorted
+     * before the comparison can be done.
+     *
+     * @see java.lang.Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        return entry.hashCode();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasObjectClass( String... objectClasses )
+    {
+        return entry.hasObjectClass( objectClasses );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasObjectClass( Attribute... objectClasses )
+    {
+        return entry.hasObjectClass( objectClasses );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSchemaAware()
+    {
+        return entry.isSchemaAware();
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        return entry.equals( o );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return entry.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString( String tabs )
+    {
+        return entry.toString( tabs );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Modification.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Modification.java
new file mode 100644
index 0000000..c6f5de8
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Modification.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.Externalizable;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * An internal interface for a ModificationItem. The name has been
+ * chosen so that it does not conflict with @see ModificationItem
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Modification extends Cloneable, Externalizable
+{
+    /**
+     *  @return the operation
+     */
+    ModificationOperation getOperation();
+
+
+    /**
+     * Store the modification operation
+     *
+     * @param operation The DirContext value to assign
+     */
+    void setOperation( int operation );
+
+
+    /**
+     * Store the modification operation
+     *
+     * @param operation The ModificationOperation value to assign
+     */
+    void setOperation( ModificationOperation operation );
+
+
+    /**
+     * @return the attribute containing the modifications
+     */
+    Attribute getAttribute();
+
+
+    /**
+     * Set the attribute's modification
+     *
+     * @param attribute The modified attribute
+     */
+    void setAttribute( Attribute attribute );
+
+
+    /**
+     * The clone operation
+     *
+     * @return a clone of the current modification
+     */
+    Modification clone();
+
+
+    /**
+     * Apply the AttributeType to the Modification
+     * 
+     * @param AttributeType the injected AttributeType
+     */
+    void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException;
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ModificationOperation.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ModificationOperation.java
new file mode 100644
index 0000000..691c632
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/ModificationOperation.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+/**
+ * An enum storing the different modification operation which can be used
+ * in a Modification. There is a one to one mapping with the DirContext.ADD_ATTRIBUTE,
+ * DirContext.REMOVE_ATTRIBUTE, DirContext.REPLACE_ATTRIBUTE
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum ModificationOperation
+{
+    ADD_ATTRIBUTE(0),
+    REMOVE_ATTRIBUTE(1),
+    REPLACE_ATTRIBUTE(2);
+
+    /** Internal value */
+    private int value;
+
+
+    /**
+     * Creates a new instance of ModificationOperation.
+     */
+    private ModificationOperation( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The integer value associated with the element. This value
+     * is equivalent to the one found in DirContext.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Get the ModificationOperation from an int value
+     *
+     * @param value the ModificationOperation int value
+     * @return the associated ModifciationOperation instance
+     */
+    public static ModificationOperation getOperation( int value )
+    {
+        if ( value == ADD_ATTRIBUTE.value )
+        {
+            return ADD_ATTRIBUTE;
+        }
+        else if ( value == REMOVE_ATTRIBUTE.value )
+        {
+            return REMOVE_ATTRIBUTE;
+        }
+        else if ( value == REPLACE_ATTRIBUTE.value )
+        {
+            return REPLACE_ATTRIBUTE;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        switch ( this )
+        {
+            case ADD_ATTRIBUTE:
+                return "add";
+
+            case REPLACE_ATTRIBUTE:
+                return "replace";
+
+            case REMOVE_ATTRIBUTE:
+                return "remove";
+
+            default:
+                return "";
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/StringValue.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/StringValue.java
new file mode 100644
index 0000000..b7541d7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/StringValue.java
@@ -0,0 +1,848 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Comparator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.util.Serialize;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.exception.NotImplementedException;
+
+
+/**
+ * A server side schema aware wrapper around a String attribute value.
+ * This value wrapper uses schema information to syntax check values,
+ * and to compare them for equality and ordering.  It caches results
+ * and invalidates them when the user provided value changes.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StringValue extends AbstractValue<String>
+{
+    /** Used for serialization */
+    private static final long serialVersionUID = 2L;
+
+    /** The UTF-8 bytes for this value */
+    private byte[] bytes;
+
+
+    // -----------------------------------------------------------------------
+    // Constructors
+    // -----------------------------------------------------------------------
+    /**
+     * Creates a StringValue without an initial user provided value.
+     *
+     * @param attributeType the schema attribute type associated with this StringValue
+     */
+    public StringValue( AttributeType attributeType )
+    {
+        if ( attributeType != null )
+        {
+            // We must have a Syntax
+            if ( attributeType.getSyntax() == null )
+            {
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04445 ) );
+            }
+
+            if ( !attributeType.getSyntax().isHumanReadable() )
+            {
+                LOG.warn( "Treating a value of a binary attribute {} as a String: "
+                    + "\nthis could cause data corruption!", attributeType.getName() );
+            }
+
+            this.attributeType = attributeType;
+        }
+    }
+
+
+    /**
+     * Creates a StringValue with an initial user provided String value.
+     *
+     * @param value the value to wrap which can be null
+     */
+    public StringValue( String value )
+    {
+        this.upValue = value;
+        this.normalizedValue = value;
+        bytes = Strings.getBytesUtf8( value );
+    }
+
+
+    /**
+     * Creates a StringValue with an initial user provided String value and a normalized value.
+     *
+     * @param value the user provided value to wrap which can be null
+     * @param normValue the normalized value to wrap which can be null
+     */
+    public StringValue( String value, String normalizedValue )
+    {
+        this.upValue = value;
+        this.normalizedValue = normalizedValue;
+        bytes = Strings.getBytesUtf8( normalizedValue );
+    }
+
+
+    /**
+     * Creates a schema aware StringValue with an initial user provided String value.
+     *
+     * @param attributeType the schema type associated with this StringValue
+     * @param value the value to wrap
+     * @throws LdapInvalidAttributeValueException If the added value is invalid accordingly
+     * to the schema
+     */
+    public StringValue( AttributeType attributeType, String value ) throws LdapInvalidAttributeValueException
+    {
+        this( value, value );
+        apply( attributeType );
+    }
+
+
+    /**
+     * Creates a schema aware StringValue with an initial user provided String value.
+     *
+     * @param attributeType the schema type associated with this StringValue
+     * @param value the value to wrap
+     * @throws LdapInvalidAttributeValueException If the added value is invalid accordingly
+     * to the schema
+     */
+    public StringValue( AttributeType attributeType, String value, String normValue ) throws LdapInvalidAttributeValueException
+    {
+        this( value, normValue );
+        apply( attributeType );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Value<String> Methods
+    // -----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public String getValue()
+    {
+        // The String is immutable, we can safely return the internal
+        // object without copying it.
+        return upValue;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getNormValue()
+    {
+        return normalizedValue;
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Comparable<String> Methods
+    // -----------------------------------------------------------------------
+    /**
+     * @see ServerValue#compareTo(Value)
+     * @throws IllegalStateException on failures to extract the comparator, or the
+     * normalizers needed to perform the required comparisons based on the schema
+     */
+    public int compareTo( Value<String> value )
+    {
+        if ( isNull() )
+        {
+            if ( ( value == null ) || value.isNull() )
+            {
+                return 0;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+        else if ( ( value == null ) || value.isNull() )
+        {
+            return 1;
+        }
+
+        if ( !( value instanceof StringValue ) )
+        {
+            String message = I18n.err( I18n.ERR_04128, toString(), value.getClass() );
+            LOG.error( message );
+            throw new NotImplementedException( message );
+        }
+
+        StringValue stringValue = ( StringValue ) value;
+
+        if ( attributeType != null )
+        {
+            if ( stringValue.getAttributeType() == null )
+            {
+                return getNormValue().compareTo( stringValue.getNormValue() );
+            }
+            else
+            {
+                if ( !attributeType.equals( stringValue.getAttributeType() ) )
+                {
+                    String message = I18n.err( I18n.ERR_04128, toString(), value.getClass() );
+                    LOG.error( message );
+                    throw new NotImplementedException( message );
+                }
+            }
+        }
+        else
+        {
+            return getNormValue().compareTo( stringValue.getNormValue() );
+        }
+
+        try
+        {
+            return getLdapComparator().compare( getNormValue(), stringValue.getNormValue() );
+        }
+        catch ( LdapException e )
+        {
+            String msg = I18n.err( I18n.ERR_04443, this, value );
+            LOG.error( msg, e );
+            throw new IllegalStateException( msg, e );
+        }
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Cloneable methods
+    // -----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public StringValue clone()
+    {
+        return ( StringValue ) super.clone();
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Object Methods
+    // -----------------------------------------------------------------------
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hashcode
+     */
+    public int hashCode()
+    {
+        if ( h == 0 )
+        {
+            // return zero if the value is null so only one null value can be
+            // stored in an attribute - the binary version does the same
+            if ( isNull() )
+            {
+                return 0;
+            }
+
+            // If the normalized value is null, will default to user provided
+            // which cannot be null at this point.
+            // If the normalized value is null, will default to user provided
+            // which cannot be null at this point.
+            String normalized = getNormValue();
+
+            if ( normalized != null )
+            {
+                h = normalized.hashCode();
+            }
+            else
+            {
+                h = 17;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * Two StringValue are equals if their normalized values are equal
+     * 
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( !( obj instanceof StringValue ) )
+        {
+            return false;
+        }
+
+        StringValue other = ( StringValue ) obj;
+
+        // First check if we have an attrbuteType.
+        if ( attributeType != null )
+        {
+            // yes : check for the other value
+            if ( other.attributeType != null )
+            {
+                if ( attributeType.getOid().equals( other.getAttributeType().getOid() ) )
+                {
+                    // Both AttributeType have the same OID, we can assume they are 
+                    // equals. We don't check any further, because the unicity of OID
+                    // makes it unlikely that the two AT are different.
+                    // The values may be both null
+                    if ( isNull() )
+                    {
+                        return other.isNull();
+                    }
+
+                    // Shortcut : if we have an AT for both the values, check the 
+                    // already normalized values
+                    if ( upValue.equals( other.upValue ) )
+                    {
+                        return true;
+                    }
+
+                    // We have an AttributeType, we use the associated comparator
+                    try
+                    {
+                        Comparator<String> comparator = getLdapComparator();
+
+                        // Compare normalized values
+                        if ( comparator == null )
+                        {
+                            return getNormReference().equals( other.getNormReference() );
+                        }
+                        else
+                        {
+                            return comparator.compare( getNormReference(), other.getNormReference() ) == 0;
+                        }
+                    }
+                    catch ( LdapException ne )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    // We can't compare two values when the two ATs are different
+                    return false;
+                }
+            }
+            else
+            {
+                // We only have one AT : we will assume that both values are for the 
+                // same AT.
+                // The values may be both null
+                if ( isNull() )
+                {
+                    return other.isNull();
+                }
+
+                // We have an AttributeType on the base value, we need to use its comparator
+                try
+                {
+                    Comparator<String> comparator = getLdapComparator();
+
+                    // Compare normalized values. We have to normalized the other value,
+                    // as it has no AT
+                    MatchingRule equality = getAttributeType().getEquality();
+
+                    if ( equality == null )
+                    {
+                        // No matching rule : compare the raw values
+                        return getNormReference().equals( other.getNormReference() );
+                    }
+
+                    Normalizer normalizer = equality.getNormalizer();
+
+                    StringValue otherValue = ( StringValue ) normalizer.normalize( other );
+
+                    if ( comparator == null )
+                    {
+                        return getNormReference().equals( otherValue.getNormReference() );
+                    }
+                    else
+                    {
+                        return comparator.compare( getNormReference(), otherValue.getNormReference() ) == 0;
+                    }
+                }
+                catch ( LdapException ne )
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            // No : check for the other value
+            if ( other.attributeType != null )
+            {
+                // We only have one AT : we will assume that both values are for the 
+                // same AT.
+                // The values may be both null
+                if ( isNull() )
+                {
+                    return other.isNull();
+                }
+
+                try
+                {
+                    Comparator<String> comparator = other.getLdapComparator();
+
+                    // Compare normalized values. We have to normalized the other value,
+                    // as it has no AT
+                    MatchingRule equality = other.getAttributeType().getEquality();
+
+                    if ( equality == null )
+                    {
+                        // No matching rule : compare the raw values
+                        return getNormReference().equals( other.getNormReference() );
+                    }
+
+                    Normalizer normalizer = equality.getNormalizer();
+
+                    StringValue thisValue = ( StringValue ) normalizer.normalize( this );
+
+                    if ( comparator == null )
+                    {
+                        return thisValue.getNormReference().equals( other.getNormReference() );
+                    }
+                    else
+                    {
+                        return comparator.compare( thisValue.getNormReference(), other.getNormReference() ) == 0;
+                    }
+                }
+                catch ( LdapException ne )
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                // The values may be both null
+                if ( isNull() )
+                {
+                    return other.isNull();
+                }
+
+                // Now check the normalized values
+                return getNormReference().equals( other.getNormReference() );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isHumanReadable()
+    {
+        return true;
+    }
+
+
+    /**
+     * @return The length of the interned value
+     */
+    public int length()
+    {
+        return upValue != null ? upValue.length() : 0;
+    }
+
+
+    /**
+     * Get the user provided value as a byte[].
+     * @return the user provided value as a byte[]
+     */
+    public byte[] getBytes()
+    {
+        return bytes;
+    }
+
+
+    /**
+     * Get the user provided value as a String.
+     *
+     * @return the user provided value as a String
+     */
+    public String getString()
+    {
+        return upValue != null ? upValue : "";
+    }
+
+
+    /**
+     * Deserialize a StringValue. It will return a new StringValue instance.
+     * 
+     * @param in The input stream
+     * @return A new StringValue instance
+     * @throws IOException If the stream can't be read
+     * @throws ClassNotFoundException If we can't instanciate a StringValue
+     */
+    public static StringValue deserialize( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        StringValue value = new StringValue( ( AttributeType ) null );
+        value.readExternal( in );
+
+        return value;
+    }
+
+
+    /**
+     * Deserialize a schemaAware StringValue. It will return a new StringValue instance.
+     * 
+     * @param attributeType The AttributeType associated with the Value. Can be null
+     * @param in The input stream
+     * @return A new StringValue instance
+     * @throws IOException If the stream can't be read
+     * @throws ClassNotFoundException If we can't instanciate a StringValue
+     */
+    public static StringValue deserialize( AttributeType attributeType, ObjectInput in ) throws IOException,
+        ClassNotFoundException
+    {
+        StringValue value = new StringValue( attributeType );
+        value.readExternal( in );
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the STRING flag
+        boolean isHR = in.readBoolean();
+
+        if ( !isHR )
+        {
+            throw new IOException( "The serialized value is not a String value" );
+        }
+
+        // Read the user provided value, if it's not null
+        if ( in.readBoolean() )
+        {
+            upValue = in.readUTF();
+            bytes = Strings.getBytesUtf8( upValue );
+        }
+
+        // Read the isNormalized flag
+        boolean normalized = in.readBoolean();
+
+        if ( normalized )
+        {
+            // Read the normalized value, if not null
+            if ( in.readBoolean() )
+            {
+                normalizedValue = in.readUTF();
+            }
+        }
+        else
+        {
+            if ( attributeType != null )
+            {
+                try
+                {
+                    MatchingRule equality = attributeType.getEquality();
+
+                    if ( equality == null )
+                    {
+                        normalizedValue = upValue;
+                    }
+                    else
+                    {
+                        Normalizer normalizer = equality.getNormalizer();
+
+                        if ( normalizer != null )
+                        {
+                            normalizedValue = normalizer.normalize( upValue );
+                        }
+                        else
+                        {
+                            normalizedValue = upValue;
+                        }
+                    }
+                }
+                catch ( LdapException le )
+                {
+                    normalizedValue = upValue;
+                }
+            }
+            else
+            {
+                normalizedValue = upValue;
+            }
+        }
+
+        // The hashCoe
+        h = in.readInt();
+    }
+
+
+    /**
+     * Serialize the StringValue into a buffer at the given position.
+     * 
+     * @param buffer The buffer which will contain the serialized StringValue
+     * @param pos The position in the buffer for the serialized value
+     * @return The new position in the buffer
+     */
+    public int serialize( byte[] buffer, int pos )
+    {
+        // Compute the length
+        // The value type, the user provided value presence flag,
+        // the normalizedValue presence flag and the hash length.
+        int length = 1 + 1 + 1 + 4;
+
+        byte[] upValueBytes = null;
+        byte[] normalizedValueBytes = null;
+
+        if ( upValue != null )
+        {
+            upValueBytes = Strings.getBytesUtf8( upValue );
+            length += 4 + upValueBytes.length;
+        }
+
+        if ( attributeType != null )
+        {
+            if ( normalizedValue != null )
+            {
+                normalizedValueBytes = Strings.getBytesUtf8( normalizedValue );
+                length += 1 + 4 + normalizedValueBytes.length;
+            }
+            else
+            {
+                length += 1;
+            }
+        }
+
+        // Check that we will be able to store the data in the buffer
+        if ( buffer.length - pos < length )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        // The STRING flag
+        buffer[pos] = Serialize.TRUE;
+        pos++;
+
+        // Write the user provided value, if it's not null
+        if ( upValue != null )
+        {
+            buffer[pos++] = Serialize.TRUE;
+            pos = Serialize.serialize( upValueBytes, buffer, pos );
+        }
+        else
+        {
+            buffer[pos++] = Serialize.FALSE;
+        }
+
+        // Write the isNormalized flag
+        if ( attributeType != null )
+        {
+            // This flag is present to tell that we have a normalized value different
+            // from the upValue
+
+            buffer[pos++] = Serialize.TRUE;
+
+            // Write the normalized value, if not null
+            if ( normalizedValue != null )
+            {
+                buffer[pos++] = Serialize.TRUE;
+                pos = Serialize.serialize( normalizedValueBytes, buffer, pos );
+            }
+            else
+            {
+                buffer[pos++] = Serialize.FALSE;
+            }
+        }
+        else
+        {
+            // No normalized value
+            buffer[pos++] = Serialize.FALSE;
+        }
+
+        // Write the hashCode
+        pos = Serialize.serialize( h, buffer, pos );
+
+        return pos;
+    }
+
+
+    /**
+     * Deserialize a StringValue from a byte[], starting at a given position
+     * 
+     * @param buffer The buffer containing the StringValue
+     * @param pos The position in the buffer
+     * @return The new position
+     * @throws IOException If the serialized value is not a StringValue
+     */
+    public int deserialize( byte[] buffer, int pos ) throws IOException
+    {
+        if ( ( pos < 0 ) || ( pos >= buffer.length ) )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        // Read the STRING flag
+        boolean isHR = Serialize.deserializeBoolean( buffer, pos );
+        pos++;
+
+        if ( !isHR )
+        {
+            throw new IOException( "The serialized value is not a String value" );
+        }
+
+        // Read the user provided value, if it's not null
+        boolean hasWrappedValue = Serialize.deserializeBoolean( buffer, pos );
+        pos++;
+
+        if ( hasWrappedValue )
+        {
+            byte[] upValueBytes = Serialize.deserializeBytes( buffer, pos );
+            pos += 4 + upValueBytes.length;
+            upValue = Strings.utf8ToString( upValueBytes );
+        }
+
+        // Read the isNormalized flag
+        boolean hasAttributeType = Serialize.deserializeBoolean( buffer, pos );
+        pos++;
+
+        if ( hasAttributeType )
+        {
+            // Read the normalized value, if not null
+            boolean hasNormalizedValue = Serialize.deserializeBoolean( buffer, pos );
+            pos++;
+
+            if ( hasNormalizedValue )
+            {
+                byte[] normalizedValueBytes = Serialize.deserializeBytes( buffer, pos );
+                pos += 4 + normalizedValueBytes.length;
+                normalizedValue = Strings.utf8ToString( normalizedValueBytes );
+            }
+        }
+        else
+        {
+            if ( attributeType != null )
+            {
+                try
+                {
+                    MatchingRule equality = attributeType.getEquality();
+
+                    if ( equality == null )
+                    {
+                        normalizedValue = upValue;
+                    }
+                    else
+                    {
+                        Normalizer normalizer = equality.getNormalizer();
+
+                        if ( normalizer != null )
+                        {
+                            normalizedValue = normalizer.normalize( upValue );
+                        }
+                        else
+                        {
+                            normalizedValue = upValue;
+                        }
+                    }
+                }
+                catch ( LdapException le )
+                {
+                    normalizedValue = upValue;
+                }
+            }
+            else
+            {
+                normalizedValue = upValue;
+            }
+        }
+
+        // The hashCode
+        h = Serialize.deserializeInt( buffer, pos );
+        pos += 4;
+
+        return pos;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        // Write a boolean for the HR flag
+        out.writeBoolean( STRING );
+
+        // Write the user provided value, if it's not null
+        if ( upValue != null )
+        {
+            out.writeBoolean( true );
+            out.writeUTF( upValue );
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        // Write the isNormalized flag
+        if ( attributeType != null )
+        {
+            // This flag is present to tell that we have a normalized value different
+            // from the upValue
+            out.writeBoolean( true );
+
+            // Write the normalized value, if not null
+            if ( normalizedValue != null )
+            {
+                out.writeBoolean( true );
+                out.writeUTF( normalizedValue );
+            }
+            else
+            {
+                out.writeBoolean( false );
+            }
+        }
+        else
+        {
+            // No normalized value
+            out.writeBoolean( false );
+        }
+
+        // Write the hashCode
+        out.writeInt( h );
+
+        // and flush the data
+        out.flush();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return upValue == null ? "null" : upValue;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Value.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Value.java
new file mode 100644
index 0000000..42cf72a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/entry/Value.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import java.io.Externalizable;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+
+
+/**
+ * A interface for wrapping attribute values stored into an EntryAttribute. These
+ * values can be a String or a byte[].
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Value<T> extends Cloneable, Externalizable, Comparable<Value<T>>
+{
+    /** Two flags used to tell if the value is HR or not in serialization */
+    boolean STRING = true;
+    boolean BINARY = false;
+
+
+    /**
+     * Clone a Value
+     * 
+     * @return A cloned value
+     */
+    Value<T> clone();
+
+
+    /**
+     * Check if the contained value is null or not
+     * 
+     * @return <code>true</code> if the inner value is null.
+     */
+    boolean isNull();
+
+
+    /**
+     * Get the associated AttributeType
+     * 
+     * @return The AttributeType
+     */
+    AttributeType getAttributeType();
+
+
+    /**
+     * Check if the value is stored into an instance of the given
+     * AttributeType, or one of its ascendant.
+     * 
+     * For instance, if the Value is associated with a CommonName,
+     * checking for Name will match.
+     * 
+     * @param attributeType The AttributeType we are looking at
+     * @return <code>true</code> if the value is associated with the given
+     * attributeType or one of its ascendant
+     */
+    boolean isInstanceOf( AttributeType attributeType );
+
+
+    /**
+     * Get the User Provided value. It will return a copy, not a reference.
+     *
+     * @return a copy of the wrapped value
+     */
+    T getValue();
+
+
+    /**
+     * Get the wrapped value as a byte[]. If the original value
+     * is binary, this method will return a copy of the wrapped byte[]
+     *
+     * @return the wrapped value as a byte[]
+     */
+    byte[] getBytes();
+
+
+    /**
+     * Get the user provided value as a String. If the original value
+     * is binary, this method will return the value as if it was
+     * an UTF-8 encoded String.
+     *
+     * @return the wrapped value as a String
+     */
+    String getString();
+
+
+    /**
+     * Gets a reference to the wrapped value.
+     * 
+     * Warning ! The value is not copied !!!
+     *
+     * @return a direct handle on the value that is wrapped
+     */
+    T getReference();
+
+
+    /**
+     * Tells if the value is schema aware or not.
+     *
+     * @return <code>true</code> if the value is sxhema aware
+     */
+    boolean isSchemaAware();
+
+
+    /**
+     * Uses the syntaxChecker associated with the attributeType to check if the
+     * value is valid.
+     * 
+     * @param checker the SyntaxChecker to use to validate the value
+     * @return <code>true</code> if the value is valid
+     * @exception LdapInvalidAttributeValueException if the value cannot be validated
+     */
+    boolean isValid( SyntaxChecker checker ) throws LdapInvalidAttributeValueException;
+
+
+    /**
+     * Gets the normalized (canonical) representation for the wrapped string.
+     * If the wrapped String is null, null is returned, otherwise the normalized
+     * form is returned.  If the normalizedValue is null, then this method
+     * will attempt to generate it from the wrapped value.
+     *
+     * @return gets the normalized value
+     */
+    T getNormValue();
+
+
+    /**
+     * Gets a reference to the the normalized (canonical) representation
+     * for the wrapped value.
+     *
+     * @return gets a reference to the normalized value
+     */
+    T getNormReference();
+
+
+    /**
+     * Tells if the current value is Human Readable
+     * 
+     * @return <code>true</code> if the value is a String, <code>false</code> otherwise
+     */
+    boolean isHumanReadable();
+
+
+    /**
+     * @return The length of the interned value
+     */
+    int length();
+    
+    
+    /**
+     * Apply the AttributeType to this value. Note that this can't be done twice.
+     *
+     * @param attributeType The AttributeType to apply
+     */
+    void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/AbstractLdapReferralException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/AbstractLdapReferralException.java
new file mode 100644
index 0000000..c0595d6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/AbstractLdapReferralException.java
@@ -0,0 +1,126 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.exception.NotImplementedException;
+
+
+/**
+ * A {@link LdapOperationException} which associates a resultCode namely the
+ * {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#REFERRAL} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AbstractLdapReferralException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+    /** The remaining Dn */
+    private Dn remainingDn;
+
+    /** TODO */
+    private Object resolvedObject;
+
+
+    /**
+     * 
+     * Creates a new instance of AbstractLdapReferralException.
+     *
+     * @param explanation The associated message
+     */
+    public AbstractLdapReferralException( String explanation )
+    {
+        super( explanation );
+    }
+
+
+    /**
+     * Always returns {@link ResultCodeEnum#REFERRAL}
+     * 
+     * @see LdapException#getResultCode()
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return ResultCodeEnum.REFERRAL;
+    }
+
+
+    public Context getReferralContext() throws NamingException
+    {
+        throw new NotImplementedException();
+    }
+
+
+    public Context getReferralContext( Hashtable<?, ?> arg ) throws NamingException
+    {
+        throw new NotImplementedException();
+    }
+
+
+    public void retryReferral()
+    {
+        throw new NotImplementedException();
+    }
+
+
+    /**
+     * @return the remainingDn
+     */
+    public Dn getRemainingDn()
+    {
+        return remainingDn;
+    }
+
+
+    /**
+     * @param remainingDn the remainingName to set
+     */
+    public void setRemainingDn( Dn remainingDn )
+    {
+        this.remainingDn = remainingDn;
+    }
+
+
+    /**
+     * @return the resolvedObject
+     */
+    public Object getResolvedObject()
+    {
+        return resolvedObject;
+    }
+
+
+    /**
+     * @param resolvedObject the resolvedObject to set
+     */
+    public void setResolvedObject( Object resolvedObject )
+    {
+        this.resolvedObject = resolvedObject;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAdminLimitExceededException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAdminLimitExceededException.java
new file mode 100644
index 0000000..3383548
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAdminLimitExceededException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapTimeLimitExceededException which associates a resultCode namely the
+ * {@link ResultCodeEnum#ADMIN_LIMIT_EXCEEDED} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapAdminLimitExceededException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapAdminLimitExceededException.
+     *
+     */
+    public LdapAdminLimitExceededException()
+    {
+        super( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED, null );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapAdminLimitExceededException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapAdminLimitExceededException( String explanation )
+    {
+        super( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED, explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAffectMultipleDsaException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAffectMultipleDsaException.java
new file mode 100644
index 0000000..5a7fad3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAffectMultipleDsaException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link ResultCodeEnum#AFFECTS_MULTIPLE_DSAS} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapAffectMultipleDsaException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapAffectMultipleDsaException.
+     *
+     * @param message The exception message
+     */
+    public LdapAffectMultipleDsaException( String message )
+    {
+        super( ResultCodeEnum.AFFECTS_MULTIPLE_DSAS, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapAffectMultipleDsaException.
+     */
+    public LdapAffectMultipleDsaException()
+    {
+        super( ResultCodeEnum.AFFECTS_MULTIPLE_DSAS, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAliasDereferencingException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAliasDereferencingException.java
new file mode 100644
index 0000000..f87d43f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAliasDereferencingException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#ALIAS_DEREFERENCING_PROBLEM} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapAliasDereferencingException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapAliasDereferencingException.
+     *
+     * @param message The exception message
+     */
+    public LdapAliasDereferencingException( String message )
+    {
+        super( ResultCodeEnum.ALIAS_DEREFERENCING_PROBLEM, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapAliasDereferencingException.
+     */
+    public LdapAliasDereferencingException()
+    {
+        super( ResultCodeEnum.ALIAS_DEREFERENCING_PROBLEM, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAliasException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAliasException.java
new file mode 100644
index 0000000..9a9ab91
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAliasException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link ResultCodeEnum#ALIAS_PROBLEM} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapAliasException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapAliasException.
+     *
+     * @param message The exception message
+     */
+    public LdapAliasException( String message )
+    {
+        super( ResultCodeEnum.ALIAS_PROBLEM, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapAliasException.
+     */
+    public LdapAliasException()
+    {
+        super( ResultCodeEnum.ALIAS_PROBLEM, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAttributeInUseException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAttributeInUseException.java
new file mode 100644
index 0000000..bb9513d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAttributeInUseException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which holds the LDAP resultCode
+ * associated with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapAttributeInUseException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapAttributeInUseException.
+     *
+     * @param message The exception message
+     */
+    public LdapAttributeInUseException( String message )
+    {
+        super( ResultCodeEnum.ATTRIBUTE_OR_VALUE_EXISTS, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapAttributeInUseException.
+     */
+    public LdapAttributeInUseException()
+    {
+        super( ResultCodeEnum.ATTRIBUTE_OR_VALUE_EXISTS, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAuthenticationException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAuthenticationException.java
new file mode 100644
index 0000000..cb49b8f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAuthenticationException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#INVALID_CREDENTIALS} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapAuthenticationException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapAuthenticationException.
+     *
+     * @param message The exception message
+     */
+    public LdapAuthenticationException( String message )
+    {
+        super( ResultCodeEnum.INVALID_CREDENTIALS, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapAuthenticationException.
+     */
+    public LdapAuthenticationException()
+    {
+        super( ResultCodeEnum.INVALID_CREDENTIALS, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAuthenticationNotSupportedException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAuthenticationNotSupportedException.java
new file mode 100644
index 0000000..18f0aa5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapAuthenticationNotSupportedException.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of the {@link LdapOperationException} carrying along
+ * an unequivocal ResultCodeEnum value.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapAuthenticationNotSupportedException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapAuthenticationNotSupportedException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     */
+    public LdapAuthenticationNotSupportedException( ResultCodeEnum resultCode, String message )
+    {
+        super( message );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapAuthenticationNotSupportedException.
+     * 
+     * @param resultCode the ResultCodeEnum for this exception
+     */
+    public LdapAuthenticationNotSupportedException( ResultCodeEnum resultCode )
+    {
+        super( null );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Checks to make sure the resultCode value is right for this exception
+     * type.
+     * 
+     * @throws IllegalArgumentException
+     *             if the result code is not one of
+     *             {@link ResultCodeEnum#INAPPROPRIATEAUTHENTICATION},
+     *             {@link ResultCodeEnum#AUTHMETHODNOTSUPPORTED},
+     *             {@link ResultCodeEnum#CONFIDENTIALITYREQUIRED}.
+     */
+    private void checkResultCode( ResultCodeEnum resultCode )
+    {
+        switch ( resultCode )
+        {
+            case INAPPROPRIATE_AUTHENTICATION:
+            case CONFIDENTIALITY_REQUIRED:
+            case AUTH_METHOD_NOT_SUPPORTED:
+                return;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04140_UNACCEPTABLE_RESULT_CODE, resultCode ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapCannotCancelException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapCannotCancelException.java
new file mode 100644
index 0000000..d3451d1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapCannotCancelException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapCannotCancelException which associates a resultCode, namely the
+ * {@link ResultCodeEnum#CANNOT_CANCEL} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapCannotCancelException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapCannotCancelException.
+     *
+     */
+    public LdapCannotCancelException()
+    {
+        super( ResultCodeEnum.CANNOT_CANCEL, null );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapCannotCancelException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapCannotCancelException( String explanation )
+    {
+        super( ResultCodeEnum.CANNOT_CANCEL, explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapConfigurationException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapConfigurationException.java
new file mode 100644
index 0000000..ba04617
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapConfigurationException.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A {@link LdapException} which associates a resultCode namely the
+ * {@link ResultCodeEnum#OTHER} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapConfigurationException extends LdapOperationException
+{
+    /** The serial version UID */
+    static final long serialVersionUID = 1L;
+
+    /** The exception cause */
+    private Throwable cause;
+
+
+    /**
+     * Creates a new instance of LdapConfigurationException.
+     *
+     * @param message The exception message
+     */
+    public LdapConfigurationException( String message )
+    {
+        super( ResultCodeEnum.OTHER, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapConfigurationException.
+     */
+    public LdapConfigurationException()
+    {
+        super( ResultCodeEnum.OTHER, null );
+    }
+
+
+    /**
+     * Creates a new instance of LdapConfigurationException.
+     *
+     * @param message the exception message
+     * @param cause the cause
+     */
+    public LdapConfigurationException( String message, Throwable cause )
+    {
+        super( ResultCodeEnum.OTHER, message );
+        this.cause = cause;
+    }
+
+
+    /**
+     * @return the exception's cause
+     */
+    public Throwable getCause()
+    {
+        return cause;
+    }
+
+
+    /**
+     * Set the root cause.
+     *
+     * @param cause the cause
+     */
+    public void setCause( Throwable cause )
+    {
+        this.cause = cause;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapContextNotEmptyException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapContextNotEmptyException.java
new file mode 100644
index 0000000..2d98877
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapContextNotEmptyException.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapContextNotEmptyException which contains an LDAP result code.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapContextNotEmptyException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapContextNotEmptyException.
+     *
+     * @param message The exception message
+     */
+    public LdapContextNotEmptyException( String message )
+    {
+        super( ResultCodeEnum.NOT_ALLOWED_ON_NON_LEAF, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapContextNotEmptyException.
+     */
+    public LdapContextNotEmptyException()
+    {
+        super( ResultCodeEnum.NOT_ALLOWED_ON_NON_LEAF, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapEntryAlreadyExistsException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapEntryAlreadyExistsException.java
new file mode 100644
index 0000000..47a0f8a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapEntryAlreadyExistsException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A {@link LdapOperationException} which contains LDAP specific information such as
+ * a result code.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapEntryAlreadyExistsException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapEntryAlreadyExistsException.
+     *
+     * @param message The exception message
+     */
+    public LdapEntryAlreadyExistsException( String message )
+    {
+        super( ResultCodeEnum.ENTRY_ALREADY_EXISTS, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapEntryAlreadyExistsException.
+     */
+    public LdapEntryAlreadyExistsException()
+    {
+        super( ResultCodeEnum.ENTRY_ALREADY_EXISTS, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapException.java
new file mode 100644
index 0000000..ee71f3b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapException.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+/**
+ * An class for exceptions which add LDAP specific information to
+ * Exceptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapException extends Exception
+{
+    /** The serial version UUID */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapException.
+     */
+    public LdapException()
+    {
+    }
+
+
+    /**
+     * Creates a new instance of LdapException.
+     *
+     * @param explanation The message associated with the exception
+     */
+    public LdapException( String explanation )
+    {
+        super( explanation );
+    }
+
+
+    /**
+     * Creates a new instance of LdapException.
+     */
+    public LdapException( Throwable cause )
+    {
+        super( cause );
+    }
+
+
+    /**
+     * Creates a new instance of LdapException.
+     *
+     * @param explanation The message associated with the exception
+     * @param cause The root cause for this exception
+     */
+    public LdapException( String explanation, Throwable cause )
+    {
+        super( explanation, cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidAttributeTypeException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidAttributeTypeException.java
new file mode 100644
index 0000000..e4f791e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidAttributeTypeException.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which holds the LDAP
+ * resultCode associated with the exception. The LDAP result code associated
+ * with this exception is the undefinedAttributeType result code value of 17.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapInvalidAttributeTypeException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapInvalidAttributeTypeException.
+     */
+    public LdapInvalidAttributeTypeException()
+    {
+        super( ResultCodeEnum.UNDEFINED_ATTRIBUTE_TYPE, null );
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidAttributeTypeException.
+     *
+     * @param message The exception message
+     */
+    public LdapInvalidAttributeTypeException( String message )
+    {
+        super( ResultCodeEnum.UNDEFINED_ATTRIBUTE_TYPE, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidAttributeTypeException.
+     * 
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapInvalidAttributeTypeException( String message, Throwable cause )
+    {
+        super( ResultCodeEnum.UNDEFINED_ATTRIBUTE_TYPE, message, cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidAttributeValueException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidAttributeValueException.java
new file mode 100644
index 0000000..16f6aa4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidAttributeValueException.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * Makes a {@link LdapOperationException} unambiguous with respect to the result
+ * code it corresponds to by associating an LDAP specific result code with it.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapInvalidAttributeValueException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapInvalidAttributeValueException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     */
+    public LdapInvalidAttributeValueException( ResultCodeEnum resultCode, String message )
+    {
+        super( message );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidAttributeValueException.
+     * 
+     * @param resultCode the ResultCodeEnum for this exception
+     */
+    public LdapInvalidAttributeValueException( ResultCodeEnum resultCode )
+    {
+        super( null );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidAttributeValueException.
+     * 
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapInvalidAttributeValueException( ResultCodeEnum resultCode, String message, Throwable cause )
+    {
+        super( message, cause );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Checks to make sure the resultCode value is right for this exception
+     * type.
+     * 
+     * @throws IllegalArgumentException
+     *             if the result code is not one of
+     *             {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#CONSTRAINT_VIOLATION},
+     *             {@link ResultCodeEnum#INVALID_ATTRIBUTE_SYNTAX}.
+     */
+    private void checkResultCode( ResultCodeEnum resultCode )
+    {
+        switch ( resultCode )
+        {
+            case CONSTRAINT_VIOLATION:
+            case INVALID_ATTRIBUTE_SYNTAX:
+                return;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04140_UNACCEPTABLE_RESULT_CODE, resultCode ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidDnException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidDnException.java
new file mode 100644
index 0000000..a1199ab
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidDnException.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} designed to hold an unequivocal LDAP
+ * result code.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapInvalidDnException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * to be used by some special exceptions like LdapInvalidDnException
+     */
+    public LdapInvalidDnException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * to be used by some special exceptions like LdapInvalidDnException
+     * 
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapInvalidDnException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidDnException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     */
+    public LdapInvalidDnException( ResultCodeEnum resultCode, String message )
+    {
+        super( message );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidDnException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapInvalidDnException( ResultCodeEnum resultCode, String message, Throwable cause )
+    {
+        super( message, cause );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidDnException.
+     * 
+     * @param resultCode the ResultCodeEnum for this exception
+     */
+    public LdapInvalidDnException( ResultCodeEnum resultCode )
+    {
+        super( null );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Checks to make sure the resultCode value is right for this exception
+     * type.
+     * 
+     * @throws IllegalArgumentException
+     *             if the result code is not one of
+     *             {@link ResultCodeEnum#INVALID_DN_SYNTAX},
+     *             {@link ResultCodeEnum#NAMING_VIOLATION}.
+     */
+    private void checkResultCode( ResultCodeEnum resultCode )
+    {
+        switch ( resultCode )
+        {
+            case INVALID_DN_SYNTAX:
+            case NAMING_VIOLATION:
+                return;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04140_UNACCEPTABLE_RESULT_CODE, resultCode ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidSearchFilterException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidSearchFilterException.java
new file mode 100644
index 0000000..6752611
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapInvalidSearchFilterException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link ResultCodeEnum#INAPPROPRIATE_MATCHING} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapInvalidSearchFilterException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapInvalidSearchFilterException.
+     *
+     * @param message The exception message
+     */
+    public LdapInvalidSearchFilterException( String message )
+    {
+        super( ResultCodeEnum.INAPPROPRIATE_MATCHING, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapInvalidSearchFilterException.
+     */
+    public LdapInvalidSearchFilterException()
+    {
+        super( ResultCodeEnum.INAPPROPRIATE_MATCHING, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapLoopDetectedException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapLoopDetectedException.java
new file mode 100644
index 0000000..9d77daa
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapLoopDetectedException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link ResultCodeEnum#LOOP_DETECT} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapLoopDetectedException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapLoopDetectedException.
+     *
+     * @param message The exception message
+     */
+    public LdapLoopDetectedException( String message )
+    {
+        super( ResultCodeEnum.LOOP_DETECT, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapLoopDetectedException.
+     */
+    public LdapLoopDetectedException()
+    {
+        super( ResultCodeEnum.LOOP_DETECT, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoPermissionException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoPermissionException.java
new file mode 100644
index 0000000..a22ea8c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoPermissionException.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A {@link LdapOperationException} which associates a resultCode namely the
+ * {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#INSUFFICIENT_ACCESS_RIGHTS} 
+ * resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapNoPermissionException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapNoPermissionException.
+     *
+     * @param message The exception message
+     */
+    public LdapNoPermissionException( String message )
+    {
+        super( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapNoPermissionException.
+     */
+    public LdapNoPermissionException()
+    {
+        super( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchAttributeException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchAttributeException.java
new file mode 100644
index 0000000..fee60b0
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchAttributeException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which holds the LDAP resultCode
+ * associated with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapNoSuchAttributeException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapNoSuchAttributeException.
+     *
+     * @param message The exception message
+     */
+    public LdapNoSuchAttributeException( String message )
+    {
+        super( ResultCodeEnum.NO_SUCH_ATTRIBUTE, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapNoSuchAttributeException.
+     *
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapNoSuchAttributeException( String message, Throwable cause )
+    {
+        super( ResultCodeEnum.NO_SUCH_ATTRIBUTE, message, cause );
+    }
+
+
+    /**
+     * Creates a new instance of LdapNoSuchAttributeException.
+     */
+    public LdapNoSuchAttributeException()
+    {
+        super( ResultCodeEnum.NO_SUCH_ATTRIBUTE, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchObjectException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchObjectException.java
new file mode 100644
index 0000000..c838e2c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchObjectException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A {@link LdapOperationException} holding LDAP specific information such as the LDAP
+ * ResultCode.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapNoSuchObjectException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapNoSuchObjectException.
+     *
+     * @param message The exception message
+     */
+    public LdapNoSuchObjectException( String message )
+    {
+        super( ResultCodeEnum.NO_SUCH_OBJECT, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapNoSuchObjectException.
+     */
+    public LdapNoSuchObjectException()
+    {
+        super( ResultCodeEnum.NO_SUCH_OBJECT, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchOperationException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchOperationException.java
new file mode 100644
index 0000000..0c25f81
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapNoSuchOperationException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapNoSuchOperationException which associates a resultCode, namely the
+ * {@link ResultCodeEnum#NO_SUCH_OPERATION} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapNoSuchOperationException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapNoSuchOperationException.
+     *
+     */
+    public LdapNoSuchOperationException()
+    {
+        super( ResultCodeEnum.NO_SUCH_OPERATION, null );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapNoSuchOperationException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapNoSuchOperationException( String explanation )
+    {
+        super( ResultCodeEnum.NO_SUCH_OPERATION, explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOperationErrorException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOperationErrorException.java
new file mode 100644
index 0000000..58d7c76
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOperationErrorException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link ResultCodeEnum#OPERATIONS_ERROR} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapOperationErrorException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapOperationErrorException.
+     *
+     * @param message The exception message
+     */
+    public LdapOperationErrorException( String message )
+    {
+        super( ResultCodeEnum.OPERATIONS_ERROR, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapOperationErrorException.
+     *
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapOperationErrorException( String message, Throwable cause )
+    {
+        super( ResultCodeEnum.OPERATIONS_ERROR, message, cause );
+    }
+
+
+    /**
+     * Creates a new instance of LdapOperationErrorException.
+     */
+    public LdapOperationErrorException()
+    {
+        super( ResultCodeEnum.OPERATIONS_ERROR, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOperationException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOperationException.java
new file mode 100644
index 0000000..477651b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOperationException.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * An class for LDAP operation exceptions which add LDAP specific information to
+ * Exceptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapOperationException extends LdapException
+{
+    /** The serial version UUID */
+    private static final long serialVersionUID = 1L;
+
+    /** The operation resultCode */
+    protected ResultCodeEnum resultCode;
+
+    /** The resolved Dn */
+    protected Dn resolvedDn;
+
+
+    /**
+     * @return the resolvedDn
+     */
+    public Dn getResolvedDn()
+    {
+        return resolvedDn;
+    }
+
+
+    /**
+     * @param resolvedDn the resolvedDn to set
+     */
+    public void setResolvedDn( Dn resolvedDn )
+    {
+        this.resolvedDn = resolvedDn;
+    }
+
+
+    /**
+     * Creates a new instance of LdapOperationException.
+     *
+     * @param resultCode The operation resultCode
+     * @param message The exception message
+     */
+    public LdapOperationException( ResultCodeEnum resultCode, String message )
+    {
+        super( message );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapOperationException.
+     *
+     * @param resultCode The operation resultCode
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapOperationException( ResultCodeEnum resultCode, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapOperationException.
+     *
+     * @param message The exception message
+     */
+    public LdapOperationException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapOperationException.
+     *
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapOperationException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+
+    /**
+     * Gets the LDAP result code that would be associated with this exception.
+     * 
+     * @return the LDAP result code corresponding to this exception type.
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return resultCode;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOtherException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOtherException.java
new file mode 100644
index 0000000..81d101a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapOtherException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link ResultCodeEnum#OTHER} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapOtherException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapOtherException.
+     *
+     * @param message The exception message
+     */
+    public LdapOtherException( String message )
+    {
+        super( ResultCodeEnum.OTHER, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapOtherException.
+     *
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapOtherException( String message, Throwable cause )
+    {
+        super( ResultCodeEnum.OTHER, message, cause );
+    }
+
+
+    /**
+     * Creates a new instance of LdapOtherException.
+     */
+    public LdapOtherException()
+    {
+        super( ResultCodeEnum.OTHER, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapPartialResultException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapPartialResultException.java
new file mode 100644
index 0000000..2907ea7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapPartialResultException.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+/**
+ * A {@link LdapOperationException} which associates a resultCode namely the
+ * {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#REFERRAL} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapPartialResultException extends AbstractLdapReferralException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapPartialResultException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapPartialResultException( String explanation )
+    {
+        super( explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapProtocolErrorException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapProtocolErrorException.java
new file mode 100644
index 0000000..c6a0a3e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapProtocolErrorException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link ResultCodeEnum#PROTOCOL_ERROR} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapProtocolErrorException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapProtocolErrorException.
+     *
+     * @param message The exception message
+     */
+    public LdapProtocolErrorException( String message )
+    {
+        super( ResultCodeEnum.PROTOCOL_ERROR, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapProtocolErrorException.
+     *
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapProtocolErrorException( String message, Throwable cause )
+    {
+        super( ResultCodeEnum.PROTOCOL_ERROR, message, cause );
+    }
+
+
+    /**
+     * Creates a new instance of LdapProtocolErrorException.
+     */
+    public LdapProtocolErrorException()
+    {
+        super( ResultCodeEnum.PROTOCOL_ERROR, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapReferralException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapReferralException.java
new file mode 100644
index 0000000..da8de64
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapReferralException.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.exception.NotImplementedException;
+
+
+/**
+ * A {@link LdapOperationException} which associates a resultCode namely the
+ * {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#REFERRAL} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapReferralException extends AbstractLdapReferralException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+    /** The list of referrals */
+    private final List<String> refs;
+
+    /** The current index in the list of referrals */
+    private int index = 0;
+
+    /** The remaining Dn */
+    private Dn remainingDn;
+
+    /** TODO */
+    private Object resolvedObject;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapReferralException.
+     *
+     * @param refs The list of referrals
+     */
+    public LdapReferralException( Collection<String> refs )
+    {
+        super( null );
+        this.refs = new ArrayList<String>( refs );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapReferralException.
+     *
+     * @param refs The list of referrals
+     * @param explanation The associated error message
+     */
+    public LdapReferralException( Collection<String> refs, String explanation )
+    {
+        super( explanation );
+        this.refs = new ArrayList<String>( refs );
+    }
+
+
+    /**
+     * Always returns {@link ResultCodeEnum#REFERRAL}
+     * 
+     * @see LdapException#getResultCode()
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return ResultCodeEnum.REFERRAL;
+    }
+
+
+    /**
+     * @return The current Referral
+     */
+    public String getReferralInfo()
+    {
+        return refs.get( index );
+    }
+
+
+    public Context getReferralContext() throws NamingException
+    {
+        throw new NotImplementedException();
+    }
+
+
+    public Context getReferralContext( Hashtable<?, ?> arg ) throws NamingException
+    {
+        throw new NotImplementedException();
+    }
+
+
+    /**
+     * Move to the next referral
+     * @return true if there is some next referral
+     */
+    public boolean skipReferral()
+    {
+        index++;
+        return index < refs.size();
+    }
+
+
+    public void retryReferral()
+    {
+        throw new NotImplementedException();
+    }
+
+
+    /**
+     * @return the remainingDn
+     */
+    public Dn getRemainingDn()
+    {
+        return remainingDn;
+    }
+
+
+    /**
+     * @param remainingDn the remainingName to set
+     */
+    public void setRemainingDn( Dn remainingDn )
+    {
+        this.remainingDn = remainingDn;
+    }
+
+
+    /**
+     * @return the resolvedObject
+     */
+    public Object getResolvedObject()
+    {
+        return resolvedObject;
+    }
+
+
+    /**
+     * @param resolvedObject the resolvedObject to set
+     */
+    public void setResolvedObject( Object resolvedObject )
+    {
+        this.resolvedObject = resolvedObject;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaException.java
new file mode 100644
index 0000000..1a01c23
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaException.java
@@ -0,0 +1,217 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+
+
+/**
+ * A subclass of {@link LdapException} which is used to report issues 
+ * during the integrity check of the schema by the {@link SchemaManager}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapSchemaException extends LdapException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+    /** The code of the exception */
+    private LdapSchemaExceptionCodes code;
+
+    /** The 'source' schema object */
+    private SchemaObject sourceObject;
+
+    /** The 'other' schema object */
+    private SchemaObject otherObject;
+
+    /** The related ID (name or OID) of the exception */
+    private String relatedId;
+
+
+    /**
+     * Creates a new instance of LdapSchemaException.
+     */
+    public LdapSchemaException()
+    {
+        super();
+    }
+
+
+    /**
+     * Creates a new instance of LdapSchemaException.
+     *
+     * @param code
+     *      The code of the exception
+     */
+    public LdapSchemaException( LdapSchemaExceptionCodes code )
+    {
+        super();
+        this.code = code;
+    }
+
+
+    /**
+     * Creates a new instance of LdapSchemaException.
+     *
+     * @param explanation
+     *      The message associated with the exception
+     */
+    public LdapSchemaException( String explanation )
+    {
+        super( explanation );
+    }
+
+
+    /**
+     * Creates a new instance of LdapSchemaException.
+     *
+     * @param code The code of the exception
+     * @param explanation The message associated with the exception
+     */
+    public LdapSchemaException( LdapSchemaExceptionCodes code, String explanation )
+    {
+        super( explanation );
+        this.code = code;
+    }
+
+
+    /**
+     *
+     * @param code The code of the exception
+     * @param cause The root cause for this exception
+     */
+    public LdapSchemaException( LdapSchemaExceptionCodes code, Throwable cause )
+    {
+        super( cause );
+        this.code = code;
+    }
+
+
+    /**
+     * Creates a new instance of LdapSchemaException.
+     *
+     * @param code The code of the exception
+     * @param explanation The message associated with the exception
+     * @param cause The root cause for this exception
+     */
+    public LdapSchemaException( LdapSchemaExceptionCodes code, String explanation, Throwable cause )
+    {
+        super( explanation, cause );
+        this.code = code;
+    }
+
+
+    /**
+     * Gets the code of the exception.
+     *
+     * @return
+     *      the code of the exception
+     */
+    public LdapSchemaExceptionCodes getCode()
+    {
+        return code;
+    }
+
+
+    /**
+     * Sets the code of the exception.
+     *
+     * @param code
+     *      the code of the exception
+     */
+    public void setCode( LdapSchemaExceptionCodes code )
+    {
+        this.code = code;
+    }
+
+
+    /**
+     * Gets the 'source' schema object.
+     *
+     * @return
+     *      the 'source' schema object
+     */
+    public SchemaObject getSourceObject()
+    {
+        return sourceObject;
+    }
+
+
+    /**
+     * Sets the 'source' schema object.
+     *
+     * @param source
+     *      the 'source' schema object
+     */
+    public void setSourceObject( SchemaObject source )
+    {
+        this.sourceObject = source;
+    }
+
+
+    /**
+     * Gets the 'other' schema object.
+     *
+     * @return
+     *      the 'other' schema object
+     */
+    public SchemaObject getOtherObject()
+    {
+        return otherObject;
+    }
+
+
+    /**
+     * Sets the 'other' schema object.
+     *
+     * @param other
+     *      the 'other' schema object
+     */
+    public void setOtherObject( SchemaObject other )
+    {
+        this.otherObject = other;
+    }
+
+
+    /**
+     * Gets the related ID (name or OID) of the exception.
+     *
+     * @return
+     *      the related ID (name or OID)
+     */
+    public String getRelatedId()
+    {
+        return relatedId;
+    }
+
+
+    /**
+     * Sets the related ID (name or OID) of the exception.
+     *
+     * @param relatedId
+     *      the related ID (name or OID)
+     */
+    public void setRelatedId( String relatedId )
+    {
+        this.relatedId = relatedId;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaExceptionCodes.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaExceptionCodes.java
new file mode 100644
index 0000000..9116f76
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaExceptionCodes.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+/**
+ * This enum contains all the various codes that can be used to report issues 
+ * during the integrity check of the schema by the SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum LdapSchemaExceptionCodes
+{
+    // Codes for all Schema Objects
+
+    /** Characterizing a SO with an OID being already registered */
+    OID_ALREADY_REGISTERED,
+
+    /** Characterizing a SO with a name being already registered */
+    NAME_ALREADY_REGISTERED,
+
+    /** Characterizing an SO with a nonexistent schema */
+    NONEXISTENT_SCHEMA,
+
+    // Codes for Attribute Type
+
+    /** Characterizing an AT with a nonexistent superior */
+    AT_NONEXISTENT_SUPERIOR,
+
+    /** Characterizing an AT sub-typing a Collective AT  */
+    AT_CANNOT_SUBTYPE_COLLECTIVE_AT,
+
+    /** Characterizing an AT containing a cycle in its type hierarchy */
+    AT_CYCLE_TYPE_HIERARCHY,
+
+    /** Characterizing an AT with a nonexistent syntax */
+    AT_NONEXISTENT_SYNTAX,
+
+    /** Characterizing an AT has no syntax and no superior */
+    AT_SYNTAX_OR_SUPERIOR_REQUIRED,
+
+    /** Characterizing an AT with a nonexistent equality matching rule */
+    AT_NONEXISTENT_EQUALITY_MATCHING_RULE,
+
+    /** Characterizing an AT with a nonexistent ordering matching rule */
+    AT_NONEXISTENT_ORDERING_MATCHING_RULE,
+
+    /** Characterizing an AT with a nonexistent substring matching rule */
+    AT_NONEXISTENT_SUBSTRING_MATCHING_RULE,
+
+    /** Characterizing an AT which has a different usage than its superior */
+    AT_MUST_HAVE_SAME_USAGE_THAN_SUPERIOR,
+
+    /** Characterizing an AT which has a 'userApplications' usage but is not user modifiable */
+    AT_USER_APPLICATIONS_USAGE_MUST_BE_USER_MODIFIABLE,
+
+    /** Characterizing an AT which is collective but does not have a 'userApplications' usage */
+    AT_COLLECTIVE_MUST_HAVE_USER_APPLICATIONS_USAGE,
+
+    /** Characterizing an AT which is collective and is single-valued */
+    AT_COLLECTIVE_CANNOT_BE_SINGLE_VALUED,
+
+    // Codes for Object Class
+
+    /** Characterizing an abstract OC which inherits from an OC not being abstract */
+    OC_ABSTRACT_MUST_INHERIT_FROM_ABSTRACT_OC,
+
+    /** Characterizing an auxiliary OC which inherits from a structural OC */
+    OC_AUXILIARY_CANNOT_INHERIT_FROM_STRUCTURAL_OC,
+
+    /** Characterizing a structural OC which inherits from an auxiliary OC */
+    OC_STRUCTURAL_CANNOT_INHERIT_FROM_AUXILIARY_OC,
+
+    /** Characterizing an OC with a nonexistent superior */
+    OC_NONEXISTENT_SUPERIOR,
+
+    /** Characterizing an OC containing a cycle in its class hierarchy */
+    OC_CYCLE_CLASS_HIERARCHY,
+
+    /** Characterizing an OC with a collective AT in its must ATs list */
+    OC_COLLECTIVE_NOT_ALLOWED_IN_MUST,
+
+    /** Characterizing an OC with a collective AT in its may ATs list */
+    OC_COLLECTIVE_NOT_ALLOWED_IN_MAY,
+
+    /** Characterizing an OC with a duplicated AT in its must ATs list */
+    OC_DUPLICATE_AT_IN_MUST,
+
+    /** Characterizing an OC with a duplicated AT in its may ATs list */
+    OC_DUPLICATE_AT_IN_MAY,
+
+    /** Characterizing an OC with a nonexistent AT in its must ATs list */
+    OC_NONEXISTENT_MUST_AT,
+
+    /** Characterizing an OC with a nonexistent AT in its may ATs list */
+    OC_NONEXISTENT_MAY_AT,
+
+    /** Characterizing an OC with a duplicated AT in its may and must ATs list */
+    OC_DUPLICATE_AT_IN_MAY_AND_MUST,
+
+    // Codes for Matching Rule
+
+    /** Characterizing a MR with a nonexistent syntax */
+    MR_NONEXISTENT_SYNTAX,
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaViolationException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaViolationException.java
new file mode 100644
index 0000000..a954c14
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSchemaViolationException.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * Makes a {@link LdapOperationException} unambiguous with respect to the result code
+ * it corresponds to by associating an LDAP specific result code with it.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapSchemaViolationException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapSchemaViolationException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     */
+    public LdapSchemaViolationException( ResultCodeEnum resultCode, String message )
+    {
+        super( message );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapSchemaViolationException( ResultCodeEnum resultCode, String message, Throwable cause )
+    {
+        super( message, cause );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapSchemaViolationException.
+     * 
+     * @param resultCode the ResultCodeEnum for this exception
+     */
+    public LdapSchemaViolationException( ResultCodeEnum resultCode )
+    {
+        super( null );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Checks to make sure the resultCode value is right for this exception
+     * type.
+     * 
+     * @throws IllegalArgumentException
+     *             if the result code is not one of
+     *             {@link ResultCodeEnum#OBJECT_CLASS_VIOLATION},
+     *             {@link ResultCodeEnum#NOT_ALLOWED_ON_RDN}.
+     *             {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#OBJECT_CLASS_MODS_PROHIBITED}.
+     */
+    private void checkResultCode( ResultCodeEnum resultCode )
+    {
+        switch ( resultCode )
+        {
+            case OBJECT_CLASS_VIOLATION:
+            case NOT_ALLOWED_ON_RDN:
+            case OBJECT_CLASS_MODS_PROHIBITED:
+                return;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04140_UNACCEPTABLE_RESULT_CODE, resultCode ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapServiceUnavailableException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapServiceUnavailableException.java
new file mode 100644
index 0000000..b6db3c9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapServiceUnavailableException.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * LDAP specific {@link LdapOperationException} that preserves resultCode
+ * resolution.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapServiceUnavailableException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapServiceUnavailableException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     */
+    public LdapServiceUnavailableException( ResultCodeEnum resultCode, String message )
+    {
+        super( message );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapServiceUnavailableException.
+     * 
+     * @param resultCode the ResultCodeEnum for this exception
+     */
+    public LdapServiceUnavailableException( ResultCodeEnum resultCode )
+    {
+        super( null );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Checks to make sure the resultCode value is right for this exception
+     * type.
+     * 
+     * @throws IllegalArgumentException
+     *             if the result code is not one of
+     *             {@link ResultCodeEnum#BUSY},
+     *             {@link ResultCodeEnum#UNAVAILABLE}.
+     */
+    private void checkResultCode( ResultCodeEnum resultCode )
+    {
+        switch ( resultCode )
+        {
+            case BUSY:
+            case UNAVAILABLE:
+                return;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04140_UNACCEPTABLE_RESULT_CODE, resultCode ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSizeLimitExceededException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSizeLimitExceededException.java
new file mode 100644
index 0000000..0a16870
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapSizeLimitExceededException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapSizeLimitExceededException which associates a resultCode namely the
+ * {@link ResultCodeEnum#SIZE_LIMIT_EXCEEDED} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapSizeLimitExceededException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapSizeLimitExceededException.
+     *
+     */
+    public LdapSizeLimitExceededException()
+    {
+        super( ResultCodeEnum.SIZE_LIMIT_EXCEEDED, null );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapSizeLimitExceededException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapSizeLimitExceededException( String explanation )
+    {
+        super( ResultCodeEnum.SIZE_LIMIT_EXCEEDED, explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapStrongAuthenticationRequiredException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapStrongAuthenticationRequiredException.java
new file mode 100644
index 0000000..ef05f85
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapStrongAuthenticationRequiredException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A subclass of {@link LdapOperationException} which associates the
+ * {@link org.apache.directory.api.ldap.model.message.ResultCodeEnum#STRONG_AUTH_REQUIRED} value with the type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapStrongAuthenticationRequiredException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapStrongAuthenticationRequiredException.
+     *
+     * @param message The exception message
+     */
+    public LdapStrongAuthenticationRequiredException( String message )
+    {
+        super( ResultCodeEnum.STRONG_AUTH_REQUIRED, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapStrongAuthenticationRequiredException.
+     */
+    public LdapStrongAuthenticationRequiredException()
+    {
+        super( ResultCodeEnum.STRONG_AUTH_REQUIRED, null );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapTimeLimitExceededException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapTimeLimitExceededException.java
new file mode 100644
index 0000000..4c3d287
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapTimeLimitExceededException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapTimeLimitExceededException which associates a resultCode namely the
+ * {@link ResultCodeEnum#TIME_LIMIT_EXCEEDED} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapTimeLimitExceededException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapTimeLimitExceededException.
+     *
+     */
+    public LdapTimeLimitExceededException()
+    {
+        super( ResultCodeEnum.TIME_LIMIT_EXCEEDED, null );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapTimeLimitExceededException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapTimeLimitExceededException( String explanation )
+    {
+        super( ResultCodeEnum.TIME_LIMIT_EXCEEDED, explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapTooLateException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapTooLateException.java
new file mode 100644
index 0000000..3d71187
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapTooLateException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapTooLateException which associates a resultCode namely the
+ * {@link ResultCodeEnum#TOO_LATE} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapTooLateException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapTooLateException.
+     *
+     */
+    public LdapTooLateException()
+    {
+        super( ResultCodeEnum.TOO_LATE, null );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapTooLateException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapTooLateException( String explanation )
+    {
+        super( ResultCodeEnum.TOO_LATE, explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapURLEncodingException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapURLEncodingException.java
new file mode 100644
index 0000000..6424912
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapURLEncodingException.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+/**
+ * Thrown when a LdapStringEncodingDecoder has encountered a failure condition
+ * during the String creation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapURLEncodingException extends LdapException
+{
+    private static final long serialVersionUID = 193461058160901616L;
+
+
+    /**
+     * Creates a LdapStringEncodingException
+     * 
+     * @param message A message with meaning to a human
+     */
+    public LdapURLEncodingException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a LdapStringEncodingException
+     * 
+     * @param message A message with meaning to a human
+     * @param cause The root cause for this exception
+     */
+    public LdapURLEncodingException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUnknownException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUnknownException.java
new file mode 100644
index 0000000..8db0a00
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUnknownException.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A LdapUnknownException which associates a resultCode, namely the
+ * {@link ResultCodeEnum#UNKNOWN} resultCode with the exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapUnknownException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * 
+     * Creates a new instance of LdapUnknownException.
+     *
+     */
+    public LdapUnknownException()
+    {
+        super( ResultCodeEnum.UNKNOWN, null );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapUnknownException.
+     *
+     * @param explanation The associated error message
+     */
+    public LdapUnknownException( String explanation )
+    {
+        super( ResultCodeEnum.UNKNOWN, explanation );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUnwillingToPerformException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUnwillingToPerformException.java
new file mode 100644
index 0000000..6283412
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUnwillingToPerformException.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An LDAPException that extends the {@link LdapOperationException}
+ * carrying with it the corresponding result codes for this condition.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapUnwillingToPerformException extends LdapOperationException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapUnwillingToPerformException, with
+     * a default ResultCode to UNWILING_TO_PERFORM.
+     */
+    public LdapUnwillingToPerformException()
+    {
+        super( ResultCodeEnum.UNWILLING_TO_PERFORM, null );
+    }
+
+
+    /**
+     * Creates a new instance of LdapUnwillingToPerformException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     */
+    public LdapUnwillingToPerformException( ResultCodeEnum resultCode, String message )
+    {
+        super( message );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapUnwillingToPerformException( ResultCodeEnum resultCode, String message, Throwable cause )
+    {
+        super( message, cause );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Creates a new instance of LdapUnwillingToPerformException.
+     *
+     * @param message The exception message
+     */
+    public LdapUnwillingToPerformException( String message )
+    {
+        super( ResultCodeEnum.UNWILLING_TO_PERFORM, message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapUnwillingToPerformException.
+     *
+     * @param resultCode the ResultCodeEnum for this exception
+     */
+    public LdapUnwillingToPerformException( ResultCodeEnum resultCode )
+    {
+        super( null );
+        checkResultCode( resultCode );
+        this.resultCode = resultCode;
+    }
+
+
+    /**
+     * Checks to make sure the resultCode value is right for this exception
+     * type.
+     *
+     * @throws IllegalArgumentException
+     *             if the result code is not one of
+     *             {@link ResultCodeEnum#UNWILLING_TO_PERFORM},
+     *             {@link ResultCodeEnum#UNAVAILABLE_CRITICAL_EXTENSION}.
+     */
+    private void checkResultCode( ResultCodeEnum resultCode )
+    {
+        switch ( resultCode )
+        {
+            case UNWILLING_TO_PERFORM:
+            case UNAVAILABLE_CRITICAL_EXTENSION:
+                return;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04140_UNACCEPTABLE_RESULT_CODE, resultCode ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUriException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUriException.java
new file mode 100644
index 0000000..02f8416
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/LdapUriException.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+/**
+ * The URI parsing and escape encoding exception.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapUriException extends LdapException
+{
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * The constructor with a reason string argument.
+     * 
+     * @param reason the reason
+     * @param cause the root cause
+     */
+    public LdapUriException( String reason, Throwable cause )
+    {
+        // for backward compatibility of Throwable
+        super( reason, cause );
+        this.reason = reason;
+        this.reasonCode = UNKNOWN;
+    }
+
+    /**
+     * No specified reason code.
+     */
+    public static final int UNKNOWN = 0;
+
+    /**
+     * The reason code.
+     */
+    protected int reasonCode;
+
+    /**
+     * The reason message.
+     */
+    protected String reason;
+
+
+    /**
+     * Get the reason code.
+     * 
+     * @return the reason code
+     */
+    public int getReasonCode()
+    {
+        return reasonCode;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/MessageException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/MessageException.java
new file mode 100644
index 0000000..4c5982b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/MessageException.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.util.exception.RuntimeMultiException;
+
+
+/**
+ * This exception is thrown when a message processing error occurs.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MessageException extends RuntimeMultiException
+{
+
+    /** The serialVersionUID. */
+    static final long serialVersionUID = -155089078576745029L;
+
+
+    /**
+     * Constructs an Exception without a message.
+     */
+    public MessageException()
+    {
+        super();
+    }
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     * 
+     * @param message
+     *            The message associated with the exception.
+     */
+    public MessageException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/OperationAbandonedException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/OperationAbandonedException.java
new file mode 100644
index 0000000..3fbb00b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/OperationAbandonedException.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.exception;
+
+
+/**
+ * Marker exception thrown when an operation is cancelled.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OperationAbandonedException extends LdapException
+{
+    /** The serial version UUID */
+    static final long serialVersionUID = 1L;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/ResponseCarryingMessageException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/ResponseCarryingMessageException.java
new file mode 100644
index 0000000..29d281c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/ResponseCarryingMessageException.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.exception;
+
+
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.exception.RuntimeMultiException;
+
+
+/**
+ * This exception is thrown when a message processing error occurs.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ResponseCarryingMessageException extends RuntimeMultiException
+{
+    /**
+     * Declares the Serial Version Uid.
+     * 
+     * @see <a
+     *      href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
+     *      Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /** The response with the error cause */
+    private Message response;
+
+
+    /**
+     * Constructs an Exception without a message.
+     */
+    public ResponseCarryingMessageException()
+    {
+        super();
+    }
+
+
+    /**
+     * Constructs an Exception without a message.
+     *
+     * @param cause The original cause
+     */
+    public ResponseCarryingMessageException( Throwable cause )
+    {
+        super( "", cause );
+    }
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     * 
+     * @param message The message associated with the exception.
+     */
+    public ResponseCarryingMessageException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     * 
+     * @param message The message associated with the exception.
+     * @param cause The original cause
+     */
+    public ResponseCarryingMessageException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+
+    /**
+     * Set a response if we get an exception while parsing the message
+     * @param response the constructed response
+     */
+    public void setResponse( Message response )
+    {
+        this.response = response;
+    }
+
+
+    /**
+     * Get the constructed response
+     * @return The constructed response
+     */
+    public Message getResponse()
+    {
+        return response;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/UrlDecoderException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/UrlDecoderException.java
new file mode 100644
index 0000000..ae37ad3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/exception/UrlDecoderException.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.exception;
+
+
+/**
+ * Thrown when a Decoder has encountered a failure condition during a decode.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UrlDecoderException extends LdapException
+{
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a DecoderException
+     * 
+     * @param message A message with meaning to a human
+     */
+    public UrlDecoderException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a DecoderException
+     * 
+     * @param message A message with meaning to a human
+     * @param cause The root cause for this exception
+     */
+    public UrlDecoderException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AbstractExprNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AbstractExprNode.java
new file mode 100644
index 0000000..8dfe364
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AbstractExprNode.java
@@ -0,0 +1,361 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+
+
+/**
+ * Abstract implementation of a expression node.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractExprNode implements ExprNode
+{
+    /** The map of annotations */
+    protected Map<String, Object> annotations;
+
+    /** The node type */
+    protected final AssertionType assertionType;
+
+    /** A flag set to true if the Node is Schema aware */
+    protected boolean isSchemaAware;
+
+
+    /**
+     * Creates a node by setting abstract node type.
+     * 
+     * @param assertionType The node's type
+     */
+    protected AbstractExprNode( AssertionType assertionType )
+    {
+        this.assertionType = assertionType;
+    }
+
+
+    /**
+     * @see ExprNode#getAssertionType()
+     * 
+     * @return the node's type
+     */
+    public AssertionType getAssertionType()
+    {
+        return assertionType;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     *@return <code>true</code> if both objects are equal 
+     */
+    public boolean equals( Object o )
+    {
+        // Shortcut for equals object
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof AbstractExprNode ) )
+        {
+            return false;
+        }
+
+        AbstractExprNode that = ( AbstractExprNode ) o;
+
+        // Check the node type
+        if ( this.assertionType != that.assertionType )
+        {
+            return false;
+        }
+
+        if ( annotations == null )
+        {
+            return that.annotations == null;
+        }
+        else if ( that.annotations == null )
+        {
+            return false;
+        }
+
+        // Check all the annotation
+        for ( Map.Entry<String, Object> entry : annotations.entrySet() )
+        {
+            String key = entry.getKey();
+        
+            if ( !that.annotations.containsKey( key ) )
+            {
+                return false;
+            }
+
+            Object thisAnnotation = entry.getValue();
+            Object thatAnnotation = that.annotations.get( key );
+
+            if ( thisAnnotation == null )
+            {
+                if ( thatAnnotation != null )
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if ( !thisAnnotation.equals( thatAnnotation ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Handles the escaping of special characters in LDAP search filter assertion values using the
+     * &lt;valueencoding&gt; rule as described in
+     * <a href="http://www.ietf.org/rfc/rfc4515.txt">RFC 4515</a>. Needed so that
+     * {@link ExprNode#printToBuffer(StringBuffer)} results in a valid filter string that can be parsed
+     * again (as a way of cloning filters).
+     *
+     * @param value Right hand side of "attrId=value" assertion occurring in an LDAP search filter.
+     * @return Escaped version of <code>value</code>
+     */
+    protected static Value<?> escapeFilterValue( Value<?> value )
+    {
+        if ( value.isNull() )
+        {
+            return value;
+        }
+
+        StringBuilder sb = null;
+        String val;
+
+        if ( !value.isHumanReadable() )
+        {
+            sb = new StringBuilder( ( ( BinaryValue ) value ).getReference().length * 3 );
+
+            for ( byte b : ( ( BinaryValue ) value ).getReference() )
+            {
+                if ( ( b < 0x7F ) && ( b >= 0 ) )
+                {
+                    switch ( b )
+                    {
+                        case '*':
+                            sb.append( "\\2A" );
+                            break;
+
+                        case '(':
+                            sb.append( "\\28" );
+                            break;
+
+                        case ')':
+                            sb.append( "\\29" );
+                            break;
+
+                        case '\\':
+                            sb.append( "\\5C" );
+                            break;
+
+                        case '\0':
+                            sb.append( "\\00" );
+                            break;
+
+                        default:
+                            sb.append( ( char ) b );
+                    }
+                }
+                else
+                {
+                    sb.append( '\\' );
+                    String digit = Integer.toHexString( b & 0x00FF );
+
+                    if ( digit.length() == 1 )
+                    {
+                        sb.append( '0' );
+                    }
+
+                    sb.append( digit.toUpperCase() );
+                }
+            }
+
+            return new StringValue( sb.toString() );
+        }
+
+        val = ( ( StringValue ) value ).getString();
+        String encodedVal = FilterEncoder.encodeFilterValue( val );
+        if ( val.equals( encodedVal ) )
+        {
+            return value;
+        }
+        else
+        {
+            return new StringValue( encodedVal );
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int h = 37;
+
+        if ( annotations != null )
+        {
+            for ( Map.Entry<String, Object> entry : annotations.entrySet() )
+            {
+                String key = entry.getKey();
+                Object value = entry.getValue();
+
+                h = h * 17 + key.hashCode();
+                h = h * 17 + ( value == null ? 0 : value.hashCode() );
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see ExprNode#get(java.lang.Object)
+     * 
+     * @return the annotation value.
+     */
+    public Object get( Object key )
+    {
+        if ( null == annotations )
+        {
+            return null;
+        }
+
+        return annotations.get( key );
+    }
+
+
+    /**
+     * @see ExprNode#set(java.lang.Object,
+     *      java.lang.Object)
+     */
+    public void set( String key, Object value )
+    {
+        if ( null == annotations )
+        {
+            annotations = new HashMap<String, Object>( 2 );
+        }
+
+        annotations.put( key, value );
+    }
+
+
+    /**
+     * Gets the annotations as a Map.
+     * 
+     * @return the annotation map.
+     */
+    protected Map<String, Object> getAnnotations()
+    {
+        return annotations;
+    }
+
+
+    /**
+     * Tells if this Node is Schema aware.
+     * 
+     * @return true if the Node is SchemaAware
+     */
+    public boolean isSchemaAware()
+    {
+        return isSchemaAware;
+    }
+
+
+    /**
+     * Default implementation for this method : just throw an exception.
+     * 
+     * @param buf the buffer to append to.
+     * @return The buffer in which the refinement has been appended
+     * @throws UnsupportedOperationException if this node isn't a part of a refinement.
+     */
+    public StringBuilder printRefinementToBuffer( StringBuilder buf )
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04144 ) );
+    }
+
+
+    /**
+     * Clone the object
+     */
+    @Override
+    public ExprNode clone()
+    {
+        try
+        {
+            ExprNode clone = ( ExprNode ) super.clone();
+
+            if ( annotations != null )
+            {
+                for ( Map.Entry<String, Object> entry : annotations.entrySet() )
+                {
+                    // Note : the value aren't cloned ! 
+                    ( ( AbstractExprNode ) clone ).annotations.put( entry.getKey(), entry.getValue() );
+                }
+            }
+
+            return clone;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        if ( ( null != annotations ) && annotations.containsKey( "count" ) )
+        {
+            Long count = ( Long ) annotations.get( "count" );
+
+            if ( count == Long.MAX_VALUE )
+            {
+                return ":[\u221E]";
+            }
+
+            return ":[" + count + "]";
+        }
+        else
+        {
+            return "";
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AndNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AndNode.java
new file mode 100644
index 0000000..c3178b3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AndNode.java
@@ -0,0 +1,222 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.util.List;
+
+
+/**
+ * Node representing an AND connector in a filter operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AndNode extends BranchNode
+{
+    /**
+     * Creates a AndNode using a logical operator and a list of children.
+     * 
+     * @param childList the child nodes under this branch node.
+     */
+    public AndNode( List<ExprNode> childList )
+    {
+        super( AssertionType.AND, childList );
+    }
+
+
+    /**
+     * Creates a AndNode using a logical operator and a list of children.
+     * 
+     * @param childList the child nodes under this branch node.
+     */
+    public AndNode( ExprNode... childList )
+    {
+        super( AssertionType.AND, childList );
+    }
+
+
+    /**
+     * Creates an empty AndNode
+     */
+    public AndNode()
+    {
+        super( AssertionType.AND );
+    }
+
+
+    /**
+     * Gets the operator for this branch node.
+     * 
+     * @return the operator constant.
+     */
+    public AssertionType getOperator()
+    {
+        return AssertionType.AND;
+    }
+
+
+    /**
+     * Tests whether or not this node is a disjunction (a OR'ed branch).
+     * 
+     * @return true if the operation is a OR, false otherwise.
+     */
+    public boolean isDisjunction()
+    {
+        return false;
+    }
+
+
+    /**
+     * Tests whether or not this node is a conjunction (a AND'ed branch).
+     * 
+     * @return true if the operation is a AND, false otherwise.
+     */
+    public boolean isConjunction()
+    {
+        return true;
+    }
+
+
+    /**
+     * Tests whether or not this node is a negation (a NOT'ed branch).
+     * 
+     * @return true if the operation is a NOT, false otherwise.
+     */
+    public boolean isNegation()
+    {
+        return false;
+    }
+
+
+    /**
+     * @see ExprNode#printRefinementToBuffer(StringBuffer)
+     * 
+     * @param buf the buffer to append to.
+     * @return The buffer in which the refinement has been appended
+     * @throws UnsupportedOperationException if this node isn't a part of a refinement.
+     */
+    public StringBuilder printRefinementToBuffer( StringBuilder buf )
+    {
+        buf.append( "and: {" );
+        boolean isFirst = true;
+
+        for ( ExprNode node : children )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+                buf.append( ' ' );
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            node.printRefinementToBuffer( buf );
+        }
+
+        buf.append( " }" );
+
+        return buf;
+    }
+
+
+    /**
+     * Gets the recursive prefix string represent of the filter from this node
+     * down.
+     * 
+     * @see java.lang.Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append( "(&" );
+
+        buf.append( super.toString() );
+
+        for ( ExprNode child : getChildren() )
+        {
+            buf.append( child );
+        }
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + AssertionType.AND.hashCode();
+        hash = hash * 17 + ( annotations == null ? 0 : annotations.hashCode() );
+        return hash;
+    }
+
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object other )
+    {
+        if ( this == other )
+        {
+            return true;
+        }
+
+        if ( !( other instanceof AndNode ) )
+        {
+            return false;
+        }
+
+        AndNode otherExprNode = ( AndNode ) other;
+
+        List<ExprNode> otherChildren = otherExprNode.getChildren();
+
+        if ( otherChildren == children )
+        {
+            return true;
+        }
+
+        if ( children.size() != otherChildren.size() )
+        {
+            return false;
+        }
+
+        for ( int i = 0; i < children.size(); i++ )
+        {
+            ExprNode child = children.get( i );
+            ExprNode otherChild = otherChildren.get( i );
+
+            if ( !child.equals( otherChild ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ApproximateNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ApproximateNode.java
new file mode 100644
index 0000000..fe8517f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ApproximateNode.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * A simple assertion value node.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ApproximateNode<T> extends SimpleNode<T>
+{
+    /**
+     * Creates a new ApproximateNode object.
+     * 
+     * @param attributeType the attribute type
+     * @param value the value to test for
+     */
+    public ApproximateNode( AttributeType attributeType, Value<T> value )
+    {
+        super( attributeType, value, AssertionType.APPROXIMATE );
+    }
+
+
+    /**
+     * Creates a new ApproximateNode object.
+     * 
+     * @param attribute the attribute name
+     * @param value the value to test for
+     */
+    public ApproximateNode( String attribute, Value<T> value )
+    {
+        super( attribute, value, AssertionType.APPROXIMATE );
+    }
+
+
+    /**
+     * @see Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( '(' );
+
+        if ( attributeType != null )
+        {
+            buf.append( attributeType.getName() );
+        }
+        else
+        {
+            buf.append( attribute );
+        }
+
+        buf.append( "~=" );
+
+        Value<?> escapedValue = getEscapedValue();
+        if ( !escapedValue.isNull() )
+        {
+            buf.append( escapedValue );
+        }
+
+        buf.append( super.toString() );
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/Assertion.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/Assertion.java
new file mode 100644
index 0000000..0329441
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/Assertion.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import javax.naming.NamingException;
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+
+
+/**
+ * A candidacy predicate which tests if an entry satisfies some condition before
+ * being returned by a search.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Assertion extends Cloneable
+{
+    /**
+     * Checks to see if a candidate is valid by asserting an arbitrary predicate
+     * against the candidate. Where available entry will be provided
+     * however there is no guarantee. The entry's attributes are only provided
+     * if they were previously accessed. All assertions should handle cases
+     * where the entry argument is null.
+     * 
+     * @param entry the entry if available
+     * @return true if the candidate satisfies the predicate, false otherwise
+     * @throws NamingException if an error occurs while asserting the predicate
+     */
+    boolean assertCandidate( Entry entry ) throws NamingException;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AssertionNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AssertionNode.java
new file mode 100644
index 0000000..e638e76
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AssertionNode.java
@@ -0,0 +1,221 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Node used for the application of arbitrary predicates on return candidates.
+ * Applies dynamic and programatic criteria for the selection of candidates for
+ * return. Nodes of this type may be introduced into the filter expression to
+ * provided the opportunity to constrain the search further without altering the
+ * search algorithm.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AssertionNode extends AbstractExprNode
+{
+    /** The assertion or predicate to apply */
+    private final Assertion assertion;
+
+    /** Description of assertion for polish printouts */
+    private final String desc;
+
+
+    // ------------------------------------------------------------------------
+    // C O N S T R U C T O R S
+    // ------------------------------------------------------------------------
+
+    /**
+     * Creates an AssertionNode using an arbitrary candidate assertion.
+     * 
+     * @param assertion the arbitrary selection logic.
+     */
+    public AssertionNode( Assertion assertion )
+    {
+        this( assertion, "ASSERTION" );
+
+        isSchemaAware = true;
+    }
+
+
+    /**
+     * Creates an AssertionNode using an arbitrary candidate assertion with a
+     * descriptions used for filter AST walker dumps.
+     * 
+     * @param assertion the arbitrary selection logic.
+     * @param desc the printout representation for filter prints.
+     */
+    public AssertionNode( Assertion assertion, String desc )
+    {
+        super( AssertionType.ASSERTION );
+        this.desc = desc;
+        this.assertion = assertion;
+
+        /*
+         * We never want this node to ever make it to the point of becoming a
+         * candidate for use in an enumeration so we set the scan count to the
+         * maximum value.
+         */
+        set( "count", Long.MAX_VALUE );
+    }
+
+
+    /**
+     * Makes a full clone in new memory space of the current node and children
+     * 
+     * @return the clone
+     */
+    @Override
+    public ExprNode clone()
+    {
+        return ( ExprNode ) super.clone();
+    }
+
+
+    /**
+     * Gets the Assertion used by this assertion node.
+     * 
+     * @return the assertion used by this node
+     */
+    public Assertion getAssertion()
+    {
+        return assertion;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // A B S T R A C T M E T H O D I M P L E M E N T A T I O N S
+    // ------------------------------------------------------------------------
+
+    /**
+     * Always returns true since an AssertionNode has no children.
+     * 
+     * @see ExprNode#isLeaf()
+     * @return true if the node is a leaf,false otherwise
+     */
+    public boolean isLeaf()
+    {
+        return true;
+    }
+
+
+    /**
+     * @see ExprNode#printRefinementToBuffer(StringBuilder) 
+     */
+    public StringBuilder printRefinementToBuffer( StringBuilder buf ) throws UnsupportedOperationException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04145 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof AssertionNode ) )
+        {
+            return false;
+        }
+        AssertionNode that = ( AssertionNode ) obj;
+        if ( assertion == null )
+        {
+            if ( that.assertion != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !assertion.equals( that.assertion ) )
+            {
+                return false;
+            }
+        }
+        if ( desc == null )
+        {
+            if ( that.desc != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !desc.equals( that.desc ) )
+            {
+                return false;
+            }
+        }
+        return super.equals( obj );
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + ( assertion != null ? assertion.hashCode() : 0 );
+        h = h * 17 + ( desc != null ? desc.hashCode() : 0 );
+
+        return h;
+    }
+
+
+    /**
+     * @see ExprNode#accept(
+     *FilterVisitor)
+     */
+    public Object accept( FilterVisitor visitor )
+    {
+        return visitor.visit( this );
+    }
+
+
+    /**
+     * @see Object#toString
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "(@" );
+        buf.append( desc );
+        buf.append( super.toString() );
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AssertionType.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AssertionType.java
new file mode 100644
index 0000000..0eb1196
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/AssertionType.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+/**
+ * All the different kind of assertions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum AssertionType
+{
+    /** equality assertion node */
+    EQUALITY,
+
+    /** presence assertion node */
+    PRESENCE,
+
+    /** substring match assertion node */
+    SUBSTRING,
+
+    /** greater than or equal to assertion node */
+    GREATEREQ,
+
+    /** less than or equal to assertion node */
+    LESSEQ,
+
+    /** approximate assertion node */
+    APPROXIMATE,
+
+    /** extensible match assertion node */
+    EXTENSIBLE,
+
+    /** scope assertion node */
+    SCOPE,
+
+    /** Predicate assertion node */
+    ASSERTION,
+
+    /** OR operator constant */
+    OR,
+
+    /** AND operator constant */
+    AND,
+
+    /** NOT operator constant */
+    NOT,
+
+    /** Undefined operation */
+    UNDEFINED,
+
+    /** (ObjectClass=*) filter */
+    OBJECTCLASS;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/BranchNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/BranchNode.java
new file mode 100644
index 0000000..30aed12
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/BranchNode.java
@@ -0,0 +1,304 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.collections.CollectionUtils;
+
+
+/**
+ * Node representing branches within the expression tree corresponding to
+ * logical operators within the filter expression.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BranchNode extends AbstractExprNode
+{
+    /** child node list for this branch node */
+    protected List<ExprNode> children = null;
+
+
+    /**
+     * Creates a BranchNode using a logical operator and a list of children.
+     * @param assertionType the node's type
+     * @param childList the child nodes under this branch node.
+     */
+    protected BranchNode( AssertionType assertionType, List<ExprNode> childList )
+    {
+        super( assertionType );
+
+        if ( null == childList )
+        {
+            this.children = new ArrayList<ExprNode>( 2 );
+        }
+        else
+        {
+            this.children = childList;
+        }
+
+        isSchemaAware = true;
+    }
+
+
+    /**
+     * Creates a BranchNode using a logical operator and a list of children.
+     * 
+     * @param assertionType the node's type
+     * @param childList the child nodes under this branch node.
+     */
+    protected BranchNode( AssertionType assertionType, ExprNode... childList )
+    {
+        super( assertionType );
+
+        if ( null == children )
+        {
+            this.children = new ArrayList<ExprNode>( childList.length );
+        }
+
+        CollectionUtils.addAll( children, childList );
+    }
+
+
+    /**
+     * Creates a BranchNode using a logical operator.
+     * 
+     * @param assertionType the node's type
+     */
+    protected BranchNode( AssertionType assertionType )
+    {
+        super( assertionType );
+
+        this.children = new ArrayList<ExprNode>( 2 );
+        isSchemaAware = true;
+    }
+
+
+    /**
+     * @see ExprNode#isLeaf()
+     * @return false all the time.
+     */
+    public final boolean isLeaf()
+    {
+        return false;
+    }
+
+
+    /**
+     * Makes a full clone in new memory space of the current node and children
+     * 
+     * @return the clone
+     */
+    @Override
+    public ExprNode clone()
+    {
+        ExprNode clone = ( ExprNode ) super.clone();
+
+        // Clone the children
+        if ( children != null )
+        {
+            ( ( BranchNode ) clone ).children = new ArrayList<ExprNode>();
+
+            for ( ExprNode child : children )
+            {
+                ( ( BranchNode ) clone ).children.add( ( ExprNode ) child.clone() );
+            }
+        }
+
+        return clone;
+    }
+
+
+    /**
+     * Adds a child node to this branch node node
+     * 
+     * @param node the child expression to add to this branch node
+     */
+    public void addNode( ExprNode node )
+    {
+        children.add( node );
+    }
+
+
+    /**
+     * Adds a child node to this branch node at the head rather than the tail. 
+     * 
+     * @param node the child expression to add to this branch node
+     */
+    public void addNodeToHead( ExprNode node )
+    {
+        children.add( 0, node );
+    }
+
+
+    /**
+     * Gets the children below this BranchNode. We purposefully do not clone the
+     * array list so that backends can sort the order of children using their
+     * own search optimization algorithms. We want backends and other parts of
+     * the system to be able to induce side effects on the tree structure.
+     * 
+     * @return the list of child nodes under this branch node.
+     */
+    public List<ExprNode> getChildren()
+    {
+        return children;
+    }
+
+
+    /**
+     * Sets the list of children under this node.
+     * 
+     * @param list the list of children to set.
+     */
+    public void setChildren( List<ExprNode> list )
+    {
+        children = list;
+    }
+
+
+    /**
+     * Convenience method that gets the first child in the children array. Its
+     * very useful for NOT nodes since they only have one child by avoiding code
+     * that looks like: <code> ( ExprNode ) m_children.get( 0 ) </code>
+     * 
+     * @return the first child
+     */
+    public ExprNode getFirstChild()
+    {
+        if ( children.size() > 0 )
+        {
+            return children.get( 0 );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * @see ExprNode#accept(
+     *FilterVisitor)
+     *      
+     * @return The modified element
+     */
+    public final Object accept( FilterVisitor visitor )
+    {
+        if ( visitor.isPrefix() )
+        {
+            List<ExprNode> childrenList = visitor.getOrder( this, this.children );
+            ExprNode result = null;
+
+            if ( visitor.canVisit( this ) )
+            {
+                result = ( ExprNode ) visitor.visit( this );
+            }
+
+            for ( ExprNode node : childrenList )
+            {
+                node.accept( visitor );
+            }
+
+            return result;
+        }
+        else
+        {
+            if ( visitor.canVisit( this ) )
+            {
+                return visitor.visit( this );
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+
+        if ( children != null )
+        {
+            for ( ExprNode child : children )
+            {
+                h = h * 17 + child.hashCode();
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object other )
+    {
+        if ( this == other )
+        {
+            return true;
+        }
+
+        if ( !( other instanceof BranchNode ) )
+        {
+            return false;
+        }
+
+        if ( other.getClass() != this.getClass() )
+        {
+            return false;
+        }
+
+        BranchNode otherExprNode = ( BranchNode ) other;
+
+        List<ExprNode> otherChildren = otherExprNode.getChildren();
+
+        if ( otherChildren == children )
+        {
+            return true;
+        }
+
+        if ( children.size() != otherChildren.size() )
+        {
+            return false;
+        }
+
+        for ( int i = 0; i < children.size(); i++ )
+        {
+            ExprNode child = children.get( i );
+            ExprNode otherChild = children.get( i );
+
+            if ( !child.equals( otherChild ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/BranchNormalizedVisitor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/BranchNormalizedVisitor.java
new file mode 100644
index 0000000..a120b6c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/BranchNormalizedVisitor.java
@@ -0,0 +1,164 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.text.ParseException;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * Visitor which traverses a filter tree while normalizing the branch node
+ * order. Filter expressions can change the order of expressions in branch nodes
+ * without effecting the logical meaning of the expression. This visitor orders
+ * the children of expression tree branch nodes consistantly. It is really
+ * useful for comparing expression trees which may be altered for performance or
+ * altered because of codec idiosyncracies: for example the SNACC4J codec uses a
+ * hashmap to store expressions in a sequence which rearranges the order of
+ * children based on object hashcodes. We need this visitor to remove such
+ * inconsitancies in order hence normalizing the branch node's child order.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BranchNormalizedVisitor implements FilterVisitor
+{
+    public Object visit( ExprNode node )
+    {
+        if ( !( node instanceof BranchNode ) )
+        {
+            return null;
+        }
+
+        BranchNode branch = ( BranchNode ) node;
+
+        Comparator<ExprNode> nodeComparator = new NodeComparator();
+
+        Set<ExprNode> set = new TreeSet<ExprNode>( nodeComparator );
+
+        List<ExprNode> children = branch.getChildren();
+
+        for ( ExprNode child : branch.getChildren() )
+        {
+            if ( !child.isLeaf() )
+            {
+                ExprNode newChild = ( ExprNode ) visit( child );
+
+                if ( newChild != null )
+                {
+                    set.add( newChild );
+                }
+            }
+            else
+            {
+                set.add( child );
+            }
+        }
+
+        children.clear();
+
+        children.addAll( set );
+
+        return branch;
+    }
+
+
+    public boolean canVisit( ExprNode node )
+    {
+        return node instanceof BranchNode;
+    }
+
+
+    public boolean isPrefix()
+    {
+        return false;
+    }
+
+
+    public List<ExprNode> getOrder( BranchNode node, List<ExprNode> children )
+    {
+        return children;
+    }
+
+
+    /**
+     * Normalizes a filter expression to a canonical representation while
+     * retaining logical meaning of the expression.
+     * 
+     * @param filter the filter to normalize
+     * @return the normalized version of the filter
+     * @throws java.text.ParseException
+     *             if the filter is malformed
+     */
+    public static String getNormalizedFilter( SchemaManager schemaManager, String filter ) throws ParseException
+    {
+        ExprNode originalNode = FilterParser.parse( schemaManager, filter );
+
+        return getNormalizedFilter( originalNode );
+    }
+
+
+    /**
+     * Normalizes a filter expression to a canonical representation while
+     * retaining logical meaning of the expression.
+     * 
+     * @param filter
+     *            the filter to normalize
+     * @return the normalized String version of the filter
+     */
+    public static String getNormalizedFilter( ExprNode filter )
+    {
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+
+        ExprNode result = ( ExprNode ) visitor.visit( filter );
+
+        return result.toString().trim();
+    }
+
+    static class NodeComparator implements Comparator<ExprNode>
+    {
+        public int compare( ExprNode o1, ExprNode o2 )
+        {
+            StringBuilder buf = new StringBuilder();
+
+            buf.setLength( 0 );
+
+            String s1 = null;
+
+            buf.append( o1.toString() );
+
+            s1 = buf.toString();
+
+            buf.setLength( 0 );
+
+            String s2 = null;
+
+            buf.append( o2.toString() );
+
+            s2 = buf.toString();
+
+            return s1.compareTo( s2 );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/EqualityNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/EqualityNode.java
new file mode 100644
index 0000000..bdf1f88
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/EqualityNode.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * A assertion value node for Equality.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EqualityNode<T> extends SimpleNode<T>
+{
+    /**
+     * Creates a new Equality object.
+     * 
+     * @param attributeType the attributeType
+     * @param value the value to test for
+     */
+    public EqualityNode( AttributeType attributeType, Value<T> value )
+    {
+        super( attributeType, value, AssertionType.EQUALITY );
+    }
+
+
+    /**
+     * Creates a new Equality object.
+     * 
+     * @param attribute the attribute name
+     * @param value the value to test for
+     */
+    public EqualityNode( String attribute, Value<T> value )
+    {
+        super( attribute, value, AssertionType.EQUALITY );
+    }
+
+
+    /**
+     * @see Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( '(' );
+
+        if ( attributeType != null )
+        {
+            buf.append( attributeType.getName() );
+        }
+        else
+        {
+            buf.append( attribute );
+        }
+
+        buf.append( "=" );
+
+        Value<?> escapedValue = getEscapedValue();
+        if ( !escapedValue.isNull() )
+        {
+            buf.append( escapedValue );
+        }
+
+        buf.append( super.toString() );
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ExprNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ExprNode.java
new file mode 100644
index 0000000..b0911d7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ExprNode.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.filter;
+
+
+/**
+ * Root expression node interface which all expression nodes in the filter
+ * expression tree implement.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ExprNode extends Cloneable
+{
+    /**
+     * Gets an annotation on the tree by key.
+     * 
+     * @param key the annotation key.
+     * @return the annotation value.
+     */
+    Object get( Object key );
+
+
+    /**
+     * Sets a annotation key to a value.
+     * 
+     * @param key the annotation key.
+     * @param value the annotation value.
+     */
+    void set( String key, Object value );
+
+
+    /**
+     * Tests to see if this node is a leaf or branch node.
+     * 
+     * @return true if the node is a leaf,false otherwise
+     */
+    boolean isLeaf();
+
+
+    /**
+     * Tells if this Node is Schema aware.
+     * 
+     * @return true if the Node is SchemaAware
+     */
+    boolean isSchemaAware();
+
+
+    /**
+     * Gets the assertion type of this node. Make it possible to use switch
+     * statements on the node type.
+     * 
+     * @return the assertion type
+     */
+    AssertionType getAssertionType();
+
+
+    /**
+     * Recursively appends the refinement string representation of this node and its
+     * descendants in prefix notation to a buffer.
+     *
+     * TODO - Why is this here? Why not put it in some utility class?
+     * 
+     * @param buf the buffer to append to.
+     * @return The buffer in which the refinement has been appended
+     * @throws UnsupportedOperationException if this node isn't a part of a refinement.
+     */
+    StringBuilder printRefinementToBuffer( StringBuilder buf ) throws UnsupportedOperationException;
+
+
+    /**
+     * Element/node accept method for visitor pattern.
+     * 
+     * @param visitor the filter expression tree structure visitor
+     * TODO - what is this modified element ?
+     * @return the modified element
+     */
+    Object accept( FilterVisitor visitor );
+
+
+    /**
+     * Clone this expression node.
+     * 
+     * @return the cloned expression node
+     */
+    ExprNode clone();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ExtensibleNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ExtensibleNode.java
new file mode 100644
index 0000000..34d9611
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ExtensibleNode.java
@@ -0,0 +1,290 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * Filter expression tree node for extensible assertions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtensibleNode extends LeafNode
+{
+    /** The value of the attribute to match for */
+    private Value<?> value;
+
+    /** The matching rules id */
+    private String matchingRuleId;
+
+    /** The name of the dn attributes */
+    private boolean dnAttributes = false;
+
+
+    /**
+     * Creates a new emptyExtensibleNode object.
+     * 
+     * @param attributeType the attributeType associated with this node
+     */
+    public ExtensibleNode( AttributeType attributeType )
+    {
+        super( attributeType, AssertionType.EXTENSIBLE );
+
+        dnAttributes = false;
+    }
+
+
+    /**
+     * Creates a new emptyExtensibleNode object.
+     * 
+     * @param attribute the attribute associated with this node
+     */
+    public ExtensibleNode( String attribute )
+    {
+        super( attribute, AssertionType.EXTENSIBLE );
+
+        dnAttributes = false;
+    }
+
+
+    /**
+     * Creates a new ExtensibleNode object.
+     * 
+     * @param attributeType the attributeType used for the extensible assertion
+     * @param value the value to match for
+     * @param matchingRuleId the OID of the matching rule
+     * @param dnAttributes the dn attributes
+     */
+    public ExtensibleNode( AttributeType attributeType, Value<?> value, String matchingRuleId, boolean dnAttributes )
+    {
+        super( attributeType, AssertionType.EXTENSIBLE );
+
+        this.value = value;
+        this.matchingRuleId = matchingRuleId;
+        this.dnAttributes = dnAttributes;
+    }
+
+
+    /**
+     * Creates a new ExtensibleNode object.
+     * 
+     * @param attribute the attribute used for the extensible assertion
+     * @param value the value to match for
+     * @param matchingRuleId the OID of the matching rule
+     * @param dnAttributes the dn attributes
+     */
+    public ExtensibleNode( String attribute, Value<?> value, String matchingRuleId, boolean dnAttributes )
+    {
+        super( attribute, AssertionType.EXTENSIBLE );
+
+        this.value = value;
+        this.matchingRuleId = matchingRuleId;
+        this.dnAttributes = dnAttributes;
+    }
+
+
+    /**
+     * Makes a full clone in new memory space of the current node and children
+     * 
+     * @return the clone
+     */
+    @Override
+    public ExprNode clone()
+    {
+        ExprNode clone = ( ExprNode ) super.clone();
+
+        // Copy the value
+        if ( value != null )
+        {
+            ( ( ExtensibleNode ) clone ).value = value.clone();
+        }
+
+        return clone;
+    }
+
+
+    /**
+     * Gets the Dn attributes.
+     * 
+     * @return the dn attributes
+     */
+    public boolean hasDnAttributes()
+    {
+        return dnAttributes;
+    }
+
+
+    /**
+     * Set the dnAttributes flag
+     *
+     * @param dnAttributes The flag to set
+     */
+    public void setDnAttributes( boolean dnAttributes )
+    {
+        this.dnAttributes = dnAttributes;
+    }
+
+
+    /**
+     * Gets the matching rule id as an OID string.
+     * 
+     * @return the OID
+     */
+    public String getMatchingRuleId()
+    {
+        return matchingRuleId;
+    }
+
+
+    /**
+     * Sets the matching rule id as an OID string.
+     * 
+     * @param matchingRuleId The maching rule ID
+     */
+    public void setMatchingRuleId( String matchingRuleId )
+    {
+        this.matchingRuleId = matchingRuleId;
+    }
+
+
+    /**
+     * Gets the value.
+     * 
+     * @return the value
+     */
+    public final Value<?> getValue()
+    {
+        return value;
+    }
+
+
+    /** 
+     * @return representation of value, escaped for use in a filter if required 
+     */
+    public Value<?> getEscapedValue()
+    {
+        if ( value.isHumanReadable() )
+        {
+            return escapeFilterValue( value );
+        }
+
+        return value;
+    }
+
+
+    /**
+     * Sets the value.
+     * 
+     * @param value the value
+     */
+    public final void setValue( Value<?> value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof ExtensibleNode ) )
+        {
+            return false;
+        }
+        ExtensibleNode that = ( ExtensibleNode ) obj;
+
+        if ( dnAttributes != that.dnAttributes )
+        {
+            return false;
+        }
+        if ( !matchingRuleId.equals( that.matchingRuleId ) )
+        {
+            return false;
+        }
+        if ( !value.equals( that.value ) )
+        {
+            return false;
+        }
+
+        return super.equals( obj );
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + ( dnAttributes ? 1 : 0 );
+        h = h * 17 + matchingRuleId.hashCode();
+        h = h * 17 + value.hashCode();
+
+        return h;
+    }
+
+
+    /**
+     * @see java.lang.Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( '(' );
+
+        if ( attributeType != null )
+        {
+            buf.append( attributeType.getName() );
+        }
+        else
+        {
+            buf.append( attribute );
+        }
+
+        buf.append( "-" );
+        buf.append( dnAttributes );
+        buf.append( "-EXTENSIBLE-" );
+        buf.append( matchingRuleId );
+        buf.append( "-" );
+        buf.append( value );
+
+        buf.append( super.toString() );
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterEncoder.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterEncoder.java
new file mode 100644
index 0000000..9283a79
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterEncoder.java
@@ -0,0 +1,254 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.text.Format;
+import java.text.MessageFormat;
+
+
+/**
+ * An encoder for LDAP filters.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class FilterEncoder
+{
+    private static final String[] EMPTY = new String[0];
+
+
+    private FilterEncoder()
+    {
+    }
+
+
+    /**
+     * Formats a filter and handles encoding of special characters in the value arguments using the
+     * &lt;valueencoding&gt; rule as described in <a href="http://www.ietf.org/rfc/rfc4515.txt">RFC 4515</a>.
+     * <p>
+     * Example of filter template format: <code>(&(cn={0})(uid={1}))</code>
+     * 
+     * @param filterTemplate the filter with placeholders
+     * @param values the values to encode and substitute
+     * @return the formatted filter with escaped values
+     * @throws IllegalArgumentException if the number of values does not match the number of placeholders in the template
+     */
+    public static String format( String filterTemplate, String... values ) throws IllegalArgumentException
+    {
+        if ( values == null )
+        {
+            values = EMPTY;
+        }
+
+        MessageFormat mf = new MessageFormat( filterTemplate );
+
+        // check element count and argument count
+        Format[] formats = mf.getFormatsByArgumentIndex();
+        if ( formats.length != values.length )
+        {
+            // TODO: I18n
+            String msg = "Filter template {0} has {1} placeholders but {2} arguments provided.";
+            throw new IllegalArgumentException( MessageFormat.format( msg, filterTemplate, formats.length,
+                values.length ) );
+        }
+
+        // encode arguments
+        for ( int i = 0; i < values.length; i++ )
+        {
+            values[i] = encodeFilterValue( values[i] );
+        }
+
+        // format the filter
+        String format = mf.format( values );
+        return format;
+    }
+
+
+    /**
+     * Handles encoding of special characters in LDAP search filter assertion values using the
+     * &lt;valueencoding&gt; rule as described in <a href="http://www.ietf.org/rfc/rfc4515.txt">RFC 4515</a>.
+     *
+     * @param value Right hand side of "attrId=value" assertion occurring in an LDAP search filter.
+     * @return Escaped version of <code>value</code>
+     */
+    public static String encodeFilterValue( String value )
+    {
+        StringBuilder sb = new StringBuilder( value.length() );
+        boolean escaped = false;
+        boolean hexPair = false;
+        char hex = '\0';
+
+        for ( int i = 0; i < value.length(); i++ )
+        {
+            char ch = value.charAt( i );
+
+            switch ( ch )
+            {
+                case '*':
+                    if ( escaped )
+                    {
+                        sb.append( "\\5C" );
+
+                        if ( hexPair )
+                        {
+                            sb.append( hex );
+                            hexPair = false;
+                        }
+
+                        escaped = false;
+                    }
+
+                    sb.append( "\\2A" );
+                    break;
+
+                case '(':
+                    if ( escaped )
+                    {
+                        sb.append( "\\5C" );
+
+                        if ( hexPair )
+                        {
+                            sb.append( hex );
+                            hexPair = false;
+                        }
+
+                        escaped = false;
+                    }
+
+                    sb.append( "\\28" );
+                    break;
+
+                case ')':
+                    if ( escaped )
+                    {
+                        sb.append( "\\5C" );
+
+                        if ( hexPair )
+                        {
+                            sb.append( hex );
+                            hexPair = false;
+                        }
+
+                        escaped = false;
+                    }
+
+                    sb.append( "\\29" );
+                    break;
+
+                case '\0':
+                    if ( escaped )
+                    {
+                        sb.append( "\\5C" );
+
+                        if ( hexPair )
+                        {
+                            sb.append( hex );
+                            hexPair = false;
+                        }
+
+                        escaped = false;
+                    }
+
+                    sb.append( "\\00" );
+                    break;
+
+                case '\\':
+                    if ( escaped )
+                    {
+                        sb.append( "\\5C" );
+                        escaped = false;
+                    }
+                    else
+                    {
+                        escaped = true;
+                        hexPair = false;
+                    }
+
+                    break;
+
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                case 'a':
+                case 'b':
+                case 'c':
+                case 'd':
+                case 'e':
+                case 'f':
+                case 'A':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'E':
+                case 'F':
+                    if ( escaped )
+                    {
+                        if ( hexPair )
+                        {
+                            sb.append( '\\' ).append( hex ).append( ch );
+                            escaped = false;
+                            hexPair = false;
+                        }
+                        else
+                        {
+                            hexPair = true;
+                            hex = ch;
+                        }
+                    }
+                    else
+                    {
+                        sb.append( ch );
+                    }
+
+                    break;
+
+                default:
+                    if ( escaped )
+                    {
+                        sb.append( "\\5C" );
+
+                        if ( hexPair )
+                        {
+                            sb.append( hex );
+                            hexPair = false;
+                        }
+
+                        escaped = false;
+                    }
+
+                    sb.append( ch );
+            }
+        }
+
+        if ( escaped )
+        {
+            sb.append( "\\5C" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterParser.java
new file mode 100644
index 0000000..fca526c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterParser.java
@@ -0,0 +1,1065 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.AttributeUtils;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Hex;
+import org.apache.directory.api.util.Position;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.Unicode;
+
+
+/**
+ * This class parse a Ldap filter. The grammar is given in RFC 4515
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class FilterParser
+{
+    private FilterParser()
+    {
+    }
+
+
+    /**
+     * Parse an extensible
+     *
+     * extensible     = ( attr [":dn"] [':' oid] ":=" assertionvalue )
+     *                  / ( [":dn"] ':' oid ":=" assertionvalue )
+     * matchingrule   = ":" oid
+     */
+    private static ExprNode parseExtensible( SchemaManager schemaManager, String attribute, byte[] filter,
+        Position pos, boolean relaxed ) throws LdapException, ParseException
+    {
+        ExtensibleNode node = null;
+
+        if ( schemaManager != null )
+        {
+            AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+            if ( attributeType != null )
+            {
+                node = new ExtensibleNode( attributeType );
+            }
+            else
+            {
+                return UndefinedNode.UNDEFINED_NODE;
+            }
+        }
+        else
+        {
+            node = new ExtensibleNode( attribute );
+        }
+
+        if ( attribute != null )
+        {
+            // First check if we have a ":dn"
+            if ( Strings.areEquals( filter, pos.start, "dn" ) >= 0 )
+            {
+                // Set the dnAttributes flag and move forward in the string
+                node.setDnAttributes( true );
+                pos.start += 2;
+            }
+            else
+            {
+                // Push back the ':'
+                pos.start--;
+            }
+
+            // Do we have a MatchingRule ?
+            if ( Strings.byteAt( filter, pos.start ) == ':' )
+            {
+                pos.start++;
+
+                if ( Strings.byteAt( filter, pos.start ) == '=' )
+                {
+                    pos.start++;
+
+                    // Get the assertionValue
+                    node.setValue( parseAssertionValue( schemaManager, filter, pos ) );
+
+                    return node;
+                }
+                else
+                {
+                    String matchingRuleId = AttributeUtils.parseAttribute( filter, pos, false, relaxed );
+
+                    node.setMatchingRuleId( matchingRuleId );
+
+                    if ( Strings.areEquals( filter, pos.start, ":=" ) >= 0 )
+                    {
+                        pos.start += 2;
+
+                        // Get the assertionValue
+                        node.setValue( parseAssertionValue( schemaManager, filter, pos ) );
+
+                        return node;
+                    }
+                    else
+                    {
+                        throw new ParseException( I18n.err( I18n.ERR_04146 ), pos.start );
+                    }
+                }
+            }
+            else
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04147 ), pos.start );
+            }
+        }
+        else
+        {
+            // No attribute
+            boolean oidRequested = false;
+
+            // First check if we have a ":dn"
+            if ( Strings.areEquals( filter, pos.start, ":dn" ) >= 0 )
+            {
+                // Set the dnAttributes flag and move forward in the string
+                node.setDnAttributes( true );
+                pos.start += 3;
+            }
+            else
+            {
+                oidRequested = true;
+            }
+
+            // Do we have a MatchingRule ?
+            if ( Strings.byteAt( filter, pos.start ) == ':' )
+            {
+                pos.start++;
+
+                if ( Strings.byteAt( filter, pos.start ) == '=' )
+                {
+                    if ( oidRequested )
+                    {
+                        throw new ParseException( I18n.err( I18n.ERR_04148 ), pos.start );
+                    }
+
+                    pos.start++;
+
+                    // Get the assertionValue
+                    node.setValue( parseAssertionValue( schemaManager, null, filter, pos ) );
+
+                    return node;
+                }
+                else
+                {
+                    String matchingRuleId = AttributeUtils.parseAttribute( filter, pos, false, relaxed );
+
+                    node.setMatchingRuleId( matchingRuleId );
+
+                    if ( Strings.areEquals( filter, pos.start, ":=" ) >= 0 )
+                    {
+                        pos.start += 2;
+
+                        // Get the assertionValue
+                        node.setValue( parseAssertionValue( schemaManager, null, filter, pos ) );
+
+                        return node;
+                    }
+                    else
+                    {
+                        throw new ParseException( I18n.err( I18n.ERR_04146 ), pos.start );
+                    }
+                }
+            }
+            else
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04147 ), pos.start );
+            }
+        }
+    }
+
+
+    /**
+     * An assertion value :
+     * assertionvalue = valueencoding
+     * valueencoding  = 0*(normal / escaped)
+     * normal         = UTF1SUBSET / UTFMB
+     * escaped        = '\' HEX HEX
+     * HEX            = '0'-'9' / 'A'-'F' / 'a'-'f'
+     * UTF1SUBSET     = %x01-27 / %x2B-5B / %x5D-7F (Everything but '\0', '*', '(', ')' and '\')
+     * UTFMB          = UTF2 / UTF3 / UTF4
+     * UTF0           = %x80-BF
+     * UTF2           = %xC2-DF UTF0
+     * UTF3           = %xE0 %xA0-BF UTF0 / %xE1-EC UTF0 UTF0 / %xED %x80-9F UTF0 / %xEE-EF UTF0 UTF0
+     * UTF4           = %xF0 %x90-BF UTF0 UTF0 / %xF1-F3 UTF0 UTF0 UTF0 / %xF4 %x80-8F UTF0 UTF0
+     *
+     * With the specific constraints (RFC 4515):
+     *    "The <valueencoding> rule ensures that the entire filter string is a"
+     *    "valid UTF-8 string and provides that the octets that represent the"
+     *    "ASCII characters "*" (ASCII 0x2a), "(" (ASCII 0x28), ")" (ASCII"
+     *    "0x29), "\" (ASCII 0x5c), and NUL (ASCII 0x00) are represented as a"
+     *    "backslash "\" (ASCII 0x5c) followed by the two hexadecimal digits"
+     *    "representing the value of the encoded octet."
+     *
+     * The incoming String is already transformed from UTF-8 to unicode, so we must assume that the
+     * grammar we have to check is the following :
+     *
+     * assertionvalue = valueencoding
+     * valueencoding  = 0*(normal / escaped)
+     * normal         = unicodeSubset
+     * escaped        = '\' HEX HEX
+     * HEX            = '0'-'9' / 'A'-'F' / 'a'-'f'
+     * unicodeSubset     = %x01-27 / %x2B-5B / %x5D-FFFF
+     * @throws LdapInvalidAttributeValueException 
+     */
+    private static Value<?> parseAssertionValue( SchemaManager schemaManager, String attribute, byte[] filter,
+        Position pos ) throws ParseException
+    {
+        byte b = Strings.byteAt( filter, pos.start );
+
+        // Create a buffer big enough to contain the value once converted
+        byte[] value = new byte[filter.length - pos.start];
+        int current = 0;
+
+        do
+        {
+            if ( Unicode.isUnicodeSubset( b ) )
+            {
+                value[current++] = b;
+                pos.start++;
+            }
+            else if ( Strings.isCharASCII( filter, pos.start, '\\' ) )
+            {
+                // Maybe an escaped
+                pos.start++;
+
+                // First hex
+                if ( Chars.isHex( filter, pos.start ) )
+                {
+                    pos.start++;
+                }
+                else
+                {
+                    throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
+                }
+
+                // second hex
+                if ( Chars.isHex( filter, pos.start ) )
+                {
+                    value[current++] = Hex.getHexValue( filter[pos.start - 1], filter[pos.start] );
+                    pos.start++;
+                }
+                else
+                {
+                    throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
+                }
+            }
+            else
+            {
+                // not a valid char, so let's get out
+                break;
+            }
+
+            b = Strings.byteAt( filter, pos.start );
+        }
+        while ( b != '\0' );
+
+        if ( current != 0 )
+        {
+            byte[] result = new byte[current];
+            System.arraycopy( value, 0, result, 0, current );
+
+            if ( schemaManager != null )
+            {
+                AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                if ( attributeType == null )
+                {
+                    return new BinaryValue( result );
+                }
+
+                if ( attributeType.getSyntax().isHumanReadable() )
+                {
+                    return new StringValue( Strings.utf8ToString( result ) );
+                }
+                else
+                {
+                    return new BinaryValue( result );
+                }
+            }
+            else
+            {
+                return new BinaryValue( result );
+            }
+        }
+        else
+        {
+            if ( schemaManager != null )
+            {
+                AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                if ( attributeType.getEquality().getSyntax().isHumanReadable() )
+                {
+                    return new StringValue( ( String ) null );
+                }
+                else
+                {
+                    return new BinaryValue( null );
+                }
+            }
+            else
+            {
+                return new BinaryValue( ( byte[] ) null );
+            }
+        }
+    }
+
+
+    /**
+     * An assertion value :
+     * assertionvalue = valueencoding
+     * valueencoding  = 0*(normal / escaped)
+     * normal         = UTF1SUBSET / UTFMB
+     * escaped        = '\' HEX HEX
+     * HEX            = '0'-'9' / 'A'-'F' / 'a'-'f'
+     * UTF1SUBSET     = %x01-27 / %x2B-5B / %x5D-7F (Everything but '\0', '*', '(', ')' and '\')
+     * UTFMB          = UTF2 / UTF3 / UTF4
+     * UTF0           = %x80-BF
+     * UTF2           = %xC2-DF UTF0
+     * UTF3           = %xE0 %xA0-BF UTF0 / %xE1-EC UTF0 UTF0 / %xED %x80-9F UTF0 / %xEE-EF UTF0 UTF0
+     * UTF4           = %xF0 %x90-BF UTF0 UTF0 / %xF1-F3 UTF0 UTF0 UTF0 / %xF4 %x80-8F UTF0 UTF0
+     *
+     * With the specific constraints (RFC 4515):
+     *    "The <valueencoding> rule ensures that the entire filter string is a"
+     *    "valid UTF-8 string and provides that the octets that represent the"
+     *    "ASCII characters "*" (ASCII 0x2a), "(" (ASCII 0x28), ")" (ASCII"
+     *    "0x29), "\" (ASCII 0x5c), and NUL (ASCII 0x00) are represented as a"
+     *    "backslash "\" (ASCII 0x5c) followed by the two hexadecimal digits"
+     *    "representing the value of the encoded octet."
+     *
+     * The incoming String is already transformed from UTF-8 to unicode, so we must assume that the
+     * grammar we have to check is the following :
+     *
+     * assertionvalue = valueencoding
+     * valueencoding  = 0*(normal / escaped)
+     * normal         = unicodeSubset
+     * escaped        = '\' HEX HEX
+     * HEX            = '0'-'9' / 'A'-'F' / 'a'-'f'
+     * unicodeSubset     = %x01-27 / %x2B-5B / %x5D-FFFF
+     */
+    private static Value<?> parseAssertionValue( SchemaManager schemaManager, byte[] filter, Position pos )
+        throws ParseException
+    {
+        byte b = Strings.byteAt( filter, pos.start );
+
+        // Create a buffer big enough to contain the value once converted
+        byte[] value = new byte[filter.length - pos.start];
+        int current = 0;
+
+        do
+        {
+            if ( Unicode.isUnicodeSubset( b ) )
+            {
+                value[current++] = b;
+                pos.start++;
+            }
+            else if ( Strings.isCharASCII( filter, pos.start, '\\' ) )
+            {
+                // Maybe an escaped
+                pos.start++;
+
+                // First hex
+                if ( Chars.isHex( filter, pos.start ) )
+                {
+                    pos.start++;
+                }
+                else
+                {
+                    throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
+                }
+
+                // second hex
+                if ( Chars.isHex( filter, pos.start ) )
+                {
+                    value[current++] = Hex.getHexValue( filter[pos.start - 1], filter[pos.start] );
+                    pos.start++;
+                }
+                else
+                {
+                    throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
+                }
+            }
+            else
+            {
+                // not a valid char, so let's get out
+                break;
+            }
+
+            b = Strings.byteAt( filter, pos.start );
+        }
+        while ( b != '\0' );
+
+        if ( current != 0 )
+        {
+            byte[] result = new byte[current];
+            System.arraycopy( value, 0, result, 0, current );
+
+            return new BinaryValue( result );
+        }
+        else
+        {
+            return new BinaryValue( null );
+        }
+    }
+
+
+    /**
+     * Parse a substring
+     */
+    private static ExprNode parseSubstring( SchemaManager schemaManager, String attribute, Value<?> initial,
+        byte[] filter, Position pos )
+        throws ParseException, LdapException
+    {
+        if ( Strings.isCharASCII( filter, pos.start, '*' ) )
+        {
+            // We have found a '*' : this is a substring
+            SubstringNode node = null;
+
+            if ( schemaManager != null )
+            {
+                AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute );
+
+                if ( attributeType != null )
+                {
+                    node = new SubstringNode( schemaManager.lookupAttributeTypeRegistry( attribute ) );
+                }
+                else
+                {
+                    return null;
+                }
+            }
+            else
+            {
+                node = new SubstringNode( attribute );
+            }
+
+            if ( ( initial != null ) && !initial.isNull() )
+            {
+                // We have a substring starting with a value : val*...
+                // Set the initial value. It must be a String
+                String initialStr = initial.getString();
+                node.setInitial( initialStr );
+            }
+
+            pos.start++;
+
+            //
+            while ( true )
+            {
+                Value<?> assertionValue = parseAssertionValue( schemaManager, attribute, filter, pos );
+
+                // Is there anything else but a ')' after the value ?
+                if ( Strings.isCharASCII( filter, pos.start, ')' ) )
+                {
+                    // Nope : as we have had [initial] '*' (any '*' ) *,
+                    // this is the final
+                    if ( !assertionValue.isNull() )
+                    {
+                        String finalStr = assertionValue.getString();
+                        node.setFinal( finalStr );
+                    }
+
+                    return node;
+                }
+                else if ( Strings.isCharASCII( filter, pos.start, '*' ) )
+                {
+                    // We have a '*' : it's an any
+                    // If the value is empty, that means we have more than
+                    // one consecutive '*' : do nothing in this case.
+                    if ( !assertionValue.isNull() )
+                    {
+                        String anyStr = assertionValue.getString();
+                        node.addAny( anyStr );
+                    }
+
+                    pos.start++;
+                }
+                else
+                {
+                    // This is an error
+                    throw new ParseException( I18n.err( I18n.ERR_04150 ), pos.start );
+                }
+            }
+        }
+        else
+        {
+            // This is an error
+            throw new ParseException( I18n.err( I18n.ERR_04150 ), pos.start );
+        }
+    }
+
+
+    /**
+     * Here is the grammar to parse :
+     *
+     * simple    ::= '=' assertionValue
+     * present   ::= '=' '*'
+     * substring ::= '=' [initial] any [final]
+     * initial   ::= assertionValue
+     * any       ::= '*' ( assertionValue '*')*
+     *
+     * As we can see, there is an ambiguity in the grammar : attr=* can be
+     * seen as a present or as a substring. As stated in the RFC :
+     *
+     * "Note that although both the <substring> and <present> productions in"
+     * "the grammar above can produce the "attr=*" construct, this construct"
+     * "is used only to denote a presence filter." (RFC 4515, 3)
+     *
+     * We have also to consider the difference between a substring and the
+     * equality node : this last node does not contain a '*'
+     *
+     * @param attributeType
+     * @param filter
+     * @param pos
+     * @return
+     */
+    @SuppressWarnings(
+        { "rawtypes", "unchecked" })
+    private static ExprNode parsePresenceEqOrSubstring( SchemaManager schemaManager, String attribute, byte[] filter,
+        Position pos )
+        throws ParseException, LdapException
+    {
+        if ( Strings.isCharASCII( filter, pos.start, '*' ) )
+        {
+            // To be a present node, the next char should be a ')'
+            pos.start++;
+
+            if ( Strings.isCharASCII( filter, pos.start, ')' ) )
+            {
+                // This is a present node
+                if ( schemaManager != null )
+                {
+                    AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                    if ( attributeType != null )
+                    {
+                        return new PresenceNode( attributeType );
+                    }
+                    else
+                    {
+                        return null;
+                    }
+                }
+                else
+                {
+                    return new PresenceNode( attribute );
+                }
+            }
+            else
+            {
+                // Definitively a substring with no initial or an error
+                // Push back the '*' on the string
+                pos.start--;
+                return parseSubstring( schemaManager, attribute, null, filter, pos );
+            }
+        }
+        else if ( Strings.isCharASCII( filter, pos.start, ')' ) )
+        {
+            // An empty equality Node
+            if ( schemaManager != null )
+            {
+                AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                if ( attributeType != null )
+                {
+                    return new EqualityNode( attributeType, new BinaryValue( ( byte[] ) null ) );
+                }
+
+                else
+                {
+                    return null;
+                }
+            }
+            else
+            {
+                return new EqualityNode( attribute, new BinaryValue( ( byte[] ) null ) );
+            }
+        }
+        else
+        {
+            // A substring or an equality node
+            Value<?> value = parseAssertionValue( schemaManager, attribute, filter, pos );
+
+            // Is there anything else but a ')' after the value ?
+            if ( Strings.isCharASCII( filter, pos.start, ')' ) )
+            {
+                // This is an equality node
+                if ( schemaManager != null )
+                {
+                    AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                    if ( attributeType != null )
+                    {
+                        return new EqualityNode( attributeType, value );
+                    }
+                    else
+                    {
+                        return null;
+                    }
+                }
+                else
+                {
+                    return new EqualityNode( attribute, value );
+                }
+            }
+
+            return parseSubstring( schemaManager, attribute, value, filter, pos );
+        }
+    }
+
+
+    /**
+     * Parse the following grammar :
+     * item           = simple / present / substring / extensible
+     * simple         = attr filtertype assertionvalue
+     * filtertype     = '=' / '~=' / '>=' / '<='
+     * present        = attr '=' '*'
+     * substring      = attr '=' [initial] any [final]
+     * extensible     = ( attr [":dn"] [':' oid] ":=" assertionvalue )
+     *                  / ( [":dn"] ':' oid ":=" assertionvalue )
+     * matchingrule   = ":" oid
+     *
+     * An item starts with an attribute or a colon.
+     */
+    @SuppressWarnings(
+        { "rawtypes", "unchecked" })
+    private static ExprNode parseItem( SchemaManager schemaManager, byte[] filter, Position pos, byte b,
+        boolean relaxed ) throws ParseException, LdapException
+    {
+        String attribute = null;
+
+        if ( b == '\0' )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04151 ), pos.start );
+        }
+
+        if ( b == ':' )
+        {
+            // If we have a colon, then the item is an extensible one
+            return parseExtensible( schemaManager, null, filter, pos, relaxed );
+        }
+        else
+        {
+            // We must have an attribute
+            attribute = AttributeUtils.parseAttribute( filter, pos, true, relaxed );
+
+            // Now, we may have a present, substring, simple or an extensible
+            b = Strings.byteAt( filter, pos.start );
+
+            switch ( b )
+            {
+                case '=':
+                    // It can be a presence, an equal or a substring
+                    pos.start++;
+                    return parsePresenceEqOrSubstring( schemaManager, attribute, filter, pos );
+
+                case '~':
+                    // Approximate node
+                    pos.start++;
+
+                    // Check that we have a '='
+                    if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
+                    {
+                        throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
+                    }
+
+                    pos.start++;
+
+                    // Parse the value and create the node
+                    if ( schemaManager == null )
+                    {
+                        return new ApproximateNode( attribute, parseAssertionValue( schemaManager, attribute, filter,
+                            pos ) );
+                    }
+                    else
+                    {
+                        AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                        if ( attributeType != null )
+                        {
+                            return new ApproximateNode( attributeType, parseAssertionValue( schemaManager, attribute,
+                                filter, pos ) );
+                        }
+                        else
+                        {
+                            return UndefinedNode.UNDEFINED_NODE;
+                        }
+                    }
+
+                case '>':
+                    // Greater or equal node
+                    pos.start++;
+
+                    // Check that we have a '='
+                    if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
+                    {
+                        throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
+                    }
+
+                    pos.start++;
+
+                    // Parse the value and create the node
+                    if ( schemaManager == null )
+                    {
+                        return new GreaterEqNode( attribute,
+                            parseAssertionValue( schemaManager, attribute, filter, pos ) );
+                    }
+                    else
+                    {
+                        AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                        if ( attributeType != null )
+                        {
+                            return new GreaterEqNode( attributeType, parseAssertionValue( schemaManager, attribute,
+                                filter, pos ) );
+                        }
+                        else
+                        {
+                            return UndefinedNode.UNDEFINED_NODE;
+                        }
+                    }
+
+                case '<':
+                    // Less or equal node
+                    pos.start++;
+
+                    // Check that we have a '='
+                    if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
+                    {
+                        throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
+                    }
+
+                    pos.start++;
+
+                    // Parse the value and create the node
+                    if ( schemaManager == null )
+                    {
+                        return new LessEqNode( attribute, parseAssertionValue( schemaManager, attribute, filter, pos ) );
+                    }
+                    else
+                    {
+                        AttributeType attributeType = schemaManager.getAttributeType( attribute );
+
+                        if ( attributeType != null )
+                        {
+                            return new LessEqNode( attributeType, parseAssertionValue( schemaManager, attribute,
+                                filter, pos ) );
+                        }
+                        else
+                        {
+                            return UndefinedNode.UNDEFINED_NODE;
+                        }
+                    }
+
+                case ':':
+                    // An extensible node
+                    pos.start++;
+                    return parseExtensible( schemaManager, attribute, filter, pos, relaxed );
+
+                default:
+                    // This is an error
+                    throw new ParseException( I18n.err( I18n.ERR_04153 ), pos.start );
+            }
+        }
+    }
+
+
+    /**
+     * Parse AND, OR and NOT nodes :
+     *
+     * and            = '&' filterlist
+     * or             = '|' filterlist
+     * not            = '!' filter
+     * filterlist     = 1*filter
+     *
+     * @return
+     */
+    private static ExprNode parseBranchNode( SchemaManager schemaManager, ExprNode node, byte[] filter, Position pos,
+        boolean relaxed ) throws ParseException, LdapException
+    {
+        BranchNode branchNode = ( BranchNode ) node;
+        int nbChildren = 0;
+
+        // We must have at least one filter
+        ExprNode child = parseFilterInternal( schemaManager, filter, pos, relaxed );
+
+        if ( child != UndefinedNode.UNDEFINED_NODE )
+        {
+            // Add the child to the node children
+            branchNode.addNode( child );
+
+            if ( branchNode instanceof NotNode )
+            {
+                return node;
+            }
+
+            nbChildren++;
+        }
+        else if ( node instanceof AndNode )
+        {
+            return UndefinedNode.UNDEFINED_NODE;
+        }
+
+        // Now, iterate recusively though all the remaining filters, if any
+        while ( ( child = parseFilterInternal( schemaManager, filter, pos, relaxed ) ) != UndefinedNode.UNDEFINED_NODE )
+        {
+            // Add the child to the node children if not null
+            if ( child != null )
+            {
+                branchNode.addNode( child );
+                nbChildren++;
+            }
+            else if ( node instanceof AndNode )
+            {
+                return UndefinedNode.UNDEFINED_NODE;
+            }
+        }
+
+        if ( nbChildren > 0 )
+        {
+            return node;
+        }
+        else
+        {
+            return UndefinedNode.UNDEFINED_NODE;
+        }
+    }
+
+
+    /**
+     * filtercomp     = and / or / not / item
+     * and            = '&' filterlist
+     * or             = '|' filterlist
+     * not            = '!' filter
+     * item           = simple / present / substring / extensible
+     * simple         = attr filtertype assertionvalue
+     * present        = attr EQUALS ASTERISK
+     * substring      = attr EQUALS [initial] any [final]
+     * extensible     = ( attr [dnattrs]
+     *                    [matchingrule] COLON EQUALS assertionvalue )
+     *                    / ( [dnattrs]
+     *                         matchingrule COLON EQUALS assertionvalue )
+     */
+    private static ExprNode parseFilterComp( SchemaManager schemaManager, byte[] filter, Position pos,
+        boolean relaxed ) throws ParseException, LdapException
+    {
+        ExprNode node = null;
+
+        if ( pos.start == pos.length )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04154 ), pos.start );
+        }
+
+        byte c = Strings.byteAt( filter, pos.start );
+
+        switch ( c )
+        {
+            case '&':
+                // This is a AND node
+                pos.start++;
+                node = new AndNode();
+                node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
+                break;
+
+            case '|':
+                // This is an OR node
+                pos.start++;
+                node = new OrNode();
+                node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
+                break;
+
+            case '!':
+                // This is a NOT node
+                pos.start++;
+                node = new NotNode();
+                node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
+                break;
+
+            default:
+                // This is an item
+                node = parseItem( schemaManager, filter, pos, c, relaxed );
+                break;
+
+        }
+
+        return node;
+    }
+
+
+    /**
+     * Pasre the grammar rule :
+     * filter ::= '(' filterComp ')'
+     */
+    private static ExprNode parseFilterInternal( SchemaManager schemaManager, byte[] filter, Position pos,
+        boolean relaxed ) throws ParseException, LdapException
+    {
+        // Check for the left '('
+        if ( !Strings.isCharASCII( filter, pos.start, '(' ) )
+        {
+            // No more node, get out
+            if ( ( pos.start == 0 ) && ( pos.length != 0 ) )
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04155 ), 0 );
+            }
+            else
+            {
+                return UndefinedNode.UNDEFINED_NODE;
+            }
+        }
+
+        pos.start++;
+
+        // parse the filter component
+        ExprNode node = parseFilterComp( schemaManager, filter, pos, relaxed );
+
+        if ( node == UndefinedNode.UNDEFINED_NODE )
+        {
+            return UndefinedNode.UNDEFINED_NODE;
+        }
+
+        // Check that we have a right ')'
+        if ( !Strings.isCharASCII( filter, pos.start, ')' ) )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04157 ), pos.start );
+        }
+
+        pos.start++;
+
+        return node;
+    }
+
+
+    /**
+     * Parses a search filter from it's string representation to an expression node object.
+     * 
+     * @param filter the search filter in it's string representation
+     * @return the expression node object
+     */
+    public static ExprNode parse( String filter ) throws ParseException
+    {
+        return parse( null, Strings.getBytesUtf8( filter ), false );
+    }
+
+
+    /**
+     * @see FilterParser#parse(String)
+     */
+    public static ExprNode parse( byte[] filter ) throws ParseException
+    {
+        return parse( null, filter, false );
+    }
+
+
+    /**
+     * @see FilterParser#parse(String)
+     */
+    public static ExprNode parse( SchemaManager schemaManager, String filter ) throws ParseException
+    {
+        return parse( schemaManager, Strings.getBytesUtf8( filter ), false );
+    }
+
+
+    /**
+     * @see FilterParser#parse(String)
+     */
+    public static ExprNode parse( SchemaManager schemaManager, byte[] filter ) throws ParseException
+    {
+        return parse( schemaManager, filter, false );
+    }
+
+
+    private static ExprNode parse( SchemaManager schemaManager, byte[] filter, boolean relaxed )
+        throws ParseException
+    {
+        // The filter must not be null. This is a defensive test
+        if ( Strings.isEmpty( filter ) )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04158 ), 0 );
+        }
+
+        Position pos = new Position();
+        pos.start = 0;
+        pos.end = 0;
+        pos.length = filter.length;
+
+        try
+        {
+            return parseFilterInternal( schemaManager, filter, pos, relaxed );
+        }
+        catch ( LdapException le )
+        {
+            throw new ParseException( le.getMessage(), pos.start );
+        }
+    }
+
+
+    /**
+     * @see FilterParser#parse(String)
+     */
+    public static ExprNode parse( SchemaManager schemaManager, String filter, Position pos ) throws ParseException
+    {
+        // The filter must not be null. This is a defensive test
+        if ( Strings.isEmpty( filter ) )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04158 ), 0 );
+        }
+
+        pos.start = 0;
+        pos.end = 0;
+        pos.length = filter.length();
+
+        try
+        {
+            return parseFilterInternal( schemaManager, Strings.getBytesUtf8( filter ), pos, false );
+        }
+        catch ( LdapException le )
+        {
+            throw new ParseException( le.getMessage(), pos.start );
+        }
+    }
+
+
+    /**
+     * Parses a search filter from it's string representation to an expression node object.
+     * 
+     * In <code>relaxed</code> mode the filter may violate RFC 4515, e.g. the underscore in attribute names is allowed.
+     * 
+     * @param filter the search filter in it's string representation
+     * @param relaxed <code>true</code> to parse the filter in relaxed mode
+     * @return the expression node object
+     */
+    public static ExprNode parse( String filter, boolean relaxed ) throws ParseException
+    {
+        return parse( null, Strings.getBytesUtf8( filter ), relaxed );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterVisitor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterVisitor.java
new file mode 100644
index 0000000..0cac107
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/FilterVisitor.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.util.List;
+
+
+/**
+ * Filter expression tree node visitor interface. Note that this is a variation
+ * of the extrinsic visitor variation. It has the following advantages over the
+ * standard visitor pattern:
+ * <ul>
+ * <li>Visitor takes responsibility that a visitor can visit a node</li>
+ * <li>Each visitor knows which types of concrete classes it can visit</li>
+ * <li>New visitors can be created without changing the node class</li>
+ * <li>New node classes can be added without having to change old visitors</li>
+ * <li>Visitation order can be controled in every respect:</li>
+ * <ul>
+ * <li>Visitation rejection with canVisit() and/or getOrder()</li>
+ * <li>Recursive visitation ordering with isPrefix()</li>
+ * <li>Child visitation ordering with getOrder()</li>
+ * </ul>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface FilterVisitor
+{
+    /**
+     * Visits a filter expression AST using a specific visitation order.
+     * 
+     * @param node the node to visit
+     * @return node the resulting modified node
+     */
+    Object visit( ExprNode node );
+
+
+    /**
+     * Checks to see if a node can be visited.
+     * 
+     * @param node the node to be visited
+     * @return whether or node the node should be visited
+     */
+    boolean canVisit( ExprNode node );
+
+
+    /**
+     * Determines whether the visitation order is prefix or postfix.
+     * 
+     * @return true if the visitation is in prefix order, false otherwise.
+     */
+    boolean isPrefix();
+
+
+    /**
+     * Get the array of children to visit sequentially to determine the order of
+     * child visitations. Some children may not be returned at all if canVisit()
+     * returns false on them.
+     * 
+     * @param node the parent branch node
+     * @param children the child node array
+     * @return the new reordered array of children
+     */
+    List<ExprNode> getOrder( BranchNode node, List<ExprNode> children );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/GreaterEqNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/GreaterEqNode.java
new file mode 100644
index 0000000..2fe9b3b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/GreaterEqNode.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * A assertion value node for GreaterOrEqual.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GreaterEqNode<T> extends SimpleNode<T>
+{
+    /**
+     * Creates a new GreaterOrEqual object.
+     * 
+     * @param attributeType the attributeType
+     * @param value the value to test for
+     */
+    public GreaterEqNode( AttributeType attributeType, Value<T> value )
+    {
+        super( attributeType, value, AssertionType.GREATEREQ );
+    }
+
+
+    /**
+     * Creates a new GreaterOrEqual object.
+     * 
+     * @param attribute the attribute name
+     * @param value the value to test for
+     */
+    public GreaterEqNode( String attribute, Value<T> value )
+    {
+        super( attribute, value, AssertionType.GREATEREQ );
+    }
+
+
+    /**
+     * @see Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( '(' );
+
+        if ( attributeType != null )
+        {
+            buf.append( attributeType.getName() );
+        }
+        else
+        {
+            buf.append( attribute );
+        }
+
+        buf.append( ">=" );
+
+        Value<?> escapedValue = getEscapedValue();
+        if ( !escapedValue.isNull() )
+        {
+            buf.append( escapedValue );
+        }
+
+        buf.append( super.toString() );
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/LeafNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/LeafNode.java
new file mode 100644
index 0000000..0ac4c2f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/LeafNode.java
@@ -0,0 +1,214 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * Abstract base class for leaf nodes within the expression filter tree.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class LeafNode extends AbstractExprNode
+{
+    /** attributeType on which this leaf is based */
+    protected AttributeType attributeType;
+
+    /** attribute on which this leaf is based */
+    protected String attribute;
+
+
+    /**
+     * Creates a leaf node.
+     * 
+     * @param attributeType the attribute this node is based on
+     * @param assertionType the type of this leaf node
+     */
+    protected LeafNode( AttributeType attributeType, AssertionType assertionType )
+    {
+        super( assertionType );
+        this.attributeType = attributeType;
+
+        if ( attributeType != null )
+        {
+            this.attribute = attributeType.getName();
+            isSchemaAware = true;
+        }
+        else
+        {
+            throw new NullPointerException( "Cannot create a Node with a null Attribute" );
+        }
+    }
+
+
+    /**
+     * Creates a leaf node.
+     * 
+     * @param attributeType the attribute this node is based on
+     * @param assertionType the type of this leaf node
+     */
+    protected LeafNode( String attribute, AssertionType assertionType )
+    {
+        super( assertionType );
+        this.attributeType = null;
+        this.attribute = attribute;
+        isSchemaAware = false;
+    }
+
+
+    /**
+     * Gets whether this node is a leaf - the answer is always true here.
+     * 
+     * @return true always
+     */
+    public final boolean isLeaf()
+    {
+        return true;
+    }
+
+
+    /**
+     * Gets the attributeType this leaf node is based on.
+     * 
+     * @return the attributeType asserted
+     */
+    public final AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    /**
+     * Gets the attribute this leaf node is based on.
+     * 
+     * @return the attribute asserted
+     */
+    public final String getAttribute()
+    {
+        return attribute;
+    }
+
+
+    /**
+     * Sets the attributeType this leaf node is based on.
+     * 
+     * @param attributeType the attributeType that is asserted by this filter node
+     */
+    public void setAttributeType( AttributeType attributeType )
+    {
+        this.attributeType = attributeType;
+
+        if ( attributeType != null )
+        {
+            attribute = attributeType.getName();
+            isSchemaAware = true;
+        }
+    }
+
+
+    /**
+     * Sets the attribute this leaf node is based on.
+     * 
+     * @param attribute the attribute that is asserted by this filter node
+     */
+    public void setAttribute( String attribute )
+    {
+        this.attribute = attribute;
+        isSchemaAware = false;
+    }
+
+
+    /**
+     * @see ExprNode#accept(
+     *FilterVisitor)
+     * 
+     * @param visitor the filter expression tree structure visitor
+     * @return The modified element
+     */
+    public final Object accept( FilterVisitor visitor )
+    {
+        if ( visitor.canVisit( this ) )
+        {
+            return visitor.visit( this );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+
+        if ( attributeType != null )
+        {
+            h = h * 17 + attributeType.hashCode();
+        }
+        else
+        {
+            h = h * 17 + attribute.hashCode();
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object other )
+    {
+        if ( this == other )
+        {
+            return true;
+        }
+
+        if ( !( other instanceof LeafNode ) )
+        {
+            return false;
+        }
+
+        LeafNode otherNode = ( LeafNode ) other;
+
+        if ( other.getClass() != this.getClass() )
+        {
+            return false;
+        }
+
+        if ( attributeType != null )
+        {
+            return attributeType.equals( otherNode.getAttributeType() );
+        }
+        else
+        {
+            return attribute.equalsIgnoreCase( otherNode.getAttribute() );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/LessEqNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/LessEqNode.java
new file mode 100644
index 0000000..b150b45
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/LessEqNode.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * A assertion value node for LessOrEqual.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LessEqNode<T> extends SimpleNode<T>
+{
+    /**
+     * Creates a new LessEqNode object.
+     * 
+     * @param attributeType the attributeType
+     * @param value the value to test for
+     */
+    public LessEqNode( AttributeType attributeType, Value<T> value )
+    {
+        super( attributeType, value, AssertionType.LESSEQ );
+    }
+
+
+    /**
+     * Creates a new LessEqNode object.
+     * 
+     * @param attribute the attribute name
+     * @param value the value to test for
+     */
+    public LessEqNode( String attribute, Value<T> value )
+    {
+        super( attribute, value, AssertionType.LESSEQ );
+    }
+
+
+    /**
+     * @see Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( '(' );
+
+        if ( attributeType != null )
+        {
+            buf.append( attributeType.getName() );
+        }
+        else
+        {
+            buf.append( attribute );
+        }
+
+        buf.append( "<=" );
+
+        Value<?> escapedValue = getEscapedValue();
+        if ( !escapedValue.isNull() )
+        {
+            buf.append( escapedValue );
+        }
+
+        buf.append( super.toString() );
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/NotNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/NotNode.java
new file mode 100644
index 0000000..015478f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/NotNode.java
@@ -0,0 +1,207 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Node representing an Not connector in a filter operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NotNode extends BranchNode
+{
+    /**
+     * Creates a NotNode using a logical NOT operator and a list of children.
+     * 
+     * A Not node could contain only one child
+     * 
+     * @param childList the child nodes under this branch node.
+     */
+    public NotNode( List<ExprNode> childList )
+    {
+        super( AssertionType.NOT );
+
+        if ( childList != null )
+        {
+            setChildren( childList );
+        }
+    }
+
+
+    /**
+     * Creates a NotNode using a logical NOT operator and the given child.
+     * 
+     * @param child the child node under this branch node.
+     */
+    public NotNode( ExprNode child )
+    {
+        super( AssertionType.NOT );
+
+        if ( child != null )
+        {
+            addNode( child );
+        }
+    }
+
+
+    /**
+     * Creates an empty NotNode
+     */
+    public NotNode()
+    {
+        this( ( ExprNode ) null );
+    }
+
+
+    /**
+     * Adds a child node to this NOT node node
+     * 
+     * @param node the child expression to add to this NOT node
+     */
+    public void addNode( ExprNode node )
+    {
+        if ( ( children == null ) || ( children.size() >= 1 ) )
+        {
+            throw new IllegalStateException( I18n.err( I18n.ERR_04159 ) );
+        }
+
+        children.add( node );
+    }
+
+
+    /**
+     * Adds a child node to this NOT node at the head rather than the tail. 
+     * 
+     * @param node the child expression to add to this branch node
+     */
+    public void addNodeToHead( ExprNode node )
+    {
+        if ( children.size() >= 1 )
+        {
+            throw new IllegalStateException( I18n.err( I18n.ERR_04159 ) );
+        }
+
+        children.add( node );
+    }
+
+
+    /**
+     * Sets the list of children under this node.
+     * 
+     * @param childList the list of children to set.
+     */
+    public void setChildren( List<ExprNode> childList )
+    {
+        if ( ( childList != null ) && ( childList.size() > 1 ) )
+        {
+            throw new IllegalStateException( I18n.err( I18n.ERR_04159 ) );
+        }
+
+        children = childList;
+    }
+
+
+    /**
+     * Gets the operator for this branch node.
+     * 
+     * @return the operator constant.
+     */
+    public AssertionType getOperator()
+    {
+        return AssertionType.NOT;
+    }
+
+
+    /**
+     * Tests whether or not this node is a disjunction (a OR'ed branch).
+     * 
+     * @return true if the operation is a OR, false otherwise.
+     */
+    public boolean isDisjunction()
+    {
+        return false;
+    }
+
+
+    /**
+     * Tests whether or not this node is a conjunction (a AND'ed branch).
+     * 
+     * @return true if the operation is a AND, false otherwise.
+     */
+    public boolean isConjunction()
+    {
+        return false;
+    }
+
+
+    /**
+     * Tests whether or not this node is a negation (a NOT'ed branch).
+     * 
+     * @return true if the operation is a NOT, false otherwise.
+     */
+    public boolean isNegation()
+    {
+        return true;
+    }
+
+
+    /**
+     * @see ExprNode#printRefinementToBuffer(StringBuffer)
+     * 
+     * @return The buffer in which the refinement has been appended
+     * @throws UnsupportedOperationException if this node isn't a part of a refinement.
+     */
+    public StringBuilder printRefinementToBuffer( StringBuilder buf )
+    {
+        buf.append( "not: " );
+
+        // There is only one item for a not refinement
+        children.get( 0 ).printRefinementToBuffer( buf );
+
+        return buf;
+    }
+
+
+    /**
+     * Gets the recursive prefix string represent of the filter from this node
+     * down.
+     * 
+     * @see java.lang.Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+        buf.append( "(!" );
+
+        buf.append( super.toString() );
+
+        buf.append( getFirstChild() );
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ObjectClassNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ObjectClassNode.java
new file mode 100644
index 0000000..06c6355
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ObjectClassNode.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+/**
+ * An empty class used for the (ObjectClass=*) node.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public final class ObjectClassNode extends AbstractExprNode
+{
+    /** A static instance of this node */
+    public static final ExprNode OBJECT_CLASS_NODE = new ObjectClassNode();
+
+
+    /**
+     * Creates a new instance of ObjectClassNode.
+     */
+    private ObjectClassNode()
+    {
+        super( AssertionType.OBJECTCLASS );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * This implementation always returns true.
+     */
+    public boolean isLeaf()
+    {
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * This implementation always returns null.
+     */
+    public Object accept( FilterVisitor visitor )
+    {
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "All";
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/OrNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/OrNode.java
new file mode 100644
index 0000000..ce8ee2a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/OrNode.java
@@ -0,0 +1,221 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.util.List;
+
+
+/**
+ * Node representing an OR connector in a filter operation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OrNode extends BranchNode
+{
+    /**
+     * Creates a OrNode using a logical operator and a list of children.
+     * 
+     * @param childList the child nodes under this branch node.
+     */
+    public OrNode( List<ExprNode> childList )
+    {
+        super( AssertionType.OR, childList );
+    }
+
+
+    /**
+     * Creates a OrNode using a logical operator and a list of children.
+     * 
+     * @param childList the child nodes under this branch node.
+     */
+    public OrNode( ExprNode... childList )
+    {
+        super( AssertionType.OR, childList );
+    }
+
+
+    /**
+     * Creates an empty OrNode
+     */
+    public OrNode()
+    {
+        super( AssertionType.OR );
+    }
+
+
+    /**
+     * Gets the operator for this branch node.
+     * 
+     * @return the operator constant.
+     */
+    public AssertionType getOperator()
+    {
+        return AssertionType.OR;
+    }
+
+
+    /**
+     * Tests whether or not this node is a disjunction (a OR'ed branch).
+     * 
+     * @return true if the operation is a OR, false otherwise.
+     */
+    public boolean isDisjunction()
+    {
+        return true;
+    }
+
+
+    /**
+     * Tests whether or not this node is a conjunction (a AND'ed branch).
+     * 
+     * @return true if the operation is a AND, false otherwise.
+     */
+    public boolean isConjunction()
+    {
+        return false;
+    }
+
+
+    /**
+     * Tests whether or not this node is a negation (a NOT'ed branch).
+     * 
+     * @return true if the operation is a NOT, false otherwise.
+     */
+    public boolean isNegation()
+    {
+        return false;
+    }
+
+
+    /**
+     * @see ExprNode#printRefinementToBuffer(StringBuffer)
+     * 
+     * @return The buffer in which the refinement has been appended
+     * @throws UnsupportedOperationException if this node isn't a part of a refinement.
+     */
+    public StringBuilder printRefinementToBuffer( StringBuilder buf )
+    {
+        buf.append( "or: {" );
+        boolean isFirst = true;
+
+        for ( ExprNode node : children )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+                buf.append( ' ' );
+            }
+            else
+            {
+                buf.append( ", " );
+            }
+
+            node.printRefinementToBuffer( buf );
+        }
+
+        buf.append( " }" );
+
+        return buf;
+    }
+
+
+    /**
+     * Gets the recursive prefix string represent of the filter from this node
+     * down.
+     * 
+     * @see java.lang.Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+        buf.append( "(|" );
+
+        buf.append( super.toString() );
+
+        for ( ExprNode child : getChildren() )
+        {
+            buf.append( child );
+        }
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + AssertionType.OR.hashCode();
+        hash = hash * 17 + ( annotations == null ? 0 : annotations.hashCode() );
+        return hash;
+    }
+
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object other )
+    {
+        if ( this == other )
+        {
+            return true;
+        }
+
+        if ( !( other instanceof OrNode ) )
+        {
+            return false;
+        }
+
+        OrNode otherExprNode = ( OrNode ) other;
+
+        List<ExprNode> otherChildren = otherExprNode.getChildren();
+
+        if ( otherChildren == children )
+        {
+            return true;
+        }
+
+        if ( children.size() != otherChildren.size() )
+        {
+            return false;
+        }
+
+        for ( int i = 0; i < children.size(); i++ )
+        {
+            ExprNode child = children.get( i );
+            ExprNode otherChild = otherChildren.get( i );
+
+            if ( !child.equals( otherChild ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/PresenceNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/PresenceNode.java
new file mode 100644
index 0000000..fb8fbff
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/PresenceNode.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * Filter expression tree node representing a filter attribute value assertion
+ * for presence.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PresenceNode extends LeafNode
+{
+    /**
+     * Creates a PresenceNode object based on an attribute.
+     * 
+     * @param attributeType the attributeType to assert the presence of
+     */
+    public PresenceNode( AttributeType attributeType )
+    {
+        super( attributeType, AssertionType.PRESENCE );
+    }
+
+
+    /**
+     * Creates a PresenceNode object based on an attribute.
+     * 
+     * @param attribute the attribute to assert the presence of
+     */
+    public PresenceNode( String attribute )
+    {
+        super( attribute, AssertionType.PRESENCE );
+    }
+
+
+    /**
+     * @see java.lang.Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( '(' );
+
+        if ( attributeType != null )
+        {
+            buf.append( attributeType.getName() );
+        }
+        else
+        {
+            buf.append( attribute );
+        }
+
+        buf.append( "=*" );
+
+        buf.append( super.toString() );
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ScopeNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ScopeNode.java
new file mode 100644
index 0000000..9d1db2a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/ScopeNode.java
@@ -0,0 +1,255 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.ldap.model.message.AliasDerefMode;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Node used not to represent a published assertion but an assertion on the
+ * scope of the search.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ScopeNode extends AbstractExprNode
+{
+    /** the scope of this node */
+    private final SearchScope scope;
+
+    /** the search base */
+    private final Dn baseDn;
+
+    /** the search ID */
+    private final String baseId;
+
+    /** the alias dereferencing mode */
+    private final AliasDerefMode aliasDerefAliases;
+
+
+    /**
+     * Creates a new ScopeNode object.
+     * 
+     * @param aliasDerefAliases the alias dereferencing mode
+     * @param baseDn the search base
+     * @param scope the search scope
+     */
+    public ScopeNode( AliasDerefMode aliasDerefAliases, Dn baseDn, String baseId, SearchScope scope )
+    {
+        super( AssertionType.SCOPE );
+        this.scope = scope;
+        this.baseDn = baseDn;
+        this.aliasDerefAliases = aliasDerefAliases;
+        this.baseId = baseId;
+        isSchemaAware = true;
+    }
+
+
+    /**
+     * Always returns true since a scope node has no children.
+     * 
+     * @see ExprNode#isLeaf()
+     * @return <code>true</code>
+     */
+    public boolean isLeaf()
+    {
+        return true;
+    }
+
+
+    /**
+     * Gets the search scope.
+     * 
+     * @return the search scope 
+     */
+    public SearchScope getScope()
+    {
+        return scope;
+    }
+
+
+    /**
+     * Gets the base dn.
+     * 
+     * @return the base dn
+     */
+    public Dn getBaseDn()
+    {
+        return baseDn;
+    }
+
+
+    /**
+     * Gets the base ID.
+     * 
+     * @return the base ID
+     */
+    public String getBaseId()
+    {
+        return baseId;
+    }
+
+
+    /**
+     * Gets the alias dereferencing mode type safe enumeration.
+     * 
+     * @return the alias dereferencing enumeration constant.
+     */
+    public AliasDerefMode getDerefAliases()
+    {
+        return aliasDerefAliases;
+    }
+
+
+    /**
+     * @see ExprNode#accept(
+     *FilterVisitor)
+     * 
+     * @param visitor the filter expression tree structure visitor
+     * @return The modified element
+     */
+    public Object accept( FilterVisitor visitor )
+    {
+        if ( visitor.canVisit( this ) )
+        {
+            return visitor.visit( this );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof ScopeNode ) )
+        {
+            return false;
+        }
+        ScopeNode that = ( ScopeNode ) obj;
+        if ( aliasDerefAliases == null )
+        {
+            if ( that.aliasDerefAliases != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !aliasDerefAliases.equals( that.aliasDerefAliases ) )
+            {
+                return false;
+            }
+        }
+        if ( baseDn == null )
+        {
+            if ( that.baseDn != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !baseDn.equals( that.baseDn ) )
+            {
+                return false;
+            }
+        }
+        if ( scope.getScope() != that.scope.getScope() )
+        {
+            return false;
+        }
+        return super.equals( obj );
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + ( aliasDerefAliases != null ? aliasDerefAliases.hashCode() : 0 );
+        h = h * 17 + ( baseDn != null ? baseDn.hashCode() : 0 );
+        h = h * 17 + scope.getScope();
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( "(#{" );
+
+        switch ( scope )
+        {
+            case OBJECT:
+                buf.append( "OBJECT_SCOPE" );
+
+                break;
+
+            case ONELEVEL:
+                buf.append( "ONE_LEVEL_SCOPE" );
+
+                break;
+
+            case SUBTREE:
+                buf.append( "SUBTREE_SCOPE (Estimated)" );
+
+                break;
+
+            default:
+                buf.append( "UNKNOWN" );
+                break;
+        }
+
+        buf.append( ", '" );
+        buf.append( baseDn );
+        buf.append( "', " );
+        buf.append( aliasDerefAliases );
+        buf.append( "}" );
+        buf.append( super.toString() );
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/SimpleNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/SimpleNode.java
new file mode 100644
index 0000000..4512ae4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/SimpleNode.java
@@ -0,0 +1,225 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+
+/**
+ * A simple assertion value node.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class SimpleNode<T> extends LeafNode
+{
+    /** the value */
+    protected Value<T> value;
+
+    /** Constants for comparisons : > */
+    public static final boolean EVAL_GREATER = true;
+
+    /** Constants for comparisons : < */
+    public static final boolean EVAL_LESSER = false;
+
+
+    /**
+     * Creates a new SimpleNode object.
+     * 
+     * @param attribute the attribute name
+     * @param value the value to test for
+     * @param assertionType the type of assertion represented by this ExprNode
+     */
+    protected SimpleNode( String attribute, Value<T> value, AssertionType assertionType )
+    {
+        super( attribute, assertionType );
+        this.value = value;
+    }
+
+
+    /**
+     * Creates a new SimpleNode object.
+     * 
+     * @param attribute the attribute name
+     * @param value the value to test for
+     * @param assertionType the type of assertion represented by this ExprNode
+     */
+    protected SimpleNode( AttributeType attributeType, Value<T> value, AssertionType assertionType )
+    {
+        super( attributeType, assertionType );
+        this.value = value;
+    }
+
+
+    /**
+     * Makes a full clone in new memory space of the current node and children
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public ExprNode clone()
+    {
+        ExprNode clone = super.clone();
+
+        // Clone the value
+        ( ( SimpleNode<T> ) clone ).value = value.clone();
+
+        return clone;
+    }
+
+
+    /**
+     * Gets the value.
+     * 
+     * @return the value
+     */
+    public final Value<T> getValue()
+    {
+        return value;
+    }
+
+
+    /** 
+     * @return representation of value, escaped for use in a filter if required 
+     */
+    public Value<?> getEscapedValue()
+    {
+        return escapeFilterValue( value );
+    }
+
+
+    /**
+     * Sets the value of this node.
+     * 
+     * @param value the value for this node
+     */
+    public void setValue( Value<T> value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * Pretty prints this expression node along with annotation information.
+     *
+     * TODO - perhaps this belong in some utility class?
+     *
+     * @param buf the buffer to print into
+     * @return the same buf argument returned for call chaining
+     */
+    public StringBuilder printToBuffer( StringBuilder buf )
+    {
+        if ( ( null != getAnnotations() ) && getAnnotations().containsKey( "count" ) )
+        {
+            buf.append( ":[" );
+            buf.append( getAnnotations().get( "count" ).toString() );
+            buf.append( "] " );
+        }
+
+        buf.append( ')' );
+
+        return buf;
+    }
+
+
+    /**
+     * @see ExprNode#printRefinementToBuffer(StringBuilder)
+     * @return The buffer in which the refinement has been appended
+     * @throws UnsupportedOperationException if this node isn't a part of a refinement.
+     */
+    public StringBuilder printRefinementToBuffer( StringBuilder buf )
+    {
+        if ( isSchemaAware )
+        {
+            if ( !attributeType.getOid().equals( SchemaConstants.OBJECT_CLASS_AT_OID ) )
+            {
+                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04162, attribute ) );
+            }
+        }
+        else
+        {
+            if ( ( attribute == null )
+                || !( SchemaConstants.OBJECT_CLASS_AT.equalsIgnoreCase( attribute )
+                || SchemaConstants.OBJECT_CLASS_AT_OID.equalsIgnoreCase( attribute ) ) )
+            {
+                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04162, attribute ) );
+            }
+        }
+
+        buf.append( "item: " ).append( value );
+
+        return buf;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + ( value == null ? 0 : value.hashCode() );
+
+        return h;
+    }
+
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object other )
+    {
+        if ( this == other )
+        {
+            return true;
+        }
+
+        if ( !( other instanceof SimpleNode<?> ) )
+        {
+            return false;
+        }
+
+        if ( other.getClass() != this.getClass() )
+        {
+            return false;
+        }
+
+        if ( !super.equals( other ) )
+        {
+            return false;
+        }
+
+        SimpleNode<?> otherNode = ( SimpleNode<?> ) other;
+
+        if ( value == null )
+        {
+            return otherNode.value == null;
+        }
+        else
+        {
+            return value.equals( otherNode.value );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/SubstringNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/SubstringNode.java
new file mode 100644
index 0000000..4fa5197
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/SubstringNode.java
@@ -0,0 +1,482 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+
+
+/**
+ * Filter expression tree node used to represent a substring assertion.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubstringNode extends LeafNode
+{
+    /** The initial fragment before any wildcard */
+    private String initialPattern;
+
+    /** The end fragment after wildcard */
+    private String finalPattern;
+
+    /** List of fragments between wildcard */
+    private List<String> anyPattern;
+
+
+    /**
+     * Creates a new SubstringNode object with only one wildcard and no internal
+     * any fragments between wildcards.
+     * 
+     * @param attributeType the name of the attributeType to substring assert
+     * @param initialPattern the initial fragment
+     * @param finalPattern the final fragment
+     */
+    public SubstringNode( AttributeType attributeType, String initialPattern, String finalPattern )
+    {
+        super( attributeType, AssertionType.SUBSTRING );
+
+        anyPattern = new ArrayList<String>( 2 );
+        this.finalPattern = finalPattern;
+        this.initialPattern = initialPattern;
+    }
+
+
+    /**
+     * Creates a new SubstringNode object with only one wildcard and no internal
+     * any fragments between wildcards.
+     * 
+     * @param attribute the name of the attribute to substring assert
+     * @param initialPattern the initial fragment
+     * @param finalPattern the final fragment
+     */
+    public SubstringNode( String attribute, String initialPattern, String finalPattern )
+    {
+        super( attribute, AssertionType.SUBSTRING );
+
+        anyPattern = new ArrayList<String>( 2 );
+        this.finalPattern = finalPattern;
+        this.initialPattern = initialPattern;
+    }
+
+
+    /**
+     * Creates a new SubstringNode object without any value
+     * 
+     * @param attribute the name of the attribute to substring assert
+     */
+    public SubstringNode( AttributeType attribute )
+    {
+        super( attribute, AssertionType.SUBSTRING );
+
+        anyPattern = new ArrayList<String>( 2 );
+        this.finalPattern = null;
+        this.initialPattern = null;
+    }
+
+
+    /**
+     * Creates a new SubstringNode object without any value
+     * 
+     * @param attributeType the attributeType to substring assert
+     */
+    public SubstringNode( String attributeType )
+    {
+        super( attributeType, AssertionType.SUBSTRING );
+
+        anyPattern = new ArrayList<String>( 2 );
+        this.finalPattern = null;
+        this.initialPattern = null;
+    }
+
+
+    /**
+     * Creates a new SubstringNode object more than one wildcard and an any
+     * list.
+     * 
+     * @param anyPattern list of internal fragments between wildcards
+     * @param attributeType the attributeType to substring assert
+     * @param initialPattern the initial fragment
+     * @param finalPattern the final fragment
+     */
+    public SubstringNode( List<String> anyPattern, AttributeType attributeType, String initialPattern,
+        String finalPattern )
+    {
+        super( attributeType, AssertionType.SUBSTRING );
+
+        this.anyPattern = anyPattern;
+        this.finalPattern = finalPattern;
+        this.initialPattern = initialPattern;
+    }
+
+
+    /**
+     * Creates a new SubstringNode object more than one wildcard and an any
+     * list.
+     * 
+     * @param anyPattern list of internal fragments between wildcards
+     * @param attribute the name of the attribute to substring assert
+     * @param initialPattern the initial fragment
+     * @param finalPattern the final fragment
+     */
+    public SubstringNode( List<String> anyPattern, String attribute, String initialPattern, String finalPattern )
+    {
+        super( attribute, AssertionType.SUBSTRING );
+
+        this.anyPattern = anyPattern;
+        this.finalPattern = finalPattern;
+        this.initialPattern = initialPattern;
+    }
+
+
+    /**
+     * Creates a regular expression from an LDAP substring assertion filter
+     * specification.
+     *
+     * @param initialPattern
+     *            the initial fragment before wildcards
+     * @param anyPattern
+     *            fragments surrounded by wildcards if any
+     * @param finalPattern
+     *            the final fragment after last wildcard if any
+     * @return the regular expression for the substring match filter
+     * @throws java.util.regex.PatternSyntaxException
+     *             if a syntactically correct regular expression cannot be
+     *             compiled
+     */
+    public static Pattern getRegex( String initialPattern, String[] anyPattern, String finalPattern )
+        throws PatternSyntaxException
+    {
+        StringBuffer buf = new StringBuffer();
+
+        if ( initialPattern != null )
+        {
+            buf.append( '^' ).append( Pattern.quote( initialPattern ) );
+        }
+
+        if ( anyPattern != null )
+        {
+            for ( int i = 0; i < anyPattern.length; i++ )
+            {
+                buf.append( ".*" ).append( Pattern.quote( anyPattern[i] ) );
+            }
+        }
+
+        if ( finalPattern != null )
+        {
+            buf.append( ".*" ).append( Pattern.quote( finalPattern ) );
+        }
+        else
+        {
+            buf.append( ".*" );
+        }
+
+        return Pattern.compile( buf.toString() );
+    }
+
+
+    /**
+     * Clone the Node
+     */
+    @Override
+    public ExprNode clone()
+    {
+        ExprNode clone = ( ExprNode ) super.clone();
+
+        if ( anyPattern != null )
+        {
+            ( ( SubstringNode ) clone ).anyPattern = new ArrayList<String>();
+
+            for ( String any : anyPattern )
+            {
+                ( ( SubstringNode ) clone ).anyPattern.add( any );
+            }
+        }
+
+        return clone;
+    }
+
+
+    /**
+     * Gets the initial fragment.
+     * 
+     * @return the initial prefix
+     */
+    public final String getInitial()
+    {
+        return initialPattern;
+    }
+
+
+    /**
+     * Set the initial pattern
+     * @param initialPattern The initial pattern
+     */
+    public void setInitial( String initialPattern )
+    {
+        this.initialPattern = initialPattern;
+    }
+
+
+    /**
+     * Gets the final fragment or suffix.
+     * 
+     * @return the suffix
+     */
+    public final String getFinal()
+    {
+        return finalPattern;
+    }
+
+
+    /**
+     * Set the final pattern
+     * @param finalPattern The final pattern
+     */
+    public void setFinal( String finalPattern )
+    {
+        this.finalPattern = finalPattern;
+    }
+
+
+    /**
+     * Gets the list of wildcard surrounded any fragments.
+     * 
+     * @return the any fragments
+     */
+    public final List<String> getAny()
+    {
+        return anyPattern;
+    }
+
+
+    /**
+     * Set the any patterns
+     * @param anyPattern The any patterns
+     */
+    public void setAny( List<String> anyPattern )
+    {
+        this.anyPattern = anyPattern;
+    }
+
+
+    /**
+     * Add an any pattern
+     * @param anyPattern The any pattern
+     */
+    public void addAny( String anyPattern )
+    {
+        this.anyPattern.add( anyPattern );
+    }
+
+
+    /**
+     * Gets the compiled regular expression for the substring expression.
+     * 
+     * @param normalizer the normalizer to use for pattern component normalization
+     * @return the equivalent compiled regular expression
+     * @throws LdapException if there are problems while normalizing
+     */
+    public final Pattern getRegex( Normalizer normalizer ) throws LdapException
+    {
+        if ( ( anyPattern != null ) && ( anyPattern.size() > 0 ) )
+        {
+            String[] any = new String[anyPattern.size()];
+
+            for ( int i = 0; i < any.length; i++ )
+            {
+                any[i] = ( String ) normalizer.normalize( anyPattern.get( i ) );
+
+                if ( any[i].length() == 0 )
+                {
+                    any[i] = " ";
+                }
+            }
+
+            String initialStr = null;
+
+            if ( initialPattern != null )
+            {
+                initialStr = ( String ) normalizer.normalize( initialPattern );
+            }
+
+            String finalStr = null;
+
+            if ( finalPattern != null )
+            {
+                finalStr = ( String ) normalizer.normalize( finalPattern );
+            }
+
+            return getRegex( initialStr, any, finalStr );
+        }
+
+        String initialStr = null;
+
+        if ( initialPattern != null )
+        {
+            initialStr = ( String ) normalizer.normalize( initialPattern );
+        }
+
+        String finalStr = null;
+
+        if ( finalPattern != null )
+        {
+            finalStr = ( String ) normalizer.normalize( finalPattern );
+        }
+
+        return getRegex( initialStr, null, finalStr );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof SubstringNode ) )
+        {
+            return false;
+        }
+        SubstringNode that = ( SubstringNode ) obj;
+
+        if ( initialPattern == null )
+        {
+            if ( that.initialPattern != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !initialPattern.equals( that.initialPattern ) )
+            {
+                return false;
+            }
+        }
+
+        if ( finalPattern == null )
+        {
+            if ( that.finalPattern != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !finalPattern.equals( that.finalPattern ) )
+            {
+                return false;
+            }
+        }
+
+        return super.equals( obj );
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = 37;
+
+        h = h * 17 + super.hashCode();
+        h = h * 17 + ( initialPattern != null ? initialPattern.hashCode() : 0 );
+
+        if ( anyPattern != null )
+        {
+            for ( String pattern : anyPattern )
+            {
+                h = h * 17 + pattern.hashCode();
+            }
+        }
+
+        h = h * 17 + ( finalPattern != null ? finalPattern.hashCode() : 0 );
+
+        return h;
+    }
+
+
+    /**
+     * @see java.lang.Object#toString()
+     * @return A string representing the AndNode
+     */
+    public String toString()
+    {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append( '(' );
+
+        if ( attributeType != null )
+        {
+            buf.append( attributeType.getName() );
+        }
+        else
+        {
+            buf.append( attribute );
+        }
+
+        buf.append( '=' );
+
+        if ( null != initialPattern )
+        {
+            buf.append( escapeFilterValue( new StringValue( initialPattern ) ) ).append( '*' );
+        }
+        else
+        {
+            buf.append( '*' );
+        }
+
+        if ( null != anyPattern )
+        {
+            for ( String any : anyPattern )
+            {
+                buf.append( escapeFilterValue( new StringValue( any ) ) );
+                buf.append( '*' );
+            }
+        }
+
+        if ( null != finalPattern )
+        {
+            buf.append( escapeFilterValue( new StringValue( finalPattern ) ) );
+        }
+
+        buf.append( super.toString() );
+
+        buf.append( ')' );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/UndefinedNode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/UndefinedNode.java
new file mode 100644
index 0000000..487f280
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/filter/UndefinedNode.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+/**
+ * An empty class used for Undefined Nodes.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public final class UndefinedNode extends AbstractExprNode
+{
+    /** A static instance of this node */
+    public static final UndefinedNode UNDEFINED_NODE = new UndefinedNode();
+
+
+    /**
+     * Creates a new instance of UndefinedNode.
+     */
+    private UndefinedNode()
+    {
+        super( AssertionType.UNDEFINED );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * This implementation always returns false.
+     */
+    public boolean isLeaf()
+    {
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * This implementation always returns null.
+     */
+    public Object accept( FilterVisitor visitor )
+    {
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return "Undefined";
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/ChangeType.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/ChangeType.java
new file mode 100755
index 0000000..6846179
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/ChangeType.java
@@ -0,0 +1,127 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A type safe enumeration for an LDIF record's change type.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum ChangeType
+{
+    /** The Add changeType */
+    Add(0),
+
+    /** The Modify changeType */
+    Modify(1),
+
+    /** The ModDn changeType */
+    ModDn(2),
+
+    /** The ModRdn changeType */
+    ModRdn(3),
+
+    /** The Delete changeType */
+    Delete(4),
+
+    /** A place-holder when we have no changeType */
+    None(-1);
+
+    /** Add ordinal value */
+    public static final int ADD_ORDINAL = 0;
+
+    /** Modify ordinal value */
+    public static final int MODIFY_ORDINAL = 1;
+
+    /** ModDN ordinal value */
+    public static final int MODDN_ORDINAL = 2;
+
+    /** ModRDN ordinal value */
+    public static final int MODRDN_ORDINAL = 3;
+
+    /** Delete ordinal value */
+    public static final int DELETE_ORDINAL = 4;
+
+    /** None ordinal value */
+    public static final int NONE_ORDINAL = -1;
+
+    /** the ordinal value for a change type */
+    private final int changeType;
+
+
+    /**
+     * Creates a new instance of ChangeType.
+     *
+     * @param changeType The associated value 
+     */
+    private ChangeType( int changeType )
+    {
+        this.changeType = changeType;
+    }
+
+
+    /**
+     * Get's the ordinal value for a ChangeType.
+     * 
+     * @return the changeType
+     */
+    public int getChangeType()
+    {
+        return changeType;
+    }
+
+
+    /**
+     * Get the ChangeType instance from an integer value 
+     *
+     * @param val The value for the ChangeType we are looking for
+     * @return The associated ChangeType instance
+     */
+    public static ChangeType getChangeType( int val )
+    {
+        switch ( val )
+        {
+            case -1:
+                return None;
+
+            case 0:
+                return Add;
+
+            case 1:
+                return Modify;
+
+            case 2:
+                return ModDn;
+
+            case 3:
+                return ModRdn;
+
+            case 4:
+                return Delete;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_12001_UNKNOWN_CHANGE_TYPE, val ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdapLdifException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdapLdifException.java
new file mode 100644
index 0000000..fe99832
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdapLdifException.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * An exception throws when we get an error while parsing a LDIF file.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapLdifException extends LdapException
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of LdapLdifException.
+     *
+     * @param message The exception message
+     */
+    public LdapLdifException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Creates a new instance of LdapLdifException.
+     *
+     * @param message The exception message
+     * @param cause The root cause for this exception
+     */
+    public LdapLdifException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifAttributesReader.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifAttributesReader.java
new file mode 100644
index 0000000..7c79134
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifAttributesReader.java
@@ -0,0 +1,615 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * <pre>
+ *  &lt;ldif-file&gt; ::= &quot;version:&quot; &lt;fill&gt; &lt;number&gt; &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt;
+ *  &lt;ldif-content-change&gt;
+ *
+ *  &lt;ldif-content-change&gt; ::=
+ *    &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt;
+ *    &lt;ldif-attrval-record-e&gt; |
+ *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt;
+ *    &lt;ldif-attrval-record-e&gt; |
+ *    &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt; &lt;criticality&gt;
+ *    &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt;
+ *        &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; |
+ *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt;
+ *
+ *  &lt;ldif-attrval-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;attributeType&gt;
+ *    &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt;
+ *    &lt;ldif-attrval-record-e&gt; | e
+ *
+ *  &lt;ldif-change-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt;
+ *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; | e
+ *
+ *  &lt;dn-spec&gt; ::= &quot;dn:&quot; &lt;fill&gt; &lt;safe-string&gt; | &quot;dn::&quot; &lt;fill&gt; &lt;base64-string&gt;
+ *
+ *  &lt;controls-e&gt; ::= &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt; &lt;criticality&gt;
+ *    &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt; | e
+ *
+ *  &lt;criticality&gt; ::= &quot;true&quot; | &quot;false&quot; | e
+ *
+ *  &lt;oid&gt; ::= '.' &lt;number&gt; &lt;oid&gt; | e
+ *
+ *  &lt;attrval-specs-e&gt; ::= &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt;
+ *  &lt;attrval-specs-e&gt; |
+ *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; | e
+ *
+ *  &lt;value-spec-e&gt; ::= &lt;value-spec&gt; | e
+ *
+ *  &lt;value-spec&gt; ::= ':' &lt;fill&gt; &lt;safe-string-e&gt; |
+ *    &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt; |
+ *    &quot;:&lt;&quot; &lt;fill&gt; &lt;url&gt;
+ *
+ *  &lt;attributeType&gt; ::= &lt;number&gt; &lt;oid&gt; | &lt;alpha&gt; &lt;chars-e&gt;
+ *
+ *  &lt;options-e&gt; ::= ';' &lt;char&gt; &lt;chars-e&gt; &lt;options-e&gt; |e
+ *
+ *  &lt;chars-e&gt; ::= &lt;char&gt; &lt;chars-e&gt; |  e
+ *
+ *  &lt;changerecord-type&gt; ::= &quot;add&quot; &lt;sep&gt; &lt;attributeType&gt; &lt;options-e&gt; &lt;value-spec&gt;
+ *  &lt;sep&gt; &lt;attrval-specs-e&gt; |
+ *    &quot;delete&quot; &lt;sep&gt; |
+ *    &quot;modify&quot; &lt;sep&gt; &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt; &lt;options-e&gt; &lt;sep&gt;
+ *    &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; |
+ *    &quot;moddn&quot; &lt;sep&gt; &lt;newrdn&gt; &lt;sep&gt; &quot;deleteoldrdn:&quot; &lt;fill&gt; &lt;0-1&gt; &lt;sep&gt;
+ *    &lt;newsuperior-e&gt; &lt;sep&gt; |
+ *    &quot;modrdn&quot; &lt;sep&gt; &lt;newrdn&gt; &lt;sep&gt; &quot;deleteoldrdn:&quot; &lt;fill&gt; &lt;0-1&gt; &lt;sep&gt;
+ *    &lt;newsuperior-e&gt; &lt;sep&gt;
+ *
+ *  &lt;newrdn&gt; ::= ':' &lt;fill&gt; &lt;safe-string&gt; | &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt;
+ *
+ *  &lt;newsuperior-e&gt; ::= &quot;newsuperior&quot; &lt;newrdn&gt; | e
+ *
+ *  &lt;mod-specs-e&gt; ::= &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt; &lt;options-e&gt;
+ *    &lt;sep&gt; &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; | e
+ *
+ *  &lt;mod-type&gt; ::= &quot;add:&quot; | &quot;delete:&quot; | &quot;replace:&quot;
+ *
+ *  &lt;url&gt; ::= &lt;a Uniform Resource Locator, as defined in [6]&gt;
+ *
+ *
+ *
+ *  LEXICAL
+ *  -------
+ *
+ *  &lt;fill&gt;           ::= ' ' &lt;fill&gt; | e
+ *  &lt;char&gt;           ::= &lt;alpha&gt; | &lt;digit&gt; | '-'
+ *  &lt;number&gt;         ::= &lt;digit&gt; &lt;digits&gt;
+ *  &lt;0-1&gt;            ::= '0' | '1'
+ *  &lt;digits&gt;         ::= &lt;digit&gt; &lt;digits&gt; | e
+ *  &lt;digit&gt;          ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+ *  &lt;seps&gt;           ::= &lt;sep&gt; &lt;seps-e&gt;
+ *  &lt;seps-e&gt;         ::= &lt;sep&gt; &lt;seps-e&gt; | e
+ *  &lt;sep&gt;            ::= 0x0D 0x0A | 0x0A
+ *  &lt;spaces&gt;         ::= ' ' &lt;spaces-e&gt;
+ *  &lt;spaces-e&gt;       ::= ' ' &lt;spaces-e&gt; | e
+ *  &lt;safe-string-e&gt;  ::= &lt;safe-string&gt; | e
+ *  &lt;safe-string&gt;    ::= &lt;safe-init-char&gt; &lt;safe-chars&gt;
+ *  &lt;safe-init-char&gt; ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B | [0x3D-0x7F]
+ *  &lt;safe-chars&gt;     ::= &lt;safe-char&gt; &lt;safe-chars&gt; | e
+ *  &lt;safe-char&gt;      ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F]
+ *  &lt;base64-string&gt;  ::= &lt;base64-char&gt; &lt;base64-chars&gt;
+ *  &lt;base64-chars&gt;   ::= &lt;base64-char&gt; &lt;base64-chars&gt; | e
+ *  &lt;base64-char&gt;    ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-9x5A] | [0x61-0x7A]
+ *  &lt;alpha&gt;          ::= [0x41-0x5A] | [0x61-0x7A]
+ *
+ *  COMMENTS
+ *  --------
+ *  - The ldap-oid VN is not correct in the RFC-2849. It has been changed from 1*DIGIT 0*1(&quot;.&quot; 1*DIGIT) to
+ *  DIGIT+ (&quot;.&quot; DIGIT+)*
+ *  - The mod-spec lacks a sep between *attrval-spec and &quot;-&quot;.
+ *  - The BASE64-UTF8-STRING should be BASE64-CHAR BASE64-STRING
+ *  - The ValueSpec rule must accept multilines values. In this case, we have a LF followed by a
+ *  single space before the continued value.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifAttributesReader extends LdifReader
+{
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( LdifAttributesReader.class );
+
+
+    /**
+     * Constructors
+     */
+    public LdifAttributesReader()
+    {
+        lines = new ArrayList<String>();
+        position = 0;
+        version = DEFAULT_VERSION;
+    }
+
+
+    /**
+     * Parse an AttributeType/AttributeValue
+     *
+     * @param attributes The entry where to store the value
+     * @param line The line to parse
+     * @param lowerLine The same line, lowercased
+     * @throws LdapLdifException If anything goes wrong
+     */
+    private void parseAttribute( Attributes attributes, String line, String lowerLine ) throws LdapLdifException
+    {
+        int colonIndex = line.indexOf( ':' );
+
+        String attributeType = lowerLine.substring( 0, colonIndex );
+
+        // We should *not* have a Dn twice
+        if ( attributeType.equals( "dn" ) )
+        {
+            LOG.error( I18n.err( I18n.ERR_12002_ENTRY_WITH_TWO_DNS ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12003_LDIF_ENTRY_WITH_TWO_DNS ) );
+        }
+
+        Object attributeValue = parseValue( line, colonIndex );
+
+        // Update the entry
+        javax.naming.directory.Attribute attribute = attributes.get( attributeType );
+
+        if ( attribute == null )
+        {
+            attributes.put( attributeType, attributeValue );
+        }
+        else
+        {
+            attribute.add( attributeValue );
+        }
+    }
+
+
+    /**
+     * Parse an AttributeType/AttributeValue
+     *
+     * @param schemaManager The SchemaManager
+     * @param entry The entry where to store the value
+     * @param line The line to parse
+     * @param lowerLine The same line, lowercased
+     * @throws LdapLdifException If anything goes wrong
+     */
+    private void parseEntryAttribute( SchemaManager schemaManager, Entry entry, String line, String lowerLine )
+        throws LdapLdifException
+    {
+        int colonIndex = line.indexOf( ':' );
+
+        String attributeName = lowerLine.substring( 0, colonIndex );
+        AttributeType attributeType = null;
+
+        // We should *not* have a Dn twice
+        if ( attributeName.equals( "dn" ) )
+        {
+            LOG.error( I18n.err( I18n.ERR_12002_ENTRY_WITH_TWO_DNS ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12003_LDIF_ENTRY_WITH_TWO_DNS ) );
+        }
+
+        if ( schemaManager != null )
+        {
+            attributeType = schemaManager.getAttributeType( attributeName );
+
+            if ( attributeType == null )
+            {
+                LOG.error( "" );
+                throw new LdapLdifException( "" );
+            }
+        }
+
+        Object attributeValue = parseValue( line, colonIndex );
+
+        // Update the entry
+        Attribute attribute = null;
+
+        if ( schemaManager == null )
+        {
+            attribute = entry.get( attributeName );
+        }
+        else
+        {
+            attribute = entry.get( attributeType );
+        }
+
+        if ( attribute == null )
+        {
+            if ( schemaManager == null )
+            {
+                if ( attributeValue instanceof String )
+                {
+                    entry.put( attributeName, ( String ) attributeValue );
+                }
+                else
+                {
+                    entry.put( attributeName, ( byte[] ) attributeValue );
+                }
+            }
+            else
+            {
+                try
+                {
+                    if ( attributeValue instanceof String )
+                    {
+                        entry.put( attributeName, attributeType, ( String ) attributeValue );
+                    }
+                    else
+                    {
+                        entry.put( attributeName, attributeType, ( byte[] ) attributeValue );
+                    }
+                }
+                catch ( LdapException le )
+                {
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12057_BAD_ATTRIBUTE ), le );
+                }
+            }
+        }
+        else
+        {
+            try
+            {
+                if ( attributeValue instanceof String )
+                {
+                    attribute.add( ( String ) attributeValue );
+                }
+                else
+                {
+                    attribute.add( ( byte[] ) attributeValue );
+                }
+            }
+            catch ( LdapInvalidAttributeValueException liave )
+            {
+                throw new LdapLdifException( liave.getMessage(), liave );
+            }
+        }
+    }
+
+
+    /**
+     * Parse a ldif file. The following rules are processed :
+     *
+     * &lt;ldif-file&gt; ::= &lt;ldif-attrval-record&gt; &lt;ldif-attrval-records&gt; |
+     * &lt;ldif-change-record&gt; &lt;ldif-change-records&gt; &lt;ldif-attrval-record&gt; ::=
+     * &lt;dn-spec&gt; &lt;sep&gt; &lt;attrval-spec&gt; &lt;attrval-specs&gt; &lt;ldif-change-record&gt; ::=
+     * &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt; &lt;changerecord&gt; &lt;dn-spec&gt; ::= "dn:" &lt;fill&gt;
+     * &lt;distinguishedName&gt; | "dn::" &lt;fill&gt; &lt;base64-distinguishedName&gt;
+     * &lt;changerecord&gt; ::= "changetype:" &lt;fill&gt; &lt;change-op&gt;
+     *
+     * @param schemaManager The SchemaManager
+     * @return The read entry
+     * @throws LdapLdifException If the entry can't be read or is invalid
+     */
+    private Entry parseEntry( SchemaManager schemaManager ) throws LdapLdifException
+    {
+        if ( ( lines == null ) || ( lines.size() == 0 ) )
+        {
+            LOG.debug( "The entry is empty : end of ldif file" );
+            return null;
+        }
+
+        Entry entry = new DefaultEntry( schemaManager );
+
+        // Now, let's iterate through the other lines
+        for ( String line : lines )
+        {
+            // Each line could start either with an OID, an attribute type, with
+            // "control:" or with "changetype:"
+            String lowerLine = Strings.toLowerCase( line );
+
+            // We have three cases :
+            // 1) The first line after the Dn is a "control:" -> this is an error
+            // 2) The first line after the Dn is a "changeType:" -> this is an error
+            // 3) The first line after the Dn is anything else
+            if ( lowerLine.startsWith( "control:" ) )
+            {
+                LOG.error( I18n.err( I18n.ERR_12004_CHANGE_NOT_ALLOWED ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12005_NO_CHANGE ) );
+            }
+            else if ( lowerLine.startsWith( "changetype:" ) )
+            {
+                LOG.error( I18n.err( I18n.ERR_12004_CHANGE_NOT_ALLOWED ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12005_NO_CHANGE ) );
+            }
+            else if ( line.indexOf( ':' ) > 0 )
+            {
+                parseEntryAttribute( schemaManager, entry, line, lowerLine );
+            }
+            else
+            {
+                // Invalid attribute Value
+                LOG.error( I18n.err( I18n.ERR_12006_EXPECTING_ATTRIBUTE_TYPE ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12007_BAD_ATTRIBUTE ) );
+            }
+        }
+
+        LOG.debug( "Read an attributes : {}", entry );
+
+        return entry;
+    }
+
+
+    /**
+     * Parse a ldif file. The following rules are processed :
+     *
+     * &lt;ldif-file&gt; ::= &lt;ldif-attrval-record&gt; &lt;ldif-attrval-records&gt; |
+     * &lt;ldif-change-record&gt; &lt;ldif-change-records&gt; &lt;ldif-attrval-record&gt; ::=
+     * &lt;dn-spec&gt; &lt;sep&gt; &lt;attrval-spec&gt; &lt;attrval-specs&gt; &lt;ldif-change-record&gt; ::=
+     * &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt; &lt;changerecord&gt; &lt;dn-spec&gt; ::= "dn:" &lt;fill&gt;
+     * &lt;distinguishedName&gt; | "dn::" &lt;fill&gt; &lt;base64-distinguishedName&gt;
+     * &lt;changerecord&gt; ::= "changetype:" &lt;fill&gt; &lt;change-op&gt;
+     *
+     * @return The read entry
+     * @throws LdapLdifException If the entry can't be read or is invalid
+     */
+    private Attributes parseAttributes() throws LdapLdifException
+    {
+        if ( ( lines == null ) || ( lines.size() == 0 ) )
+        {
+            LOG.debug( "The entry is empty : end of ldif file" );
+            return null;
+        }
+
+        Attributes attributes = new BasicAttributes( true );
+
+        // Now, let's iterate through the other lines
+        for ( String line : lines )
+        {
+            // Each line could start either with an OID, an attribute type, with
+            // "control:" or with "changetype:"
+            String lowerLine = Strings.toLowerCase( line );
+
+            // We have three cases :
+            // 1) The first line after the Dn is a "control:" -> this is an error
+            // 2) The first line after the Dn is a "changeType:" -> this is an error
+            // 3) The first line after the Dn is anything else
+            if ( lowerLine.startsWith( "control:" ) )
+            {
+                LOG.error( I18n.err( I18n.ERR_12004_CHANGE_NOT_ALLOWED ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12005_NO_CHANGE ) );
+            }
+            else if ( lowerLine.startsWith( "changetype:" ) )
+            {
+                LOG.error( I18n.err( I18n.ERR_12004_CHANGE_NOT_ALLOWED ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12005_NO_CHANGE ) );
+            }
+            else if ( line.indexOf( ':' ) > 0 )
+            {
+                parseAttribute( attributes, line, lowerLine );
+            }
+            else
+            {
+                // Invalid attribute Value
+                LOG.error( I18n.err( I18n.ERR_12006_EXPECTING_ATTRIBUTE_TYPE ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12007_BAD_ATTRIBUTE ) );
+            }
+        }
+
+        LOG.debug( "Read an attributes : {}", attributes );
+
+        return attributes;
+    }
+
+
+    /**
+     * A method which parses a ldif string and returns a list of Attributes.
+     *
+     * @param ldif The ldif string
+     * @return A list of Attributes, or an empty List
+     * @throws LdapLdifException If something went wrong
+     */
+    public Attributes parseAttributes( String ldif ) throws LdapLdifException
+    {
+        lines = new ArrayList<String>();
+        position = 0;
+
+        LOG.debug( "Starts parsing ldif buffer" );
+
+        if ( Strings.isEmpty( ldif ) )
+        {
+            return new BasicAttributes( true );
+        }
+
+        StringReader strIn = new StringReader( ldif );
+        reader = new BufferedReader( strIn );
+
+        try
+        {
+            readLines();
+
+            Attributes attributes = parseAttributes();
+
+            if ( LOG.isDebugEnabled() )
+            {
+                if ( attributes == null )
+                {
+                    LOG.debug( "Parsed no entry." );
+                }
+                else
+                {
+                    LOG.debug( "Parsed one entry." );
+                }
+            }
+
+            return attributes;
+        }
+        catch ( LdapLdifException ne )
+        {
+            LOG.error( I18n.err( I18n.ERR_12008_CANNOT_PARSE_LDIF_BUFFER, ne.getLocalizedMessage() ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12009_ERROR_PARSING_LDIF_BUFFER ), ne );
+        }
+        finally
+        {
+            try
+            {
+                reader.close();
+            }
+            catch ( IOException ioe )
+            {
+                throw new LdapLdifException( I18n.err( I18n.ERR_12024_CANNOT_CLOSE_FILE ), ioe );
+            }
+        }
+    }
+
+
+    /**
+     * A method which parses a ldif string and returns an Entry.
+     *
+     * @param ldif The ldif string
+     * @return An entry
+     * @throws LdapLdifException If something went wrong
+     */
+    public Entry parseEntry( String ldif ) throws LdapLdifException
+    {
+        lines = new ArrayList<String>();
+        position = 0;
+
+        LOG.debug( "Starts parsing ldif buffer" );
+
+        if ( Strings.isEmpty( ldif ) )
+        {
+            return new DefaultEntry();
+        }
+
+        StringReader strIn = new StringReader( ldif );
+        reader = new BufferedReader( strIn );
+
+        try
+        {
+            readLines();
+
+            Entry entry = parseEntry( ( SchemaManager ) null );
+
+            if ( LOG.isDebugEnabled() )
+            {
+                if ( entry == null )
+                {
+                    LOG.debug( "Parsed no entry." );
+                }
+                else
+                {
+                    LOG.debug( "Parsed one entry." );
+                }
+
+            }
+
+            return entry;
+        }
+        catch ( LdapLdifException ne )
+        {
+            LOG.error( I18n.err( I18n.ERR_12008_CANNOT_PARSE_LDIF_BUFFER, ne.getLocalizedMessage() ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12009_ERROR_PARSING_LDIF_BUFFER ), ne );
+        }
+        finally
+        {
+            try
+            {
+                reader.close();
+            }
+            catch ( IOException ioe )
+            {
+                throw new LdapLdifException( I18n.err( I18n.ERR_12024_CANNOT_CLOSE_FILE ), ioe );
+            }
+        }
+    }
+
+
+    /**
+     * A method which parses a ldif string and returns an Entry.
+     *
+     * @param schemaManager The SchemaManager
+     * @param ldif The ldif string
+     * @return An entry
+     * @throws LdapLdifException If something went wrong
+     */
+    public Entry parseEntry( SchemaManager schemaManager, String ldif ) throws LdapLdifException
+    {
+        lines = new ArrayList<String>();
+        position = 0;
+
+        LOG.debug( "Starts parsing ldif buffer" );
+
+        if ( Strings.isEmpty( ldif ) )
+        {
+            return new DefaultEntry( schemaManager );
+        }
+
+        StringReader strIn = new StringReader( ldif );
+        reader = new BufferedReader( strIn );
+
+        try
+        {
+            readLines();
+
+            Entry entry = parseEntry( schemaManager );
+
+            if ( LOG.isDebugEnabled() )
+            {
+                if ( entry == null )
+                {
+                    LOG.debug( "Parsed no entry." );
+                }
+                else
+                {
+                    LOG.debug( "Parsed one entry." );
+                }
+
+            }
+
+            return entry;
+        }
+        catch ( LdapLdifException ne )
+        {
+            LOG.error( I18n.err( I18n.ERR_12008_CANNOT_PARSE_LDIF_BUFFER, ne.getLocalizedMessage() ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12009_ERROR_PARSING_LDIF_BUFFER ), ne );
+        }
+        finally
+        {
+            try
+            {
+                reader.close();
+            }
+            catch ( IOException ioe )
+            {
+                throw new LdapLdifException( I18n.err( I18n.ERR_12024_CANNOT_CLOSE_FILE ), ioe );
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifControl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifControl.java
new file mode 100644
index 0000000..55f2023
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifControl.java
@@ -0,0 +1,230 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * The LdifControl class stores a control defined for an entry found in a LDIF
+ * file.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifControl implements Control, Externalizable
+{
+    /** The control type */
+    private String oid;
+
+    /** The criticality (default value is false) */
+    private boolean criticality = false;
+
+    /** Optional control value */
+    protected byte[] value;
+
+
+    /**
+     * Create a new Control
+     */
+    public LdifControl()
+    {
+    }
+
+
+    /**
+     * Create a new Control
+     * 
+     * @param oid OID of the created control
+     */
+    public LdifControl( String oid )
+    {
+        this.oid = oid;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return "LdifControl : {" + getOid() + ", " + isCritical() + ", " + Strings.dumpBytes( getValue() ) + "}";
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return oid;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isCritical()
+    {
+        return criticality;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCritical( boolean criticality )
+    {
+        this.criticality = criticality;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setValue( byte[] value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasValue()
+    {
+        return value != null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        out.writeUTF( oid );
+        out.writeBoolean( criticality );
+
+        if ( hasValue() )
+        {
+            out.writeBoolean( true );
+            out.writeInt( value.length );
+
+            if ( value.length > 0 )
+            {
+                out.write( value );
+            }
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        out.flush();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        oid = in.readUTF();
+        criticality = in.readBoolean();
+
+        if ( in.readBoolean() )
+        {
+            int valueLength = in.readInt();
+
+            if ( valueLength > 0 )
+            {
+                value = new byte[valueLength];
+                in.readFully( value );
+            }
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    public int hashCode()
+    {
+        int h = 17;
+        h = h * 37 + ( criticality ? 1 : 0 );
+        h = h * 37 + ( oid == null ? 0 : oid.hashCode() );
+
+        if ( value != null )
+        {
+            for ( byte v : value )
+            {
+                h = h * 37 + v;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        if ( o == this )
+        {
+            return true;
+        }
+
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof Control ) )
+        {
+            return false;
+        }
+
+        Control otherControl = ( Control ) o;
+
+        if ( !oid.equalsIgnoreCase( otherControl.getOid() ) )
+        {
+            return false;
+        }
+
+        return criticality == otherControl.isCritical();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifEntry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifEntry.java
new file mode 100644
index 0000000..bb67721
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifEntry.java
@@ -0,0 +1,1467 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A entry to be populated by an ldif parser.
+ * 
+ * We will have different kind of entries : 
+ * <ul>
+ * <li>added entries</li>
+ * <li>deleted entries</li>
+ * <li>modified entries</li>
+ * <li>Rdn modified entries</li>
+ * <li>Dn modified entries</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifEntry implements Cloneable, Externalizable
+{
+    /** Used in toArray() */
+    public static final Modification[] EMPTY_MODS = new Modification[0];
+
+    /** the change type */
+    private ChangeType changeType;
+
+    /** the modification item list */
+    private List<Modification> modificationList;
+
+    /** The map containing all the modifications */
+    private Map<String, Modification> modifications;
+
+    /** The new superior */
+    private String newSuperior;
+
+    /** The new rdn */
+    private String newRdn;
+
+    /** The delete old rdn flag */
+    private boolean deleteOldRdn;
+
+    /** the entry */
+    private Entry entry;
+
+    /** the DN */
+    private Dn entryDn;
+
+    /** The controls */
+    private Map<String, LdifControl> controls;
+
+    /** The lengthBeforeParsing of the entry at the time of parsing. This includes
+     *  the lengthBeforeParsing of the comments present in entry at the time of parsing
+     *  so this lengthBeforeParsing may not always match with the lengthBeforeParsing of the entry
+     *  data present in memory.
+     */
+    private int lengthBeforeParsing = 0;
+
+    /** the position of the entry in the file or given input string*/
+    private long offset = 0;
+
+
+    /**
+     * Creates a new LdifEntry object.
+     */
+    public LdifEntry()
+    {
+        // Default LDIF content
+        changeType = ChangeType.None;
+        modificationList = new LinkedList<Modification>();
+        modifications = new HashMap<String, Modification>();
+        entry = new DefaultEntry( ( Dn ) null );
+        entryDn = null;
+        controls = null;
+    }
+
+
+    /**
+     * Creates a new schema aware LdifEntry object.
+     */
+    public LdifEntry( SchemaManager schemaManager )
+    {
+        // Default LDIF content
+        changeType = ChangeType.None;
+        modificationList = new LinkedList<Modification>();
+        modifications = new HashMap<String, Modification>();
+        entry = new DefaultEntry( schemaManager, ( Dn ) null );
+        entryDn = null;
+        controls = null;
+    }
+
+
+    /**
+     * Creates a new LdifEntry object, storing an Entry
+     */
+    public LdifEntry( Entry entry )
+    {
+        // Default LDIF content
+        changeType = ChangeType.None;
+        modificationList = new LinkedList<Modification>();
+        modifications = new HashMap<String, Modification>();
+        this.entry = entry;
+        entryDn = entry.getDn();
+        controls = null;
+    }
+
+
+    /**
+     * Creates a LdifEntry using a list of strings representing the Ldif element
+     * 
+     * @param dn The LdifEntry DN
+     * @param avas The Ldif to convert to an LdifEntry
+     * @throws LdapInvalidAttributeValueException If either the AttributeType or the associated value
+     * is incorrect
+     * @throws LdapLdifException If we get any other exception
+     */
+    public LdifEntry( Dn dn, Object... avas ) throws LdapInvalidAttributeValueException, LdapLdifException
+    {
+        // First, convert the arguments to a full LDIF
+        StringBuilder sb = new StringBuilder();
+        int pos = 0;
+        boolean valueExpected = false;
+        String dnStr = null;
+
+        if ( dn == null )
+        {
+            dnStr = "";
+        }
+        else
+        {
+            dnStr = dn.getName();
+        }
+
+        if ( LdifUtils.isLDIFSafe( dnStr ) )
+        {
+            sb.append( "dn: " ).append( dnStr ).append( '\n' );
+        }
+        else
+        {
+            sb.append( "dn:: " ).append( Base64.encode( Strings.getBytesUtf8( dnStr ) ) ).append( '\n' );
+        }
+
+        for ( Object ava : avas )
+        {
+            if ( !valueExpected )
+            {
+                if ( !( ava instanceof String ) )
+                {
+                    throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                        I18n.ERR_12085, ( pos + 1 ) ) );
+                }
+
+                String attribute = ( String ) ava;
+                sb.append( attribute );
+
+                if ( attribute.indexOf( ':' ) != -1 )
+                {
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    valueExpected = true;
+                }
+            }
+            else
+            {
+                if ( ava instanceof String )
+                {
+                    sb.append( ": " ).append( ( String ) ava ).append( '\n' );
+                }
+                else if ( ava instanceof byte[] )
+                {
+                    sb.append( ":: " );
+                    sb.append( new String( Base64.encode( ( byte[] ) ava ) ) );
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                        I18n.ERR_12086, ( pos + 1 ) ) );
+                }
+
+                valueExpected = false;
+            }
+        }
+
+        if ( valueExpected )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n
+                .err( I18n.ERR_12087 ) );
+        }
+
+        // Now, parse the Ldif and convert it to a LdifEntry
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> ldifEntries = reader.parseLdif( sb.toString() );
+
+        try
+        {
+            reader.close();
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+        }
+
+        if ( ( ldifEntries != null ) && ( ldifEntries.size() == 1 ) )
+        {
+            LdifEntry ldifEntry = ldifEntries.get( 0 );
+
+            changeType = ldifEntry.getChangeType();
+            controls = ldifEntry.getControls();
+            entryDn = ldifEntry.getDn();
+
+            switch ( ldifEntry.getChangeType() )
+            {
+                case Add:
+                    // Fallback
+                case None:
+                    entry = ldifEntry.getEntry();
+                    break;
+
+                case Delete:
+                    break;
+
+                case ModDn:
+                case ModRdn:
+                    newRdn = ldifEntry.getNewRdn();
+                    newSuperior = ldifEntry.getNewSuperior();
+                    deleteOldRdn = ldifEntry.isDeleteOldRdn();
+                    break;
+
+                case Modify:
+                    modificationList = ldifEntry.getModifications();
+                    modifications = new HashMap<String, Modification>();
+
+                    for ( Modification modification : modificationList )
+                    {
+                        modifications.put( modification.getAttribute().getId(), modification );
+                    }
+
+                    break;
+
+                default:
+                    throw new IllegalArgumentException( "Unexpected ChangeType: " + changeType );
+            }
+        }
+    }
+
+
+    /**
+     * Creates a LdifEntry using a list of strings representing the Ldif element
+     * 
+     * @param dn The LdifEntry DN
+     * @param avas The Ldif attributes and values to convert to an LdifEntry
+     * @throws LdapInvalidDnException If the Dn is invalid
+     * @throws LdapInvalidAttributeValueException If either the AttributeType or the associated value
+     * is incorrect
+     * @throws LdapLdifException If we get any other exception
+     */
+    public LdifEntry( String dn, Object... strings )
+        throws LdapInvalidAttributeValueException, LdapLdifException, LdapInvalidDnException
+    {
+        this( new Dn( dn ), strings );
+    }
+
+
+    /**
+     * Set the Distinguished Name
+     * 
+     * @param dn The Distinguished Name
+     */
+    public void setDn( Dn dn )
+    {
+        entryDn = dn;
+        entry.setDn( dn );
+    }
+
+
+    /**
+     * Set the Distinguished Name
+     * 
+     * @param dn The Distinguished Name
+     * @throws LdapInvalidDnException If the Dn is invalid
+     */
+    public void setDn( String dn ) throws LdapInvalidDnException
+    {
+        entryDn = new Dn( dn );
+        entry.setDn( entryDn );
+    }
+
+
+    /**
+     * Set the modification type
+     * 
+     * @param changeType The change type
+     * 
+     */
+    public void setChangeType( ChangeType changeType )
+    {
+        this.changeType = changeType;
+    }
+
+
+    /**
+     * Set the change type
+     * 
+     * @param changeType The change type
+     */
+    public void setChangeType( String changeType )
+    {
+        if ( "add".equals( changeType ) )
+        {
+            this.changeType = ChangeType.Add;
+        }
+        else if ( "modify".equals( changeType ) )
+        {
+            this.changeType = ChangeType.Modify;
+        }
+        else if ( "moddn".equals( changeType ) )
+        {
+            this.changeType = ChangeType.ModDn;
+        }
+        else if ( "modrdn".equals( changeType ) )
+        {
+            this.changeType = ChangeType.ModRdn;
+        }
+        else if ( "delete".equals( changeType ) )
+        {
+            this.changeType = ChangeType.Delete;
+        }
+    }
+
+
+    /**
+     * Add a modification item (used by modify operations)
+     * 
+     * @param modification The modification to be added
+     */
+    public void addModification( Modification modification )
+    {
+        if ( changeType == ChangeType.Modify )
+        {
+            modificationList.add( modification );
+            modifications.put( modification.getAttribute().getId(), modification );
+        }
+    }
+
+
+    /**
+     * Add a modification item (used by modify operations)
+     * 
+     * @param modOp The operation. One of : 
+     * <ul>
+     * <li>ModificationOperation.ADD_ATTRIBUTE</li>
+     * <li>ModificationOperation.REMOVE_ATTRIBUTE</li>
+     * <li>ModificationOperation.REPLACE_ATTRIBUTE</li>
+     * </ul>
+     * 
+     * @param attr The attribute to be added
+     */
+    public void addModification( ModificationOperation modOp, Attribute attr )
+    {
+        if ( changeType == ChangeType.Modify )
+        {
+            Modification item = new DefaultModification( modOp, attr );
+            modificationList.add( item );
+            modifications.put( attr.getId(), item );
+        }
+    }
+
+
+    /**
+     * Add a modification with no value
+     * 
+     * @param modOp The modification operation value. One of : 
+     * <ul>
+     * <li>ModificationOperation.ADD_ATTRIBUTE</li>
+     * <li>ModificationOperation.REMOVE_ATTRIBUTE</li>
+     * <li>ModificationOperation.REPLACE_ATTRIBUTE</li>
+     * </ul>
+     * 
+     * @param id The attribute's ID
+     */
+    public void addModification( ModificationOperation modOp, String id )
+    {
+        if ( changeType == ChangeType.Modify )
+        {
+            Attribute attr = new DefaultAttribute( id );
+
+            Modification item = new DefaultModification( modOp, attr );
+            modificationList.add( item );
+            modifications.put( id, item );
+        }
+    }
+
+
+    /**
+     * Add a modification
+     * 
+     * @param modOp The modification operation value. One of : 
+     * <ul>
+     * <li>ModificationOperation.ADD_ATTRIBUTE</li>
+     * <li>ModificationOperation.REMOVE_ATTRIBUTE</li>
+     * <li>ModificationOperation.REPLACE_ATTRIBUTE</li>
+     * </ul>
+     * 
+     * @param id The attribute's ID
+     * @param value The attribute's value
+     */
+    public void addModification( ModificationOperation modOp, String id, Object value )
+    {
+        if ( changeType == ChangeType.Modify )
+        {
+            Attribute attr;
+
+            if ( value == null )
+            {
+                value = new StringValue( ( String ) null );
+                attr = new DefaultAttribute( id, ( Value<?> ) value );
+            }
+            else
+            {
+                attr = ( Attribute ) value;
+            }
+
+            Modification item = new DefaultModification( modOp, attr );
+            modificationList.add( item );
+            modifications.put( id, item );
+        }
+    }
+
+
+    /**
+     * Add an attribute to the entry
+     * 
+     * @param attr The attribute to be added
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if something went wrong
+     */
+    public void addAttribute( Attribute attr ) throws LdapException
+    {
+        entry.put( attr );
+    }
+
+
+    /**
+     * Add an attribute to the entry
+     * 
+     * @param id The attribute ID
+     * 
+     * @param values The attribute values
+     * @throws LdapException if something went wrong
+     */
+    public void addAttribute( String id, Object... values ) throws LdapException
+    {
+        Attribute attribute = entry.get( id );
+        Boolean isHR = null;
+
+        if ( attribute != null )
+        {
+            isHR = attribute.isHumanReadable();
+        }
+
+        if ( values != null )
+        {
+            for ( Object value : values )
+            {
+                if ( value instanceof String )
+                {
+                    if ( isHR != null )
+                    {
+                        if ( isHR )
+                        {
+                            entry.add( id, ( String ) value );
+                        }
+                        else
+                        {
+                            entry.add( id, Strings.getBytesUtf8( ( String ) value ) );
+                        }
+                    }
+                    else
+                    {
+                        entry.add( id, ( String ) value );
+                    }
+                }
+                else
+                {
+                    if ( isHR != null )
+                    {
+                        if ( isHR )
+                        {
+                            entry.add( id, Strings.utf8ToString( ( byte[] ) value ) );
+                        }
+                        else
+                        {
+                            entry.add( id, ( byte[] ) value );
+                        }
+                    }
+                    else
+                    {
+                        entry.add( id, ( byte[] ) value );
+                    }
+                }
+            }
+        }
+        else
+        {
+            entry.add( id, ( Value<?> ) null );
+        }
+    }
+
+
+    /**
+     * Remove a list of Attributes from the LdifEntry
+     *
+     * @param ids The Attributes to remove
+     * @return The list of removed EntryAttributes
+     */
+    public void removeAttribute( String... ids )
+    {
+        if ( entry.containsAttribute( ids ) )
+        {
+            entry.removeAttributes( ids );
+        }
+    }
+
+
+    /**
+     * Add an attribute value to an existing attribute
+     * 
+     * @param id The attribute ID
+     * 
+     * @param value The attribute value
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if something went wrong
+     */
+    public void putAttribute( String id, Object value ) throws LdapException
+    {
+        if ( value instanceof String )
+        {
+            entry.add( id, ( String ) value );
+        }
+        else
+        {
+            entry.add( id, ( byte[] ) value );
+        }
+    }
+
+
+    /**
+     * Get the change type
+     * 
+     * @return The change type. One of : 
+     * <ul>
+     * <li>ADD</li>
+     * <li>MODIFY</li>
+     * <li>MODDN</li>
+     * <li>MODRDN</li>
+     * <li>DELETE</li>
+     * <li>NONE</li>
+     * </ul>
+     */
+    public ChangeType getChangeType()
+    {
+        return changeType;
+    }
+
+
+    /**
+     * @return The list of modification items
+     */
+    public List<Modification> getModifications()
+    {
+        return modificationList;
+    }
+
+
+    /**
+     * Gets the modification items as an array.
+     *
+     * @return modification items as an array.
+     */
+    public Modification[] getModificationArray()
+    {
+        return modificationList.toArray( EMPTY_MODS );
+    }
+
+
+    /**
+     * @return The entry Distinguished name
+     */
+    public Dn getDn()
+    {
+        return entryDn;
+    }
+
+
+    /**
+     * @return The number of entry modifications
+     */
+    public int size()
+    {
+        return modificationList.size();
+    }
+
+
+    /**
+     * Returns a attribute given it's id
+     * 
+     * @param attributeId The attribute Id
+     * @return The attribute if it exists
+     */
+    public Attribute get( String attributeId )
+    {
+        if ( "dn".equalsIgnoreCase( attributeId ) )
+        {
+            return new DefaultAttribute( "dn", entry.getDn().getName() );
+        }
+
+        return entry.get( attributeId );
+    }
+
+
+    /**
+     * Get the entry's entry
+     * 
+     * @return the stored Entry
+     */
+    public Entry getEntry()
+    {
+        if ( isEntry() )
+        {
+            return entry;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * @return True, if the old Rdn should be deleted.
+     */
+    public boolean isDeleteOldRdn()
+    {
+        return deleteOldRdn;
+    }
+
+
+    /**
+     * Set the flage deleteOldRdn
+     * 
+     * @param deleteOldRdn True if the old Rdn should be deleted
+     */
+    public void setDeleteOldRdn( boolean deleteOldRdn )
+    {
+        this.deleteOldRdn = deleteOldRdn;
+    }
+
+
+    /**
+     * @return The new Rdn
+     */
+    public String getNewRdn()
+    {
+        return newRdn;
+    }
+
+
+    /**
+     * Set the new Rdn
+     * 
+     * @param newRdn The new Rdn
+     */
+    public void setNewRdn( String newRdn )
+    {
+        this.newRdn = newRdn;
+    }
+
+
+    /**
+     * @return The new superior
+     */
+    public String getNewSuperior()
+    {
+        return newSuperior;
+    }
+
+
+    /**
+     * Set the new superior
+     * 
+     * @param newSuperior The new Superior
+     */
+    public void setNewSuperior( String newSuperior )
+    {
+        this.newSuperior = newSuperior;
+    }
+
+
+    /**
+     * @return True if this is a content ldif
+     */
+    public boolean isLdifContent()
+    {
+        return changeType == ChangeType.None;
+    }
+
+
+    /**
+     * @return True if there is this is a change ldif
+     */
+    public boolean isLdifChange()
+    {
+        return changeType != ChangeType.None;
+    }
+
+
+    /**
+     * @return True if the entry is an ADD entry
+     */
+    public boolean isChangeAdd()
+    {
+        return changeType == ChangeType.Add;
+    }
+
+
+    /**
+     * @return True if the entry is a DELETE entry
+     */
+    public boolean isChangeDelete()
+    {
+        return changeType == ChangeType.Delete;
+    }
+
+
+    /**
+     * @return True if the entry is a MODDN entry
+     */
+    public boolean isChangeModDn()
+    {
+        return changeType == ChangeType.ModDn;
+    }
+
+
+    /**
+     * @return True if the entry is a MODRDN entry
+     */
+    public boolean isChangeModRdn()
+    {
+        return changeType == ChangeType.ModRdn;
+    }
+
+
+    /**
+     * @return True if the entry is a MODIFY entry
+     */
+    public boolean isChangeModify()
+    {
+        return changeType == ChangeType.Modify;
+    }
+
+
+    /**
+     * Tells if the current entry is a added one
+     *
+     * @return <code>true</code> if the entry is added
+     */
+    public boolean isEntry()
+    {
+        return ( changeType == ChangeType.None ) || ( changeType == ChangeType.Add );
+    }
+
+
+    /**
+     * @return true if the entry has some controls
+     */
+    public boolean hasControls()
+    {
+        return controls != null;
+    }
+
+
+    /**
+     * @return The set of controls for this entry
+     */
+    public Map<String, LdifControl> getControls()
+    {
+        return controls;
+    }
+
+
+    /**
+     * @param oid The control's OID
+     * @return The associated control, if any
+     */
+    public LdifControl getControl( String oid )
+    {
+        if ( controls != null )
+        {
+            return controls.get( oid );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Add a control to the entry
+     * 
+     * @param controls The added controls
+     */
+    public void addControl( Control... controls )
+    {
+        if ( controls == null )
+        {
+            throw new IllegalArgumentException( "The added control must not be null" );
+        }
+
+        for ( Control control : controls )
+        {
+            if ( changeType == ChangeType.None )
+            {
+                changeType = ChangeType.Add;
+            }
+
+            if ( this.controls == null )
+            {
+                this.controls = new ConcurrentHashMap<String, LdifControl>();
+            }
+
+            if ( control instanceof LdifControl )
+            {
+                this.controls.put( control.getOid(), ( LdifControl ) control );
+            }
+            else
+            {
+                LdifControl ldifControl = new LdifControl( control.getOid() );
+                ldifControl.setCritical( control.isCritical() );
+                this.controls.put( control.getOid(), new LdifControl( control.getOid() ) );
+            }
+        }
+    }
+
+
+    /**
+     * Clone method
+     * @return a clone of the current instance
+     * @exception CloneNotSupportedException If there is some problem while cloning the instance
+     */
+    public LdifEntry clone() throws CloneNotSupportedException
+    {
+        LdifEntry clone = ( LdifEntry ) super.clone();
+
+        if ( modificationList != null )
+        {
+            for ( Modification modif : modificationList )
+            {
+                Modification modifClone = new DefaultModification( modif.getOperation(),
+                    modif.getAttribute().clone() );
+                clone.modificationList.add( modifClone );
+            }
+        }
+
+        if ( modifications != null )
+        {
+            for ( Map.Entry<String, Modification> entry : modifications.entrySet() )
+            {
+                Modification modif = entry.getValue();
+                Modification modifClone = new DefaultModification( modif.getOperation(),
+                    modif.getAttribute().clone() );
+                clone.modifications.put( entry.getKey(), modifClone );
+            }
+
+        }
+
+        if ( entry != null )
+        {
+            clone.entry = entry.clone();
+        }
+
+        return clone;
+    }
+
+
+    /** 
+     *  Returns the lengthBeforeParsing of the entry at the time of parsing. This includes
+     *  the lengthBeforeParsing of the comments present in entry at the time of parsing
+     *  so this lengthBeforeParsing may not always match with the lengthBeforeParsing of the entry
+     *  data present in memory.
+     */
+    public int getLengthBeforeParsing()
+    {
+        return lengthBeforeParsing;
+    }
+
+
+    /**
+     * @param lengthBeforeParsing the lengthBeforeParsing to set
+     */
+    /**No qualifier*/
+    void setLengthBeforeParsing( int length )
+    {
+        this.lengthBeforeParsing = length;
+    }
+
+
+    /**
+     * @return the offset
+     */
+    public long getOffset()
+    {
+        return offset;
+    }
+
+
+    /**
+     * @param offset the offset to set
+     */
+    /**No qualifier*/
+    void setOffset( long offset )
+    {
+        this.offset = offset;
+    }
+
+
+    /**
+     * @return a String representing the Entry, as a LDIF 
+     */
+    public String toString()
+    {
+        try
+        {
+            return LdifUtils.convertToLdif( this );
+        }
+        catch ( LdapException ne )
+        {
+            return "";
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * 
+     * @return the instance's hash code
+     */
+    public int hashCode()
+    {
+        int result = 37;
+
+        if ( entry != null && entry.getDn() != null )
+        {
+            result = result * 17 + entry.getDn().hashCode();
+        }
+
+        if ( changeType != null )
+        {
+            result = result * 17 + changeType.hashCode();
+
+            // Check each different cases
+            switch ( changeType )
+            {
+                case None:
+                    // Fall through
+                case Add:
+                    // Checks the attributes
+                    if ( entry != null )
+                    {
+                        result = result * 17 + entry.hashCode();
+                    }
+
+                    break;
+
+                case Delete:
+                    // Nothing to compute
+                    break;
+
+                case Modify:
+                    if ( modificationList != null )
+                    {
+                        result = result * 17 + modificationList.hashCode();
+
+                        for ( Modification modification : modificationList )
+                        {
+                            result = result * 17 + modification.hashCode();
+                        }
+                    }
+
+                    break;
+
+                case ModDn:
+                case ModRdn:
+                    result = result * 17;
+
+                    if ( deleteOldRdn )
+                    {
+                        result++;
+                    }
+                    else
+                    {
+                        result--;
+                    }
+
+                    if ( newRdn != null )
+                    {
+                        result = result * 17 + newRdn.hashCode();
+                    }
+
+                    if ( newSuperior != null )
+                    {
+                        result = result * 17 + newSuperior.hashCode();
+                    }
+
+                    break;
+
+                default:
+                    // do nothing
+                    break;
+            }
+        }
+
+        if ( controls != null )
+        {
+            for ( String control : controls.keySet() )
+            {
+                result = result * 17 + control.hashCode();
+            }
+        }
+
+        return result;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals( Object o )
+    {
+        // Basic equals checks
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof LdifEntry ) )
+        {
+            return false;
+        }
+
+        LdifEntry otherEntry = ( LdifEntry ) o;
+
+        // Check the Dn
+        Dn thisDn = entryDn;
+        Dn dnEntry = otherEntry.getDn();
+
+        if ( !thisDn.equals( dnEntry ) )
+        {
+            return false;
+        }
+
+        // Check the changeType
+        if ( changeType != otherEntry.changeType )
+        {
+            return false;
+        }
+
+        // Check each different cases
+        switch ( changeType )
+        {
+            case None:
+                // Fall through
+            case Add:
+                // Checks the attributes
+                if ( entry.size() != otherEntry.entry.size() )
+                {
+                    return false;
+                }
+
+                if ( !entry.equals( otherEntry.entry ) )
+                {
+                    return false;
+                }
+
+                break;
+
+            case Delete:
+                // Nothing to do, if the DNs are equals
+                break;
+
+            case Modify:
+                // Check the modificationItems list
+
+                // First, deal with special cases
+                if ( modificationList == null )
+                {
+                    if ( otherEntry.modificationList != null )
+                    {
+                        return false;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+
+                if ( otherEntry.modificationList == null )
+                {
+                    return false;
+                }
+
+                if ( modificationList.size() != otherEntry.modificationList.size() )
+                {
+                    return false;
+                }
+
+                // Now, compares the contents
+                int i = 0;
+
+                for ( Modification modification : modificationList )
+                {
+                    if ( !modification.equals( otherEntry.modificationList.get( i ) ) )
+                    {
+                        return false;
+                    }
+
+                    i++;
+                }
+
+                break;
+
+            case ModDn:
+            case ModRdn:
+                // Check the deleteOldRdn flag
+                if ( deleteOldRdn != otherEntry.deleteOldRdn )
+                {
+                    return false;
+                }
+
+                // Check the newRdn value
+                try
+                {
+                    Rdn thisNewRdn = new Rdn( newRdn );
+                    Rdn entryNewRdn = new Rdn( otherEntry.newRdn );
+
+                    if ( !thisNewRdn.equals( entryNewRdn ) )
+                    {
+                        return false;
+                    }
+                }
+                catch ( LdapInvalidDnException ine )
+                {
+                    return false;
+                }
+
+                // Check the newSuperior value
+                try
+                {
+                    Dn thisNewSuperior = new Dn( newSuperior );
+                    Dn entryNewSuperior = new Dn( otherEntry.newSuperior );
+
+                    if ( !thisNewSuperior.equals( entryNewSuperior ) )
+                    {
+                        return false;
+                    }
+                }
+                catch ( LdapInvalidDnException ine )
+                {
+                    return false;
+                }
+
+                break;
+
+            default:
+                // do nothing
+                break;
+        }
+
+        if ( controls != null )
+        {
+            Map<String, LdifControl> otherControls = otherEntry.controls;
+
+            if ( otherControls == null )
+            {
+                return false;
+            }
+
+            if ( controls.size() != otherControls.size() )
+            {
+                return false;
+            }
+
+            for ( Map.Entry<String, LdifControl> entry : controls.entrySet() )
+            {
+                String controlOid = entry.getKey();
+
+                if ( !otherControls.containsKey( controlOid ) )
+                {
+                    return false;
+                }
+
+                Control thisControl = entry.getValue();
+                Control otherControl = otherControls.get( controlOid );
+
+                if ( thisControl == null )
+                {
+                    if ( otherControl != null )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    if ( !thisControl.equals( otherControl ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            return true;
+        }
+        else
+        {
+            return otherEntry.controls == null;
+        }
+    }
+
+
+    /**
+     * @see Externalizable#readExternal(ObjectInput)
+     * 
+     * @param in The stream from which the LdifEntry is read
+     * @throws IOException If the stream can't be read
+     * @throws ClassNotFoundException If the LdifEntry can't be created 
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the changeType
+        int type = in.readInt();
+        changeType = ChangeType.getChangeType( type );
+
+        // Read the modification
+        switch ( changeType )
+        {
+            case Add:
+            case None:
+                // Read the entry
+                entry.readExternal( in );
+                entryDn = entry.getDn();
+
+                break;
+
+            case Delete:
+                // Read the Dn
+                entryDn = new Dn();
+                entryDn.readExternal( in );
+
+                break;
+
+            case ModDn:
+                // Fallback
+            case ModRdn:
+                // Read the Dn
+                entryDn = new Dn();
+                entryDn.readExternal( in );
+
+                deleteOldRdn = in.readBoolean();
+
+                if ( in.readBoolean() )
+                {
+                    newRdn = in.readUTF();
+                }
+
+                if ( in.readBoolean() )
+                {
+                    newSuperior = in.readUTF();
+                }
+
+                break;
+
+            case Modify:
+                // Read the Dn
+                entryDn = new Dn();
+                entryDn.readExternal( in );
+
+                // Read the modifications
+                int nbModifs = in.readInt();
+
+                for ( int i = 0; i < nbModifs; i++ )
+                {
+                    Modification modification = new DefaultModification();
+                    modification.readExternal( in );
+
+                    addModification( modification );
+                }
+
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected ChangeType: " + changeType );
+        }
+
+        int nbControls = in.readInt();
+
+        // We have at least a control
+        if ( nbControls > 0 )
+        {
+            controls = new ConcurrentHashMap<String, LdifControl>( nbControls );
+
+            for ( int i = 0; i < nbControls; i++ )
+            {
+                LdifControl control = new LdifControl();
+
+                control.readExternal( in );
+
+                controls.put( control.getOid(), control );
+            }
+        }
+    }
+
+
+    /**
+     * @see Externalizable#readExternal(ObjectInput)
+     * @param out The stream in which the ChangeLogEvent will be serialized.
+     * @throws IOException If the serialization fail
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        // Write the changeType
+        out.writeInt( changeType.getChangeType() );
+
+        // Write the data
+        switch ( changeType )
+        {
+            case Add:
+            case None:
+                entry.writeExternal( out );
+                break;
+
+            // Fallback
+            case Delete:
+                // we write the Dn
+                entryDn.writeExternal( out );
+                break;
+
+            case ModDn:
+                // Fallback
+            case ModRdn:
+                // Write the Dn
+                entryDn.writeExternal( out );
+
+                out.writeBoolean( deleteOldRdn );
+
+                if ( newRdn == null )
+                {
+                    out.writeBoolean( false );
+                }
+                else
+                {
+                    out.writeBoolean( true );
+                    out.writeUTF( newRdn );
+                }
+
+                if ( newSuperior != null )
+                {
+                    out.writeBoolean( true );
+                    out.writeUTF( newSuperior );
+                }
+                else
+                {
+                    out.writeBoolean( false );
+                }
+                break;
+
+            case Modify:
+                // Write the Dn
+                entryDn.writeExternal( out );
+
+                // Write the modifications
+                out.writeInt( modificationList.size() );
+
+                for ( Modification modification : modificationList )
+                {
+                    modification.writeExternal( out );
+                }
+
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected ChangeType: " + changeType );
+        }
+
+        // The controls
+        if ( controls != null )
+        {
+            // Write the control
+            out.writeInt( controls.size() );
+
+            for ( LdifControl control : controls.values() )
+            {
+                control.writeExternal( out );
+            }
+        }
+        else
+        {
+            // No control, write -1
+            out.writeInt( -1 );
+        }
+
+        // and flush the result
+        out.flush();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifReader.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifReader.java
new file mode 100644
index 0000000..8c47c29
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifReader.java
@@ -0,0 +1,2217 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.name.Ava;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.exception.NotImplementedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * <pre>
+ *  &lt;ldif-file&gt; ::= &quot;version:&quot; &lt;fill&gt; &lt;number&gt; &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt;
+ *  &lt;ldif-content-change&gt;
+ *
+ *  &lt;ldif-content-change&gt; ::=
+ *    &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt;
+ *    &lt;attrval-specs-e&gt; &lt;ldif-attrval-record-e&gt; |
+ *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt;
+ *    &lt;attrval-specs-e&gt; &lt;ldif-attrval-record-e&gt; |
+ *    &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt;
+ *    &lt;criticality&gt; &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt;
+ *        &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; |
+ *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt;
+ *
+ *  &lt;ldif-attrval-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;attributeType&gt;
+ *    &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt;
+ *    &lt;ldif-attrval-record-e&gt; | e
+ *
+ *  &lt;ldif-change-record-e&gt; ::= &lt;seps&gt; &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt;
+ *    &quot;changetype:&quot; &lt;fill&gt; &lt;changerecord-type&gt; &lt;ldif-change-record-e&gt; | e
+ *
+ *  &lt;dn-spec&gt; ::= &quot;dn:&quot; &lt;fill&gt; &lt;safe-string&gt; | &quot;dn::&quot; &lt;fill&gt; &lt;base64-string&gt;
+ *
+ *  &lt;controls-e&gt; ::= &quot;control:&quot; &lt;fill&gt; &lt;number&gt; &lt;oid&gt; &lt;spaces-e&gt; &lt;criticality&gt;
+ *    &lt;value-spec-e&gt; &lt;sep&gt; &lt;controls-e&gt; | e
+ *
+ *  &lt;criticality&gt; ::= &quot;true&quot; | &quot;false&quot; | e
+ *
+ *  &lt;oid&gt; ::= '.' &lt;number&gt; &lt;oid&gt; | e
+ *
+ *  &lt;attrval-specs-e&gt; ::= &lt;number&gt; &lt;oid&gt; &lt;options-e&gt; &lt;value-spec&gt;
+ *  &lt;sep&gt; &lt;attrval-specs-e&gt; |
+ *    &lt;alpha&gt; &lt;chars-e&gt; &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; | e
+ *
+ *  &lt;value-spec-e&gt; ::= &lt;value-spec&gt; | e
+ *
+ *  &lt;value-spec&gt; ::= ':' &lt;fill&gt; &lt;safe-string-e&gt; |
+ *    &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt; |
+ *    &quot;:&lt;&quot; &lt;fill&gt; &lt;url&gt;
+ *
+ *  &lt;attributeType&gt; ::= &lt;number&gt; &lt;oid&gt; | &lt;alpha&gt; &lt;chars-e&gt;
+ *
+ *  &lt;options-e&gt; ::= ';' &lt;char&gt; &lt;chars-e&gt; &lt;options-e&gt; |e
+ *
+ *  &lt;chars-e&gt; ::= &lt;char&gt; &lt;chars-e&gt; |  e
+ *
+ *  &lt;changerecord-type&gt; ::= &quot;add&quot; &lt;sep&gt; &lt;attributeType&gt;
+ *  &lt;options-e&gt; &lt;value-spec&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; |
+ *    &quot;delete&quot; &lt;sep&gt; |
+ *    &quot;modify&quot; &lt;sep&gt; &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt;
+ *    &lt;options-e&gt; &lt;sep&gt; &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; |
+ *    &quot;moddn&quot; &lt;sep&gt; &lt;newrdn&gt; &lt;sep&gt; &quot;deleteoldrdn:&quot;
+ *    &lt;fill&gt; &lt;0-1&gt; &lt;sep&gt; &lt;newsuperior-e&gt; &lt;sep&gt; |
+ *    &quot;modrdn&quot; &lt;sep&gt; &lt;newrdn&gt; &lt;sep&gt; &quot;deleteoldrdn:&quot;
+ *    &lt;fill&gt; &lt;0-1&gt; &lt;sep&gt; &lt;newsuperior-e&gt; &lt;sep&gt;
+ *
+ *  &lt;newrdn&gt; ::= ':' &lt;fill&gt; &lt;safe-string&gt; | &quot;::&quot; &lt;fill&gt; &lt;base64-chars&gt;
+ *
+ *  &lt;newsuperior-e&gt; ::= &quot;newsuperior&quot; &lt;newrdn&gt; | e
+ *
+ *  &lt;mod-specs-e&gt; ::= &lt;mod-type&gt; &lt;fill&gt; &lt;attributeType&gt; &lt;options-e&gt;
+ *    &lt;sep&gt; &lt;attrval-specs-e&gt; &lt;sep&gt; '-' &lt;sep&gt; &lt;mod-specs-e&gt; | e
+ *
+ *  &lt;mod-type&gt; ::= &quot;add:&quot; | &quot;delete:&quot; | &quot;replace:&quot;
+ *
+ *  &lt;url&gt; ::= &lt;a Uniform Resource Locator, as defined in [6]&gt;
+ *
+ *
+ *
+ *  LEXICAL
+ *  -------
+ *
+ *  &lt;fill&gt;           ::= ' ' &lt;fill&gt; | e
+ *  &lt;char&gt;           ::= &lt;alpha&gt; | &lt;digit&gt; | '-'
+ *  &lt;number&gt;         ::= &lt;digit&gt; &lt;digits&gt;
+ *  &lt;0-1&gt;            ::= '0' | '1'
+ *  &lt;digits&gt;         ::= &lt;digit&gt; &lt;digits&gt; | e
+ *  &lt;digit&gt;          ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+ *  &lt;seps&gt;           ::= &lt;sep&gt; &lt;seps-e&gt;
+ *  &lt;seps-e&gt;         ::= &lt;sep&gt; &lt;seps-e&gt; | e
+ *  &lt;sep&gt;            ::= 0x0D 0x0A | 0x0A
+ *  &lt;spaces&gt;         ::= ' ' &lt;spaces-e&gt;
+ *  &lt;spaces-e&gt;       ::= ' ' &lt;spaces-e&gt; | e
+ *  &lt;safe-string-e&gt;  ::= &lt;safe-string&gt; | e
+ *  &lt;safe-string&gt;    ::= &lt;safe-init-char&gt; &lt;safe-chars&gt;
+ *  &lt;safe-init-char&gt; ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B | [0x3D-0x7F]
+ *  &lt;safe-chars&gt;     ::= &lt;safe-char&gt; &lt;safe-chars&gt; | e
+ *  &lt;safe-char&gt;      ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F]
+ *  &lt;base64-string&gt;  ::= &lt;base64-char&gt; &lt;base64-chars&gt;
+ *  &lt;base64-chars&gt;   ::= &lt;base64-char&gt; &lt;base64-chars&gt; | e
+ *  &lt;base64-char&gt;    ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-9x5A] | [0x61-0x7A]
+ *  &lt;alpha&gt;          ::= [0x41-0x5A] | [0x61-0x7A]
+ *
+ *  COMMENTS
+ *  --------
+ *  - The ldap-oid VN is not correct in the RFC-2849. It has been changed from 1*DIGIT 0*1(&quot;.&quot; 1*DIGIT) to
+ *  DIGIT+ (&quot;.&quot; DIGIT+)*
+ *  - The mod-spec lacks a sep between *attrval-spec and &quot;-&quot;.
+ *  - The BASE64-UTF8-STRING should be BASE64-CHAR BASE64-STRING
+ *  - The ValueSpec rule must accept multilines values. In this case, we have a LF followed by a
+ *  single space before the continued value.
+ * </pre>
+ * The relaxed mode is used when a SchemaManager is injected.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifReader implements Iterable<LdifEntry>, Closeable
+{
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( LdifReader.class );
+
+    /** A list of read lines */
+    protected List<String> lines;
+
+    /** The current position */
+    protected int position;
+
+    /** The ldif file version default value */
+    protected static final int DEFAULT_VERSION = 1;
+
+    /** The ldif version */
+    protected int version;
+
+    /** Type of element read : ENTRY */
+    protected static final int LDIF_ENTRY = 0;
+
+    /** Type of element read : CHANGE */
+    protected static final int CHANGE = 1;
+
+    /** Type of element read : UNKNOWN */
+    protected static final int UNKNOWN = 2;
+
+    /** Size limit for file contained values */
+    protected long sizeLimit = SIZE_LIMIT_DEFAULT;
+
+    /** The default size limit : 1Mo */
+    protected static final long SIZE_LIMIT_DEFAULT = 1024000;
+
+    /** State values for the modify operation : MOD_SPEC */
+    protected static final int MOD_SPEC = 0;
+
+    /** State values for the modify operation : ATTRVAL_SPEC */
+    protected static final int ATTRVAL_SPEC = 1;
+
+    /** State values for the modify operation : ATTRVAL_SPEC_OR_SEP */
+    protected static final int ATTRVAL_SPEC_OR_SEP = 2;
+
+    /** Iterator prefetched entry */
+    protected LdifEntry prefetched;
+
+    /** The ldif Reader */
+    protected Reader reader;
+
+    /** A flag set if the ldif contains entries */
+    protected boolean containsEntries;
+
+    /** A flag set if the ldif contains changes */
+    protected boolean containsChanges;
+
+    /** The SchemaManager instance, if any */
+    protected SchemaManager schemaManager;
+
+    /**
+     * An Exception to handle error message, has Iterator.next() can't throw
+     * exceptions
+     */
+    protected Exception error;
+
+    /** total length of an LDIF entry including the comments */
+    protected int entryLen = 0;
+
+    /** the parsed entry's starting position */
+    protected long entryOffset = 0;
+
+    /** the current offset of the reader */
+    protected long offset = 0;
+
+    /** the numer of the current line being parsed by the reader */
+    protected int lineNumber;
+
+    /** flag to turn on/off of the DN validation. By default DNs are validated after parsing */
+    protected boolean validateDn = true;
+    
+    /** A counter used to create facked OIDs */
+    private int oidCounter = 0;
+
+
+    /**
+     * Constructors
+     */
+    public LdifReader()
+    {
+        lines = new ArrayList<String>();
+        position = 0;
+        version = DEFAULT_VERSION;
+    }
+
+
+    /**
+     * Constructors
+     */
+    public LdifReader( SchemaManager schemaManager )
+    {
+        lines = new ArrayList<String>();
+        position = 0;
+        version = DEFAULT_VERSION;
+        this.schemaManager = schemaManager;
+    }
+
+
+    /**
+     * Store the reader and intialize the LdifReader
+     */
+    private void initReader( BufferedReader reader ) throws LdapException
+    {
+        this.reader = reader;
+        init();
+    }
+
+
+    /**
+     * Initialize the LdifReader
+     * 
+     * @throws LdapException If the initialization failed
+     */
+    public void init() throws LdapException
+    {
+        lines = new ArrayList<String>();
+        position = 0;
+        version = DEFAULT_VERSION;
+        containsChanges = false;
+        containsEntries = false;
+
+        // First get the version - if any -
+        version = parseVersion();
+        prefetched = parseEntry();
+    }
+
+
+    /**
+     * A constructor which takes a file name
+     *
+     * @param ldifFileName A file name containing ldif formated input
+     * @throws LdapLdifException If the file cannot be processed or if the format is incorrect
+     */
+    public LdifReader( String ldifFileName ) throws LdapLdifException
+    {
+        File file = new File( ldifFileName );
+
+        if ( !file.exists() )
+        {
+            String msg = I18n.err( I18n.ERR_12010_CANNOT_FIND_FILE, file.getAbsoluteFile() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg );
+        }
+
+        if ( !file.canRead() )
+        {
+            String msg = I18n.err( I18n.ERR_12011_CANNOT_READ_FILE, file.getName() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg );
+        }
+
+        try
+        {
+            initReader( new BufferedReader( new FileReader( file ) ) );
+        }
+        catch ( FileNotFoundException fnfe )
+        {
+            String msg = I18n.err( I18n.ERR_12010_CANNOT_FIND_FILE, file.getAbsoluteFile() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg, fnfe );
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            throw new LdapLdifException( lide.getMessage(), lide );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapLdifException( le.getMessage(), le );
+        }
+    }
+
+
+    /**
+     * A constructor which takes a Reader
+     *
+     * @param in A Reader containing ldif formated input
+     * @throws LdapException If the file cannot be processed or if the format is incorrect
+     */
+    public LdifReader( Reader in ) throws LdapException
+    {
+        initReader( new BufferedReader( in ) );
+    }
+
+
+    /**
+     * A constructor which takes an InputStream
+     *
+     * @param in An InputStream containing ldif formated input
+     * @throws LdapException If the file cannot be processed or if the format is incorrect
+     */
+    public LdifReader( InputStream in ) throws LdapException
+    {
+        initReader( new BufferedReader( new InputStreamReader( in ) ) );
+    }
+
+
+    /**
+     * A constructor which takes a File
+     *
+     * @param file A File containing ldif formated input
+     * @throws LdapLdifException If the file cannot be processed or if the format is incorrect
+     */
+    public LdifReader( File file ) throws LdapLdifException
+    {
+        if ( !file.exists() )
+        {
+            String msg = I18n.err( I18n.ERR_12010_CANNOT_FIND_FILE, file.getAbsoluteFile() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg );
+        }
+
+        if ( !file.canRead() )
+        {
+            String msg = I18n.err( I18n.ERR_12011_CANNOT_READ_FILE, file.getName() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg );
+        }
+
+        try
+        {
+            initReader( new BufferedReader( new FileReader( file ) ) );
+        }
+        catch ( FileNotFoundException fnfe )
+        {
+            String msg = I18n.err( I18n.ERR_12010_CANNOT_FIND_FILE, file.getAbsoluteFile() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg, fnfe );
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            throw new LdapLdifException( lide.getMessage(), lide );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapLdifException( le.getMessage(), le );
+        }
+    }
+
+
+    /**
+     * A constructor which takes a File and a SchemaManager
+     *
+     * @param file A File containing ldif formated input
+     * @param schemaManager The SchemaManager instance to use
+     * @throws LdapLdifException If the file cannot be processed or if the format is incorrect
+     */
+    public LdifReader( File file, SchemaManager schemaManager ) throws LdapLdifException
+    {
+        if ( !file.exists() )
+        {
+            String msg = I18n.err( I18n.ERR_12010_CANNOT_FIND_FILE, file.getAbsoluteFile() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg );
+        }
+
+        if ( !file.canRead() )
+        {
+            String msg = I18n.err( I18n.ERR_12011_CANNOT_READ_FILE, file.getName() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg );
+        }
+
+        this.schemaManager = schemaManager;
+
+        try
+        {
+            initReader( new BufferedReader( new FileReader( file ) ) );
+        }
+        catch ( FileNotFoundException fnfe )
+        {
+            String msg = I18n.err( I18n.ERR_12010_CANNOT_FIND_FILE, file.getAbsoluteFile() );
+            LOG.error( msg );
+            throw new LdapLdifException( msg, fnfe );
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            throw new LdapLdifException( lide.getMessage(), lide );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapLdifException( le.getMessage(), le );
+        }
+    }
+
+
+    /**
+     * @return The ldif file version
+     */
+    public int getVersion()
+    {
+        return version;
+    }
+
+
+    /**
+     * @return The maximum size of a file which is used into an attribute value.
+     */
+    public long getSizeLimit()
+    {
+        return sizeLimit;
+    }
+
+
+    /**
+     * Set the maximum file size that can be accepted for an attribute value
+     *
+     * @param sizeLimit The size in bytes
+     */
+    public void setSizeLimit( long sizeLimit )
+    {
+        this.sizeLimit = sizeLimit;
+    }
+
+
+    // <fill> ::= ' ' <fill> | e
+    private void parseFill( char[] document )
+    {
+        while ( Chars.isCharASCII( document, position, ' ' ) )
+        {
+            position++;
+        }
+    }
+
+
+    /**
+     * Parse a number following the rules :
+     *
+     * &lt;number&gt; ::= &lt;digit&gt; &lt;digits&gt; &lt;digits&gt; ::= &lt;digit&gt; &lt;digits&gt; | e &lt;digit&gt;
+     * ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * Check that the number is in the interval
+     *
+     * @param document The document containing the number to parse
+     * @return a String representing the parsed number
+     */
+    private String parseNumber( char[] document )
+    {
+        int initPos = position;
+
+        while ( true )
+        {
+            if ( Chars.isDigit( document, position ) )
+            {
+                position++;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        if ( position == initPos )
+        {
+            return null;
+        }
+        else
+        {
+            return new String( document, initPos, position - initPos );
+        }
+    }
+
+
+    /**
+     * Parse the changeType
+     *
+     * @param line The line which contains the changeType
+     * @return The operation.
+     */
+    protected ChangeType parseChangeType( String line )
+    {
+        ChangeType operation = ChangeType.Add;
+
+        String modOp = Strings.trim( line.substring( "changetype:".length() ) );
+
+        if ( "add".equalsIgnoreCase( modOp ) )
+        {
+            operation = ChangeType.Add;
+        }
+        else if ( "delete".equalsIgnoreCase( modOp ) )
+        {
+            operation = ChangeType.Delete;
+        }
+        else if ( "modify".equalsIgnoreCase( modOp ) )
+        {
+            operation = ChangeType.Modify;
+        }
+        else if ( "moddn".equalsIgnoreCase( modOp ) )
+        {
+            operation = ChangeType.ModDn;
+        }
+        else if ( "modrdn".equalsIgnoreCase( modOp ) )
+        {
+            operation = ChangeType.ModRdn;
+        }
+
+        return operation;
+    }
+
+
+    /**
+     * Parse the Dn of an entry
+     *
+     * @param line The line to parse
+     * @return A Dn
+     * @throws LdapLdifException If the Dn is invalid
+     */
+    protected String parseDn( String line ) throws LdapLdifException
+    {
+        String dn;
+
+        String lowerLine = Strings.toLowerCaseAscii( line );
+
+        if ( lowerLine.startsWith( "dn:" ) || lowerLine.startsWith( "Dn:" ) )
+        {
+            // Ok, we have a Dn. Is it base 64 encoded ?
+            int length = line.length();
+
+            if ( length == 3 )
+            {
+                // The Dn is empty : it's a rootDSE
+                dn = "";
+            }
+            else if ( line.charAt( 3 ) == ':' )
+            {
+                if ( length > 4 )
+                {
+                    // This is a base 64 encoded Dn.
+                    String trimmedLine = line.substring( 4 ).trim();
+
+                    try
+                    {
+                        dn = new String( Base64.decode( trimmedLine.toCharArray() ), "UTF-8" );
+                    }
+                    catch ( UnsupportedEncodingException uee )
+                    {
+                        // The Dn is not base 64 encoded
+                        LOG.error( I18n.err( I18n.ERR_12014_BASE64_DN_EXPECTED, lineNumber ) );
+                        throw new LdapLdifException( I18n.err( I18n.ERR_12015_INVALID_BASE64_DN ), uee );
+                    }
+                }
+                else
+                {
+                    // The Dn is empty : error
+                    LOG.error( I18n.err( I18n.ERR_12012_EMPTY_DN_NOT_ALLOWED, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12013_NO_DN ) );
+                }
+            }
+            else
+            {
+                dn = line.substring( 3 ).trim();
+            }
+        }
+        else
+        {
+            LOG.error( I18n.err( I18n.ERR_12016_DN_EXPECTED, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12013_NO_DN ) );
+        }
+
+        // Check that the Dn is valid. If not, an exception will be thrown
+        if ( validateDn && !Dn.isValid( dn ) )
+        {
+            String message = I18n.err( I18n.ERR_12017_INVALID_DN, dn, lineNumber );
+            LOG.error( message );
+            throw new LdapLdifException( message );
+        }
+
+        return dn;
+    }
+
+
+    /**
+     * Parse the value part.
+     *
+     * @param line The line which contains the value
+     * @param pos The starting position in the line
+     * @return A String or a byte[], depending of the kind of value we get
+     */
+    protected static Object parseSimpleValue( String line, int pos )
+    {
+        if ( line.length() > pos + 1 )
+        {
+            char c = line.charAt( pos + 1 );
+
+            if ( c == ':' )
+            {
+                String value = Strings.trim( line.substring( pos + 2 ) );
+
+                return Base64.decode( value.toCharArray() );
+            }
+            else
+            {
+                return Strings.trim( line.substring( pos + 1 ) );
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Parse the value part.
+     *
+     * @param line The line which contains the value
+     * @param pos The starting position in the line
+     * @return A String or a byte[], depending of the kind of value we get
+     * @throws LdapLdifException If something went wrong
+     */
+    protected Object parseValue( String line, int pos ) throws LdapLdifException
+    {
+        if ( line.length() > pos + 1 )
+        {
+            char c = line.charAt( pos + 1 );
+
+            if ( c == ':' )
+            {
+                String value = Strings.trim( line.substring( pos + 2 ) );
+
+                return Base64.decode( value.toCharArray() );
+            }
+            else if ( c == '<' )
+            {
+                String urlName = Strings.trim( line.substring( pos + 2 ) );
+
+                try
+                {
+                    URL url = new URL( urlName );
+
+                    if ( "file".equals( url.getProtocol() ) )
+                    {
+                        String fileName = url.getFile();
+
+                        File file = new File( fileName );
+
+                        if ( !file.exists() )
+                        {
+                            LOG.error( I18n.err( I18n.ERR_12018_FILE_NOT_FOUND, fileName, lineNumber ) );
+                            throw new LdapLdifException( I18n.err( I18n.ERR_12019_BAD_URL_FILE_NOT_FOUND ) );
+                        }
+                        else
+                        {
+                            long length = file.length();
+
+                            if ( length > sizeLimit )
+                            {
+                                String message = I18n.err( I18n.ERR_12020_FILE_TOO_BIG, fileName, lineNumber );
+                                LOG.error( message );
+                                throw new LdapLdifException( message );
+                            }
+                            else
+                            {
+                                byte[] data = new byte[( int ) length];
+                                DataInputStream inf = null;
+
+                                try
+                                {
+                                    inf = new DataInputStream( new FileInputStream( file ) );
+                                    inf.readFully( data );
+
+                                    return data;
+                                }
+                                catch ( FileNotFoundException fnfe )
+                                {
+                                    // We can't reach this point, the file
+                                    // existence has already been
+                                    // checked
+                                    LOG.error( I18n.err( I18n.ERR_12018_FILE_NOT_FOUND, fileName, lineNumber ) );
+                                    throw new LdapLdifException( I18n.err( I18n.ERR_12019_BAD_URL_FILE_NOT_FOUND ),
+                                        fnfe );
+                                }
+                                catch ( IOException ioe )
+                                {
+                                    LOG.error( I18n.err( I18n.ERR_12022_ERROR_READING_FILE, fileName, lineNumber ) );
+                                    throw new LdapLdifException( I18n.err( I18n.ERR_12023_ERROR_READING_BAD_URL ), ioe );
+                                }
+                                finally
+                                {
+                                    try
+                                    {
+                                        if ( inf != null )
+                                        {
+                                            inf.close();
+                                        }
+                                    }
+                                    catch ( IOException ioe )
+                                    {
+                                        LOG.error(
+                                            I18n.err( I18n.ERR_12024_CANNOT_CLOSE_FILE, ioe.getMessage(), lineNumber ),
+                                            ioe );
+                                        // Just do nothing ...
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        LOG.error( I18n.err( I18n.ERR_12025_BAD_PROTOCOL ) );
+                        throw new LdapLdifException( I18n.err( I18n.ERR_12026_UNSUPPORTED_PROTOCOL, lineNumber ) );
+                    }
+                }
+                catch ( MalformedURLException mue )
+                {
+                    String message = I18n.err( I18n.ERR_12027_BAD_URL, urlName, lineNumber );
+                    LOG.error( message );
+                    throw new LdapLdifException( message, mue );
+                }
+            }
+            else
+            {
+                String value = Strings.trimLeft( line.substring( pos + 1 ) );
+                int end = value.length();
+
+                for ( int i = value.length() - 1; i > 0; i-- )
+                {
+                    char cc = value.charAt( i );
+
+                    if ( cc == ' ' )
+                    {
+                        if ( value.charAt( i - 1 ) == '\\' )
+                        {
+                            // Escaped space : do nothing
+                            break;
+                        }
+                        else
+                        {
+                            end = i;
+                        }
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+
+                String result = null;
+
+                result = value.substring( 0, end );
+
+                return result;
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Parse a control. The grammar is :
+     * <pre>
+     * &lt;control&gt; ::= "control:" &lt;fill&gt; &lt;ldap-oid&gt; &lt;critical-e&gt; &lt;value-spec-e&gt; &lt;sep&gt;
+     * &lt;critical-e&gt; ::= &lt;spaces&gt; &lt;boolean&gt; | e
+     * &lt;boolean&gt; ::= "true" | "false"
+     * &lt;value-spec-e&gt; ::= &lt;value-spec&gt; | e
+     * &lt;value-spec&gt; ::= ":" &lt;fill&gt; &lt;SAFE-STRING-e&gt; | "::" &lt;fill&gt; &lt;BASE64-STRING&gt; | ":<" &lt;fill&gt; &lt;url&gt;
+     * </pre>
+     *
+     * It can be read as :
+     * <pre>
+     * "control:" &lt;fill&gt; &lt;ldap-oid&gt; [ " "+ ( "true" |
+     * "false") ] [ ":" &lt;fill&gt; &lt;SAFE-STRING-e&gt; | "::" &lt;fill&gt; &lt;BASE64-STRING&gt; | ":<"
+     * &lt;fill&gt; &lt;url&gt; ]
+     * </pre>
+     *
+     * @param line The line containing the control
+     * @return A control
+     * @exception LdapLdifException If the control has no OID or if the OID is incorrect,
+     * of if the criticality is not set when it's mandatory.
+     */
+    private Control parseControl( String line ) throws LdapLdifException
+    {
+        String lowerLine = Strings.toLowerCaseAscii( line ).trim();
+        char[] controlValue = line.trim().toCharArray();
+        int pos = 0;
+        int length = controlValue.length;
+
+        // Get the <ldap-oid>
+        if ( pos > length )
+        {
+            // No OID : error !
+            LOG.error( I18n.err( I18n.ERR_12029_CONTROL_WITHOUT_OID, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12029_CONTROL_WITHOUT_OID ) );
+        }
+
+        int initPos = pos;
+
+        while ( Chars.isCharASCII( controlValue, pos, '.' ) || Chars.isDigit( controlValue, pos ) )
+        {
+            pos++;
+        }
+
+        if ( pos == initPos )
+        {
+            // Not a valid OID !
+            LOG.error( I18n.err( I18n.ERR_12029_CONTROL_WITHOUT_OID, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12029_CONTROL_WITHOUT_OID ) );
+        }
+
+        // Create and check the OID
+        String oidString = lowerLine.substring( 0, pos );
+
+        if ( !Oid.isOid( oidString ) )
+        {
+            String message = I18n.err( I18n.ERR_12031_INVALID_OID, oidString, lineNumber );
+            LOG.error( message );
+            throw new LdapLdifException( message );
+        }
+
+        LdifControl control = new LdifControl( oidString );
+
+        // Get the criticality, if any
+        // Skip the <fill>
+        while ( Chars.isCharASCII( controlValue, pos, ' ' ) )
+        {
+            pos++;
+        }
+
+        // Check if we have a "true" or a "false"
+        int criticalPos = lowerLine.indexOf( ':' );
+
+        int criticalLength;
+
+        if ( criticalPos == -1 )
+        {
+            criticalLength = length - pos;
+        }
+        else
+        {
+            criticalLength = criticalPos - pos;
+        }
+
+        if ( ( criticalLength == 4 ) && ( "true".equalsIgnoreCase( lowerLine.substring( pos, pos + 4 ) ) ) )
+        {
+            control.setCritical( true );
+        }
+        else if ( ( criticalLength == 5 ) && ( "false".equalsIgnoreCase( lowerLine.substring( pos, pos + 5 ) ) ) )
+        {
+            control.setCritical( false );
+        }
+        else if ( criticalLength != 0 )
+        {
+            // If we have a criticality, it should be either "true" or "false",
+            // nothing else
+            LOG.error( I18n.err( I18n.ERR_12033_INVALID_CRITICALITY, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12033_INVALID_CRITICALITY ) );
+        }
+
+        if ( criticalPos > 0 )
+        {
+            // We have a value. It can be a normal value, a base64 encoded value
+            // or a file contained value
+            if ( Chars.isCharASCII( controlValue, criticalPos + 1, ':' ) )
+            {
+                // Base 64 encoded value
+
+                // Skip the <fill>
+                pos = criticalPos + 2;
+
+                while ( Chars.isCharASCII( controlValue, pos, ' ' ) )
+                {
+                    pos++;
+                }
+
+                byte[] value = Base64.decode( line.substring( pos ).toCharArray() );
+                control.setValue( value );
+            }
+            else if ( Chars.isCharASCII( controlValue, criticalPos + 1, '<' ) )
+            {
+                // File contained value
+                throw new NotImplementedException( "See DIRSERVER-1547" );
+            }
+            else
+            {
+                // Skip the <fill>
+                pos = criticalPos + 1;
+
+                while ( Chars.isCharASCII( controlValue, pos, ' ' ) )
+                {
+                    pos++;
+                }
+
+                // Standard value
+                byte[] value = new byte[length - pos];
+
+                for ( int i = 0; i < length - pos; i++ )
+                {
+                    value[i] = ( byte ) controlValue[i + pos];
+                }
+
+                control.setValue( value );
+            }
+        }
+
+        return control;
+    }
+
+
+    /**
+     * Parse an AttributeType/AttributeValue
+     *
+     * @param line The line to parse
+     * @return the parsed Attribute
+     */
+    public static Attribute parseAttributeValue( String line )
+    {
+        int colonIndex = line.indexOf( ':' );
+
+        if ( colonIndex != -1 )
+        {
+            String attributeType = line.substring( 0, colonIndex );
+            Object attributeValue = parseSimpleValue( line, colonIndex );
+
+            // Create an attribute
+            if ( attributeValue instanceof String )
+            {
+                return new DefaultAttribute( attributeType, ( String ) attributeValue );
+            }
+            else
+            {
+                return new DefaultAttribute( attributeType, ( byte[] ) attributeValue );
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Parse an AttributeType/AttributeValue
+     *
+     * @param entry The entry where to store the value
+     * @param line The line to parse
+     * @param lowerLine The same line, lowercased
+     * @throws LdapException If anything goes wrong
+     */
+    public void parseAttributeValue( LdifEntry entry, String line, String lowerLine ) throws LdapException
+    {
+        int colonIndex = line.indexOf( ':' );
+
+        String attributeType = lowerLine.substring( 0, colonIndex );
+
+        // We should *not* have a Dn twice
+        if ( attributeType.equals( "dn" ) )
+        {
+            LOG.error( I18n.err( I18n.ERR_12002_ENTRY_WITH_TWO_DNS, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12003_LDIF_ENTRY_WITH_TWO_DNS ) );
+        }
+
+        Object attributeValue = parseValue( line, colonIndex );
+
+        if ( schemaManager != null )
+        {
+            AttributeType at = schemaManager.getAttributeType( attributeType );
+
+            if ( at != null )
+            {
+                if ( at.getSyntax().isHumanReadable() )
+                {
+                    if ( attributeValue instanceof byte[] )
+                    {
+                        attributeValue = Strings.utf8ToString( ( byte[] ) attributeValue );
+                    }
+                }
+                else
+                {
+                    if ( attributeValue instanceof String )
+                    {
+                        attributeValue = Strings.getBytesUtf8( ( String ) attributeValue );
+                    }
+                }
+            }
+        }
+
+        // Update the entry
+        try
+        {
+            entry.addAttribute( attributeType, attributeValue );
+        }
+        catch ( Exception e )
+        {
+            // The attribute does not exist already, create a fake one 
+            if ( ( schemaManager != null ) && schemaManager.isRelaxed() )
+            {
+                MutableAttributeType newAttributeType = new MutableAttributeType( "1.3.6.1.4.1.18060.0.9999." + oidCounter++ );
+                newAttributeType.setNames( attributeType );
+                newAttributeType.setSyntax( schemaManager.getLdapSyntaxRegistry().get( SchemaConstants.DIRECTORY_STRING_SYNTAX ) );
+                schemaManager.add( newAttributeType );
+                entry.addAttribute( attributeType, attributeValue );
+            }
+        }
+    }
+
+
+    /**
+     * Parse a ModRDN operation
+     *
+     * @param entry The entry to update
+     * @param iter The lines iterator
+     * @throws LdapLdifException If anything goes wrong
+     */
+    private void parseModRdn( LdifEntry entry, Iterator<String> iter ) throws LdapLdifException
+    {
+        // We must have two lines : one starting with "newrdn:" or "newrdn::",
+        // and the second starting with "deleteoldrdn:"
+        if ( iter.hasNext() )
+        {
+            String line = iter.next();
+            String lowerLine = Strings.toLowerCaseAscii( line );
+
+            if ( lowerLine.startsWith( "newrdn::" ) || lowerLine.startsWith( "newrdn:" ) )
+            {
+                int colonIndex = line.indexOf( ':' );
+                Object attributeValue = parseValue( line, colonIndex );
+
+                if ( attributeValue instanceof String )
+                {
+                    entry.setNewRdn( ( String ) attributeValue );
+                }
+                else
+                {
+                    entry.setNewRdn( Strings.utf8ToString( ( byte[] ) attributeValue ) );
+                }
+            }
+            else
+            {
+                LOG.error( I18n.err( I18n.ERR_12035_BAD_MODRDN_OPERATION, lineNumber ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12035_BAD_MODRDN_OPERATION ) );
+            }
+        }
+        else
+        {
+            LOG.error( I18n.err( I18n.ERR_12035_BAD_MODRDN_OPERATION, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12035_BAD_MODRDN_OPERATION ) );
+        }
+
+        if ( iter.hasNext() )
+        {
+            String line = iter.next();
+            String lowerLine = Strings.toLowerCaseAscii( line );
+
+            if ( lowerLine.startsWith( "deleteoldrdn:" ) )
+            {
+                int colonIndex = line.indexOf( ':' );
+                Object attributeValue = parseValue( line, colonIndex );
+                entry.setDeleteOldRdn( "1".equals( attributeValue ) );
+            }
+            else
+            {
+                LOG.error( I18n.err( I18n.ERR_12038_NO_DELETEOLDRDN, lineNumber ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12038_NO_DELETEOLDRDN ) );
+            }
+        }
+        else
+        {
+            LOG.error( I18n.err( I18n.ERR_12038_NO_DELETEOLDRDN, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12038_NO_DELETEOLDRDN ) );
+        }
+    }
+
+
+    /**
+     * Parse a modify change type.
+     *
+     * The grammar is :
+     * <pre>
+     * &lt;changerecord&gt; ::= "changetype:" FILL "modify" SEP &lt;mod-spec&gt; &lt;mod-specs-e&gt;
+     * &lt;mod-spec&gt; ::= "add:" &lt;mod-val&gt; | "delete:" &lt;mod-val-del&gt; | "replace:" &lt;mod-val&gt;
+     * &lt;mod-specs-e&gt; ::= &lt;mod-spec&gt;
+     * &lt;mod-specs-e&gt; | e
+     * &lt;mod-val&gt; ::= FILL ATTRIBUTE-DESCRIPTION SEP ATTRVAL-SPEC &lt;attrval-specs-e&gt; "-" SEP
+     * &lt;mod-val-del&gt; ::= FILL ATTRIBUTE-DESCRIPTION SEP &lt;attrval-specs-e&gt; "-" SEP
+     * &lt;attrval-specs-e&gt; ::= ATTRVAL-SPEC &lt;attrval-specs&gt; | e
+     * </pre>
+     *
+     * @param entry The entry to feed
+     * @param iter The lines
+     * @exception LdapLdifException If the modify operation is invalid
+     */
+    private void parseModify( LdifEntry entry, Iterator<String> iter ) throws LdapLdifException
+    {
+        int state = MOD_SPEC;
+        String modified = null;
+        ModificationOperation modificationType = ModificationOperation.ADD_ATTRIBUTE;
+        Attribute attribute = null;
+
+        // The following flag is used to deal with empty modifications
+        boolean isEmptyValue = true;
+
+        while ( iter.hasNext() )
+        {
+            String line = iter.next();
+            String lowerLine = Strings.toLowerCaseAscii( line );
+
+            if ( lowerLine.startsWith( "-" ) )
+            {
+                if ( ( state != ATTRVAL_SPEC_OR_SEP ) && ( state != ATTRVAL_SPEC ) )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12040_BAD_MODIFY_SEPARATOR, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12040_BAD_MODIFY_SEPARATOR ) );
+                }
+                else
+                {
+                    if ( isEmptyValue )
+                    {
+                        if ( state == ATTRVAL_SPEC_OR_SEP )
+                        {
+                            entry.addModification( modificationType, modified );
+                        }
+                        else
+                        {
+                            // Update the entry with a null value
+                            entry.addModification( modificationType, modified, null );
+                        }
+                    }
+                    else
+                    {
+                        // Update the entry with the attribute
+                        entry.addModification( modificationType, attribute );
+                    }
+
+                    state = MOD_SPEC;
+                    isEmptyValue = true;
+                }
+            }
+            else if ( lowerLine.startsWith( "add:" ) )
+            {
+                if ( ( state != MOD_SPEC ) && ( state != ATTRVAL_SPEC ) )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2 ) );
+                }
+
+                modified = Strings.trim( line.substring( "add:".length() ) );
+                modificationType = ModificationOperation.ADD_ATTRIBUTE;
+                attribute = new DefaultAttribute( modified );
+
+                state = ATTRVAL_SPEC;
+            }
+            else if ( lowerLine.startsWith( "delete:" ) )
+            {
+                if ( ( state != MOD_SPEC ) && ( state != ATTRVAL_SPEC ) )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2 ) );
+                }
+
+                modified = Strings.trim( line.substring( "delete:".length() ) );
+                modificationType = ModificationOperation.REMOVE_ATTRIBUTE;
+                attribute = new DefaultAttribute( modified );
+                isEmptyValue = false;
+
+                state = ATTRVAL_SPEC_OR_SEP;
+            }
+            else if ( lowerLine.startsWith( "replace:" ) )
+            {
+                if ( ( state != MOD_SPEC ) && ( state != ATTRVAL_SPEC ) )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2 ) );
+                }
+
+                modified = Strings.trim( line.substring( "replace:".length() ) );
+                modificationType = ModificationOperation.REPLACE_ATTRIBUTE;
+                attribute = new DefaultAttribute( modified );
+
+                state = ATTRVAL_SPEC_OR_SEP;
+            }
+            else
+            {
+                if ( ( state != ATTRVAL_SPEC ) && ( state != ATTRVAL_SPEC_OR_SEP ) )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12040_BAD_MODIFY_SEPARATOR, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12040_BAD_MODIFY_SEPARATOR ) );
+                }
+
+                // A standard AttributeType/AttributeValue pair
+                int colonIndex = line.indexOf( ':' );
+
+                String attributeType = line.substring( 0, colonIndex );
+
+                if ( !attributeType.equalsIgnoreCase( modified ) )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12044, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12045 ) );
+                }
+
+                // We should *not* have a Dn twice
+                if ( attributeType.equalsIgnoreCase( "dn" ) )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12002_ENTRY_WITH_TWO_DNS, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12003_LDIF_ENTRY_WITH_TWO_DNS ) );
+                }
+
+                Object attributeValue = parseValue( line, colonIndex );
+
+                try
+                {
+                    if ( attributeValue instanceof String )
+                    {
+                        attribute.add( ( String ) attributeValue );
+                    }
+                    else
+                    {
+                        attribute.add( ( byte[] ) attributeValue );
+                    }
+                }
+                catch ( LdapInvalidAttributeValueException liave )
+                {
+                    throw new LdapLdifException( liave.getMessage(), liave );
+                }
+
+                isEmptyValue = false;
+
+                state = ATTRVAL_SPEC_OR_SEP;
+            }
+        }
+
+        if ( state != MOD_SPEC )
+        {
+            LOG.error( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12042_BAD_MODIFY_SEPARATOR_2, lineNumber ) );
+        }
+    }
+
+
+    /**
+     * Parse a change operation. We have to handle different cases depending on
+     * the operation.
+     * <ul>
+     * <li>1) Delete : there should *not* be any line after the "changetype: delete" </li>
+     * <li>2) Add : we must have a list of AttributeType : AttributeValue elements </li>
+     * <li>3) ModDN : we must have two following lines: a "newrdn:" and a "deleteoldrdn:" </li>
+     * <li>4) ModRDN : the very same, but a "newsuperior:" line is expected </li>
+     * <li>5) Modify</li>
+     * </ul>
+     *
+     * The grammar is :
+     * <pre>
+     * &lt;changerecord&gt; ::= "changetype:" FILL "add" SEP &lt;attrval-spec&gt; &lt;attrval-specs-e&gt; |
+     *     "changetype:" FILL "delete" |
+     *     "changetype:" FILL "modrdn" SEP &lt;newrdn&gt; SEP &lt;deleteoldrdn&gt; SEP |
+     *     // To be checked
+     *     "changetype:" FILL "moddn" SEP &lt;newrdn&gt; SEP &lt;deleteoldrdn&gt; SEP &lt;newsuperior&gt; SEP |
+     *     "changetype:" FILL "modify" SEP &lt;mod-spec&gt; &lt;mod-specs-e&gt;
+     * &lt;newrdn&gt; ::= "newrdn:" FILL Rdn | "newrdn::" FILL BASE64-Rdn
+     * &lt;deleteoldrdn&gt; ::= "deleteoldrdn:" FILL "0" | "deleteoldrdn:" FILL "1"
+     * &lt;newsuperior&gt; ::= "newsuperior:" FILL Dn | "newsuperior::" FILL BASE64-Dn
+     * &lt;mod-specs-e&gt; ::= &lt;mod-spec&gt; &lt;mod-specs-e&gt; | e
+     * &lt;mod-spec&gt; ::= "add:" &lt;mod-val&gt; | "delete:" &lt;mod-val&gt; | "replace:" &lt;mod-val&gt;
+     * &lt;mod-val&gt; ::= FILL ATTRIBUTE-DESCRIPTION SEP ATTRVAL-SPEC &lt;attrval-specs-e&gt; "-" SEP
+     * &lt;attrval-specs-e&gt; ::= ATTRVAL-SPEC &lt;attrval-specs&gt; | e
+     * </pre>
+     *
+     * @param entry The entry to feed
+     * @param iter The lines iterator
+     * @param operation The change operation (add, modify, delete, moddn or modrdn)
+     * @exception LdapException If the change operation is invalid
+     */
+    private void parseChange( LdifEntry entry, Iterator<String> iter, ChangeType operation ) throws LdapException
+    {
+        // The changetype and operation has already been parsed.
+        entry.setChangeType( operation );
+
+        switch ( operation )
+        {
+            case Delete:
+                // The change type will tell that it's a delete operation,
+                // the dn is used as a key.
+                return;
+
+            case Add:
+                // We will iterate through all attribute/value pairs
+                while ( iter.hasNext() )
+                {
+                    String line = iter.next();
+                    String lowerLine = Strings.toLowerCaseAscii( line );
+                    parseAttributeValue( entry, line, lowerLine );
+                }
+
+                return;
+
+            case Modify:
+                parseModify( entry, iter );
+                return;
+
+            case ModDn:
+                // They are supposed to have the same syntax :
+                // No break !
+            case ModRdn:
+                // First, parse the modrdn part
+                parseModRdn( entry, iter );
+
+                // The next line should be the new superior, if we have one
+                if ( iter.hasNext() )
+                {
+                    String line = iter.next();
+                    String lowerLine = Strings.toLowerCaseAscii( line );
+
+                    if ( lowerLine.startsWith( "newsuperior:" ) )
+                    {
+                        int colonIndex = line.indexOf( ':' );
+                        Object attributeValue = parseValue( line, colonIndex );
+
+                        if ( attributeValue instanceof String )
+                        {
+                            entry.setNewSuperior( ( String ) attributeValue );
+                        }
+                        else
+                        {
+                            entry.setNewSuperior( Strings.utf8ToString( ( byte[] ) attributeValue ) );
+                        }
+                    }
+                    else
+                    {
+                        if ( operation == ChangeType.ModDn )
+                        {
+                            LOG.error( I18n.err( I18n.ERR_12046, lineNumber ) );
+                            throw new LdapLdifException( I18n.err( I18n.ERR_12047 ) );
+                        }
+                    }
+                }
+
+                return;
+
+            default:
+                // This is an error
+                LOG.error( I18n.err( I18n.ERR_12048, lineNumber ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12049 ) );
+        }
+    }
+
+
+    /**
+     * Parse a ldif file. The following rules are processed :
+     * <pre>
+     * &lt;ldif-file&gt; ::= &lt;ldif-attrval-record&gt; &lt;ldif-attrval-records&gt; |
+     *     &lt;ldif-change-record&gt; &lt;ldif-change-records&gt;
+     * &lt;ldif-attrval-record&gt; ::= &lt;dn-spec&gt; &lt;sep&gt; &lt;attrval-spec&gt; &lt;attrval-specs&gt;
+     * &lt;ldif-change-record&gt; ::= &lt;dn-spec&gt; &lt;sep&gt; &lt;controls-e&gt; &lt;changerecord&gt;
+     * &lt;dn-spec&gt; ::= "dn:" &lt;fill&gt; &lt;distinguishedName&gt; | "dn::" &lt;fill&gt; &lt;base64-distinguishedName&gt;
+     * &lt;changerecord&gt; ::= "changetype:" &lt;fill&gt; &lt;change-op&gt;
+     * </pre>
+     *
+     * @return the parsed ldifEntry
+     * @exception LdapException If the ldif file does not contain a valid entry
+     */
+    protected LdifEntry parseEntry() throws LdapException
+    {
+        if ( ( lines == null ) || ( lines.size() == 0 ) )
+        {
+            LOG.debug( "The entry is empty : end of ldif file" );
+            return null;
+        }
+
+        // The entry must start with a dn: or a dn::
+        String line = lines.get( 0 );
+
+        lineNumber -= ( lines.size() - 1 );
+
+        String name = parseDn( line );
+
+        Dn dn = null;
+        
+        try
+        {
+            dn = new Dn( schemaManager, name );
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            // Deal with the RDN whihc is not in the schema
+            // First parse the DN without the schema
+            dn = new Dn( name );
+            
+            Rdn rdn = dn.getRdn();
+            
+            // Process each Ava
+            for ( Ava ava : rdn )
+            {
+                if ( ( schemaManager != null ) && ( schemaManager.getAttributeType( ava.getType() ) == null ) 
+                    && schemaManager.isRelaxed() )
+                {
+                    // Not found : create a new one
+                    MutableAttributeType newAttributeType = new MutableAttributeType( "1.3.6.1.4.1.18060.0.9999." + oidCounter++ );
+                    newAttributeType.setNames( ava.getType() );
+                    newAttributeType.setSyntax( schemaManager.getLdapSyntaxRegistry().get( SchemaConstants.DIRECTORY_STRING_SYNTAX ) );
+                    schemaManager.add( newAttributeType );
+                }
+            }
+            
+            dn = new Dn( schemaManager, name );
+        }
+
+        // Ok, we have found a Dn
+        LdifEntry entry = createLdifEntry( schemaManager );
+        entry.setLengthBeforeParsing( entryLen );
+        entry.setOffset( entryOffset );
+
+        entry.setDn( dn );
+
+        // We remove this dn from the lines
+        lines.remove( 0 );
+
+        // Now, let's iterate through the other lines
+        Iterator<String> iter = lines.iterator();
+
+        // This flag is used to distinguish between an entry and a change
+        int type = LDIF_ENTRY;
+
+        // The following boolean is used to check that a control is *not*
+        // found elswhere than just after the dn
+        boolean controlSeen = false;
+
+        // We use this boolean to check that we do not have AttributeValues
+        // after a change operation
+        boolean changeTypeSeen = false;
+
+        ChangeType operation = ChangeType.Add;
+        String lowerLine;
+        Control control;
+
+        while ( iter.hasNext() )
+        {
+            lineNumber++;
+
+            // Each line could start either with an OID, an attribute type, with
+            // "control:" or with "changetype:"
+            line = iter.next();
+            lowerLine = Strings.toLowerCaseAscii( line );
+
+            // We have three cases :
+            // 1) The first line after the Dn is a "control:"
+            // 2) The first line after the Dn is a "changeType:"
+            // 3) The first line after the Dn is anything else
+            if ( lowerLine.startsWith( "control:" ) )
+            {
+                if ( containsEntries )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12004_CHANGE_NOT_ALLOWED, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12005_NO_CHANGE ) );
+                }
+
+                containsChanges = true;
+
+                if ( controlSeen )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12050, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12051 ) );
+                }
+
+                // Parse the control
+                control = parseControl( line.substring( "control:".length() ) );
+                entry.addControl( control );
+            }
+            else if ( lowerLine.startsWith( "changetype:" ) )
+            {
+                if ( containsEntries )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12004_CHANGE_NOT_ALLOWED, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12005_NO_CHANGE ) );
+                }
+
+                containsChanges = true;
+
+                if ( changeTypeSeen )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12052, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12053 ) );
+                }
+
+                // A change request
+                type = CHANGE;
+                controlSeen = true;
+
+                operation = parseChangeType( line );
+
+                // Parse the change operation in a separate function
+                parseChange( entry, iter, operation );
+                changeTypeSeen = true;
+            }
+            else if ( line.indexOf( ':' ) > 0 )
+            {
+                if ( containsChanges )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12004_CHANGE_NOT_ALLOWED, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12005_NO_CHANGE ) );
+                }
+
+                containsEntries = true;
+
+                if ( controlSeen || changeTypeSeen )
+                {
+                    LOG.error( I18n.err( I18n.ERR_12054, lineNumber ) );
+                    throw new LdapLdifException( I18n.err( I18n.ERR_12055 ) );
+                }
+
+                parseAttributeValue( entry, line, lowerLine );
+                type = LDIF_ENTRY;
+            }
+            else
+            {
+                // Invalid attribute Value
+                LOG.error( I18n.err( I18n.ERR_12056, lineNumber ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12057_BAD_ATTRIBUTE ) );
+            }
+        }
+
+        if ( type == LDIF_ENTRY )
+        {
+            LOG.debug( "Read an entry : {}", entry );
+        }
+        else if ( type == CHANGE )
+        {
+            entry.setChangeType( operation );
+            LOG.debug( "Read a modification : {}", entry );
+        }
+        else
+        {
+            LOG.error( I18n.err( I18n.ERR_12058_UNKNOWN_ENTRY_TYPE, lineNumber ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12059_UNKNOWN_ENTRY ) );
+        }
+
+        return entry;
+    }
+
+
+    /**
+     * Parse the version from the ldif input.
+     *
+     * @return A number representing the version (default to 1)
+     * @throws LdapLdifException If the version is incorrect or if the input is incorrect
+     */
+    protected int parseVersion() throws LdapLdifException
+    {
+        int ver = DEFAULT_VERSION;
+
+        // First, read a list of lines
+        readLines();
+
+        if ( lines.size() == 0 )
+        {
+            LOG.warn( "The ldif file is empty" );
+            return ver;
+        }
+
+        // get the first line
+        String line = lines.get( 0 );
+
+        // <ldif-file> ::= "version:" <fill> <number>
+        char[] document = line.toCharArray();
+        String versionNumber;
+
+        if ( line.startsWith( "version:" ) )
+        {
+            position += "version:".length();
+            parseFill( document );
+
+            // Version number. Must be '1' in this version
+            versionNumber = parseNumber( document );
+
+            // We should not have any other chars after the number
+            if ( position != document.length )
+            {
+                LOG.error( I18n.err( I18n.ERR_12060_VERSION_NOT_A_NUMBER, lineNumber ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12061_LDIF_PARSING_ERROR ) );
+            }
+
+            try
+            {
+                ver = Integer.parseInt( versionNumber );
+            }
+            catch ( NumberFormatException nfe )
+            {
+                LOG.error( I18n.err( I18n.ERR_12060_VERSION_NOT_A_NUMBER, lineNumber ) );
+                throw new LdapLdifException( I18n.err( I18n.ERR_12061_LDIF_PARSING_ERROR ), nfe );
+            }
+
+            LOG.debug( "Ldif version : {}", versionNumber );
+
+            // We have found the version, just discard the line from the list
+            lines.remove( 0 );
+
+            // and read the next lines if the current buffer is empty
+            if ( lines.size() == 0 )
+            {
+                // include the version line as part of the first entry
+                int tmpEntryLen = entryLen;
+
+                readLines();
+
+                entryLen += tmpEntryLen;
+            }
+        }
+        else
+        {
+            LOG.info( "No version information : assuming version: 1" );
+        }
+
+        return ver;
+    }
+
+
+    /**
+     * gets a line from the underlying data store
+     *
+     * @return a line of characters or null if EOF reached
+     * @throws IOException on read failure
+     */
+    protected String getLine() throws IOException
+    {
+        return ( ( BufferedReader ) reader ).readLine();
+    }
+
+
+    /**
+     * Reads an entry in a ldif buffer, and returns the resulting lines, without
+     * comments, and unfolded.
+     *
+     * The lines represent *one* entry.
+     *
+     * @throws LdapLdifException If something went wrong
+     */
+    protected void readLines() throws LdapLdifException
+    {
+        String line;
+        boolean insideComment = true;
+        boolean isFirstLine = true;
+
+        lines.clear();
+        entryLen = 0;
+        entryOffset = offset;
+
+        StringBuffer sb = new StringBuffer();
+
+        try
+        {
+            while ( ( line = getLine() ) != null )
+            {
+                lineNumber++;
+
+                if ( line.length() == 0 )
+                {
+                    if ( isFirstLine )
+                    {
+                        continue;
+                    }
+                    else
+                    {
+                        // The line is empty, we have read an entry
+                        insideComment = false;
+                        offset++;
+                        break;
+                    }
+                }
+
+                // We will read the first line which is not a comment
+                switch ( line.charAt( 0 ) )
+                {
+                    case '#':
+                        insideComment = true;
+                        break;
+
+                    case ' ':
+                        isFirstLine = false;
+
+                        if ( insideComment )
+                        {
+                            continue;
+                        }
+                        else if ( sb.length() == 0 )
+                        {
+                            LOG.error( I18n.err( I18n.ERR_12062_EMPTY_CONTINUATION_LINE, lineNumber ) );
+                            throw new LdapLdifException( I18n.err( I18n.ERR_12061_LDIF_PARSING_ERROR ) );
+                        }
+                        else
+                        {
+                            sb.append( line.substring( 1 ) );
+                        }
+
+                        insideComment = false;
+                        break;
+
+                    default:
+                        isFirstLine = false;
+
+                        // We have found a new entry
+                        // First, stores the previous one if any.
+                        if ( sb.length() != 0 )
+                        {
+                            lines.add( sb.toString() );
+                        }
+
+                        sb = new StringBuffer( line );
+                        insideComment = false;
+                        break;
+                }
+
+                byte[] data = Strings.getBytesUtf8( line );
+                // FIXME might fail on windows in the new line issue, yet to check
+                offset += ( data.length + 1 );
+                entryLen += ( data.length + 1 );
+            }
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapLdifException( I18n.err( I18n.ERR_12063_ERROR_WHILE_READING_LDIF_LINE ), ioe );
+        }
+
+        // Stores the current line if necessary.
+        if ( sb.length() != 0 )
+        {
+            lines.add( sb.toString() );
+        }
+    }
+
+
+    /**
+     * Parse a ldif file (using the default encoding).
+     *
+     * @param fileName The ldif file
+     * @return A list of entries
+     * @throws LdapLdifException If the parsing fails
+     */
+    public List<LdifEntry> parseLdifFile( String fileName ) throws LdapLdifException
+    {
+        return parseLdifFile( fileName, Charset.forName( Strings.getDefaultCharsetName() ).toString() );
+    }
+
+
+    /**
+     * Parse a ldif file, decoding it using the given charset encoding
+     *
+     * @param fileName The ldif file
+     * @param encoding The charset encoding to use
+     * @return A list of entries
+     * @throws LdapLdifException If the parsing fails
+     */
+    public List<LdifEntry> parseLdifFile( String fileName, String encoding ) throws LdapLdifException
+    {
+        if ( Strings.isEmpty( fileName ) )
+        {
+            LOG.error( I18n.err( I18n.ERR_12064_EMPTY_FILE_NAME ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12064_EMPTY_FILE_NAME ) );
+        }
+
+        File file = new File( fileName );
+
+        if ( !file.exists() )
+        {
+            LOG.error( I18n.err( I18n.ERR_12066, fileName ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12067, fileName ) );
+        }
+
+        BufferedReader bufferReader = null;
+
+        // Open the file and then get a channel from the stream
+        try
+        {
+            bufferReader = new BufferedReader(
+                new InputStreamReader( new FileInputStream( file ), Charset.forName( encoding ) ) );
+
+            return parseLdif( bufferReader );
+        }
+        catch ( FileNotFoundException fnfe )
+        {
+            LOG.error( I18n.err( I18n.ERR_12068, fileName ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12067, fileName ), fnfe );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapLdifException( le.getMessage(), le );
+        }
+        finally
+        {
+            // close the reader
+            try
+            {
+                if ( bufferReader != null )
+                {
+                    bufferReader.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                // Nothing to do
+            }
+        }
+    }
+
+
+    /**
+     * A method which parses a ldif string and returns a list of entries.
+     *
+     * @param ldif The ldif string
+     * @return A list of entries, or an empty List
+     * @throws LdapLdifException If something went wrong
+     */
+    public List<LdifEntry> parseLdif( String ldif ) throws LdapLdifException
+    {
+        LOG.debug( "Starts parsing ldif buffer" );
+
+        if ( Strings.isEmpty( ldif ) )
+        {
+            return new ArrayList<LdifEntry>();
+        }
+
+        BufferedReader bufferReader = new BufferedReader( new StringReader( ldif ) );
+
+        try
+        {
+            List<LdifEntry> entries = parseLdif( bufferReader );
+
+            if ( LOG.isDebugEnabled() )
+            {
+                LOG.debug( "Parsed {} entries.", Integer.valueOf( entries.size() ) );
+            }
+
+            return entries;
+        }
+        catch ( LdapLdifException ne )
+        {
+            LOG.error( I18n.err( I18n.ERR_12069, ne.getLocalizedMessage() ) );
+            throw new LdapLdifException( I18n.err( I18n.ERR_12070 ), ne );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapLdifException( le.getMessage(), le );
+        }
+        finally
+        {
+            // Close the reader
+            try
+            {
+                bufferReader.close();
+            }
+            catch ( IOException ioe )
+            {
+                throw new LdapLdifException( I18n.err( I18n.ERR_12024_CANNOT_CLOSE_FILE ), ioe );
+            }
+
+        }
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Iterator Methods
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the next LDIF on the channel.
+     *
+     * @return the next LDIF as a String.
+     */
+    private LdifEntry nextInternal()
+    {
+        try
+        {
+            LOG.debug( "next(): -- called" );
+
+            LdifEntry entry = prefetched;
+            readLines();
+
+            try
+            {
+                prefetched = parseEntry();
+            }
+            catch ( LdapLdifException ne )
+            {
+                error = ne;
+                throw new NoSuchElementException( ne.getMessage() );
+            }
+            catch ( LdapException le )
+            {
+                throw new NoSuchElementException( le.getMessage() );
+            }
+
+            LOG.debug( "next(): -- returning ldif {}\n", entry );
+
+            return entry;
+        }
+        catch ( LdapLdifException ne )
+        {
+            LOG.error( I18n.err( I18n.ERR_12071 ) );
+            error = ne;
+            return null;
+        }
+    }
+
+
+    /**
+     * Gets the next LDIF on the channel.
+     *
+     * @return the next LDIF as a String.
+     */
+    public LdifEntry next()
+    {
+        return nextInternal();
+    }
+
+
+    /**
+     * Gets the current entry, but don't move forward.
+     *
+     * @return the pre-fetched entry 
+     */
+    public LdifEntry fetch()
+    {
+        return prefetched;
+    }
+
+
+    /**
+     * Tests to see if another LDIF is on the input channel.
+     *
+     * @return true if another LDIF is available false otherwise.
+     */
+    private boolean hasNextInternal()
+    {
+        return null != prefetched;
+    }
+
+
+    /**
+     * Tests to see if another LDIF is on the input channel.
+     *
+     * @return true if another LDIF is available false otherwise.
+     */
+    public boolean hasNext()
+    {
+        if ( prefetched != null )
+        {
+            LOG.debug( "hasNext(): -- returning true" );
+        }
+        else
+        {
+            LOG.debug( "hasNext(): -- returning false" );
+        }
+
+        return hasNextInternal();
+    }
+
+
+    /**
+     * Always throws UnsupportedOperationException!
+     *
+     * @see java.util.Iterator#remove()
+     */
+    private void removeInternal()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /**
+     * Always throws UnsupportedOperationException!
+     *
+     * @see java.util.Iterator#remove()
+     */
+    public void remove()
+    {
+        removeInternal();
+    }
+
+
+    /**
+     * @return An iterator on the file
+     */
+    public Iterator<LdifEntry> iterator()
+    {
+        return new Iterator<LdifEntry>()
+        {
+            public boolean hasNext()
+            {
+                return hasNextInternal();
+            }
+
+
+            public LdifEntry next()
+            {
+                try
+                {
+                    return nextInternal();
+                }
+                catch ( NoSuchElementException nse )
+                {
+                    LOG.error( nse.getMessage() );
+                    return null;
+                }
+            }
+
+
+            public void remove()
+            {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+
+    /**
+     * @return True if an error occurred during parsing
+     */
+    public boolean hasError()
+    {
+        return error != null;
+    }
+
+
+    /**
+     * @return The exception that occurs during an entry parsing
+     */
+    public Exception getError()
+    {
+        return error;
+    }
+
+
+    /**
+     * The main entry point of the LdifParser. It reads a buffer and returns a
+     * List of entries.
+     *
+     * @param reader The buffer being processed
+     * @return A list of entries
+     * @throws LdapException If something went wrong
+     */
+    public List<LdifEntry> parseLdif( BufferedReader reader ) throws LdapException
+    {
+        // Create a list that will contain the read entries
+        List<LdifEntry> entries = new ArrayList<LdifEntry>();
+
+        this.reader = reader;
+
+        // First get the version - if any -
+        version = parseVersion();
+        prefetched = parseEntry();
+
+        // When done, get the entries one by one.
+        for ( LdifEntry entry : this )
+        {
+            if ( entry != null )
+            {
+                entries.add( entry );
+            }
+            else
+            {
+                throw new LdapLdifException( I18n.err( I18n.ERR_12072, error.getLocalizedMessage() ) );
+            }
+        }
+
+        return entries;
+    }
+
+
+    /**
+     * @return True if the ldif file contains entries, fals if it contains changes
+     */
+    public boolean containsEntries()
+    {
+        return containsEntries;
+    }
+
+
+    /**
+     * @return the current line that is being processed by the reader
+     */
+    public int getLineNumber()
+    {
+        return lineNumber;
+    }
+
+
+    /**
+     * creates a non-schemaaware LdifEntry
+     * @return an LdifEntry that is not schemaaware
+     */
+    protected LdifEntry createLdifEntry( SchemaManager schemaManager )
+    {
+        if ( schemaManager != null )
+        {
+            return new LdifEntry( schemaManager );
+        }
+        else
+        {
+            return new LdifEntry();
+        }
+    }
+
+
+    /**
+     * @return true if the DN validation is turned on
+     */
+    public boolean isValidateDn()
+    {
+        return validateDn;
+    }
+
+
+    /**
+     * Turns on/off the DN validation
+     * 
+     * @param validateDn the boolean flag
+     */
+    public void setValidateDn( boolean validateDn )
+    {
+        this.validateDn = validateDn;
+    }
+
+
+    /**
+     * @param schemaManager the schemaManager to set
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() throws IOException
+    {
+        if ( reader != null )
+        {
+            position = 0;
+            reader.close();
+            containsEntries = false;
+            containsChanges = false;
+            offset = 0;
+            entryOffset = 0;
+            lineNumber = 0;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifRevertor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifRevertor.java
new file mode 100644
index 0000000..0526a58
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifRevertor.java
@@ -0,0 +1,605 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.AttributeUtils;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Ava;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+
+
+/**
+ * A helper class which provides methods to reverse a LDIF modification operation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LdifRevertor
+{
+    /** Flag used when we want to delete the old Rdn */
+    public static final boolean DELETE_OLD_RDN = true;
+
+    /** Flag used when we want to keep the old Rdn */
+    public static final boolean KEEP_OLD_RDN = false;
+
+
+    /**
+     * Private constructor.
+     */
+    private LdifRevertor()
+    {
+    }
+
+
+    /**
+     * Compute a reverse LDIF of an AddRequest. It's simply a delete request
+     * of the added entry
+     *
+     * @param dn the dn of the added entry
+     * @return a reverse LDIF
+     */
+    public static LdifEntry reverseAdd( Dn dn )
+    {
+        LdifEntry entry = new LdifEntry();
+        entry.setChangeType( ChangeType.Delete );
+        entry.setDn( dn );
+        return entry;
+    }
+
+
+    /**
+     * Compute a reverse LDIF of a DeleteRequest. We have to get the previous
+     * entry in order to restore it.
+     *
+     * @param dn The deleted entry Dn
+     * @param deletedEntry The entry which has been deleted
+     * @return A reverse LDIF
+     * @throws LdapException If something went wrong
+     */
+    public static LdifEntry reverseDel( Dn dn, Entry deletedEntry ) throws LdapException
+    {
+        LdifEntry entry = new LdifEntry();
+
+        entry.setDn( dn );
+        entry.setChangeType( ChangeType.Add );
+
+        for ( Attribute attribute : deletedEntry )
+        {
+            entry.addAttribute( attribute );
+        }
+
+        return entry;
+    }
+
+
+    /**
+     *
+     * Compute the reversed LDIF for a modify request. We will deal with the
+     * three kind of modifications :
+     * <ul>
+     * <li>add</li>
+     * <li>remove</li>
+     * <li>replace</li>
+     * </ul>
+     * 
+     * As the modifications should be issued in a reversed order ( ie, for
+     * the initials modifications {A, B, C}, the reversed modifications will
+     * be ordered like {C, B, A}), we will change the modifications order.
+     *
+     * @param dn the dn of the modified entry
+     * @param forwardModifications the modification items for the forward change
+     * @param modifiedEntry The modified entry. Necessary for the destructive modifications
+     * @return A reversed LDIF
+     * @throws LdapException If something went wrong
+     */
+    public static LdifEntry reverseModify( Dn dn, List<Modification> forwardModifications, Entry modifiedEntry )
+        throws LdapException
+    {
+        // First, protect the original entry by cloning it : we will modify it
+        Entry clonedEntry = modifiedEntry.clone();
+
+        LdifEntry entry = new LdifEntry();
+        entry.setChangeType( ChangeType.Modify );
+
+        entry.setDn( dn );
+
+        // As the reversed modifications should be pushed in reversed order,
+        // we create a list to temporarily store the modifications.
+        List<Modification> reverseModifications = new ArrayList<Modification>();
+
+        // Loop through all the modifications. For each modification, we will
+        // have to apply it to the modified entry in order to be able to generate
+        // the reversed modification
+        for ( Modification modification : forwardModifications )
+        {
+            switch ( modification.getOperation() )
+            {
+                case ADD_ATTRIBUTE:
+                    Attribute mod = modification.getAttribute();
+
+                    Attribute previous = clonedEntry.get( mod.getId() );
+
+                    if ( mod.equals( previous ) )
+                    {
+                        continue;
+                    }
+
+                    Modification reverseModification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE,
+                        mod );
+                    reverseModifications.add( 0, reverseModification );
+                    break;
+
+                case REMOVE_ATTRIBUTE:
+                    mod = modification.getAttribute();
+
+                    previous = clonedEntry.get( mod.getId() );
+
+                    if ( previous == null )
+                    {
+                        // Nothing to do if the previous attribute didn't exist
+                        continue;
+                    }
+
+                    if ( mod.get() == null )
+                    {
+                        reverseModification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, previous );
+                        reverseModifications.add( 0, reverseModification );
+                        break;
+                    }
+
+                    reverseModification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, mod );
+                    reverseModifications.add( 0, reverseModification );
+                    break;
+
+                case REPLACE_ATTRIBUTE:
+                    mod = modification.getAttribute();
+
+                    previous = clonedEntry.get( mod.getId() );
+
+                    /*
+                     * The server accepts without complaint replace
+                     * modifications to non-existing attributes in the
+                     * entry.  When this occurs nothing really happens
+                     * but this method freaks out.  To prevent that we
+                     * make such no-op modifications produce the same
+                     * modification for the reverse direction which should
+                     * do nothing as well.
+                     */
+                    if ( ( mod.get() == null ) && ( previous == null ) )
+                    {
+                        reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
+                            new DefaultAttribute( mod.getId() ) );
+                        reverseModifications.add( 0, reverseModification );
+                        continue;
+                    }
+
+                    if ( mod.get() == null )
+                    {
+                        reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
+                            previous );
+                        reverseModifications.add( 0, reverseModification );
+                        continue;
+                    }
+
+                    if ( previous == null )
+                    {
+                        Attribute emptyAttribute = new DefaultAttribute( mod.getId() );
+                        reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
+                            emptyAttribute );
+                        reverseModifications.add( 0, reverseModification );
+                        continue;
+                    }
+
+                    reverseModification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, previous );
+                    reverseModifications.add( 0, reverseModification );
+                    break;
+
+                default:
+                    // Do nothing
+                    break;
+
+            }
+
+            AttributeUtils.applyModification( clonedEntry, modification );
+
+        }
+
+        // Special case if we don't have any reverse modifications
+        if ( reverseModifications.size() == 0 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12073, forwardModifications ) );
+        }
+
+        // Now, push the reversed list into the entry
+        for ( Modification modification : reverseModifications )
+        {
+            entry.addModification( modification );
+        }
+
+        // Return the reverted entry
+        return entry;
+    }
+
+
+    /**
+     * Compute a reverse LDIF for a forward change which if in LDIF format
+     * would represent a Move operation. Hence there is no newRdn in the
+     * picture here.
+     *
+     * @param newSuperiorDn the new parent dn to be (must not be null)
+     * @param modifiedDn the dn of the entry being moved (must not be null)
+     * @return a reverse LDIF
+     * @throws LdapException if something went wrong
+     */
+    public static LdifEntry reverseMove( Dn newSuperiorDn, Dn modifiedDn ) throws LdapException
+    {
+        LdifEntry entry = new LdifEntry();
+        Dn currentParent = null;
+        Rdn currentRdn = null;
+        Dn newDn = null;
+
+        if ( newSuperiorDn == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12074 ) );
+        }
+
+        if ( modifiedDn == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12075 ) );
+        }
+
+        if ( modifiedDn.size() == 0 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12076 ) );
+        }
+
+        currentParent = modifiedDn;
+        currentRdn = currentParent.getRdn();
+        currentParent = currentParent.getParent();
+
+        newDn = newSuperiorDn;
+        newDn = newDn.add( modifiedDn.getRdn() );
+
+        entry.setChangeType( ChangeType.ModDn );
+        entry.setDn( newDn );
+        entry.setNewRdn( currentRdn.getName() );
+        entry.setNewSuperior( currentParent.getName() );
+        entry.setDeleteOldRdn( false );
+        return entry;
+    }
+
+
+    /**
+     * A small helper class to compute the simple revert.
+     */
+    private static LdifEntry revertEntry( Entry entry, Dn newDn, Dn newSuperior, Rdn oldRdn, Rdn newRdn )
+        throws LdapInvalidDnException
+    {
+        LdifEntry reverted = new LdifEntry();
+
+        // We have a composite old Rdn, something like A=a+B=b
+        // It does not matter if the RDNs overlap
+        reverted.setChangeType( ChangeType.ModRdn );
+
+        if ( newSuperior != null )
+        {
+            Dn restoredDn = newSuperior.add( newRdn );
+            reverted.setDn( restoredDn );
+        }
+        else
+        {
+            reverted.setDn( newDn );
+        }
+
+        reverted.setNewRdn( oldRdn.getName() );
+
+        // Is the newRdn's value present in the entry ?
+        // ( case 3, 4 and 5)
+        // If keepOldRdn = true, we cover case 4 and 5
+        boolean keepOldRdn = entry.contains( newRdn.getNormType(), newRdn.getNormValue() );
+
+        reverted.setDeleteOldRdn( !keepOldRdn );
+
+        if ( newSuperior != null )
+        {
+            Dn oldSuperior = entry.getDn();
+
+            oldSuperior = oldSuperior.getParent();
+            reverted.setNewSuperior( oldSuperior.getName() );
+        }
+
+        return reverted;
+    }
+
+
+    /**
+     * A helper method to generate the modified attribute after a rename.
+     */
+    private static LdifEntry generateModify( Dn parentDn, Entry entry, Rdn oldRdn, Rdn newRdn )
+    {
+        LdifEntry restored = new LdifEntry();
+        restored.setChangeType( ChangeType.Modify );
+
+        // We have to use the parent Dn, the entry has already
+        // been renamed
+        restored.setDn( parentDn );
+
+        for ( Ava ava : newRdn )
+        {
+            // No need to add something which has already been added
+            // in the previous modification
+            if ( !entry.contains( ava.getNormType(), ava.getValue().getString() )
+                && !( ava.getNormType().equals( oldRdn.getNormType() ) && ava.getValue().getString().equals(
+                    oldRdn.getNormValue() ) ) )
+            {
+                // Create the modification, which is an Remove
+                Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE,
+                    new DefaultAttribute( ava.getType(), ava.getValue().getString() ) );
+
+                restored.addModification( modification );
+            }
+        }
+
+        return restored;
+    }
+
+
+    /**
+     * A helper method which generates a reverted entry
+     */
+    private static LdifEntry generateReverted( Dn newSuperior, Rdn newRdn, Dn newDn, Rdn oldRdn, boolean deleteOldRdn )
+        throws LdapInvalidDnException
+    {
+        LdifEntry reverted = new LdifEntry();
+        reverted.setChangeType( ChangeType.ModRdn );
+
+        if ( newSuperior != null )
+        {
+            Dn restoredDn = newSuperior.add( newRdn );
+            reverted.setDn( restoredDn );
+        }
+        else
+        {
+            reverted.setDn( newDn );
+        }
+
+        reverted.setNewRdn( oldRdn.getName() );
+
+        if ( newSuperior != null )
+        {
+            Dn oldSuperior = newDn;
+
+            oldSuperior = oldSuperior.getParent();
+            reverted.setNewSuperior( oldSuperior.getName() );
+        }
+
+        // Delete the newRDN values
+        reverted.setDeleteOldRdn( deleteOldRdn );
+
+        return reverted;
+    }
+
+
+    /**
+     * Revert a Dn to it's previous version by removing the first Rdn and adding the given Rdn.
+     * It's a rename operation. The biggest issue is that we have many corner cases, depending
+     * on the RDNs we are manipulating, and on the content of the initial entry.
+     * 
+     * @param entry The initial Entry
+     * @param newRdn The new Rdn
+     * @param deleteOldRdn A flag which tells to delete the old Rdn AVAs
+     * @return A list of LDIF reverted entries
+     * @throws LdapInvalidDnException If the name reverting failed
+     */
+    public static List<LdifEntry> reverseRename( Entry entry, Rdn newRdn, boolean deleteOldRdn )
+        throws LdapInvalidDnException
+    {
+        return reverseMoveAndRename( entry, null, newRdn, deleteOldRdn );
+    }
+
+
+    /**
+     * Revert a Dn to it's previous version by removing the first Rdn and adding the given Rdn.
+     * It's a rename operation. The biggest issue is that we have many corner cases, depending
+     * on the RDNs we are manipulating, and on the content of the initial entry.
+     * 
+     * @param entry The initial Entry
+     * @param newSuperior The new superior Dn (can be null if it's just a rename)
+     * @param newRdn The new Rdn
+     * @param deleteOldRdn A flag which tells to delete the old Rdn AVAs
+     * @return A list of LDIF reverted entries
+     * @throws LdapInvalidDnException If the name reverting failed
+     */
+    public static List<LdifEntry> reverseMoveAndRename( Entry entry, Dn newSuperior, Rdn newRdn, boolean deleteOldRdn )
+        throws LdapInvalidDnException
+    {
+        Dn parentDn = entry.getDn();
+        Dn newDn = null;
+
+        if ( newRdn == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12077 ) );
+        }
+
+        if ( parentDn == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12078 ) );
+        }
+
+        if ( parentDn.size() == 0 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12079 ) );
+        }
+
+        parentDn = entry.getDn();
+        Rdn oldRdn = parentDn.getRdn();
+
+        newDn = parentDn;
+        newDn = newDn.getParent();
+        newDn = newDn.add( newRdn );
+
+        List<LdifEntry> entries = new ArrayList<LdifEntry>( 1 );
+        LdifEntry reverted = new LdifEntry();
+
+        // Start with the cases here
+        if ( newRdn.size() == 1 )
+        {
+            // We have a simple new Rdn, something like A=a
+            reverted = revertEntry( entry, newDn, newSuperior, oldRdn, newRdn );
+
+            entries.add( reverted );
+        }
+        else
+        {
+            // We have a composite new Rdn, something like A=a+B=b
+            if ( oldRdn.size() == 1 )
+            {
+                // The old Rdn is simple
+                boolean existInEntry = false;
+
+                // Does it overlap ?
+                // Is the new Rdn AVAs contained into the entry?
+                for ( Ava atav : newRdn )
+                {
+                    if ( !atav.equals( oldRdn.getAva() )
+                        && ( entry.contains( atav.getNormType(), atav.getValue().getString() ) ) )
+                    {
+                        existInEntry = true;
+                    }
+                }
+
+                // The new Rdn includes the old one
+                if ( existInEntry )
+                {
+                    // Some of the new Rdn AVAs existed in the entry
+                    // We have to restore them, but we also have to remove
+                    // the new values
+                    reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
+
+                    entries.add( reverted );
+
+                    // Now, restore the initial values
+                    LdifEntry restored = generateModify( parentDn, entry, oldRdn, newRdn );
+
+                    entries.add( restored );
+                }
+                else
+                {
+                    // This is the simplest case, we don't have to restore
+                    // some existing values (case 8.1 and 9.1)
+                    reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
+
+                    entries.add( reverted );
+                }
+            }
+            else
+            {
+                // We have a composite new Rdn, something like A=a+B=b
+                // Does the Rdn overlap ?
+                boolean overlapping = false;
+                boolean existInEntry = false;
+
+                Set<Ava> oldAtavs = new HashSet<Ava>();
+
+                // We first build a set with all the oldRDN ATAVs
+                for ( Ava atav : oldRdn )
+                {
+                    oldAtavs.add( atav );
+                }
+
+                // Now we loop on the newRDN ATAVs to evaluate if the Rdns are overlaping
+                // and if the newRdn ATAVs are present in the entry
+                for ( Ava atav : newRdn )
+                {
+                    if ( oldAtavs.contains( atav ) )
+                    {
+                        overlapping = true;
+                    }
+                    else if ( entry.contains( atav.getNormType(), atav.getValue().getString() ) )
+                    {
+                        existInEntry = true;
+                    }
+                }
+
+                if ( overlapping )
+                {
+                    // They overlap
+                    if ( existInEntry )
+                    {
+                        // In this case, we have to reestablish the removed ATAVs
+                        // (Cases 12.2 and 13.2)
+                        reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
+
+                        entries.add( reverted );
+                    }
+                    else
+                    {
+                        // We can simply remove all the new Rdn atavs, as the
+                        // overlapping values will be re-created.
+                        // (Cases 12.1 and 13.1)
+                        reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
+
+                        entries.add( reverted );
+                    }
+                }
+                else
+                {
+                    // No overlapping
+                    if ( existInEntry )
+                    {
+                        // In this case, we have to reestablish the removed ATAVs
+                        // (Cases 10.2 and 11.2)
+                        reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, KEEP_OLD_RDN );
+
+                        entries.add( reverted );
+
+                        LdifEntry restored = generateModify( parentDn, entry, oldRdn, newRdn );
+
+                        entries.add( restored );
+                    }
+                    else
+                    {
+                        // We are safe ! We can delete all the new Rdn ATAVs
+                        // (Cases 10.1 and 11.1)
+                        reverted = generateReverted( newSuperior, newRdn, newDn, oldRdn, DELETE_OLD_RDN );
+
+                        entries.add( reverted );
+                    }
+                }
+            }
+        }
+
+        return entries;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifUtils.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifUtils.java
new file mode 100644
index 0000000..71217fc
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/LdifUtils.java
@@ -0,0 +1,776 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import java.io.IOException;
+
+import javax.naming.directory.Attributes;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.AttributeUtils;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Some LDIF helper methods.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LdifUtils
+{
+    /** The array that will be used to match the first char.*/
+    private static final boolean[] LDIF_SAFE_STARTING_CHAR_ALPHABET = new boolean[128];
+
+    /** The array that will be used to match the other chars.*/
+    private static final boolean[] LDIF_SAFE_OTHER_CHARS_ALPHABET = new boolean[128];
+
+    /** The default length for a line in a ldif file */
+    private static final int DEFAULT_LINE_LENGTH = 80;
+
+    /** The file separator */
+    private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
+
+    static
+    {
+        // Initialization of the array that will be used to match the first char.
+        for ( int i = 0; i < 128; i++ )
+        {
+            LDIF_SAFE_STARTING_CHAR_ALPHABET[i] = true;
+        }
+
+        // 0 (NUL)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[0] = false;
+        // 10 (LF)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[10] = false;
+        // 13 (CR)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[13] = false;
+        // 32 (SPACE)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[32] = false;
+        // 58 (:)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[58] = false;
+        // 60 (>)
+        LDIF_SAFE_STARTING_CHAR_ALPHABET[60] = false;
+
+        // Initialization of the array that will be used to match the other chars.
+        for ( int i = 0; i < 128; i++ )
+        {
+            LDIF_SAFE_OTHER_CHARS_ALPHABET[i] = true;
+        }
+
+        // 0 (NUL)
+        LDIF_SAFE_OTHER_CHARS_ALPHABET[0] = false;
+        // 10 (LF)
+        LDIF_SAFE_OTHER_CHARS_ALPHABET[10] = false;
+        // 13 (CR)
+        LDIF_SAFE_OTHER_CHARS_ALPHABET[13] = false;
+    }
+
+
+    /**
+     * Private constructor.
+     */
+    private LdifUtils()
+    {
+    }
+
+
+    /**
+     * Checks if the input String contains only safe values, that is, the data
+     * does not need to be encoded for use with LDIF. The rules for checking safety
+     * are based on the rules for LDIF (LDAP Data Interchange Format) per RFC 2849.
+     * The data does not need to be encoded if all the following are true:
+     *
+     * The data cannot start with the following char values:
+     * <ul>
+     * <li>00 (NUL)</li>
+     * <li>10 (LF)</li>
+     * <li>13 (CR)</li>
+     * <li>32 (SPACE)</li>
+     * <li>58 (:)</li>
+     * <li>60 (<)</li>
+     * <li>Any character with value greater than 127</li>
+     * </ul>
+     *
+     * The data cannot contain any of the following char values:
+     * <ul>
+     * <li>00 (NUL)</li>
+     * <li>10 (LF)</li>
+     * <li>13 (CR)</li>
+     * <li>Any character with value greater than 127</li>
+     * </ul>
+     *
+     * The data cannot end with a space.
+     *
+     * @param str the String to be checked
+     * @return true if encoding not required for LDIF
+     */
+    public static boolean isLDIFSafe( String str )
+    {
+        if ( Strings.isEmpty( str ) )
+        {
+            // A null string is LDIF safe
+            return true;
+        }
+
+        // Checking the first char
+        char currentChar = str.charAt( 0 );
+
+        if ( ( currentChar > 127 ) || !LDIF_SAFE_STARTING_CHAR_ALPHABET[currentChar] )
+        {
+            return false;
+        }
+
+        // Checking the other chars
+        for ( int i = 1; i < str.length(); i++ )
+        {
+            currentChar = str.charAt( i );
+
+            if ( ( currentChar > 127 ) || !LDIF_SAFE_OTHER_CHARS_ALPHABET[currentChar] )
+            {
+                return false;
+            }
+        }
+
+        // The String cannot end with a space
+        return ( currentChar != ' ' );
+    }
+
+
+    /**
+     * Convert an Attributes as LDIF
+     * 
+     * @param attrs the Attributes to convert
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs ) throws LdapException
+    {
+        return convertAttributesToLdif( AttributeUtils.toEntry( attrs, null ), DEFAULT_LINE_LENGTH );
+    }
+
+
+    /**
+     * Convert an Attributes as LDIF
+     * 
+     * @param attrs the Attributes to convert
+     * @param length The ldif line length
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs, int length ) throws LdapException
+    {
+        return convertAttributesToLdif( AttributeUtils.toEntry( attrs, null ), length );
+    }
+
+
+    /**
+     * Convert an Attributes as LDIF. The Dn is written.
+     * 
+     * @param attrs the Attributes to convert
+     * @param dn The Dn for this entry
+     * @param length The ldif line length
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs, Dn dn, int length ) throws LdapException
+    {
+        return convertToLdif( AttributeUtils.toEntry( attrs, dn ), length );
+    }
+
+
+    /**
+     * Convert an Attributes as LDIF. The Dn is written.
+     * 
+     * @param attrs the Attributes to convert
+     * @param dn The Dn for this entry
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attributes attrs, Dn dn ) throws LdapException
+    {
+        return convertToLdif( AttributeUtils.toEntry( attrs, dn ), DEFAULT_LINE_LENGTH );
+    }
+
+
+    /**
+     * Convert an Entry to LDIF
+     * 
+     * @param entry the Entry to convert
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Entry entry ) throws LdapException
+    {
+        return convertToLdif( entry, DEFAULT_LINE_LENGTH );
+    }
+
+
+    /**
+     * Convert an Entry to LDIF including a version number at the top
+     * 
+     * @param entry the Entry to convert
+     * @param includeVersionInfo flag to tell whether to include version number or not
+     * @return the corresponding LDIF code as a String
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Entry entry, boolean includeVersionInfo ) throws LdapException
+    {
+        String ldif = convertToLdif( entry, DEFAULT_LINE_LENGTH );
+
+        if ( includeVersionInfo )
+        {
+            ldif = "version: 1" + LINE_SEPARATOR + ldif;
+        }
+
+        return ldif;
+    }
+
+
+    /**
+     * Convert all the Entry's attributes to LDIF. The Dn is not written
+     * 
+     * @param entry the Entry to convert
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertAttributesToLdif( Entry entry ) throws LdapException
+    {
+        return convertAttributesToLdif( entry, DEFAULT_LINE_LENGTH );
+    }
+
+
+    /**
+     * Convert a LDIF String to a JNDI attributes.
+     *
+     * @param ldif The LDIF string containing an attribute value
+     * @return An Attributes instance
+     * @exception LdapLdifException If the LDIF String cannot be converted to an Attributes
+     */
+    public static Attributes getJndiAttributesFromLdif( String ldif ) throws LdapLdifException
+    {
+        LdifAttributesReader reader = new LdifAttributesReader();
+
+        try
+        {
+            Attributes attributes = AttributeUtils.toAttributes( reader.parseEntry( ldif ) );
+
+            reader.close();
+
+            return attributes;
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapLdifException( ioe.getMessage() );
+        }
+    }
+
+
+    /**
+     * Convert an Entry as LDIF
+     * 
+     * @param entry the Entry to convert
+     * @param length the expected line length
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Entry entry, int length ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        if ( entry.getDn() != null )
+        {
+            // First, dump the Dn
+            if ( isLDIFSafe( entry.getDn().getName() ) )
+            {
+                sb.append( stripLineToNChars( "dn: " + entry.getDn().getName(), length ) );
+            }
+            else
+            {
+                sb.append( stripLineToNChars( "dn:: " + encodeBase64( entry.getDn().getName() ), length ) );
+            }
+
+            sb.append( '\n' );
+        }
+
+        // Then all the attributes
+        for ( Attribute attribute : entry )
+        {
+            sb.append( convertToLdif( attribute, length ) );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Convert the Entry's attributes to LDIF. The Dn is not written.
+     * 
+     * @param entry the Entry to convert
+     * @param length the expected line length
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertAttributesToLdif( Entry entry, int length ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        // Then all the attributes
+        for ( Attribute attribute : entry )
+        {
+            sb.append( convertToLdif( attribute, length ) );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Convert an LdifEntry to LDIF
+     * 
+     * @param entry the LdifEntry to convert
+     * @return the corresponding LDIF as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( LdifEntry entry ) throws LdapException
+    {
+        return convertToLdif( entry, DEFAULT_LINE_LENGTH );
+    }
+
+
+    /**
+     * Convert an LdifEntry to LDIF
+     * 
+     * @param entry the LdifEntry to convert
+     * @param length The maximum line's length
+     * @return the corresponding LDIF as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( LdifEntry entry, int length ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        // First, dump the Dn
+        if ( isLDIFSafe( entry.getDn().getName() ) )
+        {
+            sb.append( stripLineToNChars( "dn: " + entry.getDn(), length ) );
+        }
+        else
+        {
+            sb.append( stripLineToNChars( "dn:: " + encodeBase64( entry.getDn().getName() ), length ) );
+        }
+
+        sb.append( '\n' );
+
+        // Dump the ChangeType
+        String changeType = Strings.toLowerCase( entry.getChangeType().toString() );
+
+        if ( entry.getChangeType() != ChangeType.None )
+        {
+            // First dump the controls if any
+            if ( entry.hasControls() )
+            {
+                for ( LdifControl control : entry.getControls().values() )
+                {
+                    StringBuilder controlStr = new StringBuilder();
+
+                    controlStr.append( "control: " ).append( control.getOid() );
+                    controlStr.append( " " ).append( control.isCritical() );
+
+                    if ( control.hasValue() )
+                    {
+                        controlStr.append( "::" ).append( Base64.encode( control.getValue() ) );
+                    }
+
+                    sb.append( stripLineToNChars( controlStr.toString(), length ) );
+                    sb.append( '\n' );
+                }
+            }
+
+            sb.append( stripLineToNChars( "changetype: " + changeType, length ) );
+            sb.append( '\n' );
+        }
+
+        switch ( entry.getChangeType() )
+        {
+            case None:
+                if ( entry.hasControls() )
+                {
+                    sb.append( stripLineToNChars( "changetype: " + ChangeType.Add, length ) );
+                }
+
+                // Fallthrough
+
+            case Add:
+                if ( ( entry.getEntry() == null ) )
+                {
+                    throw new LdapException( I18n.err( I18n.ERR_12082 ) );
+                }
+
+                // Now, iterate through all the attributes
+                for ( Attribute attribute : entry.getEntry() )
+                {
+                    sb.append( convertToLdif( attribute, length ) );
+                }
+
+                break;
+
+            case Delete:
+                if ( entry.getEntry() != null )
+                {
+                    throw new LdapException( I18n.err( I18n.ERR_12081 ) );
+                }
+
+                break;
+
+            case ModDn:
+            case ModRdn:
+                if ( entry.getEntry() != null )
+                {
+                    throw new LdapException( I18n.err( I18n.ERR_12083 ) );
+                }
+
+                // Stores the new Rdn
+                Attribute newRdn = new DefaultAttribute( "newrdn", entry.getNewRdn() );
+                sb.append( convertToLdif( newRdn, length ) );
+
+                // Stores the deleteoldrdn flag
+                sb.append( "deleteoldrdn: " );
+
+                if ( entry.isDeleteOldRdn() )
+                {
+                    sb.append( "1" );
+                }
+                else
+                {
+                    sb.append( "0" );
+                }
+
+                sb.append( '\n' );
+
+                // Stores the optional newSuperior
+                if ( !Strings.isEmpty( entry.getNewSuperior() ) )
+                {
+                    Attribute newSuperior = new DefaultAttribute( "newsuperior", entry.getNewSuperior() );
+                    sb.append( convertToLdif( newSuperior, length ) );
+                }
+
+                break;
+
+            case Modify:
+                boolean isFirst = true;
+                
+                for ( Modification modification : entry.getModifications() )
+                {
+                    
+                    if ( isFirst )
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        sb.append( "-\n" );
+                    }
+
+                    switch ( modification.getOperation() )
+                    {
+                        case ADD_ATTRIBUTE:
+                            sb.append( "add: " );
+                            break;
+
+                        case REMOVE_ATTRIBUTE:
+                            sb.append( "delete: " );
+                            break;
+
+                        case REPLACE_ATTRIBUTE:
+                            sb.append( "replace: " );
+                            break;
+
+                        default:
+                            throw new IllegalArgumentException( "Unexpected ModificationOperation: "
+                                + modification.getOperation() );
+                    }
+
+                    sb.append( modification.getAttribute().getUpId() );
+                    sb.append( '\n' );
+
+                    sb.append( convertToLdif( modification.getAttribute(), length ) );
+                }
+
+                sb.append( '-' );
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected ChangeType: " + entry.getChangeType() );
+        }
+
+        sb.append( '\n' );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Base64 encode a String
+     * 
+     * @param str The string to encode
+     * @return the base 64 encoded string
+     */
+    private static String encodeBase64( String str )
+    {
+        // force encoding using UTF-8 charset, as required in RFC2849 note 7
+        return new String( Base64.encode( Strings.getBytesUtf8( str ) ) );
+    }
+
+
+    /**
+     * Converts an EntryAttribute to LDIF
+     * 
+     * @param attr the >EntryAttribute to convert
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attribute attr ) throws LdapException
+    {
+        return convertToLdif( attr, DEFAULT_LINE_LENGTH );
+    }
+
+
+    /**
+     * Converts an EntryAttribute as LDIF
+     * 
+     * @param attr the EntryAttribute to convert
+     * @param length the expected line length
+     * @return the corresponding LDIF code as a String
+     * @throws LdapException If a naming exception is encountered.
+     */
+    public static String convertToLdif( Attribute attr, int length ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+        
+        if ( attr.size() == 0 )
+        {
+            // Special case : we don't have any value
+            return "";
+        }
+
+        for ( Value<?> value : attr )
+        {
+            StringBuilder lineBuffer = new StringBuilder();
+
+            lineBuffer.append( attr.getUpId() );
+
+            // First, deal with null value (which is valid)
+            if ( value.isNull() )
+            {
+                lineBuffer.append( ':' );
+            }
+            else if ( value.isHumanReadable() )
+            {
+                // It's a String but, we have to check if encoding isn't required
+                String str = value.getString();
+
+                if ( !LdifUtils.isLDIFSafe( str ) )
+                {
+                    lineBuffer.append( ":: " ).append( encodeBase64( str ) );
+                }
+                else
+                {
+                    lineBuffer.append( ':' );
+
+                    if ( str != null )
+                    {
+                        lineBuffer.append( ' ' ).append( str );
+                    }
+                }
+            }
+            else
+            {
+                // It is binary, so we have to encode it using Base64 before adding it
+                char[] encoded = Base64.encode( value.getBytes() );
+
+                lineBuffer.append( ":: " + new String( encoded ) );
+            }
+
+            lineBuffer.append( '\n' );
+            sb.append( stripLineToNChars( lineBuffer.toString(), length ) );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Strips the String every n specified characters
+     * 
+     * @param str the string to strip
+     * @param nbChars the number of characters
+     * @return the stripped String
+     */
+    public static String stripLineToNChars( String str, int nbChars )
+    {
+        int strLength = str.length();
+
+        if ( strLength <= nbChars )
+        {
+            return str;
+        }
+
+        if ( nbChars < 2 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_12084 ) );
+        }
+
+        // We will first compute the new size of the LDIF result
+        // It's at least nbChars chars plus one for \n
+        int charsPerLine = nbChars - 1;
+
+        int remaining = ( strLength - nbChars ) % charsPerLine;
+
+        int nbLines = 1 + ( ( strLength - nbChars ) / charsPerLine ) + ( remaining == 0 ? 0 : 1 );
+
+        int nbCharsTotal = strLength + nbLines + nbLines - 2;
+
+        char[] buffer = new char[nbCharsTotal];
+        char[] orig = str.toCharArray();
+
+        int posSrc = 0;
+        int posDst = 0;
+
+        System.arraycopy( orig, posSrc, buffer, posDst, nbChars );
+        posSrc += nbChars;
+        posDst += nbChars;
+
+        for ( int i = 0; i < nbLines - 2; i++ )
+        {
+            buffer[posDst++] = '\n';
+            buffer[posDst++] = ' ';
+
+            System.arraycopy( orig, posSrc, buffer, posDst, charsPerLine );
+            posSrc += charsPerLine;
+            posDst += charsPerLine;
+        }
+
+        buffer[posDst++] = '\n';
+        buffer[posDst++] = ' ';
+        System.arraycopy( orig, posSrc, buffer, posDst, remaining == 0 ? charsPerLine : remaining );
+
+        return new String( buffer );
+    }
+
+
+    /**
+     * Build a new Attributes instance from a LDIF list of lines. The values can be
+     * either a complete Ava, or a couple of AttributeType ID and a value (a String or
+     * a byte[]). The following sample shows the three cases :
+     *
+     * <pre>
+     * Attribute attr = AttributeUtils.createAttributes(
+     *     "objectclass: top",
+     *     "cn", "My name",
+     *     "jpegPhoto", new byte[]{0x01, 0x02} );
+     * </pre>
+     *
+     * @param avas The AttributeType and Values, using a ldif format, or a couple of
+     * Attribute ID/Value
+     * @return An Attributes instance
+     * @throws LdapException If the data are invalid
+     */
+    public static Attributes createJndiAttributes( Object... avas ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+        int pos = 0;
+        boolean valueExpected = false;
+
+        for ( Object ava : avas )
+        {
+            if ( !valueExpected )
+            {
+                if ( !( ava instanceof String ) )
+                {
+                    throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                        I18n.ERR_12085, ( pos + 1 ) ) );
+                }
+
+                String attribute = ( String ) ava;
+                sb.append( attribute );
+
+                if ( attribute.indexOf( ':' ) != -1 )
+                {
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    valueExpected = true;
+                }
+            }
+            else
+            {
+                if ( ava instanceof String )
+                {
+                    sb.append( ": " ).append( ( String ) ava ).append( '\n' );
+                }
+                else if ( ava instanceof byte[] )
+                {
+                    sb.append( ":: " );
+                    sb.append( new String( Base64.encode( ( byte[] ) ava ) ) );
+                    sb.append( '\n' );
+                }
+                else
+                {
+                    throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                        I18n.ERR_12086, ( pos + 1 ) ) );
+                }
+
+                valueExpected = false;
+            }
+        }
+
+        if ( valueExpected )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n
+                .err( I18n.ERR_12087 ) );
+        }
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = AttributeUtils.toAttributes( reader.parseEntry( sb.toString() ) );
+
+        try
+        {
+            reader.close();
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+        }
+
+        return attributes;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/Anonymizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/Anonymizer.java
new file mode 100644
index 0000000..8130e27
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/Anonymizer.java
@@ -0,0 +1,45 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.ldif.anonymizer;
+
+
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Value;
+
+
+/**
+ * An interface for Anonymizers.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Anonymizer<K>
+{
+    /**
+     * Take an attribute and its value, anonymizing all of them.
+     * 
+     * @param valueMap The existing map for value to the associated anonymized counterpart
+     * @param attribute The attribute to anonymize
+     * @return The anonymized attribute
+     */
+    Attribute anonymize( Map<Value<K>, Value<K>> valueMap, Attribute attribute );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/BinaryAnonymizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/BinaryAnonymizer.java
new file mode 100644
index 0000000..97a4d54
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/BinaryAnonymizer.java
@@ -0,0 +1,104 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.ldif.anonymizer;
+
+
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+
+
+/**
+ * A default anonymizer for attributes that are not HR
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BinaryAnonymizer implements Anonymizer<byte[]>
+{
+    /** Create a random generator */
+    Random random = new Random( System.currentTimeMillis() );
+
+
+    /**
+     * Anonymize an attribute using pure random values (either chars of bytes, depending on the Attribute type)
+     */
+    @Override
+    public Attribute anonymize( Map<Value<byte[]>, Value<byte[]>> valueMap, Attribute attribute )
+    {
+        Attribute result = new DefaultAttribute( attribute.getAttributeType() );
+        random.setSeed( System.nanoTime() );
+
+        for ( Value<?> value : attribute )
+        {
+            if ( value instanceof BinaryValue )
+            {
+                byte[] bytesValue = value.getBytes();
+
+                int length = bytesValue.length;
+
+                // Same size
+                byte[] newValue = new byte[length];
+
+                for ( int i = 0; i < length; i++ )
+                {
+                    newValue[i] = ( byte ) ( random.nextInt( 'Z' - 'A' ) + 'A' );
+                }
+
+                try
+                {
+                    result.add( newValue );
+                }
+                catch ( LdapInvalidAttributeValueException e )
+                {
+                    // TODO : handle that
+                }
+            }
+            else
+            {
+                byte[] byteValue = value.getBytes();
+
+                // Same size
+                byte[] newValue = new byte[byteValue.length];
+
+                for ( int i = 0; i < byteValue.length; i++ )
+                {
+                    newValue[i] = ( byte ) random.nextInt();
+                }
+
+                try
+                {
+                    result.add( newValue );
+                }
+                catch ( LdapInvalidAttributeValueException e )
+                {
+                    // TODO : handle that
+                }
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/DefaultAnonymizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/DefaultAnonymizer.java
new file mode 100644
index 0000000..f51389d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/DefaultAnonymizer.java
@@ -0,0 +1,104 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.ldif.anonymizer;
+
+
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+
+
+/**
+ * TODO DefaultAnonymizer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultAnonymizer<K> implements Anonymizer<K>
+{
+    /** Create a random generator */
+    Random random = new Random( System.nanoTime() );
+
+
+    /**
+     * Anonymize an attribute using pure random values (either chars of bytes, depending on the Attribute type)
+     */
+    @Override
+    public Attribute anonymize( Map<Value<K>, Value<K>> valueMap, Attribute attribute )
+    {
+        Attribute result = new DefaultAttribute( attribute.getAttributeType() );
+        random.setSeed( System.nanoTime() );
+
+        for ( Value<?> value : attribute )
+        {
+            if ( value instanceof StringValue )
+            {
+                String strValue = value.getString();
+
+                int length = strValue.length();
+
+                // Same size
+                char[] newValue = new char[length];
+
+                for ( int i = 0; i < length; i++ )
+                {
+                    newValue[i] = ( char ) ( random.nextInt( 'Z' - 'A' ) + 'A' );
+                }
+
+                try
+                {
+                    result.add( new String( newValue ) );
+                }
+                catch ( LdapInvalidAttributeValueException e )
+                {
+                    // TODO : handle that
+                }
+            }
+            else
+            {
+                byte[] byteValue = value.getBytes();
+
+                // Same size
+                byte[] newValue = new byte[byteValue.length];
+
+                for ( int i = 0; i < byteValue.length; i++ )
+                {
+                    newValue[i] = ( byte ) random.nextInt();
+                }
+
+                try
+                {
+                    result.add( newValue );
+                }
+                catch ( LdapInvalidAttributeValueException e )
+                {
+                    // TODO : handle that
+                }
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/IntegerAnonymizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/IntegerAnonymizer.java
new file mode 100644
index 0000000..fdf50bb
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/IntegerAnonymizer.java
@@ -0,0 +1,83 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.ldif.anonymizer;
+
+
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+
+
+/**
+ * A default anonymizer for attributes that is an Integer
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class IntegerAnonymizer implements Anonymizer<String>
+{
+    /** Create a random generator */
+    Random random = new Random( System.currentTimeMillis() );
+
+
+    /**
+     * Anonymize an attribute using pure random values (either chars of bytes, depending on the Attribute type)
+     */
+    @Override
+    public Attribute anonymize( Map<Value<String>, Value<String>> valueMap, Attribute attribute )
+    {
+        Attribute result = new DefaultAttribute( attribute.getAttributeType() );
+        random.setSeed( System.nanoTime() );
+
+        for ( Value<?> value : attribute )
+        {
+            if ( value instanceof StringValue )
+            {
+                String strValue = value.getString();
+
+                int length = strValue.length();
+
+                // Same size
+                char[] newValue = new char[length];
+
+                for ( int i = 0; i < length; i++ )
+                {
+                    newValue[i] = ( char ) ( random.nextInt( '9' - '0' ) + '0' );
+                }
+
+                try
+                {
+                    result.add( new String( newValue ) );
+                }
+                catch ( LdapInvalidAttributeValueException e )
+                {
+                    // TODO : handle that
+                }
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/StringAnonymizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/StringAnonymizer.java
new file mode 100644
index 0000000..635e5b6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/ldif/anonymizer/StringAnonymizer.java
@@ -0,0 +1,123 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.ldif.anonymizer;
+
+
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+
+
+/**
+ * A default anonymizer for attributes that are HR
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StringAnonymizer implements Anonymizer<String>
+{
+    /** Create a random generator */
+    Random random = new Random( System.currentTimeMillis() );
+
+
+    /**
+     * Anonymize an attribute using pure random values (either chars of bytes, depending on the Attribute type)
+     */
+    @Override
+    public Attribute anonymize( Map<Value<String>, Value<String>> valueMap, Attribute attribute )
+    {
+        Attribute result = new DefaultAttribute( attribute.getAttributeType() );
+        random.setSeed( System.nanoTime() );
+
+        for ( Value<?> value : attribute )
+        {
+            Value<String> anonymized =  valueMap.get( value );
+            
+            if ( anonymized != null )
+            {
+                try
+                {
+                    result.add( anonymized.getString() );
+                }
+                catch ( LdapInvalidAttributeValueException e )
+                {
+                    // TODO : handle that
+                }
+            }
+            else
+            {
+                if ( value instanceof StringValue )
+                {
+                    String strValue = value.getNormValue().toString();
+                    int length = strValue.length();
+    
+                    // Same size
+                    char[] newValue = new char[length];
+    
+                    for ( int i = 0; i < length; i++ )
+                    {
+                        newValue[i] = ( char ) ( random.nextInt( 'Z' - 'A' ) + 'A' );
+                    }
+    
+                    try
+                    {
+                        String newValueStr = new String( newValue );
+                        result.add( newValueStr );
+                        
+                        Value<String> anonValue = new StringValue( attribute.getAttributeType(), newValueStr );
+                        valueMap.put( ( Value<String> ) value, anonValue );
+                    }
+                    catch ( LdapInvalidAttributeValueException e )
+                    {
+                        // TODO : handle that
+                    }
+                }
+                else
+                {
+                    byte[] byteValue = value.getBytes();
+    
+                    // Same size
+                    byte[] newValue = new byte[byteValue.length];
+    
+                    for ( int i = 0; i < byteValue.length; i++ )
+                    {
+                        newValue[i] = ( byte ) random.nextInt();
+                    }
+    
+                    try
+                    {
+                        result.add( newValue );
+                    }
+                    catch ( LdapInvalidAttributeValueException e )
+                    {
+                        // TODO : handle that
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonListener.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonListener.java
new file mode 100644
index 0000000..3cd3a6c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonListener.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * A listener interested in abandon operations performed on requests.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface AbandonListener
+{
+    /**
+     * Notifies that a request has been abandoned.
+     * 
+     * @param req the request which is abandoned.
+     */
+    void requestAbandoned( AbandonableRequest req );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonRequest.java
new file mode 100644
index 0000000..4928229
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonRequest.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Abandon protocol operation request to terminate an operation already in
+ * progress.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface AbandonRequest extends Request
+{
+    /** Ldap abandon request type code */
+    MessageTypeEnum TYPE = MessageTypeEnum.ABANDON_REQUEST;
+
+
+    /**
+     * Gets the id of the request operation to terminate.
+     * 
+     * @return the id of the request message to abandon
+     */
+    int getAbandoned();
+
+
+    /**
+     * Sets the id of the request operation to terminate.
+     * 
+     * @param requestId the sequence id of the request message to abandon
+     * @return The AbandonRequest instance
+     */
+    AbandonRequest setAbandoned( int requestId );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonRequestImpl.java
new file mode 100644
index 0000000..9af5b09
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonRequestImpl.java
@@ -0,0 +1,190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Implementation of an AbandonRequest message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AbandonRequestImpl extends AbstractRequest implements AbandonRequest
+{
+    /** Sequence identifier of the outstanding request message to abandon */
+    private int abandonId;
+
+
+    /**
+     * Creates an AbandonRequest implementation for an outstanding request.
+     */
+    public AbandonRequestImpl()
+    {
+        super( -1, TYPE, false );
+    }
+
+
+    /**
+     * Creates an AbandonRequest implementation for an outstanding request.
+     * 
+     * @param abdandonnedId the sequence identifier of the AbandonRequest message.
+     */
+    public AbandonRequestImpl( final int abdandonnedId )
+    {
+        super( -1, TYPE, false );
+        abandonId = abdandonnedId;
+    }
+
+
+    /**
+     * Gets the id of the request operation to terminate.
+     * 
+     * @return the id of the request message to abandon
+     */
+    public int getAbandoned()
+    {
+        return abandonId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest setAbandoned( int abandonId )
+    {
+        this.abandonId = abandonId;
+
+        return this;
+    }
+
+
+    /**
+     * RFC 2251 [Section 4.11]: Abandon, Bind, Unbind, and StartTLS operations
+     * cannot be abandoned.
+     */
+    public void abandon()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04185 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest addControl( Control control )
+    {
+        return ( AbandonRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest addAllControls( Control[] controls )
+    {
+        return ( AbandonRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonRequest removeControl( Control control )
+    {
+        return ( AbandonRequest ) super.removeControl( control );
+    }
+
+
+    /**
+     * Checks for equality first by asking the super method which should compare
+     * all but the Abandoned request's Id. It then compares this to determine
+     * equality.
+     * 
+     * @param obj the object to test for equality to this AbandonRequest
+     * @return true if the obj equals this request, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof AbandonRequest ) )
+        {
+            return false;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        AbandonRequest req = ( AbandonRequest ) obj;
+
+        return req.getAbandoned() == abandonId;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + abandonId;
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Return a String representing an AbandonRequest
+     * 
+     * @return A String representing the AbandonRequest
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Abandon Request :\n" );
+        sb.append( "        Message Id : " ).append( abandonId );
+
+        // The controls
+        sb.append( super.toString() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonableRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonableRequest.java
new file mode 100644
index 0000000..bda0046
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbandonableRequest.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * A request which can be abandoned.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface AbandonableRequest extends Request
+{
+    /**
+     * Abandons this request.
+     */
+    void abandon();
+
+
+    /**
+     * Checks to see if this request has been abandoned.
+     * 
+     * @return true if the request has been abandoned.
+     */
+    boolean isAbandoned();
+
+
+    /**
+     * Adds listener to be notified if this request gets abandoned.
+     * 
+     * @param listener to be notified if this request gets abandoned.
+     * @return An AbandonableRequest reference
+     */
+    AbandonableRequest addAbandonListener( AbandonListener listener );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractAbandonableRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractAbandonableRequest.java
new file mode 100644
index 0000000..4bfce84
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractAbandonableRequest.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Observable;
+import java.util.Observer;
+
+
+/**
+ * The base abandonable request message class. All such requests have a response
+ * type.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AbstractAbandonableRequest extends AbstractRequest implements AbandonableRequest
+{
+    static final long serialVersionUID = -4511116249089399040L;
+
+    /** Flag indicating whether or not this request returns a response. */
+    private boolean abandoned = false;
+
+    private RequestObservable o;
+
+
+    /**
+     * Subclasses must provide these parameters via a super constructor call.
+     * 
+     * @param id
+     *            the sequential message identifier
+     * @param type
+     *            the request type enum
+     */
+    protected AbstractAbandonableRequest( final int id, final MessageTypeEnum type )
+    {
+        super( id, type, true );
+    }
+
+
+    public void abandon()
+    {
+        if ( abandoned )
+        {
+            return;
+        }
+
+        abandoned = true;
+        if ( o == null )
+        {
+            o = new RequestObservable();
+        }
+        o.setChanged();
+        o.notifyObservers();
+        o.deleteObservers();
+    }
+
+
+    public boolean isAbandoned()
+    {
+        return abandoned;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AbandonableRequest addAbandonListener( final AbandonListener listener )
+    {
+        if ( o == null )
+        {
+            o = new RequestObservable();
+        }
+
+        o.addObserver( new Observer()
+        {
+            public void update( Observable o, Object arg )
+            {
+                listener.requestAbandoned( AbstractAbandonableRequest.this );
+            }
+        } );
+
+        return this;
+    }
+
+    // False positive
+    static class RequestObservable extends Observable
+    {
+        @Override
+        public void setChanged()
+        {
+            super.setChanged();
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractExtendedRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractExtendedRequest.java
new file mode 100644
index 0000000..56f3cf9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractExtendedRequest.java
@@ -0,0 +1,248 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * ExtendedRequest implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractExtendedRequest extends AbstractRequest implements ExtendedRequest
+{
+    static final long serialVersionUID = 7916990159044177480L;
+
+    /** Extended request's Object Identifier or <b>requestName</b> */
+    private String oid;
+
+    /** The associated response */
+    private ExtendedResponse response;
+
+
+    /**
+     * Creates an ExtendedRequest implementing object used to perform
+     * extended protocol operation on the server.
+     */
+    public AbstractExtendedRequest()
+    {
+        super( -1, MessageTypeEnum.EXTENDED_REQUEST, true );
+    }
+
+
+    /**
+     * Creates an ExtendedRequest implementing object used to perform
+     * extended protocol operation on the server.
+     * 
+     * @param id the sequential message identifier
+     */
+    public AbstractExtendedRequest( final int id )
+    {
+        super( id, MessageTypeEnum.EXTENDED_REQUEST, true );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // ExtendedRequest Interface Method Implementations
+    // -----------------------------------------------------------------------
+
+    /**
+     * Gets the Object Identifier corresponding to the extended request type.
+     * This is the <b>requestName</b> portion of the ext. req. PDU.
+     * 
+     * @return the dotted-decimal representation as a String of the OID
+     */
+    public String getRequestName()
+    {
+        return oid;
+    }
+
+
+    /**
+     * Sets the Object Identifier corresponding to the extended request type.
+     * 
+     * @param newOid the dotted-decimal representation as a String of the OID
+     */
+    public ExtendedRequest setRequestName( String newOid )
+    {
+        this.oid = newOid;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addControl( Control control )
+    {
+        return ( ExtendedRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addAllControls( Control[] controls )
+    {
+        return ( ExtendedRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest removeControl( Control control )
+    {
+        return ( ExtendedRequest ) super.removeControl( control );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SingleReplyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.EXTENDED_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public abstract ExtendedResponse getResultResponse();
+
+
+    /**
+     * @return the response
+     */
+    public ExtendedResponse getResponse()
+    {
+        return response;
+    }
+
+
+    /**
+     * @param response the response to set
+     */
+    public void setResponse( ExtendedResponse response )
+    {
+        this.response = response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( oid != null )
+        {
+            hash = hash * 17 + oid.hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object equals this ExtendedRequest.
+     * 
+     * @param obj the object to be checked for equality
+     * @return true if the obj equals this ExtendedRequest, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        if ( !( obj instanceof ExtendedRequest ) )
+        {
+            return false;
+        }
+
+        ExtendedRequest req = ( ExtendedRequest ) obj;
+
+        if ( ( oid != null ) && ( req.getRequestName() == null ) )
+        {
+            return false;
+        }
+
+        if ( ( oid == null ) && ( req.getRequestName() != null ) )
+        {
+            return false;
+        }
+
+        if ( ( oid != null ) && ( req.getRequestName() != null ) && !oid.equals( req.getRequestName() ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Get a String representation of an Extended Request
+     * 
+     * @return an Extended Request String
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Extended request\n" );
+        sb.append( "        Request name : '" ).append( oid ).append( "'\n" );
+
+        // The controls
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractMessage.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractMessage.java
new file mode 100644
index 0000000..b6191e5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractMessage.java
@@ -0,0 +1,291 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Abstract message base class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractMessage implements Message
+{
+    /** Map of message controls using OID Strings for keys and Control values */
+    protected final Map<String, Control> controls;
+
+    /** The session unique message sequence identifier */
+    private int id;
+
+    /** The message type enumeration */
+    private final MessageTypeEnum type;
+
+    /** Transient Message Parameter Hash */
+    private final Map<Object, Object> parameters;
+
+
+    /**
+     * Completes the instantiation of a Message.
+     * 
+     * @param id the seq id of the message
+     * @param type the type of the message
+     */
+    protected AbstractMessage( final int id, final MessageTypeEnum type )
+    {
+        this.id = id;
+        this.type = type;
+        controls = new HashMap<String, Control>();
+        parameters = new HashMap<Object, Object>();
+    }
+
+
+    /**
+     * Gets the session unique message sequence id for this message. Requests
+     * and their responses if any have the same message id. Clients at the
+     * initialization of a session start with the first message's id set to 1
+     * and increment it with each transaction.
+     * 
+     * @return the session unique message id.
+     */
+    public int getMessageId()
+    {
+        return id;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message setMessageId( int id )
+    {
+        this.id = id;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, Control> getControls()
+    {
+        return Collections.unmodifiableMap( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Control getControl( String oid )
+    {
+        return controls.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasControl( String oid )
+    {
+        return controls.containsKey( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message addControl( Control control )
+    {
+        controls.put( control.getOid(), control );
+
+        return this;
+    }
+
+
+    /**
+     * Deletes a control removing it from this Message.
+     * 
+     * @param control the control to remove.
+     */
+    public Message removeControl( Control control )
+    {
+        controls.remove( control.getOid() );
+
+        return this;
+    }
+
+
+    /**
+     * Gets the LDAP message type code associated with this Message. Each
+     * request and response type has a unique message type code defined by the
+     * protocol in <a href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251</a>.
+     * 
+     * @return the message type code.
+     */
+    public MessageTypeEnum getType()
+    {
+        return type;
+    }
+
+
+    /**
+     * Gets a message scope parameter. Message scope parameters are temporary
+     * variables associated with a message and are set locally to be used to
+     * associate housekeeping information with a request or its processing.
+     * These parameters are never transmitted nor received, think of them as
+     * transient data associated with the message or its processing. These
+     * transient parameters are not locked down so modifications can occur
+     * without firing LockExceptions even when this Lockable is in the locked
+     * state.
+     * 
+     * @param key the key used to access a message parameter.
+     * @return the transient message parameter value.
+     */
+    public Object get( Object key )
+    {
+        return parameters.get( key );
+    }
+
+
+    /**
+     * Sets a message scope parameter. These transient parameters are not locked
+     * down so modifications can occur without firing LockExceptions even when
+     * this Lockable is in the locked state.
+     * 
+     * @param key the parameter key
+     * @param value the parameter value
+     * @return the old value or null
+     */
+    public Object put( Object key, Object value )
+    {
+        return parameters.put( key, value );
+    }
+
+
+    /**
+     * Checks to see if two messages are equivalent. Messages equivalence does
+     * not factor in parameters accessible through the get() and put()
+     * operations, nor do they factor in the Lockable properties of the Message.
+     * Only the type, controls, and the messageId are evaluated for equality.
+     * 
+     * @param obj the object to compare this Message to for equality
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof Message ) )
+        {
+            return false;
+        }
+
+        Message msg = ( Message ) obj;
+
+        if ( msg.getMessageId() != id )
+        {
+            return false;
+        }
+
+        if ( msg.getType() != type )
+        {
+            return false;
+        }
+
+        Map<String, Control> controlMap = msg.getControls();
+
+        if ( controlMap.size() != controls.size() )
+        {
+            return false;
+        }
+
+        for ( String key : controls.keySet() )
+        {
+            if ( !controlMap.containsKey( key ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + id;
+        hash = hash * 17 + ( type == null ? 0 : type.hashCode() );
+        hash = hash * 17 + ( parameters == null ? 0 : parameters.hashCode() );
+        hash = hash * 17 + ( controls == null ? 0 : controls.hashCode() );
+
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Message addAllControls( Control[] controls )
+    {
+        for ( Control c : controls )
+        {
+            this.controls.put( c.getOid(), c );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * Get a String representation of a LdapMessage
+     * 
+     * @return A LdapMessage String
+     */
+    public String toString( String message )
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "MessageType : " ).append( type ).append( '\n' );
+        sb.append( "Message ID : " ).append( id ).append( '\n' );
+
+        sb.append( message );
+
+        if ( controls != null )
+        {
+            for ( Control control : controls.values() )
+            {
+                sb.append( control );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractRequest.java
new file mode 100644
index 0000000..be7543b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractRequest.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * The base request message class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AbstractRequest extends AbstractMessage implements Request
+{
+    static final long serialVersionUID = -4511116249089399040L;
+
+    /** Flag indicating whether or not this request returns a response. */
+    private final boolean hasResponse;
+
+
+    /**
+     * Subclasses must provide these parameters via a super constructor call.
+     * 
+     * @param id the sequential message identifier
+     * @param type the request type enum
+     * @param hasResponse flag indicating if this request generates a response
+     */
+    protected AbstractRequest( final int id, final MessageTypeEnum type, boolean hasResponse )
+    {
+        super( id, type );
+
+        this.hasResponse = hasResponse;
+    }
+
+
+    /**
+     * Indicator flag used to determine whether or not this type of request
+     * produces a reply.
+     * 
+     * @return true if any reply is generated, false if no response is generated
+     */
+    public boolean hasResponse()
+    {
+        return hasResponse;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof Request ) )
+        {
+            return false;
+        }
+
+        if ( hasResponse != ( ( Request ) obj ).hasResponse() )
+        {
+            return false;
+        }
+        return super.equals( obj );
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + ( hasResponse ? 0 : 1 );
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractResponse.java
new file mode 100644
index 0000000..91093b2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractResponse.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Abstract base for a Response message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public abstract class AbstractResponse extends AbstractMessage implements Response
+{
+    // ------------------------------------------------------------------------
+    // Response Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Allows subclasses based on the abstract type to create a response to a
+     * request.
+     * 
+     * @param id the response eliciting this Request
+     * @param type the message type of the response
+     */
+    protected AbstractResponse( final int id, final MessageTypeEnum type )
+    {
+        super( id, type );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractResultResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractResultResponse.java
new file mode 100644
index 0000000..e5a9406
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AbstractResultResponse.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Abstract base for a ResultResponse message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractResultResponse extends AbstractResponse implements ResultResponse
+{
+    /** Response result components */
+    protected LdapResult ldapResult = new LdapResultImpl();
+
+
+    // ------------------------------------------------------------------------
+    // Response Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Allows subclasses based on the abstract type to create a response to a
+     * request.
+     * 
+     * @param id the response eliciting this Request
+     * @param type the message type of the response
+     */
+    protected AbstractResultResponse( final int id, final MessageTypeEnum type )
+    {
+        super( id, type );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Response Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the LdapResult components of this Response.
+     * 
+     * @return the LdapResult for this Response.
+     */
+    public LdapResult getLdapResult()
+    {
+        return ldapResult;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( getLdapResult() != null )
+        {
+            hash = hash * 17 + getLdapResult().hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object is equal to this AbstractResultResponse. First
+     * the object is checked to see if it is this AbstractResultResponse
+     * instance if so it returns true. Next it checks if the super method
+     * returns false and if it does false is returned. It then checks if the
+     * LDAPResult's are equal. If not false is returned and if they match true
+     * is returned.
+     * 
+     * @param obj
+     *            the object to compare to this LdapResult containing response
+     * @return true if they objects are equivalent false otherwise
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        if ( !( obj instanceof ResultResponse ) )
+        {
+            return false;
+        }
+
+        ResultResponse resp = ( ResultResponse ) obj;
+
+        if ( ldapResult != null && resp.getLdapResult() == null )
+        {
+            return false;
+        }
+
+        if ( ldapResult == null && resp.getLdapResult() != null )
+        {
+            return false;
+        }
+
+        return ( ( ldapResult == null ) || ( resp.getLdapResult() == null ) || ldapResult.equals( resp.getLdapResult() ) );
+    }
+
+
+    /**
+     * Get a String representation of an Response
+     * 
+     * @return An Response String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( ldapResult );
+
+        if ( ( controls != null ) && ( controls.size() != 0 ) )
+        {
+            for ( Control control : controls.values() )
+            {
+                sb.append( control );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddRequest.java
new file mode 100644
index 0000000..881a764
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddRequest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Add protocol operation request used to add a new entry to the DIT.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface AddRequest extends SingleReplyRequest, AbandonableRequest
+{
+    /**
+     * Gets the distinguished name of the entry to add.
+     * 
+     * @return the Dn of the added entry.
+     */
+    Dn getEntryDn();
+
+
+    /**
+     * Sets the distinguished name of the entry to add.
+     * 
+     * @param entry the Dn of the added entry.
+     * @return The AddRequest instance
+     */
+    AddRequest setEntryDn( Dn entry );
+
+
+    /**
+     * Gets the entry to add.
+     * 
+     * @return the added Entry
+     */
+    Entry getEntry();
+
+
+    /**
+     * Sets the Entry to add.
+     * 
+     * @param entry the added Entry
+     * @return The AddRequest instance
+     */
+    AddRequest setEntry( Entry entry );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    AddRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    AddRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    AddRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    AddRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddRequestImpl.java
new file mode 100644
index 0000000..26a6d6d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddRequestImpl.java
@@ -0,0 +1,322 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Lockable add request implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddRequestImpl extends AbstractAbandonableRequest implements AddRequest
+{
+    static final long serialVersionUID = 7534132448349520346L;
+
+    /** A MultiMap of the new entry's attributes and their values */
+    private Entry entry;
+
+    private AddResponse response;
+
+    /** The current attribute being decoded */
+    private Attribute currentAttribute;
+
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+
+    /**
+     * Creates an AddRequest implementation to create a new entry.
+     */
+    public AddRequestImpl()
+    {
+        super( -1, MessageTypeEnum.ADD_REQUEST );
+        entry = new DefaultEntry();
+    }
+
+
+    /**
+     * Create a new attributeValue
+     * 
+     * @param type The attribute's name (called 'type' in the grammar)
+     */
+    public void addAttributeType( String type ) throws LdapException
+    {
+        // do not create a new attribute if we have seen this attributeType before
+        if ( entry.get( type ) != null )
+        {
+            currentAttribute = entry.get( type );
+            return;
+        }
+
+        // fix this to use AttributeImpl(type.getString().toLowerCase())
+        currentAttribute = new DefaultAttribute( type );
+        entry.put( currentAttribute );
+    }
+
+
+    /**
+     * @return Returns the currentAttribute type.
+     */
+    public String getCurrentAttributeType()
+    {
+        return currentAttribute.getId();
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( String value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( Value<?> value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    /**
+     * Add a new value to the current attribute
+     * 
+     * @param value The value to add
+     */
+    public void addAttributeValue( byte[] value ) throws LdapException
+    {
+        currentAttribute.add( value );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // AddRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the distinguished name of the entry to add.
+     * 
+     * @return the Dn of the added entry.
+     */
+    public Dn getEntryDn()
+    {
+        return entry.getDn();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setEntryDn( Dn dn )
+    {
+        entry.setDn( dn );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry getEntry()
+    {
+        return entry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setEntry( Entry entry )
+    {
+        this.entry = entry;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest addControl( Control control )
+    {
+        return ( AddRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest addAllControls( Control[] controls )
+    {
+        return ( AddRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AddRequest removeControl( Control control )
+    {
+        return ( AddRequest ) super.removeControl( control );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SingleReplyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.ADD_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public AddResponse getResultResponse()
+    {
+        if ( response == null )
+        {
+            response = new AddResponseImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * Checks to see if an object is equivalent to this AddRequest. First
+     * there's a quick test to see if the obj is the same object as this one -
+     * if so true is returned. Next if the super method fails false is returned.
+     * Then the name of the entry is compared - if not the same false is
+     * returned. Lastly the attributes of the entry are compared. If they are
+     * not the same false is returned otherwise the method exists returning
+     * true.
+     * 
+     * @param obj the object to test for equality to this
+     * @return true if the obj is equal to this AddRequest, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        // Short circuit
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        // Check the object class. If null, it will exit.
+        if ( !( obj instanceof AddRequest ) )
+        {
+            return false;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        AddRequest req = ( AddRequest ) obj;
+
+        // Check the entry
+        if ( entry == null )
+        {
+            return ( req.getEntry() == null );
+        }
+        else
+        {
+            return ( entry.equals( req.getEntry() ) );
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + ( entry == null ? 0 : entry.hashCode() );
+        hash = hash * 17 + ( response == null ? 0 : response.hashCode() );
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Add Request :\n" );
+
+        if ( entry == null )
+        {
+            sb.append( "            No entry\n" );
+        }
+        else
+        {
+            sb.append( entry.toString() );
+        }
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddResponse.java
new file mode 100644
index 0000000..6dba723
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddResponse.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Add protocol response message used to confirm the results of a add request
+ * message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface AddResponse extends ResultResponse
+{
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddResponseImpl.java
new file mode 100644
index 0000000..e0798fc
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AddResponseImpl.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * AddResponse implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AddResponseImpl extends AbstractResultResponse implements AddResponse
+{
+    static final long serialVersionUID = 4027132942339551383L;
+
+
+    /**
+     * Creates an AddResponse as a reply to an AddRequest.
+     */
+    public AddResponseImpl()
+    {
+        super( -1, MessageTypeEnum.ADD_RESPONSE );
+    }
+
+
+    /**
+     * Creates an AddResponse as a reply to an AddRequest.
+     * 
+     * @param id the session unique message id
+     */
+    public AddResponseImpl( final int id )
+    {
+        super( id, MessageTypeEnum.ADD_RESPONSE );
+    }
+
+
+    /**
+     * Get a String representation of an AddResponse
+     * 
+     * @return An AddResponse String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Add Response\n" );
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AliasDerefMode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AliasDerefMode.java
new file mode 100644
index 0000000..1238042
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/AliasDerefMode.java
@@ -0,0 +1,270 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Map;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.JndiPropertyConstants;
+
+
+/**
+ * Type-safe derefAliases search parameter enumeration which determines the mode
+ * of alias handling. Note that the jndi values of these ValuedEnums correspond
+ * to the string value for the java.naming.ldap.derefAliases JNDI LDAP specific
+ * property.  The integer value represents the values used in the LDAP ASN.1 for
+ * different settings.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum AliasDerefMode
+{
+    /** Alias handling mode value that treats aliases like entries */
+    NEVER_DEREF_ALIASES(0, "never"),
+
+    /** Alias handling mode value that dereferences only when searching */
+    DEREF_IN_SEARCHING(1, "searching"),
+
+    /** Alias handling mode value that dereferences only in finding the base */
+    DEREF_FINDING_BASE_OBJ(2, "finding"),
+
+    /** Alias handling mode value that dereferences always */
+    DEREF_ALWAYS(3, "always");
+
+    /** Stores the integer value of each element of the enumeration */
+    private int value;
+    /** Stores the integer value of each element of the enumeration */
+    private String jndiValue;
+
+
+    /**
+     * Private constructor so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param value the integer value of the enumeration.
+     */
+    private AliasDerefMode( int value, String jndiValue )
+    {
+        this.value = value;
+        this.jndiValue = jndiValue;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Gets the enumeration from by extracting the value for the JNDI LDAP
+     * specific environment property, java.naming.ldap.derefAliases, from the
+     * environment.
+     * 
+     * @param env
+     *            the JNDI environment with a potential value for the
+     *            java.naming.ldap.derefAliases property
+     * @return the enumeration for the environment
+     */
+    public static AliasDerefMode getEnum( Map<String, Object> env )
+    {
+        String property = ( String ) env.get( JndiPropertyConstants.JNDI_LDAP_DAP_DEREF_ALIASES );
+
+        if ( null == property )
+        {
+            return DEREF_ALWAYS;
+        }
+        else
+        {
+            if ( property.trim().equalsIgnoreCase( "always" ) )
+            {
+                return DEREF_ALWAYS;
+            }
+            else if ( property.trim().equalsIgnoreCase( "never" ) )
+            {
+                return NEVER_DEREF_ALIASES;
+            }
+            else if ( property.trim().equalsIgnoreCase( "finding" ) )
+            {
+                return DEREF_FINDING_BASE_OBJ;
+            }
+            else if ( property.trim().equalsIgnoreCase( "searching" ) )
+            {
+                return DEREF_IN_SEARCHING;
+            }
+            else
+            {
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04186, property,
+                    JndiPropertyConstants.JNDI_LDAP_DAP_DEREF_ALIASES ) );
+            }
+        }
+    }
+
+
+    /**
+     * Checks to see if we dereference while searching and finding the base.
+     * 
+     * @return true if value is DEREF_ALWAYS, false otherwise
+     */
+    public boolean isDerefAlways()
+    {
+        return this == DEREF_ALWAYS;
+    }
+
+
+    /**
+     * Checks to see if we never dereference aliases.
+     * 
+     * @return true if value is NEVER_DEREF_ALIASES, false otherwise
+     */
+    public boolean isNeverDeref()
+    {
+        return this == NEVER_DEREF_ALIASES;
+    }
+
+
+    /**
+     * Checks to see if we dereference while searching.
+     * 
+     * @return true if value is DEREF_ALWAYS_VAL, or DEREF_IN_SEARCHING, and
+     *         false otherwise.
+     */
+    public boolean isDerefInSearching()
+    {
+        switch ( this )
+        {
+            case DEREF_ALWAYS:
+                return true;
+
+            case DEREF_FINDING_BASE_OBJ:
+                return false;
+
+            case DEREF_IN_SEARCHING:
+                return true;
+
+            case NEVER_DEREF_ALIASES:
+                return false;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04187 ) );
+        }
+    }
+
+
+    /**
+     * Checks to see if we dereference while finding the base.
+     * 
+     * @return true if value is DEREF_ALWAYS, or DEREF_FINDING_BASE_OBJ, and
+     *         false otherwise.
+     */
+    public boolean isDerefFindingBase()
+    {
+        switch ( this )
+        {
+            case DEREF_ALWAYS:
+                return true;
+
+            case DEREF_FINDING_BASE_OBJ:
+                return true;
+
+            case DEREF_IN_SEARCHING:
+                return false;
+
+            case NEVER_DEREF_ALIASES:
+                return false;
+
+            default:
+                throw new IllegalArgumentException( "Class has bug: check for valid enumeration values" );
+        }
+    }
+
+
+    /**
+     * get the AliasDerefMode corresponding to the integer value passed
+     *
+     * @param val the AliasDerefMode's integer value
+     * @return the AliasDerefMode whose value is equivalent to the given integer value
+     */
+    public static AliasDerefMode getDerefMode( int val )
+    {
+        switch ( val )
+        {
+            case 0:
+                return NEVER_DEREF_ALIASES;
+
+            case 1:
+                return DEREF_IN_SEARCHING;
+
+            case 2:
+                return DEREF_FINDING_BASE_OBJ;
+
+            case 3:
+                return DEREF_ALWAYS;
+
+            default:
+                throw new IllegalArgumentException( "Unknown derefmode " + val );
+        }
+    }
+
+
+    /**
+     * get the AliasDerefMode corresponding to the string value {@link  #jndiValue} passed
+     *
+     * @param val the AliasDerefMode's string value
+     * @return the AliasDerefMode whose value is equivalent to the given string value
+     */
+    public static AliasDerefMode getDerefMode( String val )
+    {
+        if ( val != null )
+        {
+            if ( val.equals( NEVER_DEREF_ALIASES.jndiValue ) )
+            {
+                return NEVER_DEREF_ALIASES;
+            }
+
+            if ( val.equals( DEREF_IN_SEARCHING.jndiValue ) )
+            {
+                return DEREF_IN_SEARCHING;
+            }
+
+            if ( val.equals( DEREF_FINDING_BASE_OBJ.jndiValue ) )
+            {
+                return DEREF_FINDING_BASE_OBJ;
+            }
+
+            if ( val.equals( DEREF_ALWAYS.jndiValue ) )
+            {
+                return DEREF_ALWAYS;
+            }
+        }
+
+        throw new IllegalArgumentException( "Unknown derefmode " + val );
+    }
+
+
+    public String getJndiValue()
+    {
+        return jndiValue;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindRequest.java
new file mode 100644
index 0000000..933030c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindRequest.java
@@ -0,0 +1,226 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Bind protocol operation request which authenticates and begins a client
+ * session. Does not yet contain interfaces for SASL authentication mechanisms.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface BindRequest extends SingleReplyRequest, AbandonableRequest
+{
+    /**
+     * Checks to see if the authentication mechanism is simple and not SASL
+     * based.
+     * 
+     * @return true if the mechanism is simple false if it is SASL based.
+     */
+    boolean isSimple();
+
+
+    /**
+     * Checks to see if the authentication mechanism is simple and not SASL
+     * based.
+     * 
+     * @return true if the mechanism is simple false if it is SASL based.
+     */
+    boolean getSimple();
+
+
+    /**
+     * Sets the authentication mechanism to simple or to SASL based
+     * authentication.
+     * 
+     * @param isSimple true if authentication is simple, false otherwise.
+     * @return The BindRequest instance
+     */
+    BindRequest setSimple( boolean isSimple );
+
+
+    /**
+     * Gets the simple credentials associated with a simple authentication
+     * attempt or null if this request uses SASL authentication mechanisms.
+     * 
+     * @return null if the mechanism is SASL, or the credentials if it is simple.
+     */
+    byte[] getCredentials();
+
+
+    /**
+     * Sets the simple credentials associated with a simple authentication
+     * attempt. Ignored if this request uses SASL authentication mechanisms.
+     * 
+     * @param credentials the credentials if authentication is simple
+     * @return The BindRequest instance
+     */
+    BindRequest setCredentials( String credentials );
+
+
+    /**
+     * Sets the simple credentials associated with a simple authentication
+     * attempt. Ignored if this request uses SASL authentication mechanisms.
+     * 
+     * @param credentials the credentials if authentication is simple
+     * @return The BindRequest instance
+     */
+    BindRequest setCredentials( byte[] credentials );
+
+
+    /**
+     * Gets the name of the subject in this authentication
+     * request. This field may take on a null value (a zero length string) for
+     * the purposes of anonymous binds, when authentication has been performed
+     * at a lower layer, or when using SASL credentials with a mechanism that
+     * includes the name in the credentials.
+     * 
+     * @return the name of the authenticating user.
+     */
+    String getName();
+
+
+    /**
+     * Sets the  name of the subject in this authentication
+     * request. This field may take on a null value (or a zero length string)
+     * for the purposes of anonymous binds, when authentication has been
+     * performed at a lower layer, or when using SASL credentials with a
+     * mechanism that includes the name in the credentials.
+     * 
+     * @param name the name of the authenticating user - leave null for anonymous user.
+     * @return The BindRequest instance
+     */
+    BindRequest setName( String name );
+
+
+    /**
+     * Gets the DN of the subject in this authentication
+     * request. This field may take on a null value (a zero length string) for
+     * the purposes of anonymous binds, when authentication has been performed
+     * at a lower layer, or when using SASL credentials with a mechanism that
+     * includes the DN in the credentials.
+     * 
+     * @return the DN of the authenticating user.
+     */
+    Dn getDn();
+
+
+    /**
+     * Sets the DN of the subject in this authentication
+     * request. This field may take on a null value (or a zero length string)
+     * for the purposes of anonymous binds, when authentication has been
+     * performed at a lower layer, or when using SASL credentials with a
+     * mechanism that includes the DN in the credentials.
+     * 
+     * @param name the DN of the authenticating user - leave null for anonymous user.
+     * @return The BindRequest instance
+     */
+    BindRequest setDn( Dn name );
+
+
+    /**
+     * Checks to see if the Ldap v3 protocol is used. Normally this would
+     * extract a version number from the bind request sent by the client
+     * indicating the version of the protocol to be used in this protocol
+     * session. The integer is either a 2 or a 3 at the moment. We thought it
+     * was better to just check if the protocol used is 3 or not rather than use
+     * an type-safe enumeration type for a binary value. If an LDAPv4 comes out
+     * then we shall convert the return type to a type safe enumeration.
+     * 
+     * @return true if client using version 3 false if it is version 2.
+     */
+    boolean isVersion3();
+
+
+    /**
+     * Gets whether or not the Ldap v3 protocol is used. Normally this would
+     * extract a version number from the bind request sent by the client
+     * indicating the version of the protocol to be used in this protocol
+     * session. The integer is either a 2 or a 3 at the moment. We thought it
+     * was better to just check if the protocol used is 3 or not rather than use
+     * an type-safe enumeration type for a binary value. If an LDAPv4 comes out
+     * then we shall convert the return type to a type safe enumeration.
+     * 
+     * @return true if client using version 3 false if it is version 2.
+     */
+    boolean getVersion3();
+
+
+    /**
+     * Sets whether or not the LDAP v3 or v2 protocol is used. Normally this
+     * would extract a version number from the bind request sent by the client
+     * indicating the version of the protocol to be used in this protocol
+     * session. The integer is either a 2 or a 3 at the moment. We thought it
+     * was better to just check if the protocol used is 3 or not rather than use
+     * an type-safe enumeration type for a binary value. If an LDAPv4 comes out
+     * then we shall convert the return type to a type safe enumeration.
+     * 
+     * @param isVersion3 if true the client will be exhibiting version 3 bind behavior,
+     *  If false is used version 2 behavior will be exhibited.
+     * @return The BindRequest instance
+     */
+    BindRequest setVersion3( boolean isVersion3 );
+
+
+    /**
+     * Gets the SASL mechanism String associated with this BindRequest if the
+     * bind operation is using SASL.
+     * 
+     * @return the SASL mechanism or null if the bind operation is simple
+     */
+    String getSaslMechanism();
+
+
+    /**
+     * Sets the SASL mechanism String associated with this BindRequest if the
+     * bind operation is using SASL.
+     * 
+     * @param saslMechanism the SASL mechanism
+     * @return The BindRequest instance
+     */
+    BindRequest setSaslMechanism( String saslMechanism );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    BindRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    BindRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    BindRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    BindRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindRequestImpl.java
new file mode 100644
index 0000000..b819810
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindRequestImpl.java
@@ -0,0 +1,499 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Bind protocol operation request which authenticates and begins a client
+ * session. Does not yet contain interfaces for SASL authentication mechanisms.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class BindRequestImpl extends AbstractAbandonableRequest implements BindRequest
+{
+
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( BindRequestImpl.class );
+
+    /**
+     * Distinguished name identifying the name of the authenticating subject -
+     * defaults to the empty string
+     */
+    private Dn dn;
+
+    /**
+     * String identifying the name of the authenticating subject -
+     * defaults to the empty string
+     */
+    private String name;
+
+    /** The passwords, keys or tickets used to verify user identity */
+    private byte[] credentials;
+
+    /** A storage for credentials hashCode */
+    private int hCredentials;
+
+    /** The mechanism used to decode user identity */
+    private String mechanism;
+
+    /** Simple vs. SASL authentication mode flag */
+    private boolean isSimple = true;
+
+    /** Bind behavior exhibited by protocol version */
+    private boolean isVersion3 = true;
+
+    /** The associated response */
+    private BindResponse response;
+
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+    /**
+     * Creates an BindRequest implementation to bind to an LDAP server.
+     */
+    public BindRequestImpl()
+    {
+        super( -1, MessageTypeEnum.BIND_REQUEST );
+        hCredentials = 0;
+    }
+
+
+    // -----------------------------------------------------------------------
+    // BindRequest Interface Method Implementations
+    // -----------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSimple()
+    {
+        return isSimple;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getSimple()
+    {
+        return isSimple;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setSimple( boolean simple )
+    {
+        this.isSimple = simple;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getCredentials()
+    {
+        return credentials;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setCredentials( String credentials )
+    {
+        return setCredentials( Strings.getBytesUtf8( credentials ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setCredentials( byte[] credentials )
+    {
+        if ( credentials != null )
+        {
+            this.credentials = new byte[credentials.length];
+            System.arraycopy( credentials, 0, this.credentials, 0, credentials.length );
+        }
+        else
+        {
+            this.credentials = null;
+        }
+
+        // Compute the hashcode
+        if ( credentials != null )
+        {
+            hCredentials = 0;
+
+            for ( byte b : credentials )
+            {
+                hCredentials = hCredentials * 31 + b;
+            }
+        }
+        else
+        {
+            hCredentials = 0;
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSaslMechanism()
+    {
+        return mechanism;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setSaslMechanism( String saslMechanism )
+    {
+        this.isSimple = false;
+        this.mechanism = saslMechanism;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setName( String name )
+    {
+        this.name = name;
+
+        try
+        {
+            this.dn = new Dn( name );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            // This might still be a valid DN (Windows AD binding for instance)
+            LOG.debug( "Unable to convert the name to a DN." );
+            this.dn = null;
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getDn()
+    {
+        return dn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setDn( Dn dn )
+    {
+        this.dn = dn;
+        this.name = dn.getName();
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isVersion3()
+    {
+        return isVersion3;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getVersion3()
+    {
+        return isVersion3;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setVersion3( boolean version3 )
+    {
+        this.isVersion3 = version3;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest addControl( Control control )
+    {
+        return ( BindRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest addAllControls( Control[] controls )
+    {
+        return ( BindRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public BindRequest removeControl( Control control )
+    {
+        return ( BindRequest ) super.removeControl( control );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // BindRequest Interface Method Implementations
+    // -----------------------------------------------------------------------
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.BIND_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public BindResponse getResultResponse()
+    {
+        if ( response == null )
+        {
+            response = new BindResponseImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * RFC 2251/4511 [Section 4.11]: Abandon, Bind, Unbind, and StartTLS operations
+     * cannot be abandoned.
+     */
+    public void abandon()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04185 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof BindRequest ) )
+        {
+            return false;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        BindRequest req = ( BindRequest ) obj;
+
+        if ( req.isSimple() != isSimple() )
+        {
+            return false;
+        }
+
+        if ( req.isVersion3() != isVersion3() )
+        {
+            return false;
+        }
+
+        String name1 = req.getName();
+        String name2 = getName();
+
+        if ( Strings.isEmpty( name1 ) )
+        {
+            if ( !Strings.isEmpty( name2 ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( Strings.isEmpty( name2 ) )
+            {
+                return false;
+            }
+            else if ( !name2.equals( name1 ) )
+            {
+                return false;
+            }
+        }
+
+        Dn dn1 = req.getDn();
+        Dn dn2 = getDn();
+
+        if ( Dn.isNullOrEmpty( dn1 ) )
+        {
+            if ( !Dn.isNullOrEmpty( dn2 ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( Dn.isNullOrEmpty( dn2 ) )
+            {
+                return false;
+            }
+            else if ( !dn1.equals( dn2 ) )
+            {
+                return false;
+            }
+        }
+
+        return Arrays.equals( req.getCredentials(), getCredentials() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + ( credentials == null ? 0 : hCredentials );
+        hash = hash * 17 + ( isSimple ? 0 : 1 );
+        hash = hash * 17 + ( isVersion3 ? 0 : 1 );
+        hash = hash * 17 + ( mechanism == null ? 0 : mechanism.hashCode() );
+        hash = hash * 17 + ( name == null ? 0 : name.hashCode() );
+        hash = hash * 17 + ( response == null ? 0 : response.hashCode() );
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Get a String representation of a BindRequest
+     * 
+     * @return A BindRequest String
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    BindRequest\n" );
+        sb.append( "        Version : '" ).append( isVersion3 ? "3" : "2" ).append( "'\n" );
+
+        if ( ( ( Strings.isEmpty( name ) ) || ( dn == null ) || Strings.isEmpty( dn.getNormName() ) )
+            && isSimple )
+        {
+            sb.append( "        Name : anonymous\n" );
+        }
+        else
+        {
+            sb.append( "        Name : '" ).append( name ).append( "'\n" );
+
+            if ( isSimple )
+            {
+                sb.append( "        Simple authentication : '" ).append( "(omitted-for-safety)" ).append( "'\n" );
+            }
+            else
+            {
+                sb.append( "        Sasl credentials\n" );
+                sb.append( "            Mechanism :'" ).append( mechanism ).append( "'\n" );
+
+                if ( credentials == null )
+                {
+                    sb.append( "            Credentials : null" );
+                }
+                else
+                {
+                    sb.append( "            Credentials : (omitted-for-safety)" );
+                }
+            }
+        }
+
+        // The controls if any
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindResponse.java
new file mode 100644
index 0000000..3422f32
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindResponse.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Bind protocol response message used to confirm the results of a bind request
+ * message. BindResponse consists simply of an indication from the server of the
+ * status of the client's request for authentication.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface BindResponse extends ResultResponse
+{
+    /**
+     * Gets the optional property holding SASL authentication response parameters
+     * that are SASL mechanism specific. Will return null if the authentication
+     * is simple.
+     * 
+     * @return the sasl mech. specific credentials or null of auth. is simple
+     */
+    byte[] getServerSaslCreds();
+
+
+    /**
+     * Sets the optional property holding SASL authentication response paramters
+     * that are SASL mechanism specific. Leave null if authentication mode is
+     * simple.
+     * 
+     * @param serverSaslCreds the sasl auth. mech. specific credentials
+     */
+    void setServerSaslCreds( byte[] serverSaslCreds );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindResponseImpl.java
new file mode 100644
index 0000000..aefb119
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindResponseImpl.java
@@ -0,0 +1,192 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * BindResponse implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class BindResponseImpl extends AbstractResultResponse implements BindResponse
+{
+    static final long serialVersionUID = -5146809476518669755L;
+
+    /** optional property holding SASL authentication response parameters */
+    private byte[] serverSaslCreds;
+
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+    /**
+     * Creates a BindResponse as a reply to an BindRequest.
+     */
+    public BindResponseImpl()
+    {
+        super( -1, MessageTypeEnum.BIND_RESPONSE );
+    }
+
+
+    /**
+     * Creates a BindResponse as a reply to an BindRequest.
+     * 
+     * @param id the session unique message id
+     */
+    public BindResponseImpl( final int id )
+    {
+        super( id, MessageTypeEnum.BIND_RESPONSE );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // BindResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the optional property holding SASL authentication response paramters
+     * that are SASL mechanism specific. Will return null if the authentication
+     * is simple.
+     * 
+     * @return the sasl mech. specific credentials or null of auth. is simple
+     */
+    public byte[] getServerSaslCreds()
+    {
+        if ( serverSaslCreds == null )
+        {
+            return null;
+        }
+
+        final byte[] copy = new byte[serverSaslCreds.length];
+        System.arraycopy( serverSaslCreds, 0, copy, 0, serverSaslCreds.length );
+        return copy;
+    }
+
+
+    /**
+     * Sets the optional property holding SASL authentication response paramters
+     * that are SASL mechanism specific. Leave null if authentication mode is
+     * simple.
+     * 
+     * @param serverSaslCreds
+     *            the sasl auth. mech. specific credentials
+     */
+    public void setServerSaslCreds( byte[] serverSaslCreds )
+    {
+        if ( serverSaslCreds != null )
+        {
+            this.serverSaslCreds = new byte[serverSaslCreds.length];
+            System.arraycopy( serverSaslCreds, 0, this.serverSaslCreds, 0, serverSaslCreds.length );
+        }
+        else
+        {
+            this.serverSaslCreds = null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + Arrays.hashCode( serverSaslCreds );
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if this BindResponse is equal to another BindResponse. The
+     * implementation and lockable properties are not factored into the
+     * evaluation of equality. Only the messageId, saslCredentials and the
+     * LdapResults of this BindResponse PDU and the compared object are taken
+     * into account if that object also implements the BindResponse interface.
+     * 
+     * @param obj
+     *            the object to test for equality with this BindResponse
+     * @return true if obj equals this BindResponse false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        // quickly return true if obj is this one
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( ( obj == null ) || !( obj instanceof BindResponse ) )
+        {
+            return false;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        BindResponse response = ( BindResponse ) obj;
+        byte[] creds = response.getServerSaslCreds();
+
+        if ( serverSaslCreds == null )
+        {
+            if ( creds != null )
+            {
+                return false;
+            }
+        }
+        else if ( creds == null )
+        {
+            return false;
+        }
+
+        return Arrays.equals( serverSaslCreds, creds );
+    }
+
+
+    /**
+     * Get a String representation of a BindResponse
+     * 
+     * @return A BindResponse String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    BindResponse\n" );
+        sb.append( super.toString() );
+
+        if ( serverSaslCreds != null )
+        {
+            sb.append( "        Server sasl credentials : '" ).append( Strings.dumpBytes( serverSaslCreds ) )
+                .append( "'\n" );
+        }
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindStatus.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindStatus.java
new file mode 100644
index 0000000..7ee04a6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/BindStatus.java
@@ -0,0 +1,51 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * An enum used to store the BindRequest state.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum BindStatus
+{
+    /** 
+     * We are in Anonymous state. The user specifically required to
+     * be anonymous
+     **/
+    ANONYMOUS,
+
+    /**
+     * We have received a Simple BindRequest
+     */
+    SIMPLE_AUTH_PENDING,
+
+    /**
+     * We have received a SASL BindRequest
+     */
+    SASL_AUTH_PENDING,
+
+    /**
+     * The user has been authenticated
+     */
+    AUTHENTICATED
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareRequest.java
new file mode 100644
index 0000000..64e2048
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareRequest.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Compare request protocol message that tests an entry to see if it abides by
+ * an attribute value assertion.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CompareRequest extends SingleReplyRequest, AbandonableRequest
+{
+    /**
+     * Gets the distinguished name of the entry to be compared using the
+     * attribute value assertion.
+     * 
+     * @return the Dn of the compared entry.
+     */
+    Dn getName();
+
+
+    /**
+     * Sets the distinguished name of the entry to be compared using the
+     * attribute value assertion.
+     * 
+     * @param name the Dn of the compared entry.
+     * @return The CompareRequest instance
+     */
+    CompareRequest setName( Dn name );
+
+
+    /**
+     * Gets the attribute value to use in making the comparison.
+     * 
+     * @return the attribute value to used in comparison.
+     */
+    Value<?> getAssertionValue();
+
+
+    /**
+     * Sets the attribute value to use in the comparison.
+     * 
+     * @param value the attribute value used in comparison.
+     * @return The CompareRequest instance
+     */
+    CompareRequest setAssertionValue( String value );
+
+
+    /**
+     * Sets the attribute value to use in the comparison.
+     * 
+     * @param value the attribute value used in comparison.
+     * @return The CompareRequest instance
+     */
+    CompareRequest setAssertionValue( byte[] value );
+
+
+    /**
+     * Gets the attribute id use in making the comparison.
+     * 
+     * @return the attribute id used in comparison.
+     */
+    String getAttributeId();
+
+
+    /**
+     * Sets the attribute id used in the comparison.
+     * 
+     * @param attrId the attribute id used in comparison.
+     * @return The CompareRequest instance
+     */
+    CompareRequest setAttributeId( String attrId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    CompareRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    CompareRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    CompareRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    CompareRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareRequestImpl.java
new file mode 100644
index 0000000..0681cb2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareRequestImpl.java
@@ -0,0 +1,357 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Comparison request implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CompareRequestImpl extends AbstractAbandonableRequest implements CompareRequest
+{
+    static final long serialVersionUID = 1699731530016468977L;
+
+    /** Distinguished name identifying the compared entry */
+    private Dn name;
+
+    /** The id of the attribute used in the comparison */
+    private String attrId;
+
+    /** The value of the attribute used in the comparison */
+    private Value<?> attrVal;
+
+    /** The associated response */
+    private CompareResponse response;
+
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+    /**
+     * Creates an CompareRequest implementation to compare a named entry with an
+     * attribute value assertion pair.
+     */
+    public CompareRequestImpl()
+    {
+        super( -1, MessageTypeEnum.COMPARE_REQUEST );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ComparisonRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the distinguished name of the entry to be compared using the
+     * attribute value assertion.
+     * 
+     * @return the Dn of the compared entry.
+     */
+    public Dn getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setName( Dn name )
+    {
+        this.name = name;
+
+        return this;
+    }
+
+
+    /**
+     * Gets the attribute value to use in making the comparison.
+     * 
+     * @return the attribute value to used in comparison.
+     */
+    public Value<?> getAssertionValue()
+    {
+        return attrVal;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAssertionValue( String value )
+    {
+        this.attrVal = new StringValue( value );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAssertionValue( byte[] value )
+    {
+        if ( value != null )
+        {
+            this.attrVal = new BinaryValue( value );
+        }
+        else
+        {
+            this.attrVal = null;
+        }
+
+        return this;
+    }
+
+
+    /**
+     * Gets the attribute id use in making the comparison.
+     * 
+     * @return the attribute id used in comparison.
+     */
+    public String getAttributeId()
+    {
+        return attrId;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setAttributeId( String attributeId )
+    {
+        this.attrId = attributeId;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest addControl( Control control )
+    {
+        return ( CompareRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest addAllControls( Control[] controls )
+    {
+        return ( CompareRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CompareRequest removeControl( Control control )
+    {
+        return ( CompareRequest ) super.removeControl( control );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SingleReplyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.COMPARE_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public CompareResponse getResultResponse()
+    {
+        if ( response == null )
+        {
+            response = new CompareResponseImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( name != null )
+        {
+            hash = hash * 17 + name.hashCode();
+        }
+        if ( attrId != null )
+        {
+            hash = hash * 17 + attrId.hashCode();
+        }
+        if ( attrVal != null )
+        {
+            hash = hash * 17 + attrVal.hashCode();
+        }
+        Value<?> reqVal = getAssertionValue();
+        if ( reqVal != null )
+        {
+            hash = hash * 17 + reqVal.hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object is equivalent to this CompareRequest.
+     * 
+     * @param obj the obj to compare with this CompareRequest
+     * @return true if the obj is equal to this request, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        CompareRequest req = ( CompareRequest ) obj;
+        Dn reqName = req.getName();
+
+        if ( ( name != null ) && ( reqName == null ) )
+        {
+            return false;
+        }
+
+        if ( ( name == null ) && ( reqName != null ) )
+        {
+            return false;
+        }
+
+        if ( ( name != null ) && ( reqName != null ) && !name.equals( req.getName() ) )
+        {
+            return false;
+        }
+
+        String reqId = req.getAttributeId();
+
+        if ( ( attrId != null ) && ( reqId == null ) )
+        {
+            return false;
+        }
+
+        if ( ( attrId == null ) && ( reqId != null ) )
+        {
+            return false;
+        }
+
+        if ( ( attrId != null ) && ( reqId != null ) && !attrId.equals( reqId ) )
+        {
+            return false;
+        }
+
+        Value<?> reqVal = req.getAssertionValue();
+
+        if ( attrVal != null )
+        {
+            if ( reqVal != null )
+            {
+                return attrVal.equals( reqVal );
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return reqVal == null;
+        }
+    }
+
+
+    /**
+     * Get a String representation of a Compare Request
+     * 
+     * @return A Compare Request String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Compare request\n" );
+        sb.append( "        Entry : '" ).append( name.toString() ).append( "'\n" );
+        sb.append( "        Attribute description : '" ).append( attrId ).append( "'\n" );
+        sb.append( "        Attribute value : '" );
+
+        if ( attrVal.isHumanReadable() )
+        {
+            sb.append( attrVal.getValue() );
+        }
+        else
+        {
+            byte[] binVal = attrVal.getBytes();
+            sb.append( Strings.utf8ToString( binVal ) ).append( '/' ).append( Strings.dumpBytes( binVal ) )
+                .append( "'\n" );
+        }
+
+        // The controls
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareResponse.java
new file mode 100644
index 0000000..24fbfd7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareResponse.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Compare protocol response message used to confirm the results of a compare
+ * request message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CompareResponse extends ResultResponse
+{
+    /**
+     * @return True if the compared response is a success
+     * @return
+     */
+    boolean isTrue();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareResponseImpl.java
new file mode 100644
index 0000000..1b325f1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/CompareResponseImpl.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * CompareResponse implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class CompareResponseImpl extends AbstractResultResponse implements CompareResponse
+{
+    static final long serialVersionUID = 6452521899386487731L;
+
+
+    /**
+     * Creates a CompareResponse as a reply to an CompareRequest.
+     */
+    public CompareResponseImpl()
+    {
+        super( -1, MessageTypeEnum.COMPARE_RESPONSE );
+    }
+
+
+    /**
+     * Creates a CompareResponse as a reply to an CompareRequest.
+     * 
+     * @param id the session unique message id
+     */
+    public CompareResponseImpl( final int id )
+    {
+        super( id, MessageTypeEnum.COMPARE_RESPONSE );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isTrue()
+    {
+        return ldapResult.getResultCode() == ResultCodeEnum.COMPARE_TRUE;
+    }
+
+
+    /**
+     * Get a String representation of an CompareResponse
+     * 
+     * @return An CompareResponse String
+     */
+    public String toString()
+    {
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Compare Response\n" );
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Control.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Control.java
new file mode 100644
index 0000000..2433f45
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Control.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Protocol request and response altering control interface. Any number of
+ * controls may be associated with a protocol message. Each control may be
+ * associated with a Request, a response, or both.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Control
+{
+    /**
+     * @return The Control's OID
+     */
+    String getOid();
+
+
+    /**
+     * Tells if the control is critical or not.
+     *
+     * @return <code>true</code> if the control is critical, <code>false</code> otherwise 
+     */
+    boolean isCritical();
+
+
+    /**
+     * Sets the critical flag which determines whether or not this control is
+     * critical for the correct operation of a request or response message. The
+     * default for this value should be false.
+     * 
+     * @param isCritical true if the control is critical false otherwise.
+     */
+    void setCritical( boolean isCritical );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteRequest.java
new file mode 100644
index 0000000..d60ee1f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteRequest.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Delete request protocol message used to remove an existing leaf entry from
+ * the directory.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface DeleteRequest extends SingleReplyRequest, AbandonableRequest
+{
+    /**
+     * Gets the distinguished name of the leaf entry to be deleted by this
+     * request.
+     * 
+     * @return the Dn of the leaf entry to delete.
+     */
+    Dn getName();
+
+
+    /**
+     * Sets the distinguished name of the leaf entry to be deleted by this
+     * request.
+     * 
+     * @param name the Dn of the leaf entry to delete.
+     * @return The DeleteRequest instance
+     */
+    DeleteRequest setName( Dn name );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    DeleteRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    DeleteRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    DeleteRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    DeleteRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteRequestImpl.java
new file mode 100644
index 0000000..4783655
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteRequestImpl.java
@@ -0,0 +1,230 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Delete request implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DeleteRequestImpl extends AbstractAbandonableRequest implements DeleteRequest
+{
+    static final long serialVersionUID = 3187847454305567542L;
+
+    /** The distinguished name of the entry to delete */
+    private Dn name;
+
+    /** The deleteResponse associated with this request */
+    private DeleteResponse response;
+
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+    /**
+     * Creates a DeleteRequest implementing object used to delete a
+     * leaf entry from the DIT.
+     */
+    public DeleteRequestImpl()
+    {
+        super( -1, MessageTypeEnum.DEL_REQUEST );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // DeleteRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the distinguished name of the leaf entry to be deleted by this
+     * request.
+     * 
+     * @return the Dn of the leaf entry to delete.
+     */
+    public Dn getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest setName( Dn name )
+    {
+        this.name = name;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest addControl( Control control )
+    {
+        return ( DeleteRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest addAllControls( Control[] controls )
+    {
+        return ( DeleteRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DeleteRequest removeControl( Control control )
+    {
+        return ( DeleteRequest ) super.removeControl( control );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SingleReplyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.DEL_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public DeleteResponse getResultResponse()
+    {
+        if ( response == null )
+        {
+            response = new DeleteResponseImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+
+        if ( name != null )
+        {
+            hash = hash * 17 + name.hashCode();
+        }
+
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object is equivalent to this DeleteRequest. First
+     * there's a quick test to see if the obj is the same object as this one -
+     * if so true is returned. Next if the super method fails false is returned.
+     * Then the name of the entry is compared - if not the same false is
+     * returned. Finally the method exists returning true.
+     * 
+     * @param obj the object to test for equality to this
+     * @return true if the obj is equal to this DeleteRequest, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        DeleteRequest req = ( DeleteRequest ) obj;
+
+        if ( name != null && req.getName() == null )
+        {
+            return false;
+        }
+
+        if ( name == null && req.getName() != null )
+        {
+            return false;
+        }
+
+        if ( ( name != null ) && ( req.getName() != null ) && !name.equals( req.getName() ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Return a String representing a DelRequest
+     * 
+     * @return A DelRequest String
+     */
+    public String toString()
+    {
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Del request\n" );
+        sb.append( "        Entry : '" ).append( name.toString() ).append( "'\n" );
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteResponse.java
new file mode 100644
index 0000000..ad11b06
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteResponse.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Delete protocol response message used to confirm the results of a delete
+ * request message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface DeleteResponse extends ResultResponse
+{
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteResponseImpl.java
new file mode 100644
index 0000000..6b25c51
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/DeleteResponseImpl.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * DeleteResponse implementation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class DeleteResponseImpl extends AbstractResultResponse implements DeleteResponse
+{
+    static final long serialVersionUID = -6830004960050713586L;
+
+
+    /**
+     * Creates a DeleteResponse as a reply to an DeleteRequest.
+     */
+    public DeleteResponseImpl()
+    {
+        super( -1, MessageTypeEnum.DEL_RESPONSE );
+    }
+
+
+    /**
+     * Creates a DeleteResponse as a reply to an DeleteRequest.
+     * 
+     * @param id the session unique message id
+     */
+    public DeleteResponseImpl( final int id )
+    {
+        super( id, MessageTypeEnum.DEL_RESPONSE );
+    }
+
+
+    /**
+     * Get a String representation of a DelResponse
+     * 
+     * @return A DelResponse String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Delete Response\n" );
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedRequest.java
new file mode 100644
index 0000000..dbb100a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedRequest.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Extended protocol request message used to add to more operations to the
+ * protocol. Here's what <a href="http://www.faqs.org/rfcs/rfc2251.html"> RFC
+ * 2251</a> says about it:
+ * 
+ * <pre>
+ *  4.12. Extended Operation
+ * 
+ *   An extension mechanism has been added in this version of LDAP, in
+ *   order to allow additional operations to be defined for services not
+ *   available elsewhere in this protocol, for instance digitally signed
+ *   operations and results.
+ * 
+ *   The extended operation allows clients to make requests and receive
+ *   responses with predefined syntaxes and semantics.  These may be
+ *   defined in RFCs or be private to particular implementations.  Each
+ *   request MUST have a unique OBJECT IDENTIFIER assigned to it.
+ * 
+ *        ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
+ *                requestName      [0] LDAPOID,
+ *                requestValue     [1] OCTET STRING OPTIONAL }
+ * 
+ *   The requestName is a dotted-decimal representation of the OBJECT
+ *   IDENTIFIER corresponding to the request. The requestValue is
+ *   information in a form defined by that request, encapsulated inside an
+ *   OCTET STRING.
+ * </pre>
+ * <br>
+ *  
+ *  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * 
+ */
+public interface ExtendedRequest extends SingleReplyRequest
+{
+    /**
+     * Gets the Object Identifier corresponding to the extended request type.
+     * This is the <b>requestName</b> portion of the ExtendedRequst PDU.
+     * 
+     * @return the dotted-decimal representation as a String of the OID
+     */
+    String getRequestName();
+
+
+    /**
+     * Sets the Object Identifier corresponding to the extended request type.
+     * 
+     * @param oid the dotted-decimal representation as a String of the OID
+     * @return The ExtendedRequest instance
+     */
+    ExtendedRequest setRequestName( String oid );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ExtendedRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ExtendedRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ExtendedRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ExtendedRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedRequestImpl.java
new file mode 100644
index 0000000..f84fd85
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedRequestImpl.java
@@ -0,0 +1,235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * ExtendedRequest implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtendedRequestImpl extends AbstractRequest implements ExtendedRequest
+{
+    static final long serialVersionUID = 7916990159044177480L;
+
+    /** Extended request's Object Identifier or <b>requestName</b> */
+    private String oid;
+
+    /** The associated response */
+    protected ExtendedResponseImpl response;
+
+
+    /**
+     * Creates an ExtendedRequest implementing object used to perform
+     * extended protocol operation on the server.
+     */
+    public ExtendedRequestImpl()
+    {
+        super( -1, MessageTypeEnum.EXTENDED_REQUEST, true );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // ExtendedRequest Interface Method Implementations
+    // -----------------------------------------------------------------------
+
+    /**
+     * Gets the Object Identifier corresponding to the extended request type.
+     * This is the <b>requestName</b> portion of the ext. req. PDU.
+     * 
+     * @return the dotted-decimal representation as a String of the OID
+     */
+    public String getRequestName()
+    {
+        return oid;
+    }
+
+
+    /**
+     * Sets the Object Identifier corresponding to the extended request type.
+     * 
+     * @param newOid the dotted-decimal representation as a String of the OID
+     */
+    public ExtendedRequest setRequestName( String newOid )
+    {
+        this.oid = newOid;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addControl( Control control )
+    {
+        return ( ExtendedRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest addAllControls( Control[] controls )
+    {
+        return ( ExtendedRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequest removeControl( Control control )
+    {
+        return ( ExtendedRequest ) super.removeControl( control );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SingleReplyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.EXTENDED_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public ExtendedResponse getExtendedResponse()
+    {
+        if ( response == null )
+        {
+            response = new ExtendedResponseImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse getResultResponse()
+    {
+        return getExtendedResponse();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( oid != null )
+        {
+            hash = hash * 17 + oid.hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object equals this ExtendedRequest.
+     * 
+     * @param obj the object to be checked for equality
+     * @return true if the obj equals this ExtendedRequest, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        if ( !( obj instanceof ExtendedRequest ) )
+        {
+            return false;
+        }
+
+        ExtendedRequest req = ( ExtendedRequest ) obj;
+
+        if ( ( oid != null ) && ( req.getRequestName() == null ) )
+        {
+            return false;
+        }
+
+        if ( ( oid == null ) && ( req.getRequestName() != null ) )
+        {
+            return false;
+        }
+
+        if ( ( oid != null ) && ( req.getRequestName() != null ) && !oid.equals( req.getRequestName() ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Get a String representation of an Extended Request
+     * 
+     * @return an Extended Request String
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Extended request\n" );
+        sb.append( "        Request name : '" ).append( oid ).append( "'\n" );
+
+        // The controls
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedResponse.java
new file mode 100644
index 0000000..a940c38
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedResponse.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Extended protocol response message used to confirm the results of a extended
+ * request message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ExtendedResponse extends ResultResponse
+{
+    /** Extended response message type enumeration value */
+    MessageTypeEnum TYPE = MessageTypeEnum.EXTENDED_RESPONSE;
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    String getResponseName();
+
+
+    /**
+     * Sets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @param oidv the OID of the extended response type.
+     */
+    void setResponseName( String oid );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedResponseImpl.java
new file mode 100644
index 0000000..761fa34
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ExtendedResponseImpl.java
@@ -0,0 +1,185 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * A simple ExtendedResponse implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExtendedResponseImpl extends AbstractResultResponse implements ExtendedResponse
+{
+    static final long serialVersionUID = -6646752766410531060L;
+
+    /** Object identifier for the extended response */
+    protected String responseName;
+
+
+    /**
+     * Creates an ExtendedResponse as a reply to an ExtendedRequest.
+     * 
+     * @param responseName the ExtendedResponse's name
+     */
+    public ExtendedResponseImpl( String responseName )
+    {
+        super( -1, TYPE );
+        this.responseName = responseName;
+    }
+
+
+    /**
+     * Creates an ExtendedResponse as a reply to an ExtendedRequest.
+     * 
+     * @param id the session unique message id
+     * @param responseName the ExtendedResponse's name
+     */
+    public ExtendedResponseImpl( final int id, String responseName )
+    {
+        super( id, TYPE );
+        this.responseName = responseName;
+    }
+
+
+    /**
+     * Creates an ExtendedResponse as a reply to an ExtendedRequest.
+     * 
+     * @param id the session unique message id
+     */
+    public ExtendedResponseImpl( int id )
+    {
+        super( id, TYPE );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the responseName of the extended response
+     */
+    public String getResponseName()
+    {
+        return ( ( responseName == null ) ? "" : responseName );
+    }
+
+
+    /**
+     * Sets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @param responseName the OID of the extended response type.
+     */
+    public void setResponseName( String responseName )
+    {
+        this.responseName = responseName;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+
+        if ( responseName != null )
+        {
+            hash = hash * 17 + responseName.hashCode();
+        }
+
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object equals this ExtendedRequest.
+     * 
+     * @param obj
+     *            the object to be checked for equality
+     * @return true if the obj equals this ExtendedRequest, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        if ( !( obj instanceof ExtendedResponse ) )
+        {
+            return false;
+        }
+
+        ExtendedResponse resp = ( ExtendedResponse ) obj;
+
+        if ( ( responseName != null ) && ( resp.getResponseName() == null ) )
+        {
+            return false;
+        }
+
+        if ( ( responseName == null ) && ( resp.getResponseName() != null ) )
+        {
+            return false;
+        }
+
+        if ( ( responseName != null ) && ( resp.getResponseName() != null )
+            && !responseName.equals( resp.getResponseName() ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Get a String representation of an ExtendedResponse
+     * 
+     * @return An ExtendedResponse String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Extended Response\n" );
+
+        if ( responseName != null )
+        {
+            sb.append( "        ResponseName :'" ).append( responseName ).append( "'\n" );
+        }
+
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/IntermediateResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/IntermediateResponse.java
new file mode 100644
index 0000000..617f3eb
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/IntermediateResponse.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Intermediate response message used to return multiple response
+ * messages for a single search request (ExtendedRequest or Control).
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface IntermediateResponse extends Response
+{
+    /** Intermediate response message type enumeration value */
+    MessageTypeEnum TYPE = MessageTypeEnum.INTERMEDIATE_RESPONSE;
+
+
+    /**
+     * Gets the response name
+     * 
+     * @return the ResponseName OID
+     */
+    String getResponseName();
+
+
+    /**
+     * Sets the response name.
+     * 
+     * @param oid the ResponseName
+     */
+    void setResponseName( String oid );
+
+
+    /**
+     * Gets the ResponseValue.
+     * 
+     * @return the responseValue
+     */
+    byte[] getResponseValue();
+
+
+    /**
+     * Sets the respponseValue
+     * 
+     * @param value The responseValue
+     */
+    void setResponseValue( byte[] value );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/IntermediateResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/IntermediateResponseImpl.java
new file mode 100644
index 0000000..7b93f62
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/IntermediateResponseImpl.java
@@ -0,0 +1,219 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Arrays;
+
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * IntermediateResponse implementation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class IntermediateResponseImpl extends AbstractResultResponse implements IntermediateResponse
+{
+    static final long serialVersionUID = -6646752766410531060L;
+
+    /** ResponseName for the intermediate response */
+    protected String responseName;
+
+    /** Response Value for the intermediate response */
+    protected byte[] responseValue;
+
+
+    public IntermediateResponseImpl( int id )
+    {
+        super( id, TYPE );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // IntermediateResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the reponseName specific encoded
+     * 
+     * @return the response value
+     */
+    public byte[] getResponseValue()
+    {
+        if ( responseValue == null )
+        {
+            return null;
+        }
+
+        final byte[] copy = new byte[responseValue.length];
+        System.arraycopy( responseValue, 0, copy, 0, responseValue.length );
+        return copy;
+    }
+
+
+    /**
+     * Sets the response value
+     * 
+     * @param value the response value.
+     */
+    public void setResponseValue( byte[] value )
+    {
+        if ( value != null )
+        {
+            this.responseValue = new byte[value.length];
+            System.arraycopy( value, 0, this.responseValue, 0, value.length );
+        }
+        else
+        {
+            this.responseValue = null;
+        }
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this Intermediate response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the Intermediate response type.
+     */
+    public String getResponseName()
+    {
+        return ( ( responseName == null ) ? "" : responseName );
+    }
+
+
+    /**
+     * Sets the OID uniquely identifying this Intermediate response (a.k.a. its
+     * name).
+     * 
+     * @param oid the OID of the Intermediate response type.
+     */
+    public void setResponseName( String oid )
+    {
+        this.responseName = oid;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( responseName != null )
+        {
+            hash = hash * 17 + responseName.hashCode();
+        }
+        if ( responseValue != null )
+        {
+            hash = hash * 17 + Arrays.hashCode( responseValue );
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object equals this IntemediateResponse.
+     * 
+     * @param obj the object to be checked for equality
+     * @return true if the obj equals this IntemediateResponse, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        if ( !( obj instanceof IntermediateResponse ) )
+        {
+            return false;
+        }
+
+        IntermediateResponse resp = ( IntermediateResponse ) obj;
+
+        if ( ( responseName != null ) && ( resp.getResponseName() == null ) )
+        {
+            return false;
+        }
+
+        if ( ( responseName == null ) && ( resp.getResponseName() != null ) )
+        {
+            return false;
+        }
+
+        if ( ( responseName != null ) && ( resp.getResponseName() != null )
+            && !responseName.equals( resp.getResponseName() ) )
+        {
+            return false;
+        }
+
+        if ( ( responseValue != null ) && ( resp.getResponseValue() == null ) )
+        {
+            return false;
+        }
+
+        if ( ( responseValue == null ) && ( resp.getResponseValue() != null ) )
+        {
+            return false;
+        }
+
+        return ( ( responseValue == null ) || ( resp.getResponseValue() == null )
+        || Arrays.equals( responseValue, resp.getResponseValue() ) );
+    }
+
+
+    /**
+     * Get a String representation of an IntermediateResponse
+     * 
+     * @return An IntermediateResponse String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Intermediate Response\n" );
+
+        if ( responseName != null )
+        {
+            sb.append( "        Response name :'" ).append( responseName ).append( "'\n" );
+        }
+
+        if ( responseValue != null )
+        {
+            sb.append( "        ResponseValue :'" );
+            sb.append( Strings.dumpBytes( responseValue ) );
+            sb.append( "'\n" );
+        }
+
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/LdapResult.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/LdapResult.java
new file mode 100644
index 0000000..935773a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/LdapResult.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * LDAPv3 result structure embedded into Responses. See section 4.1.9 in <a
+ * href="http://www.ietf.org/rfc/rfc4511.txt">RFC 4511</a> for a description of 
+ * the LDAPResult ASN.1 structure, here's a snippet from it:
+ * 
+ * <pre>
+ *   The LDAPResult is the construct used in this protocol to return
+ *   success or failure indications from servers to clients. To various
+ *  requests, servers will return responses containing the elements found
+ *  in LDAPResult to indicate the final status of the protocol operation
+ *  request.
+
+ * LDAPResult ::= SEQUENCE {
+ *     resultCode         ENUMERATED {
+ *         success                      (0),
+ *         operationsError              (1),
+ *         protocolError                (2),
+ *         timeLimitExceeded            (3),
+ *         sizeLimitExceeded            (4),
+ *         compareFalse                 (5),
+ *         compareTrue                  (6),
+ *         authMethodNotSupported       (7),
+ *         strongerAuthRequired         (8),
+ *              -- 9 reserved --
+ *         referral                     (10),
+ *         adminLimitExceeded           (11),
+ *         unavailableCriticalExtension (12),
+ *         confidentialityRequired      (13),
+ *         saslBindInProgress           (14),
+ *         noSuchAttribute              (16),
+ *         undefinedAttributeType       (17),
+ *         inappropriateMatching        (18),
+ *         constraintViolation          (19),
+ *         attributeOrValueExists       (20),
+ *         invalidAttributeSyntax       (21),
+ *              -- 22-31 unused --
+ *         noSuchObject                 (32),
+ *         aliasProblem                 (33),
+ *         invalidDNSyntax              (34),
+ *              -- 35 reserved for undefined isLeaf --
+ *         aliasDereferencingProblem    (36),
+ *              -- 37-47 unused --
+ *         inappropriateAuthentication  (48),
+ *         invalidCredentials           (49),
+ *         insufficientAccessRights     (50),
+ *         busy                         (51),
+ *         unavailable                  (52),
+ *         unwillingToPerform           (53),
+ *         loopDetect                   (54),
+ *              -- 55-63 unused --
+ *         namingViolation              (64),
+ *         objectClassViolation         (65),
+ *         notAllowedOnNonLeaf          (66),
+ *         notAllowedOnRDN              (67),
+ *         entryAlreadyExists           (68),
+ *         objectClassModsProhibited    (69),
+ *              -- 70 reserved for CLDAP --
+ *         affectsMultipleDSAs          (71),
+ *              -- 72-79 unused --
+ *         other                        (80),
+ *         ...  },
+ *     matchedDN          LDAPDN,
+ *     diagnosticMessage  LDAPString,
+ *     referral           [3] Referral OPTIONAL }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface LdapResult
+{
+    /**
+     * Gets the result code enumeration associated with the response.
+     * Corresponds to the <b> resultCode </b> field within the LDAPResult ASN.1
+     * structure.
+     * 
+     * @return the result code enum value.
+     */
+    ResultCodeEnum getResultCode();
+
+
+    /**
+     * Sets the result code enumeration associated with the response.
+     * Corresponds to the <b> resultCode </b> field within the LDAPResult ASN.1
+     * structure.
+     * 
+     * @param resultCode the result code enum value.
+     */
+    void setResultCode( ResultCodeEnum resultCode );
+
+
+    /**
+     * Gets the lowest entry in the directory that was matched. For result codes
+     * of noSuchObject, aliasProblem, invalidDNSyntax and
+     * aliasDereferencingProblem, the matchedDN field is set to the name of the
+     * lowest entry (object or alias) in the directory that was matched. If no
+     * aliases were dereferenced while attempting to locate the entry, this will
+     * be a truncated form of the name provided, or if aliases were
+     * dereferenced, of the resulting name, as defined in section 12.5 of X.511
+     * [8]. The matchedDN field is to be set to a zero length string with all
+     * other result codes.
+     * 
+     * @return the Dn of the lowest matched entry.
+     */
+    Dn getMatchedDn();
+
+
+    /**
+     * Sets the lowest entry in the directory that was matched.
+     * 
+     * @see #getMatchedDn()
+     * @param dn the Dn of the lowest matched entry.
+     */
+    void setMatchedDn( Dn dn );
+
+
+    /**
+     * Gets the descriptive diagnostic message associated with the error code. May be
+     * null for SUCCESS, COMPARETRUE, COMPAREFALSE and REFERRAL operations.
+     * 
+     * @return the descriptive diagnostic message.
+     */
+    String getDiagnosticMessage();
+
+
+    /**
+     * Sets the descriptive diagnostic message associated with the error code. May be
+     * null for SUCCESS, COMPARETRUE, and COMPAREFALSE operations.
+     * 
+     * @param diagnosticMessage the descriptive diagnostic message.
+     */
+    void setDiagnosticMessage( String diagnosticMessage );
+
+
+    /**
+     * Gets whether or not this result represents a Referral. For referrals the
+     * error code is set to REFERRAL and the referral property is not null.
+     * 
+     * @return true if this result represents a referral.
+     */
+    boolean isReferral();
+
+
+    /**
+     * Gets the Referral associated with this LdapResult if the resultCode
+     * property is set to the REFERRAL ResultCodeEnum.
+     * 
+     * @return the referral on REFERRAL resultCode, null on all others.
+     */
+    Referral getReferral();
+
+
+    /**
+     * Sets the Referral associated with this LdapResult if the resultCode
+     * property is set to the REFERRAL ResultCodeEnum. Setting this property
+     * will result in a true return from isReferral and the resultCode should be
+     * set to REFERRAL.
+     * 
+     * @param referral optional referral on REFERRAL errors.
+     */
+    void setReferral( Referral referral );
+
+
+    /**
+     * Tells if the LdapResult is a success, with no added information. The
+     * MatchedDn will be empty, as the diagnostic message and the referral.
+     * The ResultCode will always be 0.
+     * 
+     * @return True if the LdapResult is SUCCESS.
+     */
+    boolean isDefaultSuccess();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/LdapResultImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/LdapResultImpl.java
new file mode 100644
index 0000000..3ce1fab
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/LdapResultImpl.java
@@ -0,0 +1,525 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * The LdapResult implementation. RFC 4511 definition for a LdapResult is given below. <br>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapResultImpl implements LdapResult
+{
+    /** Lowest matched entry Dn - defaults to empty string */
+    private Dn matchedDn;
+
+    /** Referral associated with this LdapResult if the errorCode is REFERRAL */
+    private Referral referral;
+
+    /** Decriptive diagnostic message - defaults to empty string */
+    private String diagnosticMessage;
+
+    /** Resultant operation error code - defaults to SUCCESS */
+    private ResultCodeEnum resultCode = ResultCodeEnum.SUCCESS;
+
+    /** A flag set when the LdapResult is a SUCESS with no additional information */
+    private boolean isDefaultSuccess = true;
+
+
+    // ------------------------------------------------------------------------
+    // LdapResult Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public String getDiagnosticMessage()
+    {
+        return diagnosticMessage;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDiagnosticMessage( String diagnosticMessage )
+    {
+        this.diagnosticMessage = diagnosticMessage;
+        isDefaultSuccess = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getMatchedDn()
+    {
+        return matchedDn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setMatchedDn( Dn matchedDn )
+    {
+        this.matchedDn = matchedDn;
+        isDefaultSuccess = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ResultCodeEnum getResultCode()
+    {
+        return resultCode;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setResultCode( ResultCodeEnum resultCode )
+    {
+        this.resultCode = resultCode;
+
+        isDefaultSuccess = isDefaultSuccess & ( resultCode == ResultCodeEnum.SUCCESS );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Referral getReferral()
+    {
+        return referral;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isReferral()
+    {
+        return referral != null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReferral( Referral referral )
+    {
+        this.referral = referral;
+        isDefaultSuccess = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDefaultSuccess()
+    {
+        return isDefaultSuccess;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int hash = 37;
+
+        if ( referral != null )
+        {
+            hash = hash * 17 + referral.hashCode();
+        }
+
+        hash = hash * 17 + resultCode.hashCode();
+
+        if ( diagnosticMessage != null )
+        {
+            hash = hash * 17 + diagnosticMessage.hashCode();
+        }
+
+        if ( matchedDn != null )
+        {
+            hash = hash * 17 + matchedDn.hashCode();
+        }
+
+        return hash;
+    }
+
+
+    /**
+     * @param obj The object to compare with
+     * @return <code>true</code> if both objects are equals
+     */
+    public boolean equals( Object obj )
+    {
+        // quickly return true if this is the obj
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        // return false if object does not implement interface
+        if ( !( obj instanceof LdapResult ) )
+        {
+            return false;
+        }
+
+        // compare all the like elements of the two LdapResult objects
+        LdapResult result = ( LdapResult ) obj;
+
+        if ( referral == null && result.getReferral() != null )
+        {
+            return false;
+        }
+
+        if ( result.getReferral() == null && referral != null )
+        {
+            return false;
+        }
+
+        if ( referral != null && result.getReferral() != null && !referral.equals( result.getReferral() ) )
+        {
+            return false;
+        }
+
+        if ( !resultCode.equals( result.getResultCode() ) )
+        {
+            return false;
+        }
+
+        // Handle diagnostic Messages where "" is considered equivalent to null
+        String errMsg0 = diagnosticMessage;
+        String errMsg1 = result.getDiagnosticMessage();
+
+        if ( errMsg0 == null )
+        {
+            errMsg0 = "";
+        }
+
+        if ( errMsg1 == null )
+        {
+            errMsg1 = "";
+        }
+
+        if ( !errMsg0.equals( errMsg1 ) )
+        {
+            return false;
+        }
+
+        if ( matchedDn != null )
+        {
+            if ( !matchedDn.equals( result.getMatchedDn() ) )
+            {
+                return false;
+            }
+        }
+        // one is null other is not
+        else if ( result.getMatchedDn() != null )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Get a String representation of a LdapResult
+     * 
+     * @return A LdapResult String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "        Ldap Result\n" );
+        sb.append( "            Result code : (" ).append( resultCode ).append( ')' );
+
+        switch ( resultCode )
+        {
+
+            case SUCCESS:
+                sb.append( " success\n" );
+                break;
+
+            case OPERATIONS_ERROR:
+                sb.append( " operationsError\n" );
+                break;
+
+            case PROTOCOL_ERROR:
+                sb.append( " protocolError\n" );
+                break;
+
+            case TIME_LIMIT_EXCEEDED:
+                sb.append( " timeLimitExceeded\n" );
+                break;
+
+            case SIZE_LIMIT_EXCEEDED:
+                sb.append( " sizeLimitExceeded\n" );
+                break;
+
+            case COMPARE_FALSE:
+                sb.append( " compareFalse\n" );
+                break;
+
+            case COMPARE_TRUE:
+                sb.append( " compareTrue\n" );
+                break;
+
+            case AUTH_METHOD_NOT_SUPPORTED:
+                sb.append( " authMethodNotSupported\n" );
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                sb.append( " strongAuthRequired\n" );
+                break;
+
+            case REFERRAL:
+                sb.append( " referral -- new\n" );
+                break;
+
+            case ADMIN_LIMIT_EXCEEDED:
+                sb.append( " adminLimitExceeded -- new\n" );
+                break;
+
+            case UNAVAILABLE_CRITICAL_EXTENSION:
+                sb.append( " unavailableCriticalExtension -- new\n" );
+                break;
+
+            case CONFIDENTIALITY_REQUIRED:
+                sb.append( " confidentialityRequired -- new\n" );
+                break;
+
+            case SASL_BIND_IN_PROGRESS:
+                sb.append( " saslBindInProgress -- new\n" );
+                break;
+
+            case NO_SUCH_ATTRIBUTE:
+                sb.append( " noSuchAttribute\n" );
+                break;
+
+            case UNDEFINED_ATTRIBUTE_TYPE:
+                sb.append( " undefinedAttributeType\n" );
+                break;
+
+            case INAPPROPRIATE_MATCHING:
+                sb.append( " inappropriateMatching\n" );
+                break;
+
+            case CONSTRAINT_VIOLATION:
+                sb.append( " constraintViolation\n" );
+                break;
+
+            case ATTRIBUTE_OR_VALUE_EXISTS:
+                sb.append( " attributeOrValueExists\n" );
+                break;
+
+            case INVALID_ATTRIBUTE_SYNTAX:
+                sb.append( " invalidAttributeSyntax\n" );
+                break;
+
+            case NO_SUCH_OBJECT:
+                sb.append( " noSuchObject\n" );
+                break;
+
+            case ALIAS_PROBLEM:
+                sb.append( " aliasProblem\n" );
+                break;
+
+            case INVALID_DN_SYNTAX:
+                sb.append( " invalidDNSyntax\n" );
+                break;
+
+            case ALIAS_DEREFERENCING_PROBLEM:
+                sb.append( " aliasDereferencingProblem\n" );
+                break;
+
+            case INAPPROPRIATE_AUTHENTICATION:
+                sb.append( " inappropriateAuthentication\n" );
+                break;
+
+            case INVALID_CREDENTIALS:
+                sb.append( " invalidCredentials\n" );
+                break;
+
+            case INSUFFICIENT_ACCESS_RIGHTS:
+                sb.append( " insufficientAccessRights\n" );
+                break;
+
+            case BUSY:
+                sb.append( " busy\n" );
+                break;
+
+            case UNAVAILABLE:
+                sb.append( " unavailable\n" );
+                break;
+
+            case UNWILLING_TO_PERFORM:
+                sb.append( " unwillingToPerform\n" );
+                break;
+
+            case LOOP_DETECT:
+                sb.append( " loopDetect\n" );
+                break;
+
+            case NAMING_VIOLATION:
+                sb.append( " namingViolation\n" );
+                break;
+
+            case OBJECT_CLASS_VIOLATION:
+                sb.append( " objectClassViolation\n" );
+                break;
+
+            case NOT_ALLOWED_ON_NON_LEAF:
+                sb.append( " notAllowedOnNonLeaf\n" );
+                break;
+
+            case NOT_ALLOWED_ON_RDN:
+                sb.append( " notAllowedOnRDN\n" );
+                break;
+
+            case ENTRY_ALREADY_EXISTS:
+                sb.append( " entryAlreadyExists\n" );
+                break;
+
+            case OBJECT_CLASS_MODS_PROHIBITED:
+                sb.append( " objectClassModsProhibited\n" );
+                break;
+
+            case AFFECTS_MULTIPLE_DSAS:
+                sb.append( " affectsMultipleDSAs -- new\n" );
+                break;
+
+            case E_SYNC_REFRESH_REQUIRED:
+                sb.append( " eSyncRefreshRequired\n" );
+                break;
+
+            case OTHER:
+                sb.append( " other\n" );
+                break;
+
+            default:
+                switch ( resultCode.getResultCode() )
+                {
+                    case 9:
+                        sb.append( " -- 9 reserved --\n" );
+                        break;
+
+                    case 22:
+                    case 23:
+                    case 24:
+                    case 25:
+                    case 26:
+                    case 27:
+                    case 28:
+                    case 29:
+                    case 30:
+                    case 31:
+                        sb.append( " -- 22-31 unused --\n" );
+                        break;
+
+                    case 35:
+                        sb.append( " -- 35 reserved for undefined isLeaf --\n" );
+                        break;
+
+                    case 37:
+                    case 38:
+                    case 39:
+                    case 40:
+                    case 41:
+                    case 42:
+                    case 43:
+                    case 44:
+                    case 45:
+                    case 46:
+                    case 47:
+                        sb.append( " -- 37-47 unused --\n" );
+                        break;
+
+                    case 55:
+                    case 56:
+                    case 57:
+                    case 58:
+                    case 59:
+                    case 60:
+                    case 61:
+                    case 62:
+                    case 63:
+                        sb.append( " -- 55-63 unused --\n" );
+                        break;
+
+                    case 70:
+                        sb.append( " -- 70 reserved for CLDAP --\n" );
+                        break;
+
+                    case 72:
+                    case 73:
+                    case 74:
+                    case 75:
+                    case 76:
+                    case 77:
+                    case 78:
+                    case 79:
+                        sb.append( " -- 72-79 unused --\n" );
+                        break;
+
+                    case 81:
+                    case 82:
+                    case 83:
+                    case 84:
+                    case 85:
+                    case 86:
+                    case 87:
+                    case 88:
+                    case 89:
+                    case 90:
+                        sb.append( " -- 81-90 reserved for APIs --" );
+                        break;
+
+                    default:
+                        sb.append( "Unknown error code : " ).append( resultCode );
+                        break;
+                }
+        }
+
+        sb.append( "            Matched Dn : '" ).append( matchedDn ).append( "'\n" );
+        sb.append( "            Diagnostic message : '" ).append( diagnosticMessage ).append( "'\n" );
+
+        if ( referral != null )
+        {
+            sb.append( "            Referrals :\n" );
+
+            sb.append( "                Referral :" ).append( referral.toString() ).append( '\n' );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ManyReplyRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ManyReplyRequest.java
new file mode 100644
index 0000000..9eeb083
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ManyReplyRequest.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * A request that can generate zero, one, or more heterogenous responses for a
+ * single request.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public interface ManyReplyRequest extends ResultResponseRequest
+{
+    /**
+     * Gets the various types of messages that can be generated by this kind of
+     * request.
+     * 
+     * @return the messages types generated in response to this Request
+     */
+    MessageTypeEnum[] getResponseTypes();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Message.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Message.java
new file mode 100644
index 0000000..4600470
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Message.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Map;
+
+
+/**
+ * Root interface for all LDAP message type interfaces.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Message
+{
+    /**
+     * Gets the LDAP message type code associated with this Message. Each
+     * request and response type has a unique message type code defined by the
+     * protocol in <a href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251</a>.
+     * 
+     * @return the message type code.
+     */
+    MessageTypeEnum getType();
+
+
+    /**
+     * Gets the controls associated with this message mapped by OID.
+     * 
+     * @return Map of OID strings to Control object instances.
+     */
+    Map<String, Control> getControls();
+
+
+    /**
+     * Gets the control associated with the given OID.
+     * 
+     * @param oid The Cntrol's OID we are looking for
+     * @return The Control object instance with the OID.
+     */
+    Control getControl( String oid );
+
+
+    /**
+     * Checks whether or not this message has the specified control.
+     *
+     * @param oid the OID of the control
+     * @return true if this message has the control, false if it does not
+     */
+    boolean hasControl( String oid );
+
+
+    /**
+     * Adds a control to this Message.
+     * 
+     * @param control the control to add.
+     * @return A Message reference
+     */
+    Message addControl( Control control );
+
+
+    /**
+     * Adds an array of controls to this Message.
+     * 
+     * @param controlsToAdd the controls to add.
+     * @return A Message reference
+     */
+    Message addAllControls( Control[] controlsToAdd );
+
+
+    /**
+     * Deletes a control removing it from this Message.
+     * 
+     * @param control the control to remove.
+     * @return A Message reference
+     */
+    Message removeControl( Control control );
+
+
+    /**
+     * Gets the session unique message sequence id for this message. Requests
+     * and their responses if any have the same message id. Clients at the
+     * initialization of a session start with the first message's id set to 1
+     * and increment it with each transaction.
+     * 
+     * @return the session unique message id.
+     */
+    int getMessageId();
+
+
+    /**
+     * Gets a message scope parameter. Message scope parameters are temporary
+     * variables associated with a message and are set locally to be used to
+     * associate housekeeping information with a request or its processing.
+     * These parameters are never transmitted nor recieved, think of them as
+     * transient data associated with the message or its processing. These
+     * transient parameters are not locked down so modifications can occur
+     * without firing LockExceptions even when this Lockable is in the locked
+     * state.
+     * 
+     * @param key the key used to access a message parameter.
+     * @return the transient message parameter value.
+     */
+    Object get( Object key );
+
+
+    /**
+     * Sets a message scope parameter. These transient parameters are not locked
+     * down so modifications can occur without firing LockExceptions even when
+     * this Lockable is in the locked state.
+     * 
+     * @param key the parameter key
+     * @param value the parameter value
+     * @return the old value or null
+     */
+    Object put( Object key, Object value );
+
+
+    /**
+     * Sets the Message ID for this request
+     * @param messageId The message Id
+     * @return A Message reference
+     */
+    Message setMessageId( int messageId );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/MessageTypeEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/MessageTypeEnum.java
new file mode 100644
index 0000000..e54bca2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/MessageTypeEnum.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * An enum to store the Ldap message type.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum MessageTypeEnum
+{
+    ABANDON_REQUEST,
+    ADD_REQUEST,
+    ADD_RESPONSE,
+    BIND_REQUEST,
+    BIND_RESPONSE,
+    COMPARE_REQUEST,
+    COMPARE_RESPONSE,
+    DEL_REQUEST,
+    DEL_RESPONSE,
+    EXTENDED_REQUEST,
+    EXTENDED_RESPONSE,
+    MODIFYDN_REQUEST,
+    MODIFYDN_RESPONSE,
+    MODIFY_REQUEST,
+    MODIFY_RESPONSE,
+    SEARCH_REQUEST,
+    SEARCH_RESULT_DONE,
+    SEARCH_RESULT_ENTRY,
+    SEARCH_RESULT_REFERENCE,
+    UNBIND_REQUEST,
+    INTERMEDIATE_RESPONSE;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnRequest.java
new file mode 100644
index 0000000..5990d51
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnRequest.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+
+
+/**
+ * Modify Dn request protocol message used to rename or move an existing entry
+ * in the directory. Here's what <a
+ * href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251</a> has to say about
+ * it:
+ * 
+ * <pre>
+ *  4.9. Modify Dn Operation
+ * 
+ *   The Modify Dn Operation allows a client to change the leftmost (least
+ *   significant) component of the name of an entry in the directory, or
+ *   to move a subtree of entries to a new location in the directory.  The
+ *   Modify Dn Request is defined as follows:
+ * 
+ *        ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
+ *                entry           LDAPDN,
+ *                newrdn          RelativeLDAPDN,
+ *                deleteoldrdn    BOOLEAN,
+ *                newSuperior     [0] LDAPDN OPTIONAL }
+ * 
+ *   Parameters of the Modify Dn Request are:
+ * 
+ *   - entry: the Distinguished Name of the entry to be changed.  This
+ *     entry may or may not have subordinate entries.
+ * 
+ *   - newrdn: the Rdn that will form the leftmost component of the new
+ *     name of the entry.
+ * 
+ *   - deleteoldrdn: a boolean parameter that controls whether the old Rdn
+ *     attribute values are to be retained as attributes of the entry, or
+ *     deleted from the entry.
+ * 
+ *   - newSuperior: if present, this is the Distinguished Name of the entry
+ *     which becomes the immediate superior of the existing entry.
+ * </pre>
+ * 
+ * Note that this operation can move an entry and change its Rdn at the same
+ * time in fact it might have no choice to comply with name forms.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ModifyDnRequest extends SingleReplyRequest, AbandonableRequest
+{
+    /**
+     * Gets the entry's distinguished name representing the <b>entry</b> PDU
+     * field.
+     * 
+     * @return the distinguished name of the entry.
+     */
+    Dn getName();
+
+
+    /**
+     * Sets the entry's distinguished name representing the <b>entry</b> PDU
+     * field.
+     * 
+     * @param name the distinguished name of the entry.
+     * @return The ModifyDnRequest instance
+     */
+    ModifyDnRequest setName( Dn name );
+
+
+    /**
+     * Gets the new relative distinguished name for the entry which represents
+     * the PDU's <b>newrdn</b> field.
+     * 
+     * @return the relative dn with one component
+     */
+    Rdn getNewRdn();
+
+
+    /**
+     * Sets the new relative distinguished name for the entry which represents
+     * the PDU's <b>newrdn</b> field.
+     * 
+     * @param newRdn the relative dn with one component
+     * @return The ModifyDnRequest instance
+     */
+    ModifyDnRequest setNewRdn( Rdn newRdn );
+
+
+    /**
+     * Gets the flag which determines if the old Rdn attribute is to be removed
+     * from the entry when the new Rdn is used in its stead. This property
+     * corresponds to the <b>deleteoldrdn</b>.
+     * 
+     * @return true if the old rdn is to be deleted, false if it is not
+     */
+    boolean getDeleteOldRdn();
+
+
+    /**
+     * Sets the flag which determines if the old Rdn attribute is to be removed
+     * from the entry when the new Rdn is used in its stead. This property
+     * corresponds to the <b>deleteoldrdn</b>.
+     * 
+     * @param deleteOldRdn true if the old rdn is to be deleted, false if it is not
+     * @return The ModifyDnRequest instance
+     */
+    ModifyDnRequest setDeleteOldRdn( boolean deleteOldRdn );
+
+
+    /**
+     * Gets the optional distinguished name of the new superior entry where the
+     * candidate entry is to be moved. This property corresponds to the PDU's
+     * <b>newSuperior</b> field. May be null representing a simple Rdn change
+     * rather than a move operation.
+     * 
+     * @return the dn of the superior entry the candidate entry is moved under.
+     */
+    Dn getNewSuperior();
+
+
+    /**
+     * Sets the optional distinguished name of the new superior entry where the
+     * candidate entry is to be moved. This property corresponds to the PDU's
+     * <b>newSuperior</b> field. May be null representing a simple Rdn change
+     * rather than a move operation. Setting this property to a non-null value
+     * toggles the move flag obtained via the <code>isMove</code> method.
+     * 
+     * @param newSuperior the dn of the superior entry the candidate entry for Dn
+     * modification is moved under.
+     * @return The ModifyDnRequest instance
+     */
+    ModifyDnRequest setNewSuperior( Dn newSuperior );
+
+
+    /**
+     * Gets whether or not this request is a Dn change resulting in a move
+     * operation. Setting the newSuperior property to a non-null name, toggles
+     * this flag.
+     * 
+     * @return true if the newSuperior property is <b>NOT</b> null, false
+     * otherwise.
+     */
+    boolean isMove();
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyDnRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyDnRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyDnRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyDnRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnRequestImpl.java
new file mode 100644
index 0000000..fd7f731
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnRequestImpl.java
@@ -0,0 +1,354 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+
+
+/**
+ * ModifyDNRequest implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyDnRequestImpl extends AbstractAbandonableRequest implements ModifyDnRequest
+{
+    static final long serialVersionUID = 1233507339633051696L;
+
+    /** PDU's modify Dn candidate <b>entry</b> distinguished name property */
+    private Dn name;
+
+    /** PDU's <b>newrdn</b> relative distinguished name property */
+    private Rdn newRdn;
+
+    /** PDU's <b>newSuperior</b> distinguished name property */
+    private Dn newSuperior;
+
+    /** PDU's <b>deleteOldRdn</b> flag */
+    private boolean deleteOldRdn = false;
+
+    /** The associated response */
+    private ModifyDnResponse response;
+
+
+    // -----------------------------------------------------------------------
+    // Constructors
+    // -----------------------------------------------------------------------
+    /**
+     * Creates a ModifyDnRequest implementing object used to perform a
+     * dn change on an entry potentially resulting in an entry move.
+     */
+    public ModifyDnRequestImpl()
+    {
+        super( -1, MessageTypeEnum.MODIFYDN_REQUEST );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // ModifyDnRequest Interface Method Implementations
+    // -----------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getDeleteOldRdn()
+    {
+        return deleteOldRdn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setDeleteOldRdn( boolean deleteOldRdn )
+    {
+        this.deleteOldRdn = deleteOldRdn;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isMove()
+    {
+        return newSuperior != null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setName( Dn name )
+    {
+        this.name = name;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Rdn getNewRdn()
+    {
+        return newRdn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setNewRdn( Rdn newRdn )
+    {
+        this.newRdn = newRdn;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getNewSuperior()
+    {
+        return newSuperior;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setNewSuperior( Dn newSuperior )
+    {
+        this.newSuperior = newSuperior;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest addControl( Control control )
+    {
+        return ( ModifyDnRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest addAllControls( Control[] controls )
+    {
+        return ( ModifyDnRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyDnRequest removeControl( Control control )
+    {
+        return ( ModifyDnRequest ) super.removeControl( control );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SingleReplyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.MODIFYDN_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public ModifyDnResponse getResultResponse()
+    {
+        if ( response == null )
+        {
+            response = new ModifyDnResponseImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( name != null )
+        {
+            hash = hash * 17 + name.hashCode();
+        }
+        hash = hash * 17 + ( deleteOldRdn ? 0 : 1 );
+
+        if ( newRdn != null )
+        {
+            hash = hash * 17 + newRdn.hashCode();
+        }
+        if ( newSuperior != null )
+        {
+            hash = hash * 17 + newSuperior.hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see of an object equals this ModifyDnRequest stub. The equality
+     * presumes all ModifyDnRequest specific properties are the same.
+     * 
+     * @param obj the object to compare with this stub
+     * @return true if the obj is equal to this stub, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        ModifyDnRequest req = ( ModifyDnRequest ) obj;
+
+        if ( name != null && req.getName() == null )
+        {
+            return false;
+        }
+
+        if ( name == null && req.getName() != null )
+        {
+            return false;
+        }
+
+        if ( name != null && req.getName() != null && !name.equals( req.getName() ) )
+        {
+            return false;
+        }
+
+        if ( deleteOldRdn != req.getDeleteOldRdn() )
+        {
+            return false;
+        }
+
+        if ( newRdn != null && req.getNewRdn() == null )
+        {
+            return false;
+        }
+
+        if ( newRdn == null && req.getNewRdn() != null )
+        {
+            return false;
+        }
+
+        if ( newRdn != null && req.getNewRdn() != null && !newRdn.equals( req.getNewRdn() ) )
+        {
+            return false;
+        }
+
+        if ( newSuperior != null && req.getNewSuperior() == null )
+        {
+            return false;
+        }
+
+        if ( newSuperior == null && req.getNewSuperior() != null )
+        {
+            return false;
+        }
+
+        return ( ( newSuperior == null ) || ( req.getNewSuperior() == null ) || newSuperior.equals( req
+            .getNewSuperior() ) );
+    }
+
+
+    /**
+     * Get a String representation of a ModifyDNRequest
+     * 
+     * @return A ModifyDNRequest String
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    ModifyDN Response\n" );
+        sb.append( "        Entry : '" ).append( name ).append( "'\n" );
+        if ( newRdn != null )
+        {
+            sb.append( "        New Rdn : '" ).append( newRdn.toString() ).append( "'\n" );
+        }
+        sb.append( "        Delete old Rdn : " ).append( deleteOldRdn ).append( "\n" );
+
+        if ( newSuperior != null )
+        {
+            sb.append( "        New superior : '" ).append( newSuperior.toString() ).append( "'\n" );
+        }
+
+        // The controls
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnResponse.java
new file mode 100644
index 0000000..17d0062
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnResponse.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Modify Dn protocol response message used to confirm the results of a modify
+ * Dn request message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ModifyDnResponse extends ResultResponse
+{
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnResponseImpl.java
new file mode 100644
index 0000000..3f9e7be
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyDnResponseImpl.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * ModifyDnResponse implementation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class ModifyDnResponseImpl extends AbstractResultResponse implements ModifyDnResponse
+{
+    static final long serialVersionUID = 996870775343263543L;
+
+
+    /**
+     * Creates a ModifyDnResponse as a reply to an ModifyDnRequest.
+     */
+    public ModifyDnResponseImpl()
+    {
+        super( -1, MessageTypeEnum.MODIFYDN_RESPONSE );
+    }
+
+
+    /**
+     * Creates a ModifyDnResponse as a reply to an ModifyDnRequest.
+     * 
+     * @param id the sequence if of this response
+     */
+    public ModifyDnResponseImpl( final int id )
+    {
+        super( id, MessageTypeEnum.MODIFYDN_RESPONSE );
+    }
+
+
+    /**
+     * Get a String representation of a ModifyDNResponse
+     * 
+     * @return A ModifyDNResponse String
+     */
+    public String toString()
+    {
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Modify Dn Response\n" );
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequest.java
new file mode 100644
index 0000000..948a6d5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequest.java
@@ -0,0 +1,276 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Collection;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Modify request protocol message used to alter the attributes and values of an
+ * existing entry. Here's what <a href="">RFC 2255</a> says about it:
+ * 
+ * <pre>
+ *  4.6. Modify Operation
+ * 
+ *   The Modify Operation allows a client to request that a modification
+ *   of an entry be performed on its behalf by a server.  The Modify
+ *   Request is defined as follows:
+ * 
+ *        ModifyRequest ::= [APPLICATION 6] SEQUENCE {
+ *                object          LDAPDN,
+ *                modification    SEQUENCE OF SEQUENCE {
+ * 
+ *                        operation       ENUMERATED {
+ *                                                add     (0),
+ *                                                delete  (1),
+ *                                                replace (2) },
+ *                        modification    AttributeTypeAndValues } }
+ * 
+ *        AttributeTypeAndValues ::= SEQUENCE {
+ *                type    AttributeDescription,
+ *                vals    SET OF AttributeValue }
+ * 
+ *   Parameters of the Modify Request are:
+ * 
+ *   - object: The object to be modified. The value of this field contains
+ *     the Dn of the entry to be modified.  The server will not perform
+ *     any alias dereferencing in determining the object to be modified.
+ * 
+ *   - modification: A list of modifications to be performed on the entry.
+ *     The entire list of entry modifications MUST be performed
+ *     in the order they are listed, as a single atomic operation.  While
+ *     individual modifications may violate the directory schema, the
+ *     resulting entry after the entire list of modifications is performed
+ *     MUST conform to the requirements of the directory schema. The
+ *     values that may be taken on by the 'operation' field in each
+ *     modification construct have the following semantics respectively:
+ *  
+ * 
+ *             add: add values listed to the given attribute, creating
+ *             the attribute if necessary;
+ * 
+ *             delete: delete values listed from the given attribute,
+ *             removing the entire attribute if no values are listed, or
+ *             if all current values of the attribute are listed for
+ *             deletion;
+ * 
+ *             replace: replace all existing values of the given attribute
+ *             with the new values listed, creating the attribute if it
+ *             did not already exist.  A replace with no value will delete
+ *             the entire attribute if it exists, and is ignored if the
+ *             attribute does not exist.
+ *  </pre>
+ * 
+ *  Notice that we tried to leverage as much as we already can from the JNDI.
+ *  Both the Names and ModificationItems are used here to make the API as easy
+ *  as possible to understand.  We do not attempt here to write a JNDI provider
+ *  which losses the explicit request type usage that we are looking for.  Also
+ *  note that this library is both for the client side as well as the server side
+ *  unlike the JNDI which is strictly for the client side.  From the JNDI we
+ *  borrow good ideas and familiar signatures, interfaces and classes where we
+ *  can.
+ *  
+ *  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * 
+ */
+public interface ModifyRequest extends SingleReplyRequest, AbandonableRequest
+{
+    /**
+     * Gets the distinguished name of the entry to be modified by this request.
+     * This property represents the PDU's <b>object</b> field.
+     * 
+     * @return the Dn of the modified entry.
+     */
+    Dn getName();
+
+
+    /**
+     * Sets the distinguished name of the entry to be modified by this request.
+     * This property represents the PDU's <b>object</b> field.
+     * 
+     * @param name the Dn of the modified entry.
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest setName( Dn name );
+
+
+    /**
+     * Gets an immutable Collection of modification items representing the
+     * atomic changes to perform on the candidate entry to modify.
+     * 
+     * @return an immutable Collection of Modification instances.
+     */
+    Collection<Modification> getModifications();
+
+
+    /**
+     * Adds a ModificationItem to the set of modifications composing this modify
+     * request.
+     * 
+     * @param mod a Modification to add.
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest addModification( Modification mod );
+
+
+    /**
+     * Removes a ModificationItem to the set of modifications composing this
+     * modify request.
+     * 
+     * @param mod a Modification to remove.
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest removeModification( Modification mod );
+
+
+    /**
+     *
+     * marks a given attribute for removal with the given
+     * values from the target entry.
+     *
+     * @param attributeName name of the attribute to be removed
+     * @param attributeValue values of the attribute
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest remove( String attributeName, String... attributeValue );
+
+
+    /**
+     * @see #remove(String, String...)
+     */
+    ModifyRequest remove( String attributeName, byte[]... attributeValue );
+
+
+    /**
+     *
+     * marks a given attribute for removal from the target entry.
+     *
+     * @param attr the attribute to be removed
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest remove( Attribute attr );
+
+
+    /**
+     *
+     * marks a given attribute name for removal from the target entry.
+     *
+     * @param attributeName the attribute to be removed
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest remove( String attributeName );
+
+
+    /**
+     * Add a modification 
+     * @param attr The attribute to be modified
+     * @param modOp The operation
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest addModification( Attribute attr, ModificationOperation modOp );
+
+
+    /**
+     * marks a given attribute for addition in the target entry with the
+     * given values.
+     *
+     * @param attributeName name of the attribute to be added
+     * @param attributeValue values of the attribute
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest add( String attributeName, String... attributeValue );
+
+
+    /**
+     * @see #add(String, String...)
+     */
+    ModifyRequest add( String attributeName, byte[]... attributeValue );
+
+
+    /**
+     * marks a given attribute for addition in the target entry.
+     *
+     * @param attr the attribute to be added
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest add( Attribute attr );
+
+
+    /**
+     * @see #replace(String, String...)
+     */
+    ModifyRequest replace( String attributeName );
+
+
+    /**
+     * marks a given attribute for replacement with the given
+     * values in the target entry.
+     *
+     * @param attributeName name of the attribute to be added
+     * @param attributeValue values of the attribute
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest replace( String attributeName, String... attributeValue );
+
+
+    /**
+     * @see #replace(String, String...)
+     */
+    ModifyRequest replace( String attributeName, byte[]... attributeValue );
+
+
+    /**
+     * marks a given attribute for replacement in the target entry.
+     *
+     * @param attr the attribute to be added
+     * @return The ModifyRequest instance
+     */
+    ModifyRequest replace( Attribute attr );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    ModifyRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequestImpl.java
new file mode 100644
index 0000000..86372e7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyRequestImpl.java
@@ -0,0 +1,482 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.StringConstants;
+
+
+/**
+ * Lockable ModifyRequest implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ModifyRequestImpl extends AbstractAbandonableRequest implements ModifyRequest
+{
+    static final long serialVersionUID = -505803669028990304L;
+
+    /** Dn of the entry to modify or PDU's <b>object</b> field */
+    private Dn name;
+
+    /** Sequence of modifications or PDU's <b>modification</b> sequence field */
+    private List<Modification> mods = new ArrayList<Modification>();
+
+    /** The associated response */
+    private ModifyResponse response;
+
+
+    // -----------------------------------------------------------------------
+    // Constructors
+    // -----------------------------------------------------------------------
+    /**
+     * Creates a ModifyRequest implementing object used to modify the
+     * attributes of an entry.
+     */
+    public ModifyRequestImpl()
+    {
+        super( -1, MessageTypeEnum.MODIFY_REQUEST );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ModifyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<Modification> getModifications()
+    {
+        return Collections.unmodifiableCollection( mods );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest setName( Dn name )
+    {
+        this.name = name;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addModification( Modification mod )
+    {
+        mods.add( mod );
+
+        return this;
+    }
+
+
+    private void addModification( ModificationOperation modOp, String attributeName, byte[]... attributeValue )
+    {
+        Attribute attr = new DefaultAttribute( attributeName, attributeValue );
+        addModification( attr, modOp );
+    }
+
+
+    private void addModification( ModificationOperation modOp, String attributeName, String... attributeValue )
+    {
+        Attribute attr = new DefaultAttribute( attributeName, attributeValue );
+        addModification( attr, modOp );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addModification( Attribute attr, ModificationOperation modOp )
+    {
+        mods.add( new DefaultModification( modOp, attr ) );
+
+        return this;
+    }
+
+
+    /**
+     *{@inheritDoc}
+     */
+    public ModifyRequest add( String attributeName, String... attributeValue )
+    {
+        addModification( ModificationOperation.ADD_ATTRIBUTE, attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * @see #add(String, String...)
+     */
+    public ModifyRequest add( String attributeName, byte[]... attributeValue )
+    {
+        addModification( ModificationOperation.ADD_ATTRIBUTE, attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     *{@inheritDoc}
+     */
+    public ModifyRequest add( Attribute attr )
+    {
+        addModification( attr, ModificationOperation.ADD_ATTRIBUTE );
+
+        return this;
+    }
+
+
+    /**
+     * @see #replace(String, String...)
+     */
+    public ModifyRequest replace( String attributeName )
+    {
+        addModification( ModificationOperation.REPLACE_ATTRIBUTE, attributeName, StringConstants.EMPTY_STRINGS );
+
+        return this;
+    }
+
+
+    /**
+     *{@inheritDoc}
+     */
+    public ModifyRequest replace( String attributeName, String... attributeValue )
+    {
+        addModification( ModificationOperation.REPLACE_ATTRIBUTE, attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * @see #replace(String, String...)
+     */
+    public ModifyRequest replace( String attributeName, byte[]... attributeValue )
+    {
+        addModification( ModificationOperation.REPLACE_ATTRIBUTE, attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     *{@inheritDoc}
+     */
+    public ModifyRequest replace( Attribute attr )
+    {
+        addModification( attr, ModificationOperation.REPLACE_ATTRIBUTE );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest removeModification( Modification mod )
+    {
+        mods.remove( mod );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName, String... attributeValue )
+    {
+        addModification( ModificationOperation.REMOVE_ATTRIBUTE, attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributeName, byte[]... attributeValue )
+    {
+        addModification( ModificationOperation.REMOVE_ATTRIBUTE, attributeName, attributeValue );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( Attribute attr )
+    {
+        addModification( attr, ModificationOperation.REMOVE_ATTRIBUTE );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest remove( String attributerName )
+    {
+        addModification( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attributerName ) );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addControl( Control control )
+    {
+        return ( ModifyRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest addAllControls( Control[] controls )
+    {
+        return ( ModifyRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ModifyRequest removeControl( Control control )
+    {
+        return ( ModifyRequest ) super.removeControl( control );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SingleReplyRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    public MessageTypeEnum getResponseType()
+    {
+        return MessageTypeEnum.MODIFY_RESPONSE;
+    }
+
+
+    /**
+     * The result containing response for this request.
+     * 
+     * @return the result containing response for this request
+     */
+    public ModifyResponse getResultResponse()
+    {
+        if ( response == null )
+        {
+            response = new ModifyResponseImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( name != null )
+        {
+            hash = hash * 17 + name.hashCode();
+        }
+        hash = hash * 17 + mods.size();
+        for ( int i = 0; i < mods.size(); i++ )
+        {
+            hash = hash * 17 + ( ( DefaultModification ) mods.get( i ) ).hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if ModifyRequest stub equals another by factoring in checks
+     * for the name and modification items of the request.
+     * 
+     * @param obj
+     *            the object to compare this ModifyRequest to
+     * @return true if obj equals this ModifyRequest, false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        ModifyRequest req = ( ModifyRequest ) obj;
+
+        if ( name != null && req.getName() == null )
+        {
+            return false;
+        }
+
+        if ( name == null && req.getName() != null )
+        {
+            return false;
+        }
+
+        if ( name != null && req.getName() != null && !name.equals( req.getName() ) )
+        {
+            return false;
+        }
+
+        if ( req.getModifications().size() != mods.size() )
+        {
+            return false;
+        }
+
+        Iterator<Modification> list = req.getModifications().iterator();
+
+        for ( int i = 0; i < mods.size(); i++ )
+        {
+            Modification item = list.next();
+
+            if ( item == null )
+            {
+                if ( mods.get( i ) != null )
+                {
+                    return false;
+                }
+            }
+            else
+
+            if ( !item.equals( mods.get( i ) ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Get a String representation of a ModifyRequest
+     * 
+     * @return A ModifyRequest String
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Modify Request\n" );
+        sb.append( "        Object : '" ).append( name ).append( "'\n" );
+
+        if ( mods != null )
+        {
+
+            for ( int i = 0; i < mods.size(); i++ )
+            {
+
+                DefaultModification modification = ( DefaultModification ) mods.get( i );
+
+                sb.append( "            Modification[" ).append( i ).append( "]\n" );
+                sb.append( "                Operation : " );
+
+                switch ( modification.getOperation() )
+                {
+                    case ADD_ATTRIBUTE:
+                        sb.append( " add\n" );
+                        break;
+
+                    case REPLACE_ATTRIBUTE:
+                        sb.append( " replace\n" );
+                        break;
+
+                    case REMOVE_ATTRIBUTE:
+                        sb.append( " delete\n" );
+                        break;
+
+                    default:
+                        throw new IllegalArgumentException( "Unexpected ModificationOperation "
+                            + modification.getOperation() );
+                }
+
+                sb.append( "                Modification\n" );
+                sb.append( modification.getAttribute() );
+            }
+        }
+
+        // The controls
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyResponse.java
new file mode 100644
index 0000000..b5d1f46
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyResponse.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Modify protocol response message used to confirm the results of a modify
+ * request message.
+ * 
+ */
+public interface ModifyResponse extends ResultResponse
+{
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyResponseImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyResponseImpl.java
new file mode 100644
index 0000000..362fe06
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ModifyResponseImpl.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * ModifyResponse implementation
+ * 
+ */
+public class ModifyResponseImpl extends AbstractResultResponse implements ModifyResponse
+{
+    static final long serialVersionUID = 4132526905748233730L;
+
+
+    /**
+     * Creates a ModifyResponse as a reply to an ModifyRequest.
+     */
+    public ModifyResponseImpl()
+    {
+        super( -1, MessageTypeEnum.MODIFY_RESPONSE );
+    }
+
+
+    /**
+     * Creates a ModifyResponse as a reply to an ModifyRequest.
+     * 
+     * @param id the sequence id for this response
+     */
+    public ModifyResponseImpl( final int id )
+    {
+        super( id, MessageTypeEnum.MODIFY_RESPONSE );
+    }
+
+
+    /**
+     * Get a String representation of a ModifyResponse
+     * 
+     * @return A ModifyResponse String
+     */
+    public String toString()
+    {
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Modify Response\n" );
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Referral.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Referral.java
new file mode 100644
index 0000000..f98d112
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Referral.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Collection;
+
+
+/**
+ * Represents a referral which is a set of alternative locations where an entry
+ * can be found. Here's what <a href="http://www.faqs.org/rfcs/rfc2251.html">
+ * RFC 2251 </a> has to say about it:
+ * 
+ * <pre>
+ *  4.1.11. Referral
+ * 
+ *   The referral error indicates that the contacted server does not hold
+ *   the target entry of the request.  The referral field is present in an
+ *   LDAPResult if the LDAPResult.resultCode field value is referral, and
+ *   absent with all other result codes.  It contains a reference to
+ *   another server (or set of servers) which may be accessed via LDAP or
+ *   other protocols.  Referrals can be returned in response to any
+ *   operation request (except unbind and abandon which do not have
+ *   responses). At least one URL MUST be present in the Referral.
+ * 
+ *   The referral is not returned for a singleLevel or wholeSubtree search
+ *   in which the search scope spans multiple naming contexts, and several
+ *   different servers would need to be contacted to complete the
+ *   operation. Instead, continuation references, described in section
+ *   4.5.3, are returned.
+ * 
+ *        Referral ::= SEQUENCE OF LDAPURL  -- one or more
+ * 
+ *        LDAPURL ::= LDAPString -- limited to characters permitted in URLs
+ * 
+ *   If the client wishes to progress the operation, it MUST follow the
+ *   referral by contacting any one of servers.  All the URLs MUST be
+ *   equally capable of being used to progress the operation.  (The
+ *   mechanisms for how this is achieved by multiple servers are outside
+ *   the scope of this document.)
+ * 
+ *   URLs for servers implementing the LDAP protocol are written according
+ *   to &lt;a href=&quot;http://www.faqs.org/rfcs/rfc2255.html&quot;&gt;[9]&lt;/a&gt;.  If an alias
+ *   was dereferenced, the &lt;dn&gt; part of the URL MUST be present, with the new
+ *   target object name.  If the &lt;dn&gt; part is present, the client MUST use this
+ *   name in its next request to progress the operation, and if it is not present
+ *   the client will use the same name as in the original request.  Some servers
+ *   (e.g. participating in distributed indexing) may provide a different filter
+ *   in a referral for a search operation.  If the filter part of the URL
+ *    is present in an LDAPURL, the client MUST use this filter in its next
+ *   request to progress this search, and if it is not present the client
+ *   MUST use the same filter as it used for that search.  Other aspects
+ *   of the new request may be the same or different as the request which
+ *   generated the referral.
+ * 
+ *   Note that UTF-8 characters appearing in a Dn or search filter may not
+ *   be legal for URLs (e.g. spaces) and MUST be escaped using the %
+ *   method in RFC 1738 &lt;a href=&quot;http://www.faqs.org/rfcs/rfc1738.html&quot;&gt;[7]&lt;/a&gt;.
+ * 
+ *   Other kinds of URLs may be returned, so long as the operation could
+ *   be performed using that protocol.
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ * TODO This interface should be located in a url package under common to be
+ *       constructed from a LDAPv3 URL parser. The interface will eventually
+ *       look very different once url support is added: for one it will add and
+ *       remove LdapUrl objects instead of strings or provide both string and
+ *       LdapUrl add/remove methods.
+ */
+public interface Referral
+{
+    /**
+     * Gets an unmodifiable set of alternative referral urls.
+     * 
+     * @return the alternative url objects.
+     */
+    Collection<String> getLdapUrls();
+
+
+    /**
+     * Gets an unmodifiable set of encoded referral urls.
+     * 
+     * @return the encoded url objects.
+     */
+    Collection<byte[]> getLdapUrlsBytes();
+
+
+    /**
+     * Adds an LDAPv3 URL to this Referral.
+     * 
+     * @param url
+     *            the LDAPv3 URL to add
+     */
+    void addLdapUrl( String url );
+
+
+    /**
+     * Adds an encoded LDAPv3 URL to this Referral.
+     * 
+     * @param urlBytes the encoded LDAPv3 URL to add
+     */
+    void addLdapUrlBytes( byte[] urlBytes );
+
+
+    /**
+     * Removes an LDAPv3 URL to this Referral.
+     * 
+     * @param url
+     *            the LDAPv3 URL to remove
+     */
+    void removeLdapUrl( String url );
+
+
+    /**
+     * @return The total length of the Referral
+     */
+    int getReferralLength();
+
+
+    /**
+     * Set the length of the referral
+     * @param referralLength The total length of the Referral
+     */
+    void setReferralLength( int referralLength );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ReferralImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ReferralImpl.java
new file mode 100644
index 0000000..31d2bbe
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ReferralImpl.java
@@ -0,0 +1,216 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * A Referral implementation. For the time being this implementation uses a
+ * String representation for LDAPURLs. In the future an LdapUrl interface with
+ * default implementations will be used once a parser for an LdapUrl is created.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ReferralImpl implements Referral
+{
+    static final long serialVersionUID = 2638820668325359096L;
+
+    /** Sequence of LDAPUrls composing this Referral */
+    private final List<String> urls = new ArrayList<String>();
+
+    /** The encoded LdapURL */
+    private final List<byte[]> urlsBytes = new ArrayList<byte[]>();
+
+    /** The length of the referral */
+    private int referralLength;
+
+
+    // ------------------------------------------------------------------------
+    // LdapResult Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public int getReferralLength()
+    {
+        return referralLength;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setReferralLength( int referralLength )
+    {
+        this.referralLength = referralLength;
+    }
+
+
+    /**
+     * Gets an unmodifiable set of alternative referral urls.
+     * 
+     * @return the alternative url objects.
+     */
+    public Collection<String> getLdapUrls()
+    {
+        return Collections.unmodifiableCollection( urls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Collection<byte[]> getLdapUrlsBytes()
+    {
+        return urlsBytes;
+    }
+
+
+    /**
+     * Adds an LDAPv3 URL to this Referral.
+     * 
+     * @param url the LDAPv3 URL to add
+     */
+    public void addLdapUrl( String url )
+    {
+        urls.add( url );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addLdapUrlBytes( byte[] urlBytes )
+    {
+        urlsBytes.add( urlBytes );
+    }
+
+
+    /**
+     * Removes an LDAPv3 URL to this Referral.
+     * 
+     * @param url
+     *            the LDAPv3 URL to remove
+     */
+    public void removeLdapUrl( String url )
+    {
+        urls.remove( url );
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + urls.size();
+
+        // Order doesn't matter, so just add the url hashCode
+        for ( String url : urls )
+        {
+            hash = hash + url.hashCode();
+        }
+
+        return hash;
+    }
+
+
+    /**
+     * Compares this Referral implementation to see if it is the same as
+     * another. The classes do not have to be the same implementation to return
+     * true. Both this and the compared Referral must have the same entries
+     * exactly. The order of Referral URLs does not matter.
+     * 
+     * @param obj
+     *            the object to compare this ReferralImpl to
+     * @return true if both implementations contain exactly the same URLs
+     */
+    public boolean equals( Object obj )
+    {
+        // just in case for speed return true if obj is this object
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( obj instanceof Referral )
+        {
+            Collection<String> refs = ( ( Referral ) obj ).getLdapUrls();
+
+            // if their sizes do not match they are not equal
+            if ( refs.size() != urls.size() )
+            {
+                return false;
+            }
+
+            Iterator<String> list = urls.iterator();
+
+            while ( list.hasNext() )
+            {
+                // if one of our urls is not contained in the obj return false
+                if ( !refs.contains( list.next() ) )
+                {
+                    return false;
+                }
+            }
+
+            // made it through the checks so we have a match
+            return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Get a String representation of a Referral
+     * 
+     * @return A Referral String
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        if ( ( urls != null ) && ( urls.size() != 0 ) )
+        {
+            sb.append( "            Referrals :\n" );
+
+            Object[] urlsArray = urls.toArray();
+
+            for ( int i = 0; i < urlsArray.length; i++ )
+            {
+
+                String referral = ( String ) urlsArray[i];
+
+                sb.append( "                Referral[" ).append( i ).append( "] :" ).append( referral ).append( '\n' );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ReferralsPolicyEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ReferralsPolicyEnum.java
new file mode 100644
index 0000000..1ff19f9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ReferralsPolicyEnum.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.message;
+
+/**
+ * An enum describing the three possible actions for referrals :
+ * <ul>
+ * <li>Ignore : The referrals will be retruned as is (ie, the 'ref' attribute type will be present in the entry</li>
+ * <li>Follow : The referral will be chased by the client</li>
+ * <li>Throws : An LdapReferralException will be thrown</li>
+ * </ul>
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public enum ReferralsPolicyEnum
+{
+    IGNORE,
+    FOLLOW,
+    THROW
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Request.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Request.java
new file mode 100644
index 0000000..e756918
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Request.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Ldap protocol request messages derive from this super interface.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public interface Request extends Message
+{
+    /**
+     * Tests to see if this Request produces one or more response types.
+     * 
+     * @return true if a response can be expected, false otherwise.
+     */
+    boolean hasResponse();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Response.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Response.java
new file mode 100644
index 0000000..43969da
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/Response.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Super interface used as a marker for all protocol response type messages.
+ * Note that only 2 response interfaces directly extend this interfaces. They
+ * are listed below:
+ * <ul>
+ * <li> SearchResponseEntry </li>
+ * <li> SearchResponseReference </li>
+ * </ul>
+ * <br>
+ * All other responses derive from the ResultResponse interface. These responses
+ * unlike the three above have an LdapResult component. The ResultResponse
+ * interface takes this into account providing a Response with an LdapResult
+ * property.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Response extends Message
+{
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultCodeEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultCodeEnum.java
new file mode 100644
index 0000000..155aea1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultCodeEnum.java
@@ -0,0 +1,2250 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.CommunicationException;
+import javax.naming.LimitExceededException;
+import javax.naming.PartialResultException;
+import javax.naming.SizeLimitExceededException;
+
+import org.apache.directory.api.ldap.model.exception.LdapAdminLimitExceededException;
+import org.apache.directory.api.ldap.model.exception.LdapAffectMultipleDsaException;
+import org.apache.directory.api.ldap.model.exception.LdapAliasDereferencingException;
+import org.apache.directory.api.ldap.model.exception.LdapAliasException;
+import org.apache.directory.api.ldap.model.exception.LdapAttributeInUseException;
+import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
+import org.apache.directory.api.ldap.model.exception.LdapAuthenticationNotSupportedException;
+import org.apache.directory.api.ldap.model.exception.LdapCannotCancelException;
+import org.apache.directory.api.ldap.model.exception.LdapContextNotEmptyException;
+import org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeTypeException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidSearchFilterException;
+import org.apache.directory.api.ldap.model.exception.LdapLoopDetectedException;
+import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchObjectException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchOperationException;
+import org.apache.directory.api.ldap.model.exception.LdapOperationErrorException;
+import org.apache.directory.api.ldap.model.exception.LdapOperationException;
+import org.apache.directory.api.ldap.model.exception.LdapOtherException;
+import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
+import org.apache.directory.api.ldap.model.exception.LdapServiceUnavailableException;
+import org.apache.directory.api.ldap.model.exception.LdapSizeLimitExceededException;
+import org.apache.directory.api.ldap.model.exception.LdapStrongAuthenticationRequiredException;
+import org.apache.directory.api.ldap.model.exception.LdapTimeLimitExceededException;
+import org.apache.directory.api.ldap.model.exception.LdapTooLateException;
+import org.apache.directory.api.ldap.model.exception.LdapUnknownException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+
+
+/**
+ * Type safe LDAP message envelope result code enumeration. The resultCode is a
+ * parameter of the LDAPResult which is the construct used in this protocol to
+ * return success or failure indications from servers to clients. In response to
+ * various requests servers will return responses containing fields of type
+ * LDAPResult to indicate the final status of a protocol operation request. This
+ * enumeration represents the various status codes associated with an
+ * LDAPResult, hence it is called the ResultCodeEnum. Here are the definitions
+ * and values for error codes from section 4.1.10 of <a
+ * href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251</a>:
+ * 
+ * <pre><code>
+ *     resultCode
+ *        ENUMERATED {
+ *           success                      (0),
+ *           operationsError              (1),
+ *           protocolError                (2),
+ *           timeLimitExceeded            (3),
+ *           sizeLimitExceeded            (4),
+ *           compareFalse                 (5),
+ *           compareTrue                  (6),
+ *           authMethodNotSupported       (7),
+ *           strongAuthRequired           (8),
+ *           partialResults               (9),   -- new
+ *           referral                     (10),  -- new
+ *           adminLimitExceeded           (11),  -- new
+ *           unavailableCriticalExtension (12),  -- new
+ *           confidentialityRequired      (13),  -- new
+ *           saslBindInProgress           (14),  -- new
+ *           noSuchAttribute              (16),
+ *           undefinedAttributeType       (17),
+ *           inappropriateMatching        (18),
+ *           constraintViolation          (19),
+ *           attributeOrValueExists       (20),
+ *           invalidAttributeSyntax       (21),
+ *           -- 22-31 unused --
+ *           NO_SUCH_OBJECT                 (32),
+ *           aliasProblem                 (33),
+ *           invalidDNSyntax              (34),
+ *           -- 35 reserved for undefined isLeaf --
+ *           aliasDereferencingProblem    (36),
+ *           -- 37-47 unused --
+ *           inappropriateAuthentication  (48),
+ *           invalidCredentials           (49),
+ *           insufficientAccessRights     (50),
+ *           busy                         (51),
+ *           unavailable                  (52),
+ *           unwillingToPerform           (53),
+ *           loopDetect                   (54),
+ *           -- 55-63 unused --
+ *           namingViolation              (64),
+ *           objectClassViolation         (65),
+ *           notAllowedOnNonLeaf          (66),
+ *           notAllowedOnRDN              (67),
+ *           entryAlreadyExists           (68),
+ *           objectClassModsProhibited    (69),
+ *           -- 70 reserved for CLDAP --
+ *           affectsMultipleDSAs          (71), -- new
+ *           -- 72-79 unused --
+ *           other                        (80) },
+ *           -- 81-90 reserved for APIs --
+ * </code></pre>
+ * 
+ * All the result codes with the exception of success, compareFalse and
+ * compareTrue are to be treated as meaning the operation could not be completed
+ * in its entirety. Most of the result codes are based on problem indications
+ * from X.511 error data types. Result codes from 16 to 21 indicate an
+ * AttributeProblem, codes 32, 33, 34 and 36 indicate a NameProblem, codes 48,
+ * 49 and 50 indicate a SecurityProblem, codes 51 to 54 indicate a
+ * ServiceProblem, and codes 64 to 69 and 71 indicates an UpdateProblem. If a
+ * client receives a result code which is not listed above, it is to be treated
+ * as an unknown error condition. The majority of this javadoc was pasted in
+ * from RFC 2251. There's and expired draft out there on error codes which makes
+ * alot of sense: <a
+ * href="http://www.alternic.org/drafts/drafts-j-k/draft-just-ldapv3-rescodes-
+ * 02.html"> ietf (expired) draft</a> on error codes (read at your discretion).
+ * Result codes have been identified and split into categories:
+ * <ul>
+ * <li> Non-Erroneous: Five result codes that may be returned in LDAPResult are
+ * not used to indicate an error. </li>
+ * <li> General: returned only when no suitable specific error exists. </li>
+ * <li> Specific: Specific errors are used to indicate that a particular type of
+ * error has occurred. These error types are:
+ * <ul>
+ * <li> Name, </li>
+ * <li> Update, </li>
+ * <li> Attribute </li>
+ * <li> Security, and </li>
+ * <li> Service </li>
+ * </ul>
+ * </li>
+ * </ul>
+ * The result codes are also grouped according to the following LDAP operations
+ * which return responses:
+ * <ul>
+ * <li> bind </li>
+ * <li> search </li>
+ * <li> modify </li>
+ * <li> modifyDn </li>
+ * <li> add </li>
+ * <li> delete </li>
+ * <li> compare </li>
+ * <li> extended </li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum ResultCodeEnum
+{
+    // ------------------------------------------------------------------------
+    // Public Static Constants: Enumeration values and names.
+    // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
+    // Non Erroneous Codes:
+    //
+    // Five result codes that may be returned in LDAPResult are not used to
+    // indicate an error. These result codes are listed below. The first
+    // three codes, indicate to the client that no further action is required
+    // in order to satisfy their request. In contrast, the last two errors
+    // require further action by the client in order to complete their original
+    // operation request.
+    // ------------------------------------------------------------------------
+
+    /**
+     * It is returned when the client operation completed successfully without
+     * errors. This code is one of 5 result codes that may be returned in the
+     * LDAPResult which are not used to indicate an error. Applicable
+     * operations: all except for Compare. Result code type: Non-Erroneous
+     */
+    SUCCESS(0, "success"),
+
+    /**
+     * Servers sends this result code to LDAP v2 clients to refer them to
+     * another LDAP server. When sending this code to a client, the server
+     * includes a newline-delimited list of LDAP URLs that identify another LDAP
+     * server. If the client identifies itself as an LDAP v3 client in the
+     * request, servers send an REFERRAL result code instead of this result
+     * code.
+     */
+    PARTIAL_RESULTS(9, "partialResults"),
+
+    /**
+     * It is used to indicate that the result of a Compare operation is FALSE
+     * and does not indicate an error. 1 of 5 codes that do not indicate an
+     * error condition. Applicable operations: Compare. Result code type:
+     * Non-Erroneous
+     */
+    COMPARE_FALSE(5, "compareFalse"),
+
+    /**
+     * It is used to indicate that the result of a Compare operation is TRUE and
+     * does not indicate an error. 1 of 5 codes that do not indicate an error
+     * condition. Applicable operations: Compare. Result code type:
+     * Non-Erroneous
+     */
+    COMPARE_TRUE(6, "compareTrue"),
+
+    /**
+     * Rather than indicating an error, this result code is used to indicate
+     * that the server does not hold the target entry of the request but is able
+     * to provide alternative servers that may. A set of server(s) URLs may be
+     * returned in the referral field, which the client may subsequently query
+     * to attempt to complete their operation. 1 of 5 codes that do not indicate
+     * an error condition yet requires further action on behalf of the client to
+     * complete the request. This result code is new in LDAPv3. Applicable
+     * operations: all. Result code type: Non-Erroneous
+     */
+    REFERRAL(10, "referral"),
+
+    /**
+     * This result code is not an error response from the server, but rather, is
+     * a request for bind continuation. The server requires the client to send a
+     * new bind request, with the same SASL mechanism, to continue the
+     * authentication process [RFC2251, Section 4.2.3]. This result code is new
+     * in LDAPv3. Applicable operations: Bind. Result code type: Non-Erroneous
+     */
+    SASL_BIND_IN_PROGRESS(14, "saslBindInProgress"),
+
+    // ------------------------------------------------------------------------
+    // Problem Specific Error Codes:
+    //
+    // Specific errors are used to indicate that a particular type of error
+    // has occurred. These error types are Name, Update, Attribute, Security,
+    // and Service.
+    // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
+    // Security Problem Specific Error Codes:
+    //
+    // A security error reports a problem in carrying out an operation for
+    // security reasons [X511, Section 12.7].
+    // ------------------------------------------------------------------------
+
+    /**
+     * This error code should be returned if the client requests, in a Bind
+     * request, an authentication method which is not supported or recognized by
+     * the server. Applicable operations: Bind. Result code type: Specific
+     * (Security)
+     */
+    AUTH_METHOD_NOT_SUPPORTED(7, "authMethodNotSupported"),
+
+    /**
+     * This error may be returned on a bind request if the server only accepts
+     * strong authentication or it may be returned when a client attempts an
+     * operation which requires the client to be strongly authenticated - for
+     * example Delete. This result code may also be returned in an unsolicited
+     * notice of disconnection if the server detects that an established
+     * underlying security association protecting communication between the
+     * client and server has unexpectedly failed or been compromised. [RFC2251,
+     * Section 4.4.1] Applicable operations: all. Result code type: Specific
+     * (Security)
+     */
+    STRONG_AUTH_REQUIRED(8, "strongAuthRequired"),
+
+    /**
+     * This error code may be returned if the session is not protected by a
+     * protocol which provides session confidentiality. For example, if the
+     * client did not establish a TLS connection using a cipher suite which
+     * provides confidentiality of the session before sending any other
+     * requests, and the server requires session confidentiality then the server
+     * may reject that request with a result code of confidentialityRequired.
+     * This error code is new in LDAPv3. Applicable operations: all. Result code
+     * type: Specific (Security)
+     */
+    CONFIDENTIALITY_REQUIRED(13, "confidentialityRequired"),
+
+    /**
+     * An alias was encountered in a situation where it was not allowed or where
+     * access was denied [X511, Section 12.5]. For example, if the client does
+     * not have read permission for the aliasedObjectName attribute and its
+     * value then the error aliasDereferencingProblem should be returned. [X511,
+     * Section 7.11.1.1] Notice that this error has similar meaning to
+     * INSUFFICIENT_ACCESS_RIGHTS (50), but is specific to Searching on an alias.
+     * Applicable operations: Search. Result code type: Specific (Security)
+     */
+    ALIAS_DEREFERENCING_PROBLEM(36, "aliasDereferencingProblem"),
+
+    /**
+     * This error should be returned by the server when the client has tried to
+     * use a method of authentication that is inappropriate, that is a method of
+     * authentication which the client is unable to use correctly. In other
+     * words, the level of security associated with the requestor's credentials
+     * is inconsistent with the level of protection requested, e.g. simple
+     * credentials were supplied while strong credentials were required [X511,
+     * Section 12.7]. Applicable operations: Bind. Result code type: Specific
+     * (Security)
+     */
+    INAPPROPRIATE_AUTHENTICATION(48, "inappropriateAuthentication"),
+
+    /**
+     * This error code is returned if the Dn or password used in a simple bind
+     * operation is incorrect, or if the Dn or password is incorrect for some
+     * other reason, e.g. the password has expired. This result code only
+     * applies to Bind operations -- it should not be returned for other
+     * operations if the client does not have sufficient permission to perform
+     * the requested operation - in this case the return code should be
+     * insufficientAccessRights. Applicable operations: Bind. Result code type:
+     * Specific (Security)
+     */
+    INVALID_CREDENTIALS(49, "invalidCredentials"),
+
+    /**
+     * The requestor does not have the right to carry out the requested
+     * operation [X511, Section 12.7]. Note that the more specific
+     * aliasDereferencingProblem is returned in case of a Search on an alias
+     * where the requestor has insufficientAccessRights. Applicable operations:
+     * all except for Bind. Result code type: Specific (Security)
+     */
+    INSUFFICIENT_ACCESS_RIGHTS(50, "insufficientAccessRights"),
+
+    // ------------------------------------------------------------------------
+    // Service Problem Specific Error Codes:
+    //
+    // A service error reports a problem related to the provision of the
+    // service [X511, Section 12.8].
+    // ------------------------------------------------------------------------
+
+    /**
+     * If the server requires that the client bind before browsing or modifying
+     * the directory, the server MAY reject a request other than binding,
+     * unbinding or an extended request with the "operationsError" result.
+     * [RFC2251, Section 4.2.1] Applicable operations: all except Bind. Result
+     * code type: Specific (Service)
+     */
+    OPERATIONS_ERROR(1, "operationsError"),
+
+    /**
+     * A protocol error should be returned by the server when an invalid or
+     * malformed request is received from the client. This may be a request that
+     * is not recognized as an LDAP request, for example, if a nonexistent
+     * operation were specified in LDAPMessage. As well, it may be the result of
+     * a request that is missing a required parameter, such as a search filter
+     * in a search request. If the server can return an error, which is more
+     * specific than protocolError, then this error should be returned instead.
+     * For example if the server does not recognize the authentication method
+     * requested by the client then the error authMethodNotSupported should be
+     * returned instead of protocolError. The server may return details of the
+     * error in the error string. Applicable operations: all. Result code type:
+     * Specific (Service)
+     */
+    PROTOCOL_ERROR(2, "protocolError"),
+
+    /**
+     * This error should be returned when the time to perform an operation has
+     * exceeded either the time limit specified by the client (which may only be
+     * set by the client in a search operation) or the limit specified by the
+     * server. If the time limit is exceeded on a search operation then the
+     * result is an arbitrary selection of the accumulated results [X511,
+     * Section 7.5]. Note that an arbitrary selection of results may mean that
+     * no results are returned to the client. If the LDAP server is a front end
+     * for an X.500 server, any operation that is chained may exceed the
+     * timelimit, therefore clients can expect to receive timelimitExceeded for
+     * all operations. For stand alone LDAP- Servers that do not implement
+     * chaining it is unlikely that operations other than search operations will
+     * exceed the defined timelimit. Applicable operations: all. Result code
+     * type: Specific (Service)
+     */
+    TIME_LIMIT_EXCEEDED(3, "timeLimitExceeded"),
+
+    /**
+     * This error should be returned when the number of results generated by a
+     * search exceeds the maximum number of results specified by either the
+     * client or the server. If the size limit is exceeded then the results of a
+     * search operation will be an arbitrary selection of the accumulated
+     * results, equal in number to the size limit [X511, Section 7.5].
+     * Applicable operations: Search. Result code type: Specific (Service)
+     */
+    SIZE_LIMIT_EXCEEDED(4, "sizeLimitExceeded"),
+
+    /**
+     * The server has reached some limit set by an administrative authority, and
+     * no partial results are available to return to the user [X511, Section
+     * 12.8]. For example, there may be an administrative limit to the number of
+     * entries a server will check when gathering potential search result
+     * candidates [Net]. This error code is new in LDAPv3. Applicable
+     * operations: all. Result code type: Specific (Service)
+     */
+    ADMIN_LIMIT_EXCEEDED(11, "adminLimitExceeded"),
+
+    /**
+     * The server was unable to satisfy the request because one or more critical
+     * extensions were not available [X511, Section 12.8]. This error is
+     * returned, for example, when a control submitted with a request is marked
+     * critical but is not recognized by a server or when such a control is not
+     * appropriate for the operation type. [RFC2251 section 4.1.12]. This error
+     * code is new in LDAPv3. Applicable operations: all. Result code type:
+     * Specific (Service)
+     */
+    UNAVAILABLE_CRITICAL_EXTENSION(12, "unavailableCriticalExtension"),
+
+    /**
+     * This error code may be returned if the server is unable to process the
+     * client's request at this time. This implies that if the client retries
+     * the request shortly the server will be able to process it then.
+     * Applicable operations: all. Result code type: Specific (Service)
+     */
+    BUSY(51, "busy"),
+
+    /**
+     * This error code is returned when the server is unavailable to process the
+     * client's request. This usually means that the LDAP server is shutting
+     * down [RFC2251, Section 4.2.3]. Applicable operations: all. Result code
+     * type: Specific (Service)
+     */
+    UNAVAILABLE(52, "unavailable"),
+
+    /**
+     * This error code should be returned by the server when a client request is
+     * properly formed but which the server is unable to complete due to
+     * server-defined restrictions. For example, the server, or some part of it,
+     * is not prepared to execute this request, e.g. because it would lead to
+     * excessive consumption of resources or violates the policy of an
+     * Administrative Authority involved [X511, Section 12.8]. If the server is
+     * able to return a more specific error code such as adminLimitExceeded it
+     * should. This error may also be returned if the client attempts to modify
+     * attributes which can not be modified by users, e.g., operational
+     * attributes such as creatorsName or createTimestamp [X511, Section 7.12].
+     * If appropriate, details of the error should be provided in the error
+     * message. Applicable operations: all. Result code type: Specific (Service)
+     */
+    UNWILLING_TO_PERFORM(53, "unwillingToPerform"),
+
+    /**
+     * This error may be returned by the server if it detects an alias or
+     * referral loop, and is unable to satisfy the client's request. Applicable
+     * operations: all. Result code type: Specific (Service)
+     */
+    LOOP_DETECT(54, "loopDetect"),
+
+    // ------------------------------------------------------------------------
+    // Attribute Problem Specific Error Codes:
+    //
+    // An attribute error reports a problem related to an attribute specified
+    // by the client in their request message.
+    // ------------------------------------------------------------------------
+
+    /**
+     * This error may be returned if the attribute specified as an argument of
+     * the operation does not exist in the entry. Applicable operations: Modify,
+     * Compare. Result code type: Specific (Attribute)
+     */
+    NO_SUCH_ATTRIBUTE(16, "noSuchAttribute"),
+
+    /**
+     * This error may be returned if the specified attribute is unrecognized by
+     * the server, since it is not present in the server's defined schema. If
+     * the server doesn't recognize an attribute specified in a search request
+     * as the attribute to be returned the server should not return an error in
+     * this case - it should just return values for the requested attributes it
+     * does recognize. Note that this result code only applies to the Add and
+     * Modify operations [X.511, Section 12.4]. Applicable operations: Modify,
+     * Add. Result code type: Specific (Attribute)
+     */
+    UNDEFINED_ATTRIBUTE_TYPE(17, "undefinedAttributeType"),
+
+    /**
+     * An attempt was made, e.g., in a filter, to use a matching rule not
+     * defined for the attribute type concerned [X511, Section 12.4]. Applicable
+     * operations: Search. Result code type: Specific (Attribute)
+     */
+    INAPPROPRIATE_MATCHING(18, "inappropriateMatching"),
+
+    /**
+     * This error should be returned by the server if an attribute value
+     * specified by the client violates the constraints placed on the attribute
+     * as it was defined in the DSA - this may be a size constraint or a
+     * constraint on the content. Applicable operations: Modify, Add, ModifyDN.
+     * Result code type: Specific (Attribute)
+     */
+    CONSTRAINT_VIOLATION(19, "constraintViolation"),
+
+    /**
+     * This error should be returned by the server if the value specified by the
+     * client already exists within the attribute. Applicable operations:
+     * Modify, Add. Result code type: Specific (Attribute)
+     */
+    ATTRIBUTE_OR_VALUE_EXISTS(20, "attributeOrValueExists"),
+
+    /**
+     * This error should be returned by the server if the attribute syntax for
+     * the attribute value, specified as an argument of the operation, is
+     * unrecognized or invalid. Applicable operations: Modify, Add. Result code
+     * type: Specific (Attribute)
+     */
+    INVALID_ATTRIBUTE_SYNTAX(21, "invalidAttributeSyntax"),
+
+    // ------------------------------------------------------------------------
+    // Name Problem Specific Error Codes:
+    //
+    // A name error reports a problem related to the distinguished name
+    // provided as an argument to an operation [X511, Section 12.5].
+    //
+    // For result codes of NO_SUCH_OBJECT, aliasProblem, invalidDNSyntax and
+    // aliasDereferencingProblem (see Section 5.2.2.3.7), the matchedDN
+    // field is set to the name of the lowest entry (object or alias) in the
+    // directory that was matched. If no aliases were dereferenced while
+    // attempting to locate the entry, this will be a truncated form of the
+    // name provided, or if aliases were dereferenced, of the resulting
+    // name, as defined in section 12.5 of X.511 [X511]. The matchedDN field
+    // is to be set to a zero length string with all other result codes
+    // [RFC2251, Section 4.1.10].
+    // ------------------------------------------------------------------------
+
+    /**
+     * This error should only be returned if the target object cannot be found.
+     * For example, in a search operation if the search base can not be located
+     * in the DSA the server should return NO_SUCH_OBJECT. If, however, the search
+     * base is found but does not match the search filter, success, with no
+     * resultant objects, should be returned instead of NO_SUCH_OBJECT. If the
+     * LDAP server is a front end for an X.500 DSA then NO_SUCH_OBJECT may also be
+     * returned if discloseOnError is not granted for an entry and the client
+     * does not have permission to view or modify the entry. Applicable
+     * operations: all except for Bind. Result code type: Specific (Name)
+     */
+    NO_SUCH_OBJECT(32, "NO_SUCH_OBJECT"),
+
+    /**
+     * An alias has been dereferenced which names no object [X511, Section 12.5]
+     * Applicable operations: Search. Result code type: Specific (Name)
+     */
+    ALIAS_PROBLEM(33, "aliasProblem"),
+
+    /**
+     * This error should be returned by the server if the Dn syntax is
+     * incorrect. It should not be returned if the Dn is correctly formed but
+     * represents an entry which is not permitted by the structure rules at the
+     * DSA ; in this case namingViolation should be returned instead. Applicable
+     * operations: all. Result code type: Specific (Name)
+     */
+    INVALID_DN_SYNTAX(34, "invalidDNSyntax"),
+
+    // ------------------------------------------------------------------------
+    // Update Problem Specific Error Codes:
+    //
+    // An update error reports problems related to attempts to add, delete, or
+    // modify information in the DIB [X511, Section 12.9].
+    // ------------------------------------------------------------------------
+
+    /**
+     * The attempted addition or modification would violate the structure rules
+     * of the DIT as defined in the directory schema and X.501. That is, it
+     * would place an entry as the subordinate of an alias entry, or in a region
+     * of the DIT not permitted to a member of its object class, or would define
+     * an Rdn for an entry to include a forbidden attribute type [X511, Section
+     * 12.9]. Applicable operations: Add, ModifyDN. Result code type: Specific
+     * (Update)
+     */
+    NAMING_VIOLATION(64, "namingViolation"),
+
+    /**
+     * This error should be returned if the operation requested by the user
+     * would violate the objectClass requirements for the entry if carried out.
+     * On an add or modify operation this would result from trying to add an
+     * object class without a required attribute, or by trying to add an
+     * attribute which is not permitted by the current object class set in the
+     * entry. On a modify operation this may result from trying to remove a
+     * required attribute without removing the associated auxiliary object
+     * class, or by attempting to remove an object class while the attributes it
+     * permits are still present. Applicable operations: Add, Modify, ModifyDN.
+     * Result code type: Specific (Update)
+     */
+    OBJECT_CLASS_VIOLATION(65, "objectClassViolation"),
+
+    /**
+     * This error should be returned if the client attempts to perform an
+     * operation which is permitted only on leaf entries - e.g., if the client
+     * attempts to delete a non-leaf entry. If the directory does not permit
+     * ModifyDN for non-leaf entries then this error may be returned if the
+     * client attempts to change the Dn of a non-leaf entry. (Note that 1988
+     * edition X.500 servers only permitted change of the Rdn of an entry's Dn
+     * [X.511, Section 11.4.1]). Applicable operations: Delete, ModifyDN. Result
+     * code type: Specific (Update)
+     */
+    NOT_ALLOWED_ON_NON_LEAF(66, "notAllowedOnNonLeaf"),
+
+    /**
+     * The attempted operation would affect the Rdn (e.g., removal of an
+     * attribute which is a part of the Rdn) [X511, Section 12.9]. If the client
+     * attempts to remove from an entry any of its distinguished values, those
+     * values which form the entry's relative distinguished name the server
+     * should return the error notAllowedOnRDN. [RFC2251, Section 4.6]
+     * Applicable operations: Modify. Result code type: Specific (Update)
+     */
+    NOT_ALLOWED_ON_RDN(67, "notAllowedOnRDN"),
+
+    /**
+     * This error should be returned by the server when the client attempts to
+     * add an entry which already exists, or if the client attempts to rename an
+     * entry with the name of an entry which exists. Applicable operations: Add,
+     * ModifyDN. Result code type: Specific (Update)
+     */
+    ENTRY_ALREADY_EXISTS(68, "entryAlreadyExists"),
+
+    /**
+     * An operation attempted to modify an object class that should not be
+     * modified, e.g., the structural object class of an entry. Some servers may
+     * not permit object class modifications, especially modifications to the
+     * structural object class since this may change the entry entirely, name
+     * forms, structure rules etc. [X.511, Section 12.9]. Applicable operations:
+     * Modify. Result code type: Specific (Update)
+     */
+    OBJECT_CLASS_MODS_PROHIBITED(69, "objectClassModsProhibited"),
+
+    /**
+     * This error code should be returned to indicate that the operation could
+     * not be performed since it affects more than one DSA. This error code is
+     * new for LDAPv3. X.500 restricts the ModifyDN operation to only affect
+     * entries that are contained within a single server. If the LDAP server is
+     * mapped onto DAP, then this restriction will apply, and the resultCode
+     * affectsMultipleDSAs will be returned if this error occurred. In general
+     * clients MUST NOT expect to be able to perform arbitrary movements of
+     * entries and subtrees between servers [RFC2251, Section 4.9]. Applicable
+     * operations: ModifyDN. Result code type: Specific (Update)
+     */
+    AFFECTS_MULTIPLE_DSAS(71, "affectsMultipleDSAs"),
+
+    // ------------------------------------------------------------------------
+    // General Error Codes:
+    //
+    // A general error code typically specifies an error condition for which
+    // there is no suitable specific error code. If the server can return an
+    // error, which is more specific than the following general errors, then
+    // the specific error should be returned instead.
+    // ------------------------------------------------------------------------
+
+    /**
+     * This error code should be returned only if no other error code is
+     * suitable. Use of this error code should be avoided if possible. Details
+     * of the error should be provided in the error message. Applicable
+     * operations: all. Result code type: General
+     */
+    OTHER(80, "other"),
+
+    /**
+     * This error code is returned when an operation has been canceled using
+     * the Cancel extended operation. 
+     */
+    CANCELED(118, "canceled"),
+
+    /**
+     * This error code is returned if the server has no knowledge of
+     * the operation requested for cancelation.
+     */
+    NO_SUCH_OPERATION(119, "noSuchOperation"),
+
+    /**
+     * The tooLate resultCode is returned to indicate that it is too late to
+     * cancel the outstanding operation.  For example, the server may return
+     * tooLate for a request to cancel an outstanding modify operation which
+     * has already committed updates to the underlying data store.
+     */
+    TOO_LATE(120, "tooLate"),
+
+    /**
+     * The cannotCancel resultCode is returned if the identified operation
+     * does not support cancelation or the cancel operation could not be
+     * performed.  The following classes of operations are not cancelable:
+     *
+     * -  operations which have no response,
+     *
+     * -  operations which create, alter, or destroy authentication and/or
+     *    authorization associations,
+     *
+     * -  operations which establish, alter, or tear-down security services,
+     *    and
+     *
+     * -  operations which abandon or cancel other operations.
+     */
+    CANNOT_CANCEL(121, "cannotCancel"),
+
+    /**
+     * The server may return this result code on the initial content poll
+     * if it is safe to do so when it is unable to perform the operation
+     * due to various reasons. For more detailed explanation refer 
+     * <a href="http://www.faqs.org/rfcs/rfc4533.html">RFC 4533 (a.k.a syncrepl)</a>
+     */
+    E_SYNC_REFRESH_REQUIRED(4096, "eSyncRefreshRequired"),
+
+    /**
+     * A unknown result code to cover all the other cases
+     */
+    // -- 15 unused --
+    // -- 22-31 unused --
+    // -- 35 reserved for undefined isLeaf --
+    // -- 37-47 unused --
+    // -- 55-63 unused --
+    // -- 70 reserved for CLDAP --
+    // -- 72-79 unused --
+    // -- 81-90 reserved for APIs --
+    UNKNOWN(122, "unknown");
+
+    /** Stores the integer value of each element of the enumeration */
+    private int value;
+
+    /** Stores the description of each element of the enumeration */
+    private String message;
+
+
+    /**
+     * Private construct so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param value the integer value of the enumeration.
+     * @param message the description of the enumeration.
+     */
+    private ResultCodeEnum( int value, String message )
+    {
+        this.value = value;
+        this.message = message;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * @return The description associated with the current element.
+     */
+    public String getMessage()
+    {
+        return message;
+    }
+
+    private static final Set<ResultCodeEnum> EMPTY_RESULT_CODE_SET = new HashSet<ResultCodeEnum>();
+
+    // ------------------------------------------------------------------------
+    // Error Codes Grouped Into Categories & Static Accessors
+    // ------------------------------------------------------------------------
+
+    /**
+     * Five result codes that may be returned in LDAPResult are not used to
+     * indicate an error. The first three codes, indicate to the client that no
+     * further action is required in order to satisfy their request. In
+     * contrast, the last two errors require further action by the client in
+     * order to complete their original operation request. The set contains:
+     * <ul>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#COMPARETRUE">COMPARETRUE</a></li>
+     * <li><a href="#COMPAREFALSE">COMPAREFALSE</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#SASL_BIND_IN_PROGRESS">SASL_BIND_IN_PROGRESS</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> NON_ERRONEOUS_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.COMPARE_TRUE );
+        set.add( ResultCodeEnum.COMPARE_FALSE );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.SASL_BIND_IN_PROGRESS );
+        set.add( ResultCodeEnum.CANCELED );
+        NON_ERRONEOUS_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations that may result from bind operations.
+     * The set contains:
+     * <ul>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#SASL_BIND_IN_PROGRESS">SASL_BIND_IN_PROGRESS</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#INVALID_CREDENTIALS">INVALID_CREDENTIALS</a></li>
+     * <li><a href="#AUTH_METHOD_NOT_SUPPORTED">AUTH_METHOD_NOT_SUPPORTED</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#INAPPROPRIATE_AUTHENTICATION">INAPPROPRIATE_AUTHENTICATION</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> BIND_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.SASL_BIND_IN_PROGRESS );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.INVALID_CREDENTIALS );
+        set.add( ResultCodeEnum.AUTH_METHOD_NOT_SUPPORTED );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.INAPPROPRIATE_AUTHENTICATION );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CANCELED );
+        BIND_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations that may result from search operations.
+     * The set contains:
+     * <ul>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</a></li>
+     * <li><a href="#ALIAS_PROBLEM">ALIAS_PROBLEM</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#SIZE_LIMIT_EXCEEDED">SIZE_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#INAPPROPRIATE_MATCHING">INAPPROPRIATE_MATCHING</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</a></li>
+     * <li><a href="#ALIAS_DEREFERENCING_PROBLEM">ALIAS_DEREFERENCING_PROBLEM</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> SEARCH_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.NO_SUCH_OBJECT );
+        set.add( ResultCodeEnum.ALIAS_PROBLEM );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.SIZE_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.INAPPROPRIATE_MATCHING );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS );
+        set.add( ResultCodeEnum.ALIAS_DEREFERENCING_PROBLEM );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CANCELED );
+        set.add( ResultCodeEnum.E_SYNC_REFRESH_REQUIRED );
+        SEARCH_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations that may result from modify operations.
+     * The set contains:
+     * <ul>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#NOT_ALLOWED_ON_RDN">NOT_ALLOWED_ON_RDN</a></li>
+     * <li><a href="#NO_SUCH_ATTRIBUTE">NO_SUCH_ATTRIBUTE</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#CONSTRAINT_VIOLATION">CONSTRAINT_VIOLATION</a></li>
+     * <li><a href="#OBJECT_CLASS_VIOLATION">OBJECT_CLASS_VIOLATION</a></li>
+     * <li><a href="#INVALID_ATTRIBUTE_SYNTAX">INVALID_ATTRIBUTE_SYNTAX</a></li>
+     * <li><a href="#UNDEFINED_ATTRIBUTE_TYPE">UNDEFINED_ATTRIBUTE_TYPE</a></li>
+     * <li><a href="#ATTRIBUTE_OR_VALUE_EXISTS">ATTRIBUTE_OR_VALUE_EXISTS</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</a></li>
+     * <li><a href="#OBJECT_CLASS_MODS_PROHIBITED">OBJECT_CLASS_MODS_PROHIBITED</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> MODIFY_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.NO_SUCH_OBJECT );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.NOT_ALLOWED_ON_RDN );
+        set.add( ResultCodeEnum.NO_SUCH_ATTRIBUTE );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.CONSTRAINT_VIOLATION );
+        set.add( ResultCodeEnum.OBJECT_CLASS_VIOLATION );
+        set.add( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
+        set.add( ResultCodeEnum.UNDEFINED_ATTRIBUTE_TYPE );
+        set.add( ResultCodeEnum.ATTRIBUTE_OR_VALUE_EXISTS );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS );
+        set.add( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CANCELED );
+        MODIFY_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations that may result from add operations.
+     * The set contains:
+     * <ul>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#NAMING_VIOLATION">NAMING_VIOLATION</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#ENTRY_ALREADY_EXISTS">ENTRY_ALREADY_EXISTS</a></li>
+     * <li><a href="#CONSTRAINT_VIOLATION">CONSTRAINT_VIOLATION</a></li>
+     * <li><a href="#OBJECT_CLASS_VIOLATION">OBJECT_CLASS_VIOLATION</a></li>
+     * <li><a href="#INVALID_ATTRIBUTE_SYNTAX">INVALID_ATTRIBUTE_SYNTAX</a></li>
+     * <li><a href="#ATTRIBUTE_OR_VALUE_EXISTS">ATTRIBUTE_OR_VALUE_EXISTS</a></li>
+     * <li><a href="#UNDEFINED_ATTRIBUTE_TYPE">UNDEFINED_ATTRIBUTE_TYPE</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> ADD_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.NO_SUCH_OBJECT );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.NAMING_VIOLATION );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.ENTRY_ALREADY_EXISTS );
+        set.add( ResultCodeEnum.CONSTRAINT_VIOLATION );
+        set.add( ResultCodeEnum.OBJECT_CLASS_VIOLATION );
+        set.add( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
+        set.add( ResultCodeEnum.ATTRIBUTE_OR_VALUE_EXISTS );
+        set.add( ResultCodeEnum.UNDEFINED_ATTRIBUTE_TYPE );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CANCELED );
+        ADD_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations that may result from delete operations.
+     * The set may contain:
+     * <ul>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#NOT_ALLOWED_ON_NON_LEAF">NOT_ALLOWED_ON_NON_LEAF</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> DELETE_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.NO_SUCH_OBJECT );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.NOT_ALLOWED_ON_NON_LEAF );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CANCELED );
+        DELETE_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations resulting from modifyDn operations. The
+     * set contains:
+     * <ul>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#NAMING_VIOLATION">NAMING_VIOLATION</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#ENTRY_ALREADY_EXISTS">ENTRY_ALREADY_EXISTS</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#NOT_ALLOWED_ON_NON_LEAF">NOT_ALLOWED_ON_NON_LEAF</a></li>
+     * <li><a href="#AFFECTS_MULTIPLE_DSAS">AFFECTS_MULTIPLE_DSAS</a></li>
+     * <li><a href="#CONSTRAINT_VIOLATION">CONSTRAINT_VIOLATION</a></li>
+     * <li><a href="#OBJECT_CLASS_VIOLATION">OBJECT_CLASS_VIOLATION</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> MODIFYDN_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.NO_SUCH_OBJECT );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.NAMING_VIOLATION );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.ENTRY_ALREADY_EXISTS );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.NOT_ALLOWED_ON_NON_LEAF );
+        set.add( ResultCodeEnum.AFFECTS_MULTIPLE_DSAS );
+        set.add( ResultCodeEnum.CONSTRAINT_VIOLATION );
+        set.add( ResultCodeEnum.OBJECT_CLASS_VIOLATION );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CANCELED );
+        MODIFYDN_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations that may result from compare
+     * operations. The set contains:
+     * <ul>
+     * <li><a href="#OPERATIONSERROR">OPERATIONSERROR</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#COMPAREFALSE">COMPAREFALSE</a></li>
+     * <li><a href="#COMPARETRUE">COMPARETRUE</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#NO_SUCH_ATTRIBUTE">NO_SUCH_ATTRIBUTE</a></li>
+     * <li><a href="#INVALID_ATTRIBUTE_SYNTAX">INVALID_ATTRIBUTE_SYNTAX</a></li>
+     * <li><a href="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</a></li>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> COMPARE_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.OPERATIONS_ERROR );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.COMPARE_FALSE );
+        set.add( ResultCodeEnum.COMPARE_TRUE );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.NO_SUCH_ATTRIBUTE );
+        set.add( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
+        set.add( ResultCodeEnum.NO_SUCH_OBJECT );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS );
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.CANCELED );
+        COMPARE_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of result code enumerations that could result from extended
+     * operations. The set contains:
+     * <ul>
+     * <li></li>
+     * <li><a href="#SUCCESS">SUCCESS</a></li>
+     * <li><a href="#OPERATIONSERROR">OPERATIONSERROR</a></li>
+     * <li><a href="#PROTOCOL_ERROR">PROTOCOL_ERROR</a></li>
+     * <li><a href="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#SIZE_LIMIT_EXCEEDED">SIZE_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#COMPAREFALSE">COMPAREFALSE</a></li>
+     * <li><a href="#COMPARETRUE">COMPARETRUE</a></li>
+     * <li><a href="#AUTH_METHOD_NOT_SUPPORTED">AUTH_METHOD_NOT_SUPPORTED</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</a></li>
+     * <li><a href="#REFERRAL">REFERRAL</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</a></li>
+     * <li><a href="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</a></li>
+     * <li><a href="#SASL_BIND_IN_PROGRESS">SASL_BIND_IN_PROGRESS</a></li>
+     * <li><a href="#NO_SUCH_ATTRIBUTE">NO_SUCH_ATTRIBUTE</a></li>
+     * <li><a href="#UNDEFINED_ATTRIBUTE_TYPE">UNDEFINED_ATTRIBUTE_TYPE</a></li>
+     * <li><a href="#INAPPROPRIATE_MATCHING">INAPPROPRIATE_MATCHING</a></li>
+     * <li><a href="#CONSTRAINT_VIOLATION">CONSTRAINT_VIOLATION</a></li>
+     * <li><a href="#ATTRIBUTE_OR_VALUE_EXISTS">ATTRIBUTE_OR_VALUE_EXISTS</a></li>
+     * <li><a href="#INVALID_ATTRIBUTE_SYNTAX">INVALID_ATTRIBUTE_SYNTAX</a></li>
+     * <li><a href="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</a></li>
+     * <li><a href="#ALIAS_PROBLEM">ALIAS_PROBLEM</a></li>
+     * <li><a href="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</a></li>
+     * <li><a href="#ALIAS_DEREFERENCING_PROBLEM">ALIAS_DEREFERENCING_PROBLEM</a></li>
+     * <li><a href="#INAPPROPRIATE_AUTHENTICATION">INAPPROPRIATE_AUTHENTICATION</a></li>
+     * <li><a href="#INVALID_CREDENTIALS">INVALID_CREDENTIALS</a></li>
+     * <li><a href="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</a></li>
+     * <li><a href="#BUSY">BUSY</a></li>
+     * <li><a href="#UNAVAILABLE">UNAVAILABLE</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</a></li>
+     * <li><a href="#LOOP_DETECT">LOOP_DETECT</a></li>
+     * <li><a href="#NAMING_VIOLATION">NAMING_VIOLATION</a></li>
+     * <li><a href="#OBJECT_CLASS_VIOLATION">OBJECT_CLASS_VIOLATION</a></li>
+     * <li><a href="#NOT_ALLOWED_ON_NON_LEAF">NOT_ALLOWED_ON_NON_LEAF</a></li>
+     * <li><a href="#NOT_ALLOWED_ON_RDN">NOT_ALLOWED_ON_RDN</a></li>
+     * <li><a href="#ENTRY_ALREADY_EXISTS">ENTRY_ALREADY_EXISTS</a></li>
+     * <li><a href="#OBJECT_CLASS_MODS_PROHIBITED">OBJECT_CLASS_MODS_PROHIBITED</a></li>
+     * <li><a href="#AFFECTS_MULTIPLE_DSAS">AFFECTS_MULTIPLE_DSAS</a></li>
+     * <li><a href="#OTHER">OTHER</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> EXTENDED_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.SUCCESS );
+        set.add( ResultCodeEnum.OPERATIONS_ERROR );
+        set.add( ResultCodeEnum.PROTOCOL_ERROR );
+        set.add( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.SIZE_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.COMPARE_FALSE );
+        set.add( ResultCodeEnum.COMPARE_TRUE );
+        set.add( ResultCodeEnum.AUTH_METHOD_NOT_SUPPORTED );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.SASL_BIND_IN_PROGRESS );
+        set.add( ResultCodeEnum.NO_SUCH_ATTRIBUTE );
+        set.add( ResultCodeEnum.UNDEFINED_ATTRIBUTE_TYPE );
+        set.add( ResultCodeEnum.INAPPROPRIATE_MATCHING );
+        set.add( ResultCodeEnum.CONSTRAINT_VIOLATION );
+        set.add( ResultCodeEnum.ATTRIBUTE_OR_VALUE_EXISTS );
+        set.add( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
+        set.add( ResultCodeEnum.NO_SUCH_OBJECT );
+        set.add( ResultCodeEnum.ALIAS_PROBLEM );
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.ALIAS_DEREFERENCING_PROBLEM );
+        set.add( ResultCodeEnum.INAPPROPRIATE_AUTHENTICATION );
+        set.add( ResultCodeEnum.INVALID_CREDENTIALS );
+        set.add( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS );
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.NAMING_VIOLATION );
+        set.add( ResultCodeEnum.OBJECT_CLASS_VIOLATION );
+        set.add( ResultCodeEnum.NOT_ALLOWED_ON_NON_LEAF );
+        set.add( ResultCodeEnum.NOT_ALLOWED_ON_RDN );
+        set.add( ResultCodeEnum.ENTRY_ALREADY_EXISTS );
+        set.add( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
+        set.add( ResultCodeEnum.AFFECTS_MULTIPLE_DSAS );
+        set.add( ResultCodeEnum.OTHER );
+        set.add( ResultCodeEnum.CANCELED );
+        EXTENDED_CODES = Collections.unmodifiableSet( set );
+    }
+
+
+    /**
+     * @return The integer associated with the result code
+     */
+    public int getResultCode()
+    {
+        return value;
+    }
+
+
+    /**
+     * @return The integer associated with the result code
+     */
+    public static ResultCodeEnum getResultCode( int value )
+    {
+        switch ( value )
+        {
+            case 0:
+                return SUCCESS;
+            case 1:
+                return OPERATIONS_ERROR;
+            case 2:
+                return PROTOCOL_ERROR;
+            case 3:
+                return TIME_LIMIT_EXCEEDED;
+            case 4:
+                return SIZE_LIMIT_EXCEEDED;
+            case 5:
+                return COMPARE_FALSE;
+            case 6:
+                return COMPARE_TRUE;
+            case 7:
+                return AUTH_METHOD_NOT_SUPPORTED;
+            case 8:
+                return STRONG_AUTH_REQUIRED;
+            case 9:
+                return PARTIAL_RESULTS;
+            case 10:
+                return REFERRAL;
+            case 11:
+                return ADMIN_LIMIT_EXCEEDED;
+            case 12:
+                return UNAVAILABLE_CRITICAL_EXTENSION;
+            case 13:
+                return CONFIDENTIALITY_REQUIRED;
+            case 14:
+                return SASL_BIND_IN_PROGRESS;
+            case 16:
+                return NO_SUCH_ATTRIBUTE;
+            case 17:
+                return UNDEFINED_ATTRIBUTE_TYPE;
+            case 18:
+                return INAPPROPRIATE_MATCHING;
+            case 19:
+                return CONSTRAINT_VIOLATION;
+            case 20:
+                return ATTRIBUTE_OR_VALUE_EXISTS;
+            case 21:
+                return INVALID_ATTRIBUTE_SYNTAX;
+            case 32:
+                return NO_SUCH_OBJECT;
+            case 33:
+                return ALIAS_PROBLEM;
+            case 34:
+                return INVALID_DN_SYNTAX;
+            case 35:
+                return UNKNOWN;
+            case 36:
+                return ALIAS_DEREFERENCING_PROBLEM;
+            case 48:
+                return INAPPROPRIATE_AUTHENTICATION;
+            case 49:
+                return INVALID_CREDENTIALS;
+            case 50:
+                return INSUFFICIENT_ACCESS_RIGHTS;
+            case 51:
+                return BUSY;
+            case 52:
+                return UNAVAILABLE;
+            case 53:
+                return UNWILLING_TO_PERFORM;
+            case 54:
+                return LOOP_DETECT;
+            case 64:
+                return NAMING_VIOLATION;
+            case 65:
+                return OBJECT_CLASS_VIOLATION;
+            case 66:
+                return NOT_ALLOWED_ON_NON_LEAF;
+            case 67:
+                return NOT_ALLOWED_ON_RDN;
+            case 68:
+                return ENTRY_ALREADY_EXISTS;
+            case 69:
+                return OBJECT_CLASS_MODS_PROHIBITED;
+            case 71:
+                return AFFECTS_MULTIPLE_DSAS;
+            case 80:
+                return OTHER;
+            case 118:
+                return CANCELED;
+            case 119:
+                return NO_SUCH_OPERATION;
+            case 120:
+                return TOO_LATE;
+            case 121:
+                return CANNOT_CANCEL;
+            case 4096:
+                return E_SYNC_REFRESH_REQUIRED;
+            default:
+                return UNKNOWN;
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Getting Result Code Enumeration Object Using Integer Values
+    // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
+    // JNDI Exception to ResultCodeEnum Mappings
+    // ------------------------------------------------------------------------
+
+    /**
+     * A set of ResultCodes containing those that may correspond to NamingException.
+     * <ul>
+     * <li><a href="#OPERATIONSERROR">operationsError(1)</a></li>
+     * <li><a href="#ALIAS_PROBLEM">aliasProblem(33)</a></li>
+     * <li><a href="#ALIAS_DEREFERENCING_PROBLEM">aliasDereferencingProblem(36)</a></li>
+     * <li><a href="#LOOP_DETECT">loopDetect(54)</a></li>
+     * <li><a href="#AFFECTS_MULTIPLE_DSAS">affectsMultipleDSAs(71)</a></li>
+     * <li><a href="#OTHER">other(80)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> NAMING_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.OPERATIONS_ERROR );
+        set.add( ResultCodeEnum.ALIAS_PROBLEM );
+        set.add( ResultCodeEnum.ALIAS_DEREFERENCING_PROBLEM );
+        set.add( ResultCodeEnum.LOOP_DETECT );
+        set.add( ResultCodeEnum.AFFECTS_MULTIPLE_DSAS );
+        set.add( ResultCodeEnum.OTHER );
+        NAMING_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link Exception}.
+     * <ul>
+     * <li><a href="#AUTH_METHOD_NOT_SUPPORTED">authMethodNotSupported(7)</a></li>
+     * <li><a href="#STRONG_AUTH_REQUIRED">strongAuthRequired(8)</a></li>
+     * <li><a href="#CONFIDENTIALITY_REQUIRED">confidentialityRequired(13)</a></li>
+     * <li><a
+     * href="#INAPPROPRIATE_AUTHENTICATION">inappropriateAuthentication(48)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> AUTHENTICATION_NOT_SUPPORTED_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.AUTH_METHOD_NOT_SUPPORTED );
+        set.add( ResultCodeEnum.STRONG_AUTH_REQUIRED );
+        set.add( ResultCodeEnum.CONFIDENTIALITY_REQUIRED );
+        set.add( ResultCodeEnum.INAPPROPRIATE_AUTHENTICATION );
+        AUTHENTICATION_NOT_SUPPORTED_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link Exception}.
+     * <ul>
+     * <li><a href="#BUSY">busy(51)</a></li>
+     * <li><a href="#UNAVAILABLE">unavailable(52)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> SERVICE_UNAVAILABLE_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.BUSY );
+        set.add( ResultCodeEnum.UNAVAILABLE );
+        SERVICE_UNAVAILABLE_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link Exception}.
+     * <ul>
+     * <li><a href="#CONSTRAINT_VIOLATION">constraintViolation(19)</a></li>
+     * <li><a href="#INVALID_ATTRIBUTE_SYNTAX">invalidAttributeSyntax(21)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> INVALID_ATTRIBUTE_VALUE_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.CONSTRAINT_VIOLATION );
+        set.add( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
+        INVALID_ATTRIBUTE_VALUE_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link Exception}.
+     * <ul>
+     * <li><a href="#PARTIAL_RESULTS">partialResults(9)</a></li>
+     * <li><a href="#REFERRAL">referral(10)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> PARTIAL_RESULTS_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.PARTIAL_RESULTS );
+        set.add( ResultCodeEnum.REFERRAL );
+        PARTIAL_RESULTS_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link Exception}.
+     * <ul>
+     * <li><a href="#REFERRAL">referal(9)</a></li>
+     * <li><a href="#ADMIN_LIMIT_EXCEEDED">adminLimitExceeded(11)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> LIMIT_EXCEEDED_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.REFERRAL );
+        set.add( ResultCodeEnum.ADMIN_LIMIT_EXCEEDED );
+        LIMIT_EXCEEDED_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link Exception}.
+     * <ul>
+     * <li><a
+     * href="#UNAVAILABLECRITICALEXTENTION">unavailableCriticalExtention(12)</a></li>
+     * <li><a href="#UNWILLING_TO_PERFORM">unwillingToPerform(53)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> OPERATION_NOT_SUPPORTED_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION );
+        set.add( ResultCodeEnum.UNWILLING_TO_PERFORM );
+        OPERATION_NOT_SUPPORTED_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link Exception}.
+     * <ul>
+     * <li><a href="#INVALID_DN_SYNTAX">invalidDNSyntax(34)</a></li>
+     * <li><a href="#NAMING_VIOLATION">namingViolation(64)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> INVALID_NAME_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.INVALID_DN_SYNTAX );
+        set.add( ResultCodeEnum.NAMING_VIOLATION );
+        INVALID_NAME_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+    /**
+     * A set of ResultCodes containing those that may correspond to a
+     * {@link javax.naming.directory.SchemaViolationException}.
+     * <ul>
+     * <li><a href="#OBJECT_CLASS_VIOLATION">objectClassViolation(65)</a></li>
+     * <li><a href="#NOT_ALLOWED_ON_RDN">notAllowedOnRDN(67)</a></li>
+     * <li><a href="#OBJECT_CLASS_MODS_PROHIBITED">objectClassModsProhibited(69)</a></li>
+     * </ul>
+     */
+    private static final Set<ResultCodeEnum> SCHEMA_VIOLATION_EXCEPTION_CODES;
+
+    static
+    {
+        Set<ResultCodeEnum> set = new HashSet<ResultCodeEnum>();
+        set.add( ResultCodeEnum.OBJECT_CLASS_VIOLATION );
+        set.add( ResultCodeEnum.NOT_ALLOWED_ON_RDN );
+        set.add( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
+        SCHEMA_VIOLATION_EXCEPTION_CODES = Collections.unmodifiableSet( set );
+    }
+
+
+    /**
+     * Takes a guess at the result code to use if it cannot figure it out from
+     * known Throwable to result code mappings. Some however are ambiguous
+     * mapping the same Throwable to multiple codes. If no code can be resolved
+     * then {@link ResultCodeEnum#OTHER} is returned.
+     * 
+     * @param t
+     *            the throwable to estimate a result code for
+     * @param type
+     *            the type of operation being performed
+     * @return the result code or a good estimate of one
+     */
+    public static ResultCodeEnum getBestEstimate( Throwable t, MessageTypeEnum type )
+    {
+        Set<ResultCodeEnum> set = getResultCodes( t );
+
+        if ( set.isEmpty() )
+        {
+            return ResultCodeEnum.OTHER;
+        }
+
+        if ( set.size() == 1 )
+        {
+            return set.iterator().next();
+        }
+
+        if ( type == null )
+        {
+            Set<ResultCodeEnum> tmp = new HashSet<ResultCodeEnum>();
+            tmp.addAll( set );
+            tmp.removeAll( NON_ERRONEOUS_CODES );
+
+            if ( tmp.isEmpty() )
+            {
+                return ResultCodeEnum.OTHER;
+            }
+
+            return tmp.iterator().next();
+        }
+
+        Set<ResultCodeEnum> candidates = EMPTY_RESULT_CODE_SET;
+
+        switch ( type )
+        {
+            case ABANDON_REQUEST:
+                return set.iterator().next();
+
+            case ADD_REQUEST:
+                candidates = intersection( set, ADD_CODES );
+                break;
+
+            case ADD_RESPONSE:
+                candidates = intersection( set, ADD_CODES );
+                break;
+
+            case BIND_REQUEST:
+                candidates = intersection( set, BIND_CODES );
+                break;
+
+            case BIND_RESPONSE:
+                candidates = intersection( set, BIND_CODES );
+                break;
+
+            case COMPARE_REQUEST:
+                candidates = intersection( set, COMPARE_CODES );
+                break;
+
+            case COMPARE_RESPONSE:
+                candidates = intersection( set, COMPARE_CODES );
+                break;
+
+            case DEL_REQUEST:
+                candidates = intersection( set, DELETE_CODES );
+                break;
+
+            case DEL_RESPONSE:
+                candidates = intersection( set, DELETE_CODES );
+                break;
+
+            case EXTENDED_REQUEST:
+                candidates = intersection( set, EXTENDED_CODES );
+                break;
+
+            case EXTENDED_RESPONSE:
+                candidates = intersection( set, EXTENDED_CODES );
+                break;
+
+            case MODIFYDN_REQUEST:
+                candidates = intersection( set, MODIFYDN_CODES );
+                break;
+
+            case MODIFYDN_RESPONSE:
+                candidates = intersection( set, MODIFYDN_CODES );
+                break;
+
+            case MODIFY_REQUEST:
+                candidates = intersection( set, MODIFY_CODES );
+                break;
+
+            case MODIFY_RESPONSE:
+                candidates = intersection( set, MODIFY_CODES );
+                break;
+
+            case SEARCH_REQUEST:
+                candidates = intersection( set, SEARCH_CODES );
+                break;
+
+            case SEARCH_RESULT_DONE:
+                candidates = intersection( set, SEARCH_CODES );
+                break;
+
+            case SEARCH_RESULT_ENTRY:
+                candidates = intersection( set, SEARCH_CODES );
+                break;
+
+            case SEARCH_RESULT_REFERENCE:
+                candidates = intersection( set, SEARCH_CODES );
+                break;
+
+            case UNBIND_REQUEST:
+                return set.iterator().next();
+
+            case INTERMEDIATE_RESPONSE:
+                candidates = intersection( set, SEARCH_CODES );
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected MessageTypeEnum " + type );
+        }
+
+        // we don't want any codes that do not have anything to do w/ errors
+        candidates.removeAll( NON_ERRONEOUS_CODES );
+
+        if ( candidates.isEmpty() )
+        {
+            return ResultCodeEnum.OTHER;
+        }
+
+        return candidates.iterator().next();
+    }
+
+
+    private static Set<ResultCodeEnum> intersection( Set<ResultCodeEnum> s1, Set<ResultCodeEnum> s2 )
+    {
+        if ( s1.isEmpty() || s2.isEmpty() )
+        {
+            return new HashSet<ResultCodeEnum>();
+        }
+
+        Set<ResultCodeEnum> intersection = new HashSet<ResultCodeEnum>();
+
+        if ( s1.size() <= s2.size() )
+        {
+            for ( ResultCodeEnum item : s1 )
+            {
+                if ( s2.contains( item ) )
+                {
+                    intersection.add( item );
+                }
+            }
+        }
+        else
+        {
+            for ( ResultCodeEnum item : s2 )
+            {
+                if ( s1.contains( item ) )
+                {
+                    intersection.add( item );
+                }
+            }
+        }
+
+        return intersection;
+    }
+
+
+    /**
+     * Gets the set of result codes a Throwable may map to. If the throwable
+     * does not map to any result code at all an empty set is returned. The
+     * following Throwables and their subclasses map to result codes:
+     * 
+     * <pre>
+     * 
+     *  Unambiguous Exceptions
+     *  ======================
+     * 
+     *  CommunicationException              ==&gt; operationsError(1)
+     *  TimeLimitExceededException          ==&gt; timeLimitExceeded(3)
+     *  SizeLimitExceededException          ==&gt; sizeLimitExceeded(4)
+     *  AuthenticationException             ==&gt; invalidCredentials(49)
+     *  NoPermissionException               ==&gt; insufficientAccessRights(50)
+     *  NoSuchAttributeException            ==&gt; noSuchAttribute(16)
+     *  InvalidAttributeIdentifierException ==&gt; undefinedAttributeType(17)
+     *  InvalidSearchFilterException        ==&gt; inappropriateMatching(18)
+     *  AttributeInUseException             ==&gt; attributeOrValueExists(20)
+     *  NameNotFoundException               ==&gt; NO_SUCH_OBJECT(32)
+     *  NameAlreadyBoundException           ==&gt; entryAlreadyExists(68)
+     *  ContextNotEmptyException            ==&gt; notAllowedOnNonLeaf(66)
+     * 
+     * 
+     *  Ambiguous Exceptions
+     *  ====================
+     * 
+     *  NamingException
+     *  ---------------
+     *  operationsError(1)
+     *  aliasProblem(33)
+     *  aliasDereferencingProblem(36)
+     *  loopDetect(54)
+     *  affectsMultipleDSAs(71)
+     *  other(80)
+     * 
+     *  AuthenticationNotSupportedException
+     *  -----------------------------------
+     *  authMethodNotSupported (7)
+     *  strongAuthRequired (8)
+     *  confidentialityRequired (13)
+     *  inappropriateAuthentication(48)
+     * 
+     *  ServiceUnavailableException
+     *  ---------------------------
+     *  busy(51)
+     *  unavailable(52)
+     * 
+     *  InvalidAttributeValueException
+     *  ------------------------------
+     *  constraintViolation(19)
+     *  invalidAttributeSyntax(21)
+     * 
+     *  PartialResultException
+     *  ----------------------
+     *  partialResults(9)
+     *  referral(10)
+     * 
+     *  LimitExceededException
+     *  ----------------------
+     *  referal(9)
+     *  adminLimitExceeded(11)
+     * 
+     *  OperationNotSupportedException
+     *  ------------------------------
+     *  unavailableCriticalExtention(12)
+     *  unwillingToPerform(53)
+     * 
+     *  InvalidNameException
+     *  --------------------
+     *  invalidDNSyntax(34)
+     *  namingViolation(64)
+     * 
+     *  SchemaViolationException
+     *  ------------------------
+     *  objectClassViolation(65)
+     *  notAllowedOnRDN(67)
+     *  objectClassModsProhibited(69)
+     * 
+     * </pre>
+     * 
+     * @param t
+     *            the Throwable to find the result code mappings for
+     * @return the set of mapped result codes
+     */
+    private static Set<ResultCodeEnum> getResultCodes( Throwable t )
+    {
+        ResultCodeEnum rc = getResultCode( t );
+        if ( rc != null )
+        {
+            return Collections.singleton( rc );
+        }
+
+        if ( t instanceof LdapSchemaViolationException )
+        {
+            return SCHEMA_VIOLATION_EXCEPTION_CODES;
+        }
+
+        if ( t instanceof LdapInvalidDnException )
+        {
+            return INVALID_NAME_EXCEPTION_CODES;
+        }
+
+        if ( t instanceof LdapUnwillingToPerformException )
+        {
+            return OPERATION_NOT_SUPPORTED_EXCEPTION_CODES;
+        }
+
+        if ( t instanceof LimitExceededException )
+        {
+            return LIMIT_EXCEEDED_EXCEPTION_CODES;
+        }
+
+        if ( t instanceof PartialResultException )
+        {
+            return PARTIAL_RESULTS_EXCEPTION_CODES;
+        }
+
+        if ( t instanceof LdapInvalidAttributeValueException )
+        {
+            return INVALID_ATTRIBUTE_VALUE_EXCEPTION_CODES;
+        }
+
+        if ( t instanceof LdapServiceUnavailableException )
+        {
+            return SERVICE_UNAVAILABLE_CODES;
+        }
+
+        if ( t instanceof LdapAuthenticationNotSupportedException )
+        {
+            return AUTHENTICATION_NOT_SUPPORTED_EXCEPTION_CODES;
+        }
+
+        // keep this last because others are subtypes and thier evaluation
+        // may be shorted otherwise by this comparison here
+        if ( t instanceof LdapException )
+        {
+            return NAMING_EXCEPTION_CODES;
+        }
+
+        return EMPTY_RESULT_CODE_SET;
+    }
+
+
+    /**
+     * Gets an LDAP result code from a Throwable if it can resolve it
+     * unambiguously or returns null if it cannot resolve the exception to a
+     * single ResultCode. If the Throwable is an instance of LdapException this
+     * is already done for us, otherwise we use the following mapping:
+     * 
+     * <pre>
+     * 
+     *  Unambiguous Exceptions
+     *  ======================
+     * 
+     *  CommunicationException              ==&gt; operationsError(1)
+     *  TimeLimitExceededException          ==&gt; timeLimitExceeded(3)
+     *  SizeLimitExceededException          ==&gt; sizeLimitExceeded(4)
+     *  AuthenticationException             ==&gt; invalidCredentials(49)
+     *  NoPermissionException               ==&gt; insufficientAccessRights(50)
+     *  NoSuchAttributeException            ==&gt; noSuchAttribute(16)
+     *  InvalidAttributeIdentifierException ==&gt; undefinedAttributeType(17)
+     *  InvalidSearchFilterException        ==&gt; inappropriateMatching(18)
+     *  AttributeInUseException             ==&gt; attributeOrValueExists(20)
+     *  NameNotFoundException               ==&gt; NO_SUCH_OBJECT(32)
+     *  NameAlreadyBoundException           ==&gt; entryAlreadyExists(68)
+     *  ContextNotEmptyException            ==&gt; notAllowedOnNonLeaf(66)
+     * </pre>
+     * 
+     * If we cannot find a mapping then null is returned.
+     * 
+     * @param t The exception for which we need a ResultCodeEnum
+     * @return The ResultCodeEnum associated wit the given exception 
+     */
+    public static ResultCodeEnum getResultCode( Throwable t )
+    {
+        if ( t instanceof LdapOperationException )
+        {
+            return ( ( LdapOperationException ) t ).getResultCode();
+        }
+
+        if ( t instanceof CommunicationException )
+        {
+            return ResultCodeEnum.PROTOCOL_ERROR;
+        }
+
+        if ( t instanceof LdapTimeLimitExceededException )
+        {
+            return ResultCodeEnum.TIME_LIMIT_EXCEEDED;
+        }
+
+        if ( t instanceof SizeLimitExceededException )
+        {
+            return ResultCodeEnum.SIZE_LIMIT_EXCEEDED;
+        }
+
+        if ( t instanceof LdapAuthenticationException )
+        {
+            return ResultCodeEnum.INVALID_CREDENTIALS;
+        }
+
+        if ( t instanceof LdapNoPermissionException )
+        {
+            return ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS;
+        }
+
+        if ( t instanceof LdapNoSuchAttributeException )
+        {
+            return ResultCodeEnum.NO_SUCH_ATTRIBUTE;
+        }
+
+        if ( t instanceof LdapInvalidAttributeTypeException )
+        {
+            return ResultCodeEnum.UNDEFINED_ATTRIBUTE_TYPE;
+        }
+
+        if ( t instanceof LdapInvalidSearchFilterException )
+        {
+            return ResultCodeEnum.INAPPROPRIATE_MATCHING;
+        }
+
+        if ( t instanceof LdapAttributeInUseException )
+        {
+            return ResultCodeEnum.ATTRIBUTE_OR_VALUE_EXISTS;
+        }
+
+        if ( t instanceof LdapNoSuchObjectException )
+        {
+            return ResultCodeEnum.NO_SUCH_OBJECT;
+        }
+
+        if ( t instanceof LdapEntryAlreadyExistsException )
+        {
+            return ResultCodeEnum.ENTRY_ALREADY_EXISTS;
+        }
+
+        if ( t instanceof LdapContextNotEmptyException )
+        {
+            return ResultCodeEnum.NOT_ALLOWED_ON_NON_LEAF;
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Process the response, throwing the associated exception if needed. If the result
+     * was SUCCESS, does not return anything but true. 
+     * 
+     * @param response The response to process
+     * @return For the COMPARE_TRUE or COMPARE_FALSE results, return true or false
+     * @throws LdapException The associated exception
+     */
+    public static boolean processResponse( ResultResponse response ) throws LdapException
+    {
+        LdapResult ldapResult = response.getLdapResult();
+
+        switch ( ldapResult.getResultCode() )
+        {
+        // Not erroneous code
+            case SUCCESS:
+            case PARTIAL_RESULTS:
+            case REFERRAL:
+            case SASL_BIND_IN_PROGRESS:
+            case CANCELED:
+            case COMPARE_TRUE:
+                return true;
+
+            case COMPARE_FALSE:
+                return false;
+
+            case INVALID_CREDENTIALS:
+                LdapAuthenticationException authenticationException = new LdapAuthenticationException(
+                    ldapResult.getDiagnosticMessage() );
+                authenticationException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw authenticationException;
+
+            case UNWILLING_TO_PERFORM:
+            case UNAVAILABLE_CRITICAL_EXTENSION:
+                LdapUnwillingToPerformException unwillingToPerformException =
+                    new LdapUnwillingToPerformException( ldapResult.getResultCode(), ldapResult.getDiagnosticMessage() );
+                unwillingToPerformException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw unwillingToPerformException;
+
+            case INSUFFICIENT_ACCESS_RIGHTS:
+                LdapNoPermissionException ldapNoPermissionException = new LdapNoPermissionException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapNoPermissionException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapNoPermissionException;
+
+            case NOT_ALLOWED_ON_NON_LEAF:
+                LdapContextNotEmptyException ldapContextNotEmptyException = new LdapContextNotEmptyException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapContextNotEmptyException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapContextNotEmptyException;
+
+            case NO_SUCH_OBJECT:
+                LdapNoSuchObjectException ldapNoSuchObjectException = new LdapNoSuchObjectException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapNoSuchObjectException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapNoSuchObjectException;
+
+            case NO_SUCH_ATTRIBUTE:
+                LdapNoSuchAttributeException ldapNoSuchAttributeException = new LdapNoSuchAttributeException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapNoSuchAttributeException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapNoSuchAttributeException;
+
+            case ATTRIBUTE_OR_VALUE_EXISTS:
+                LdapAttributeInUseException ldapAttributeInUseException = new LdapAttributeInUseException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapAttributeInUseException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapAttributeInUseException;
+
+            case ENTRY_ALREADY_EXISTS:
+                LdapEntryAlreadyExistsException ldapEntryAlreadyExistsException = new LdapEntryAlreadyExistsException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapEntryAlreadyExistsException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapEntryAlreadyExistsException;
+
+            case OBJECT_CLASS_VIOLATION:
+            case NOT_ALLOWED_ON_RDN:
+            case OBJECT_CLASS_MODS_PROHIBITED:
+                LdapSchemaViolationException ldapSchemaViolationException =
+                    new LdapSchemaViolationException( ldapResult.getResultCode(), ldapResult.getDiagnosticMessage() );
+                ldapSchemaViolationException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapSchemaViolationException;
+
+            case ALIAS_PROBLEM:
+                LdapAliasException ldapAliasException = new LdapAliasException( ldapResult.getDiagnosticMessage() );
+                ldapAliasException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapAliasException;
+
+            case AFFECTS_MULTIPLE_DSAS:
+                LdapAffectMultipleDsaException ldapAffectMultipleDsaException = new LdapAffectMultipleDsaException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapAffectMultipleDsaException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapAffectMultipleDsaException;
+
+            case ALIAS_DEREFERENCING_PROBLEM:
+                LdapAliasDereferencingException ldapAliasDereferencingException = new LdapAliasDereferencingException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapAliasDereferencingException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapAliasDereferencingException;
+
+            case AUTH_METHOD_NOT_SUPPORTED:
+            case INAPPROPRIATE_AUTHENTICATION:
+            case CONFIDENTIALITY_REQUIRED:
+                LdapAuthenticationNotSupportedException ldapAuthenticationNotSupportedException =
+                    new LdapAuthenticationNotSupportedException( ldapResult.getResultCode(),
+                        ldapResult.getDiagnosticMessage() );
+                ldapAuthenticationNotSupportedException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapAuthenticationNotSupportedException;
+
+            case BUSY:
+            case UNAVAILABLE:
+                LdapServiceUnavailableException ldapServiceUnavailableException =
+                    new LdapServiceUnavailableException( ldapResult.getResultCode(), ldapResult.getDiagnosticMessage() );
+                ldapServiceUnavailableException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapServiceUnavailableException;
+
+            case CONSTRAINT_VIOLATION:
+            case INVALID_ATTRIBUTE_SYNTAX:
+                LdapInvalidAttributeValueException ldapInvalidAttributeValueException =
+                    new LdapInvalidAttributeValueException( ldapResult.getResultCode(),
+                        ldapResult.getDiagnosticMessage() );
+                ldapInvalidAttributeValueException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapInvalidAttributeValueException;
+
+            case INAPPROPRIATE_MATCHING:
+                LdapInvalidSearchFilterException ldapInvalidSearchFilterException = new LdapInvalidSearchFilterException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapInvalidSearchFilterException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapInvalidSearchFilterException;
+
+            case INVALID_DN_SYNTAX:
+            case NAMING_VIOLATION:
+                LdapInvalidDnException ldapInvalidDnException =
+                    new LdapInvalidDnException( ldapResult.getResultCode(), ldapResult.getDiagnosticMessage() );
+                ldapInvalidDnException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapInvalidDnException;
+
+            case LOOP_DETECT:
+                LdapLoopDetectedException ldapLoopDetectedException = new LdapLoopDetectedException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapLoopDetectedException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapLoopDetectedException;
+
+            case OPERATIONS_ERROR:
+                LdapOperationErrorException ldapOperationErrorException = new LdapOperationErrorException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapOperationErrorException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapOperationErrorException;
+
+            case PROTOCOL_ERROR:
+                LdapProtocolErrorException ldapProtocolErrorException = new LdapProtocolErrorException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapProtocolErrorException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapProtocolErrorException;
+
+            case TIME_LIMIT_EXCEEDED:
+                LdapTimeLimitExceededException ldapTimeLimitExceededException = new LdapTimeLimitExceededException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapTimeLimitExceededException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapTimeLimitExceededException;
+
+            case UNDEFINED_ATTRIBUTE_TYPE:
+                LdapInvalidAttributeTypeException ldapInvalidAttributeTypeException = new LdapInvalidAttributeTypeException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapInvalidAttributeTypeException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapInvalidAttributeTypeException;
+
+            case OTHER:
+                LdapOtherException ldapOtherException = new LdapOtherException( ldapResult.getDiagnosticMessage() );
+                ldapOtherException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapOtherException;
+
+            case SIZE_LIMIT_EXCEEDED:
+                LdapSizeLimitExceededException ldapSizeLimitExceededException = new LdapSizeLimitExceededException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapSizeLimitExceededException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapSizeLimitExceededException;
+
+            case STRONG_AUTH_REQUIRED:
+                LdapStrongAuthenticationRequiredException ldapStrongAuthenticationRequiredException =
+                    new LdapStrongAuthenticationRequiredException( ldapResult.getDiagnosticMessage() );
+                ldapStrongAuthenticationRequiredException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapStrongAuthenticationRequiredException;
+
+            case ADMIN_LIMIT_EXCEEDED:
+                LdapAdminLimitExceededException ldapAdminLimitExceededException =
+                    new LdapAdminLimitExceededException( ldapResult.getDiagnosticMessage() );
+                ldapAdminLimitExceededException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapAdminLimitExceededException;
+
+            case TOO_LATE:
+                LdapTooLateException ldapTooLateException = new LdapTooLateException( ldapResult.getDiagnosticMessage() );
+                ldapTooLateException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapTooLateException;
+
+            case UNKNOWN:
+                LdapUnknownException ldapUnknownException = new LdapUnknownException( ldapResult.getDiagnosticMessage() );
+                ldapUnknownException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapUnknownException;
+
+            case CANNOT_CANCEL:
+                LdapCannotCancelException ldapCannotCancelException = new LdapCannotCancelException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapCannotCancelException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapCannotCancelException;
+
+            case NO_SUCH_OPERATION:
+                LdapNoSuchOperationException ldapNoSuchOperationException = new LdapNoSuchOperationException(
+                    ldapResult.getDiagnosticMessage() );
+                ldapNoSuchOperationException.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw ldapNoSuchOperationException;
+
+            case E_SYNC_REFRESH_REQUIRED:
+                // This is a specific error message. We won't encapsulate it in a dedicated exception
+                // Fallthrough
+
+            default:
+                LdapOperationException exception = new LdapOperationException( ldapResult.getResultCode(),
+                    ldapResult.getDiagnosticMessage() );
+                exception.setResolvedDn( ldapResult.getMatchedDn() );
+
+                throw exception;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultResponse.java
new file mode 100644
index 0000000..5b9d7d8
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultResponse.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * An LDAP Response that contains an LDAPResult structure within it.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ResultResponse extends Response
+{
+    /**
+     * Gets the LdapResult components of this Response.
+     * 
+     * @return the LdapResult for this Response.
+     */
+    LdapResult getLdapResult();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultResponseRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultResponseRequest.java
new file mode 100644
index 0000000..d5c027d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/ResultResponseRequest.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * A request who's one or more responses contains an LdapResult.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ResultResponseRequest extends Request
+{
+    /**
+     * If called for the first time, this method creates a result containing
+     * response object for this request.
+     * 
+     * @return a result containing response with defaults and the messageId set
+     *         in response to this specific request
+     */
+    ResultResponse getResultResponse();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchParams.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchParams.java
new file mode 100644
index 0000000..326b8f4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchParams.java
@@ -0,0 +1,351 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.directory.SearchControls;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.AttributeTypeOptions;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SchemaUtils;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A container for Search parameters. It replaces the SearchControls.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchParams
+{
+    /** The LoggerFactory used by this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SearchParams.class );
+
+    /** The search scope. Default to OBJECT */
+    private SearchScope scope = SearchScope.OBJECT;
+
+    /** The time limit. Default to 0 (infinite) */
+    private int timeLimit = 0;
+
+    /** The size limit. Default to 0 (infinite) */
+    private long sizeLimit = 0;
+
+    /** If we should return only types. Default to false */
+    private boolean typesOnly = false;
+
+    /** The aliasDerefMode. Default to DEREF_ALWAYS */
+    private AliasDerefMode aliasDerefMode = AliasDerefMode.DEREF_ALWAYS;
+
+    /** The list of attributes to return, as Strings. Default to an empty set */
+    private Set<String> returningAttributesStr;
+
+    /** The list of attributes to return, once it has been normalized. Default to an empty set */
+    private Set<AttributeTypeOptions> returningAttributes;
+
+    /** The set of controls for this search. Default to an empty set */
+    private Set<Control> controls;
+
+
+    /**
+     * Creates a new instance of SearchContext, with all the values set to 
+     * default.
+     */
+    public SearchParams()
+    {
+        returningAttributes = new HashSet<AttributeTypeOptions>();
+        returningAttributesStr = new HashSet<String>();
+        controls = new HashSet<Control>();
+    }
+
+
+    /**
+     * @return the scope
+     */
+    public SearchScope getScope()
+    {
+        return scope;
+    }
+
+
+    /**
+     * @param scope the scope to set
+     */
+    public void setScope( SearchScope scope )
+    {
+        this.scope = scope;
+    }
+
+
+    /**
+     * @return the timeLimit
+     */
+    public int getTimeLimit()
+    {
+        return timeLimit;
+    }
+
+
+    /**
+     * @param timeLimit the timeLimit to set
+     */
+    public void setTimeLimit( int timeLimit )
+    {
+        this.timeLimit = timeLimit;
+    }
+
+
+    /**
+     * @return the sizeLimit
+     */
+    public long getSizeLimit()
+    {
+        return sizeLimit;
+    }
+
+
+    /**
+     * @param sizeLimit the sizeLimit to set
+     */
+    public void setSizeLimit( long sizeLimit )
+    {
+        this.sizeLimit = sizeLimit;
+    }
+
+
+    /**
+     * @return the typesOnly
+     */
+    public boolean isTypesOnly()
+    {
+        return typesOnly;
+    }
+
+
+    /**
+     * @param typesOnly the typesOnly to set
+     */
+    public void setTypesOnly( boolean typesOnly )
+    {
+        this.typesOnly = typesOnly;
+    }
+
+
+    /**
+     * @return the aliasDerefMode
+     */
+    public AliasDerefMode getAliasDerefMode()
+    {
+        return aliasDerefMode;
+    }
+
+
+    /**
+     * @param aliasDerefMode the aliasDerefMode to set
+     */
+    public void setAliasDerefMode( AliasDerefMode aliasDerefMode )
+    {
+        this.aliasDerefMode = aliasDerefMode;
+    }
+
+
+    /**
+     * @return the returningAttributes
+     */
+    public Set<AttributeTypeOptions> getReturningAttributes()
+    {
+        return returningAttributes;
+    }
+
+
+    /**
+     * @return the returningAttributes
+     */
+    public Set<String> getReturningAttributesStr()
+    {
+        return returningAttributesStr;
+    }
+
+
+    /**
+     * Normalize the ReturningAttributes. It reads all the String from the returningAttributesString,
+     * and grab the associated AttributeType from the schema to store it into the returningAttributes
+     * Set.
+     *
+     * @param schemaManager The schema manager
+     */
+    public void normalize( SchemaManager schemaManager )
+    {
+        for ( String returnAttribute : returningAttributesStr )
+        {
+            try
+            {
+                String id = SchemaUtils.stripOptions( returnAttribute );
+                Set<String> options = SchemaUtils.getOptions( returnAttribute );
+
+                AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( id );
+                AttributeTypeOptions attrOptions = new AttributeTypeOptions( attributeType, options );
+
+                returningAttributes.add( attrOptions );
+            }
+            catch ( LdapException ne )
+            {
+                LOG.warn( "Requested attribute {} does not exist in the schema, it will be ignored", returnAttribute );
+                // Unknown attributes should be silently ignored, as RFC 2251 states
+            }
+        }
+    }
+
+
+    /**
+     * @param returningAttributes the returningAttributes to set
+     */
+    public void setReturningAttributes( String... returningAttributes )
+    {
+        if ( returningAttributes != null )
+        {
+            for ( String returnAttribute : returningAttributes )
+            {
+                this.returningAttributesStr.add( returnAttribute );
+            }
+        }
+    }
+
+
+    /**
+     * @param returningAttribute the returningAttributes to add
+     */
+    public void addReturningAttributes( String returningAttribute )
+    {
+        this.returningAttributesStr.add( returningAttribute );
+    }
+
+
+    /**
+     * @return the controls
+     */
+    public Set<Control> getControls()
+    {
+        return controls;
+    }
+
+
+    /**
+     * @param controls the controls to set
+     */
+    public void setControls( Set<Control> controls )
+    {
+        this.controls = controls;
+    }
+
+
+    /**
+     * @param control the controls to set
+     */
+    public void addControl( Control control )
+    {
+        this.controls.add( control );
+    }
+
+
+    /**
+     * Creates a {@link SearchParams} from JNDI search controls.
+     *
+     * @param searchControls the search controls
+     * @param aliasDerefMode the alias deref mode
+     * @return the search params
+     */
+    public static SearchParams toSearchParams( SearchControls searchControls, AliasDerefMode aliasDerefMode )
+    {
+        SearchParams searchParams = new SearchParams();
+
+        searchParams.setAliasDerefMode( aliasDerefMode );
+        searchParams.setTimeLimit( searchControls.getTimeLimit() );
+        searchParams.setSizeLimit( searchControls.getCountLimit() );
+        searchParams.setScope( SearchScope.getSearchScope( searchControls.getSearchScope() ) );
+        searchParams.setTypesOnly( searchControls.getReturningObjFlag() );
+
+        if ( searchControls.getReturningAttributes() != null )
+        {
+            for ( String returningAttribute : searchControls.getReturningAttributes() )
+            {
+                searchParams.addReturningAttributes( returningAttribute );
+            }
+        }
+
+        return searchParams;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "Search parameters :\n" );
+        sb.append( "    scope : " ).append( scope ).append( "\n" );
+        sb.append( "    Alias dereferencing : " ).append( aliasDerefMode ).append( "\n" );
+        sb.append( "    types only : " ).append( typesOnly ).append( "\n" );
+
+        if ( returningAttributesStr.size() != 0 )
+        {
+            sb.append( "    returning attributes : " ).append( Strings.setToString( returningAttributesStr ) )
+                .append( "\n" );
+        }
+
+        if ( timeLimit > 0 )
+        {
+            sb.append( "    timeLimit : " ).append( timeLimit ).append( "\n" );
+        }
+        else
+        {
+            sb.append( "    no timeLimit\n" );
+        }
+
+        if ( timeLimit > 0 )
+        {
+            sb.append( "    sizeLimit : " ).append( sizeLimit ).append( "\n" );
+        }
+        else
+        {
+            sb.append( "    no sizeLimit\n" );
+        }
+
+        if ( controls.size() != 0 )
+        {
+            for ( Control control : controls )
+            {
+                sb.append( "    control : " ).
+                    append( control.getOid() ).append( "/" ).
+                    append( control.getClass().getName() ).append( "\n" );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchRequest.java
new file mode 100644
index 0000000..e3fdc1a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchRequest.java
@@ -0,0 +1,303 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Search request protocol message interface.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public interface SearchRequest extends ManyReplyRequest, AbandonableRequest
+{
+    /**
+     * Different response types that a search request may return. A search
+     * request unlike any other request type can generate four different kinds
+     * of responses. It is at most required to return a done response when it is
+     * complete however before then it can return search entry, search
+     * reference, and extended responses to the client.
+     * 
+     * @see #getResponseTypes()
+     */
+    MessageTypeEnum[] RESPONSE_TYPES =
+        {
+            MessageTypeEnum.SEARCH_RESULT_DONE,
+            MessageTypeEnum.SEARCH_RESULT_ENTRY,
+            MessageTypeEnum.SEARCH_RESULT_REFERENCE,
+            MessageTypeEnum.EXTENDED_RESPONSE
+    };
+
+
+    /**
+     * Gets the different response types generated by a search request.
+     * 
+     * @return the RESPONSE_TYPES array
+     * @see #RESPONSE_TYPES
+     */
+    MessageTypeEnum[] getResponseTypes();
+
+
+    /**
+     * Gets the search base as a distinguished name.
+     * 
+     * @return the search base
+     */
+    Dn getBase();
+
+
+    /**
+     * Sets the search base as a distinguished name.
+     * 
+     * @param baseDn the search base
+     * @return The SearchRequest instance
+     */
+    SearchRequest setBase( Dn baseDn );
+
+
+    /**
+     * Gets the search scope parameter enumeration.
+     * 
+     * @return the scope enumeration parameter.
+     */
+    SearchScope getScope();
+
+
+    /**
+     * Sets the search scope parameter enumeration.
+     * 
+     * @param scope the scope enumeration parameter.
+     * @return The SearchRequest instance
+     */
+    SearchRequest setScope( SearchScope scope );
+
+
+    /**
+     * Gets the alias handling parameter.
+     * 
+     * @return the alias handling parameter enumeration.
+     */
+    AliasDerefMode getDerefAliases();
+
+
+    /**
+     * Sets the alias handling parameter.
+     * 
+     * @param aliasDerefAliases the alias handling parameter enumeration.
+     * @return The SearchRequest instance
+     */
+    SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases );
+
+
+    /**
+     * A sizelimit that restricts the maximum number of entries to be returned
+     * as a result of the search. A value of 0 in this field indicates that no
+     * client-requested sizelimit restrictions are in effect for the search.
+     * Servers may enforce a maximum number of entries to return.
+     * 
+     * @return search size limit.
+     */
+    long getSizeLimit();
+
+
+    /**
+     * Sets sizelimit that restricts the maximum number of entries to be
+     * returned as a result of the search. A value of 0 in this field indicates
+     * that no client-requested sizelimit restrictions are in effect for the
+     * search. Servers may enforce a maximum number of entries to return.
+     * 
+     * @param entriesMax maximum search result entries to return.
+     * @return The SearchRequest instance
+     */
+    SearchRequest setSizeLimit( long entriesMax );
+
+
+    /**
+     * Gets the timelimit that restricts the maximum time (in seconds) allowed
+     * for a search. A value of 0 in this field indicates that no client-
+     * requested timelimit restrictions are in effect for the search.
+     * 
+     * @return the search time limit in seconds.
+     */
+    int getTimeLimit();
+
+
+    /**
+     * Sets the timelimit that restricts the maximum time (in seconds) allowed
+     * for a search. A value of 0 in this field indicates that no client-
+     * requested timelimit restrictions are in effect for the search.
+     * 
+     * @param secondsMax the search time limit in seconds.
+     * @return The SearchRequest instance
+     */
+    SearchRequest setTimeLimit( int secondsMax );
+
+
+    /**
+     * An indicator as to whether search results will contain both attribute
+     * types and values, or just attribute types. Setting this field to TRUE
+     * causes only attribute types (no values) to be returned. Setting this
+     * field to FALSE causes both attribute types and values to be returned.
+     * 
+     * @return true for only types, false for types and values.
+     */
+    boolean getTypesOnly();
+
+
+    /**
+     * An indicator as to whether search results will contain both attribute
+     * types and values, or just attribute types. Setting this field to TRUE
+     * causes only attribute types (no values) to be returned. Setting this
+     * field to FALSE causes both attribute types and values to be returned.
+     * 
+     * @param typesOnly true for only types, false for types and values.
+     * @return The SearchRequest instance
+     */
+    SearchRequest setTypesOnly( boolean typesOnly );
+
+
+    /**
+     * Gets the search filter associated with this search request.
+     * 
+     * @return the expression node for the root of the filter expression tree.
+     */
+    ExprNode getFilter();
+
+
+    /**
+     * Sets the search filter associated with this search request.
+     * 
+     * @param filter the expression node for the root of the filter expression tree.
+     * @return The SearchRequest instance
+     */
+    SearchRequest setFilter( ExprNode filter );
+
+
+    /**
+     * Sets the search filter associated with this search request.
+     * 
+     * @param filter the expression node for the root of the filter expression tree.
+     * @return The SearchRequest instance
+     */
+    SearchRequest setFilter( String filter ) throws LdapException;
+
+
+    /**
+     * Gets a list of the attributes to be returned from each entry which
+     * matches the search filter. There are two special values which may be
+     * used: an empty list with no attributes, and the attribute description
+     * string "*". Both of these signify that all user attributes are to be
+     * returned. (The "*" allows the client to request all user attributes in
+     * addition to specific operational attributes). Attributes MUST be named at
+     * most once in the list, and are returned at most once in an entry. If
+     * there are attribute descriptions in the list which are not recognized,
+     * they are ignored by the server. If the client does not want any
+     * attributes returned, it can specify a list containing only the attribute
+     * with OID "1.1". This OID was chosen arbitrarily and does not correspond
+     * to any attribute in use. Client implementors should note that even if all
+     * user attributes are requested, some attributes of the entry may not be
+     * included in search results due to access control or other restrictions.
+     * Furthermore, servers will not return operational attributes, such as
+     * objectClasses or attributeTypes, unless they are listed by name, since
+     * there may be extremely large number of values for certain operational
+     * attributes.
+     * 
+     * @return the attributes to return for this request
+     */
+    List<String> getAttributes();
+
+
+    /**
+     * Adds some attributes to the set of entry attributes to return.
+     * 
+     * @param attributes the attributes description or identifier.
+     * @return The SearchRequest instance
+     */
+    SearchRequest addAttributes( String... attributes );
+
+
+    /**
+     * Removes an attribute to the set of entry attributes to return.
+     * 
+     * @param attribute the attribute description or identifier.
+     * @return The SearchRequest instance
+     */
+    SearchRequest removeAttribute( String attribute );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    SearchRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    SearchRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    SearchRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    SearchRequest removeControl( Control control );
+    
+    
+    /**
+     * Tells the client if it should follow referrals instead of throwing exceptions
+     * @return true if we should follow the referrals
+     */
+    boolean isFollowReferrals();
+    
+    
+    /**
+     * Tells the client to follow referrals instead of throwing exceptions
+     * @return The SearchRequest instance
+     */
+    SearchRequest followReferrals();
+    
+    
+    /**
+     * Tells the client if it should ignore referrals instead of throwing exceptions
+     * @return true if we should ignore the referrals
+     */
+    boolean isIgnoreReferrals();
+    
+    
+    /**
+     * Tells the client to ignore referrals instead of throwing exceptions. The entry
+     * will contain the referral attributeType with the link.
+     * 
+     * @return The SearchRequest instance
+     */
+    SearchRequest ignoreReferrals();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchRequestImpl.java
new file mode 100644
index 0000000..57dbae9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchRequestImpl.java
@@ -0,0 +1,643 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
+import org.apache.directory.api.ldap.model.filter.BranchNormalizedVisitor;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * SearchRequest implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class SearchRequestImpl extends AbstractAbandonableRequest implements SearchRequest
+{
+    static final long serialVersionUID = -5655881944020886218L;
+
+    /** Search base distinguished name */
+    private Dn baseDn;
+
+    /** Search filter expression tree's root node */
+    private ExprNode filterNode;
+
+    /** Search scope enumeration value */
+    private SearchScope scope;
+
+    /** Types only return flag */
+    private boolean typesOnly;
+
+    /** Max size in entries to return */
+    private long sizeLimit;
+
+    /** Max seconds to wait for search to complete */
+    private int timeLimit;
+
+    /** Alias dereferencing mode enumeration value (default to DEREF_ALWAYS) */
+    private AliasDerefMode aliasDerefMode = AliasDerefMode.DEREF_ALWAYS;
+
+    /** Attributes to return */
+    private List<String> attributes = new ArrayList<String>();
+
+    /** The final result containing SearchResponseDone response */
+    private SearchResultDone response;
+
+    /** A flag set to tell the search what to do wth referrals */
+    private ReferralsPolicyEnum referralHandling = ReferralsPolicyEnum.THROW;
+
+
+    // -----------------------------------------------------------------------
+    // Constructors
+    // -----------------------------------------------------------------------
+    /**
+     * Creates a SearcRequest implementing object used to search the
+     * DIT.
+     */
+    public SearchRequestImpl()
+    {
+        super( -1, MessageTypeEnum.SEARCH_REQUEST );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SearchRequest Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getAttributes()
+    {
+        return Collections.unmodifiableList( attributes );
+    }
+
+
+    /**
+     * Gets the search base as a distinguished name.
+     * 
+     * @return the search base
+     */
+    public Dn getBase()
+    {
+        return baseDn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setBase( Dn base )
+    {
+        baseDn = base;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AliasDerefMode getDerefAliases()
+    {
+        return aliasDerefMode;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setDerefAliases( AliasDerefMode aliasDerefAliases )
+    {
+        this.aliasDerefMode = aliasDerefAliases;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExprNode getFilter()
+    {
+        return filterNode;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setFilter( ExprNode filter )
+    {
+        this.filterNode = filter;
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setFilter( String filter ) throws LdapException
+    {
+        try
+        {
+            filterNode = FilterParser.parse( Strings.getBytesUtf8( filter ) );
+        }
+        catch ( ParseException pe )
+        {
+            String msg = "The filter " + filter + " is invalid.";
+            throw new LdapProtocolErrorException( msg, pe );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MessageTypeEnum[] getResponseTypes()
+    {
+        return RESPONSE_TYPES.clone();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchScope getScope()
+    {
+        return scope;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setScope( SearchScope scope )
+    {
+        this.scope = scope;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public long getSizeLimit()
+    {
+        return sizeLimit;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setSizeLimit( long entriesMax )
+    {
+        sizeLimit = entriesMax;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getTimeLimit()
+    {
+        return timeLimit;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setTimeLimit( int secondsMax )
+    {
+        timeLimit = secondsMax;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean getTypesOnly()
+    {
+        return typesOnly;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setTypesOnly( boolean typesOnly )
+    {
+        this.typesOnly = typesOnly;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addAttributes( String... attributesToAdd )
+    {
+        this.attributes.addAll( Arrays.asList( attributesToAdd ) );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest removeAttribute( String attribute )
+    {
+        attributes.remove( attribute );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchResultDone getResultResponse()
+    {
+        if ( response == null )
+        {
+            response = new SearchResultDoneImpl( getMessageId() );
+        }
+
+        return response;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addControl( Control control )
+    {
+        return ( SearchRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest addAllControls( Control[] controls )
+    {
+        return ( SearchRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest removeControl( Control control )
+    {
+        return ( SearchRequest ) super.removeControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+
+        if ( baseDn != null )
+        {
+            hash = hash * 17 + baseDn.hashCode();
+        }
+
+        hash = hash * 17 + aliasDerefMode.hashCode();
+        hash = hash * 17 + scope.hashCode();
+        hash = hash * 17 + Long.valueOf( sizeLimit ).hashCode();
+        hash = hash * 17 + timeLimit;
+        hash = hash * 17 + ( typesOnly ? 0 : 1 );
+
+        if ( attributes != null )
+        {
+            hash = hash * 17 + attributes.size();
+
+            // Order doesn't matter, thus just add hashCode
+            for ( String attr : attributes )
+            {
+                if ( attr != null )
+                {
+                    hash = hash + attr.hashCode();
+                }
+            }
+        }
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+        filterNode.accept( visitor );
+        hash = hash * 17 + filterNode.toString().hashCode();
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if two search requests are equal. The Lockable properties
+     * and the get/set context specific parameters are not consulted to
+     * determine equality. The filter expression tree comparison will normalize
+     * the child order of filter branch nodes then generate a string
+     * representation which is comparable. For the time being this is a very
+     * costly operation.
+     * 
+     * @param obj the object to check for equality to this SearchRequest
+     * @return true if the obj is a SearchRequest and equals this SearchRequest,
+     *         false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        SearchRequest req = ( SearchRequest ) obj;
+
+        if ( !req.getBase().equals( baseDn ) )
+        {
+            return false;
+        }
+
+        if ( req.getDerefAliases() != aliasDerefMode )
+        {
+            return false;
+        }
+
+        if ( req.getScope() != scope )
+        {
+            return false;
+        }
+
+        if ( req.getSizeLimit() != sizeLimit )
+        {
+            return false;
+        }
+
+        if ( req.getTimeLimit() != timeLimit )
+        {
+            return false;
+        }
+
+        if ( req.getTypesOnly() != typesOnly )
+        {
+            return false;
+        }
+
+        if ( req.getAttributes() == null && attributes != null && attributes.size() > 0 )
+        {
+            return false;
+        }
+
+        if ( req.getAttributes() != null && attributes == null && req.getAttributes().size() > 0 )
+        {
+            return false;
+        }
+
+        if ( req.getAttributes() != null && attributes != null )
+        {
+            if ( req.getAttributes().size() != attributes.size() )
+            {
+                return false;
+            }
+
+            for ( String attribute : attributes )
+            {
+                if ( !req.getAttributes().contains( attribute ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+        req.getFilter().accept( visitor );
+        filterNode.accept( visitor );
+
+        String myFilterString = filterNode.toString();
+        String reqFilterString = req.getFilter().toString();
+
+        return myFilterString.equals( reqFilterString );
+    }
+
+
+    /**
+     * Return a string the represent a SearchRequest
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    SearchRequest\n" );
+        sb.append( "        baseDn : '" ).append( baseDn ).append( "'\n" );
+
+        if ( filterNode != null )
+        {
+            sb.append( "        filter : '" );
+            sb.append( filterNode.toString() );
+            sb.append( "'\n" );
+        }
+
+        sb.append( "        scope : " );
+
+        switch ( scope )
+        {
+            case OBJECT:
+                sb.append( "base object" );
+                break;
+
+            case ONELEVEL:
+                sb.append( "single level" );
+                break;
+
+            case SUBTREE:
+                sb.append( "whole subtree" );
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected scope " + scope );
+        }
+
+        sb.append( '\n' );
+
+        sb.append( "        typesOnly : " ).append( typesOnly ).append( '\n' );
+
+        sb.append( "        Size Limit : " );
+
+        if ( sizeLimit == 0L )
+        {
+            sb.append( "no limit" );
+        }
+        else
+        {
+            sb.append( sizeLimit );
+        }
+
+        sb.append( '\n' );
+
+        sb.append( "        Time Limit : " );
+
+        if ( timeLimit == 0 )
+        {
+            sb.append( "no limit" );
+        }
+        else
+        {
+            sb.append( timeLimit );
+        }
+
+        sb.append( '\n' );
+
+        sb.append( "        Deref Aliases : " );
+
+        switch ( aliasDerefMode )
+        {
+            case NEVER_DEREF_ALIASES:
+                sb.append( "never Deref Aliases" );
+                break;
+
+            case DEREF_IN_SEARCHING:
+                sb.append( "deref In Searching" );
+                break;
+
+            case DEREF_FINDING_BASE_OBJ:
+                sb.append( "deref Finding Base Obj" );
+                break;
+
+            case DEREF_ALWAYS:
+                sb.append( "deref Always" );
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected aliasDerefMode " + aliasDerefMode );
+        }
+
+        sb.append( '\n' );
+        sb.append( "        attributes : " );
+
+        boolean isFirst = true;
+
+        if ( attributes != null )
+        {
+            for ( String attribute : attributes )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( ", " );
+                }
+
+                sb.append( '\'' ).append( attribute ).append( '\'' );
+            }
+        }
+
+        sb.append( '\n' );
+
+        // The controls
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isFollowReferrals()
+    {
+        return referralHandling == ReferralsPolicyEnum.FOLLOW;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest followReferrals()
+    {
+        referralHandling = ReferralsPolicyEnum.FOLLOW;
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isIgnoreReferrals()
+    {
+        return referralHandling == ReferralsPolicyEnum.IGNORE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SearchRequest ignoreReferrals()
+    {
+        referralHandling = ReferralsPolicyEnum.IGNORE;
+
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultDone.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultDone.java
new file mode 100644
index 0000000..1f3a71d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultDone.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Search done protocol response message used to indicate the completion of a
+ * search request message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ *         $Rev: 910150 $
+ */
+public interface SearchResultDone extends ResultResponse
+{
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultDoneImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultDoneImpl.java
new file mode 100644
index 0000000..ac9076e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultDoneImpl.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * SearchResponseDone implementation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class SearchResultDoneImpl extends AbstractResultResponse implements SearchResultDone
+{
+    static final long serialVersionUID = 8698484213877460215L;
+
+
+    /**
+     * Creates a SearchResponseDone as a reply to an SearchRequest to
+     * indicate the end of a search operation.
+     */
+    public SearchResultDoneImpl()
+    {
+        super( -1, MessageTypeEnum.SEARCH_RESULT_DONE );
+    }
+
+
+    /**
+     * Creates a SearchResponseDone as a reply to an SearchRequest to
+     * indicate the end of a search operation.
+     * 
+     * @param id the session unique message id
+     */
+    public SearchResultDoneImpl( final int id )
+    {
+        super( id, MessageTypeEnum.SEARCH_RESULT_DONE );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        hash = hash * 17 + getLdapResult().hashCode();
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks for equality by using the underlying LdapResult objects of this
+     * SearchResponseDone stub.
+     * 
+     * @param obj
+     *            the object to be tested for equality
+     * @return true if obj is equivalent to this SearchResponseDone impl
+     */
+    public boolean equals( Object obj )
+    {
+        // quickly return if the obj is this object
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        LdapResult result = ( ( SearchResultDone ) obj ).getLdapResult();
+
+        return getLdapResult().equals( result );
+    }
+
+
+    /**
+     * Get a String representation of a SearchResultDone
+     * 
+     * @return A SearchResultDone String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Search Result Done\n" );
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultEntry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultEntry.java
new file mode 100644
index 0000000..bbb4552
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultEntry.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Search entry protocol response message used to return non referral entries to
+ * the client in response to a search request message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SearchResultEntry extends Response
+{
+    /**
+     * Gets the distinguished name of the entry object returned.
+     * 
+     * @return the Dn of the entry returned.
+     */
+    Dn getObjectName();
+
+
+    /**
+     * Sets the distinguished name of the entry object returned.
+     * 
+     * @param objectName the Dn of the entry returned.
+     */
+    void setObjectName( Dn objectName );
+
+
+    /**
+     * Gets the entry.
+     * 
+     * @return the entry
+     */
+    Entry getEntry();
+
+
+    /**
+     * Sets an entry
+     * 
+     * @param entry the entry
+     */
+    void setEntry( Entry entry );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultEntryImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultEntryImpl.java
new file mode 100644
index 0000000..657809b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultEntryImpl.java
@@ -0,0 +1,182 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * Lockable SearchResponseEntry implementation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultEntryImpl extends AbstractResponse implements SearchResultEntry
+{
+    static final long serialVersionUID = -8357316233060886637L;
+
+    /** Entry returned in response to search */
+    private Entry entry = new DefaultEntry();
+
+
+    /**
+     * Creates a SearchResponseEntry as a reply to an SearchRequest to
+     * indicate the end of a search operation.
+     */
+    public SearchResultEntryImpl()
+    {
+        super( -1, MessageTypeEnum.SEARCH_RESULT_ENTRY );
+    }
+
+
+    /**
+     * Creates a SearchResponseEntry as a reply to an SearchRequest to
+     * indicate the end of a search operation.
+     * 
+     * @param id the session unique message id
+     */
+    public SearchResultEntryImpl( final int id )
+    {
+        super( id, MessageTypeEnum.SEARCH_RESULT_ENTRY );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SearchResponseEntry Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the entry
+     * 
+     * @return the entry
+     */
+    public Entry getEntry()
+    {
+        return entry;
+    }
+
+
+    /**
+     * Sets the entry.
+     * 
+     * @param entry the entry
+     */
+    public void setEntry( Entry entry )
+    {
+        this.entry = entry;
+    }
+
+
+    /**
+     * Gets the distinguished name of the entry object returned.
+     * 
+     * @return the Dn of the entry returned.
+     */
+    public Dn getObjectName()
+    {
+        return ( entry == null ? null : entry.getDn() );
+    }
+
+
+    /**
+     * Sets the distinguished name of the entry object returned.
+     * 
+     * @param objectName the Dn of the entry returned.
+     */
+    public void setObjectName( Dn objectName )
+    {
+        if ( entry != null )
+        {
+            entry.setDn( objectName );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( entry != null )
+        {
+            hash = hash * 17 + entry.hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks for equality by comparing the objectName, and attributes
+     * properties of this Message after delegating to the super.equals() method.
+     * 
+     * @param obj
+     *            the object to test for equality with this message
+     * @return true if the obj is equal false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        if ( !( obj instanceof SearchResultEntry ) )
+        {
+            return false;
+        }
+
+        SearchResultEntry resp = ( SearchResultEntry ) obj;
+
+        return entry.equals( resp.getEntry() );
+    }
+
+
+    /**
+     * Return a string representation of a SearchResultEntry request
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Search Result Entry\n" );
+
+        if ( entry != null )
+        {
+            sb.append( entry );
+        }
+        else
+        {
+            sb.append( "            No entry\n" );
+        }
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultReference.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultReference.java
new file mode 100644
index 0000000..5a22619
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultReference.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Search reference protocol response message used to return referrals to the
+ * client in response to a search request message.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SearchResultReference extends Response
+{
+    /**
+     * Gets the sequence of LdapUrls as a Referral instance.
+     * 
+     * @return the sequence of LdapUrls
+     */
+    Referral getReferral();
+
+
+    /**
+     * Sets the sequence of LdapUrls as a Referral instance.
+     * 
+     * @param referral the sequence of LdapUrls
+     */
+    void setReferral( Referral referral );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultReferenceImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultReferenceImpl.java
new file mode 100644
index 0000000..eafd2f2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchResultReferenceImpl.java
@@ -0,0 +1,164 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * SearchResponseReference implementation
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultReferenceImpl extends AbstractResponse implements SearchResultReference
+{
+    static final long serialVersionUID = 7423807019951309810L;
+
+    /** Referral holding the reference urls */
+    private Referral referral = new ReferralImpl();
+
+
+    /**
+     * Creates a SearchResponseReference as a reply to an SearchRequest
+     * to indicate the end of a search operation.
+     */
+    public SearchResultReferenceImpl()
+    {
+        super( -1, MessageTypeEnum.SEARCH_RESULT_REFERENCE );
+    }
+
+
+    /**
+     * Creates a SearchResponseReference as a reply to an SearchRequest
+     * to indicate the end of a search operation.
+     * 
+     * @param id the session unique message id
+     */
+    public SearchResultReferenceImpl( final int id )
+    {
+        super( id, MessageTypeEnum.SEARCH_RESULT_REFERENCE );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SearchResponseReference Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the sequence of LdapUrls as a Referral instance.
+     * 
+     * @return the sequence of LdapUrls
+     */
+    public Referral getReferral()
+    {
+        return this.referral;
+    }
+
+
+    /**
+     * Sets the sequence of LdapUrls as a Referral instance.
+     * 
+     * @param referral the sequence of LdapUrls
+     */
+    public void setReferral( Referral referral )
+    {
+        this.referral = referral;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        if ( this.referral != null )
+        {
+            hash = hash * 17 + this.referral.hashCode();
+        }
+        hash = hash * 17 + super.hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * Checks to see if an object is equal to this SearchResponseReference stub.
+     * 
+     * @param obj
+     *            the object to compare to this response stub
+     * @return true if the objects are equivalent false otherwise
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+
+        SearchResultReference resp = ( SearchResultReference ) obj;
+
+        if ( this.referral != null && resp.getReferral() == null )
+        {
+            return false;
+        }
+
+        if ( this.referral == null && resp.getReferral() != null )
+        {
+            return false;
+        }
+
+        return ( this.referral == null || resp.getReferral() == null || this.referral.equals( resp.getReferral() ) );
+    }
+
+
+    /**
+     * Returns the Search Result Reference string
+     * 
+     * @return The Search Result Reference string
+     */
+    public String toString()
+    {
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    Search Result Reference\n" );
+
+        if ( ( referral == null ) || ( referral.getLdapUrls() == null ) || ( referral.getLdapUrls().size() == 0 ) )
+        {
+            sb.append( "        No Reference\n" );
+        }
+        else
+        {
+            sb.append( "        References\n" );
+
+            for ( String url : referral.getLdapUrls() )
+            {
+                sb.append( "            '" ).append( url ).append( "'\n" );
+            }
+        }
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchScope.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchScope.java
new file mode 100644
index 0000000..59b2c5d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SearchScope.java
@@ -0,0 +1,177 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A search scope enumerated type.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SearchScope
+{
+    OBJECT(0, "base"),
+    ONELEVEL(1, "one"),
+    SUBTREE(2, "sub");
+
+    /** 
+     * The corresponding LDAP scope constant value as defined in 
+     * RFC 4511
+     */
+    private final int scope;
+
+    /**
+     * The LDAP URL string value of either base, one or sub as defined in RFC
+     * 2255.
+     * 
+     * @see <a href="http://www.faqs.org/rfcs/rfc2255.html">RFC 2255</a>
+     */
+    private final String ldapUrlValue;
+
+
+    /**
+     * Creates a new instance of SearchScope based on the respective 
+     * scope constant.
+     *
+     * @param scope the scope constant
+     * @param ldapUrlValue LDAP URL scope string value: base, one, or sub
+     */
+    private SearchScope( int scope, String ldapUrlValue )
+    {
+        this.scope = scope;
+        this.ldapUrlValue = ldapUrlValue;
+    }
+
+
+    /**
+     * Gets the LDAP URL value for the scope: according to RFC 2255 this is 
+     * either base, one, or sub.
+     * 
+     * @see <a href="http://www.faqs.org/rfcs/rfc2255.html">RFC 2255</a>
+     */
+    public String getLdapUrlValue()
+    {
+        return ldapUrlValue;
+    }
+
+
+    /**
+     * Gets the corresponding scope constant value as defined in 
+     * RFC 4511.
+     * 
+     * @return the scope
+     */
+    public int getScope()
+    {
+        return scope;
+    }
+
+
+    /**
+     * Gets the SearchScope enumerated type for the corresponding 
+     * scope numeric value.
+     *
+     * @param scope the numeric value to get SearchScope for
+     * @return the SearchScope enumerated type for the scope numeric value
+     */
+    public static SearchScope getSearchScope( int scope )
+    {
+        switch ( scope )
+        {
+            case 0:
+                return OBJECT;
+
+            case 1:
+                return ONELEVEL;
+
+            case 2:
+                return SUBTREE;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04160, scope ) );
+        }
+    }
+
+
+    /**
+     * Gets the SeacrhScope associated with a scope String
+     * 
+     * @return the scope
+     */
+    public SearchScope getScope( String scope )
+    {
+        if ( "base".equalsIgnoreCase( scope ) )
+        {
+            return OBJECT;
+        }
+        else if ( "one".equalsIgnoreCase( scope ) )
+        {
+            return ONELEVEL;
+        }
+        else if ( "sub".equalsIgnoreCase( scope ) )
+        {
+            return SUBTREE;
+        }
+        else
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04161, scope ) );
+        }
+    }
+
+
+    /**
+     * Gets the SearchScope enumerated type for the corresponding 
+     * scope value of either base, one or sub.
+     *
+     * @param scope the scope value to get SearchScope for
+     * @return the SearchScope enumerated type for the LDAP URL scope value
+     */
+    public static int getSearchScope( String scope )
+    {
+        if ( "base".equalsIgnoreCase( scope ) )
+        {
+            return OBJECT.getScope();
+        }
+        else if ( "one".equalsIgnoreCase( scope ) )
+        {
+            return ONELEVEL.getScope();
+        }
+        else if ( "sub".equalsIgnoreCase( scope ) )
+        {
+            return SUBTREE.getScope();
+        }
+        else
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04161, scope ) );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return ldapUrlValue;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SingleReplyRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SingleReplyRequest.java
new file mode 100644
index 0000000..6558d31
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/SingleReplyRequest.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Super interface for all request messages returning only one type of response.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SingleReplyRequest extends ResultResponseRequest
+{
+    /**
+     * Gets the protocol response message type for this request which produces
+     * at least one response.
+     * 
+     * @return the message type of the response.
+     */
+    MessageTypeEnum getResponseType();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/UnbindRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/UnbindRequest.java
new file mode 100644
index 0000000..402ec8e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/UnbindRequest.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+/**
+ * Unbind protocol request message used to end a client session.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public interface UnbindRequest extends Request
+{
+    /**
+     * {@inheritDoc}
+     */
+    UnbindRequest setMessageId( int messageId );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    UnbindRequest addControl( Control control );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    UnbindRequest addAllControls( Control[] controls );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    UnbindRequest removeControl( Control control );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/UnbindRequestImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/UnbindRequestImpl.java
new file mode 100644
index 0000000..3b1e882
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/UnbindRequestImpl.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Lockable UnbindRequest implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+public class UnbindRequestImpl extends AbstractRequest implements UnbindRequest
+{
+    static final long serialVersionUID = -6217184085100410116L;
+
+
+    /**
+     * Creates an UnbindRequest which takes no parameter other than those in the
+     * outer envelope to disconnect and end a client session on the server
+     * without producing any response.
+     * 
+     * @param id the sequential message identifier.
+     */
+    public UnbindRequestImpl()
+    {
+        super( -1, MessageTypeEnum.UNBIND_REQUEST, false );
+    }
+
+
+    /**
+     * RFC 2251 [Section 4.11]: Abandon, Bind, Unbind, and StartTLS operations
+     * cannot be abandoned.
+     */
+    public void abandon()
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04185 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest setMessageId( int messageId )
+    {
+        super.setMessageId( messageId );
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest addControl( Control control )
+    {
+        return ( UnbindRequest ) super.addControl( control );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest addAllControls( Control[] controls )
+    {
+        return ( UnbindRequest ) super.addAllControls( controls );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnbindRequest removeControl( Control control )
+    {
+        return ( UnbindRequest ) super.removeControl( control );
+    }
+
+
+    /**
+     * Get a String representation of a UnBindRequest
+     * 
+     * @return A UnBindRequest String
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "    UnBind Request" );
+
+        // The controls
+        sb.append( super.toString() );
+
+        return super.toString( sb.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/AbstractControl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/AbstractControl.java
new file mode 100644
index 0000000..33f5915
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/AbstractControl.java
@@ -0,0 +1,160 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A simple implementation of the {@link Control} interface with storage for 
+ * the OID and the criticality properties. When the codec factory service
+ * does not have specific control factories available, hence the control is
+ * unrecognized, it creates instances of this control for them.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractControl implements Control
+{
+    /** The control type */
+    private String oid;
+
+    /** The criticality (default value is false) */
+    private boolean criticality = false;
+
+
+    /**
+     * Creates a Control with a specific OID.
+     *
+     * @param oid The OID of this Control.
+     */
+    public AbstractControl( String oid )
+    {
+        this.oid = oid;
+    }
+
+
+    /**
+     * Creates a Control with a specific OID, and criticality set.
+     *
+     * @param oid The OID of this Control.
+     * @param criticality true if this Control is critical, false otherwise. 
+     */
+    public AbstractControl( String oid, boolean criticality )
+    {
+        this.oid = oid;
+        this.criticality = criticality;
+    }
+
+
+    /**
+     * Get the OID
+     * 
+     * @return A string which represent the control oid
+     */
+    public String getOid()
+    {
+        return oid == null ? "" : oid;
+    }
+
+
+    /**
+     * Get the criticality
+     * 
+     * @return <code>true</code> if the criticality flag is true.
+     */
+    public boolean isCritical()
+    {
+        return criticality;
+    }
+
+
+    /**
+     * Set the criticality
+     * 
+     * @param criticality The criticality value
+     */
+    public void setCritical( boolean criticality )
+    {
+        this.criticality = criticality;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    public int hashCode()
+    {
+        int h = 17;
+        h = h * 37 + ( criticality ? 1 : 0 );
+        h = h * 37 + ( oid == null ? 0 : oid.hashCode() );
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        if ( o == this )
+        {
+            return true;
+        }
+
+        if ( o == null )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof Control ) )
+        {
+            return false;
+        }
+
+        Control otherControl = ( Control ) o;
+
+        if ( !oid.equalsIgnoreCase( otherControl.getOid() ) )
+        {
+            return false;
+        }
+
+        return criticality == otherControl.isCritical();
+    }
+
+
+    /**
+     * Return a String representing a Control
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    " ).append( getClass().getSimpleName() ).append( " " );
+        sb.append( "Control\n" );
+        sb.append( "        Type OID    : '" ).append( oid ).append( "'\n" );
+        sb.append( "        Criticality : '" ).append( criticality ).append( "'\n" );
+
+        sb.append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/Cascade.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/Cascade.java
new file mode 100644
index 0000000..9f6d156
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/Cascade.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * The Cascade control
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Cascade extends Control
+{
+    /** The Cascade control OID */
+    String OID = "1.3.6.1.4.1.18060.0.0.1";
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/CascadeImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/CascadeImpl.java
new file mode 100644
index 0000000..95cee58
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/CascadeImpl.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+/**
+ * Simple Cascade control implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CascadeImpl extends AbstractControl implements Cascade
+{
+    /**
+     * Default constructor
+     */
+    public CascadeImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     * Sets criticality when creating.
+     * 
+     * @param isCritical true if critical, false otherwise.
+     */
+    public CascadeImpl( boolean isCritical )
+    {
+        super( OID );
+        setCritical( isCritical );
+    }
+
+
+    public void setValue( byte[] value )
+    {
+    }
+
+
+    public boolean hasValue()
+    {
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ChangeType.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ChangeType.java
new file mode 100644
index 0000000..e7883d3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ChangeType.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Enumeration type for entry changes associates with the persistent search
+ * control and the entry change control. Used for the following ASN1
+ * enumeration:
+ * 
+ * <pre>
+ *   changeType ENUMERATED 
+ *   {
+ *       add             (1),
+ *       delete          (2),
+ *       modify          (4),
+ *       modDN           (8)
+ *   }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum ChangeType
+{
+    ADD(1),
+
+    DELETE(2),
+
+    MODIFY(4),
+
+    MODDN(8);
+
+    private int value;
+
+
+    /**
+     * 
+     * Creates a new instance of ChangeType.
+     *
+     * @param value The value for the ChangeType.
+     */
+    private ChangeType( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The int value of the ChangeType
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Checks via bitwise AND to see if this ChangeType value is within the
+     * supplied changeTypes.
+     *
+     * @param changeTypes The supplied changeTypes.
+     * @return true, if this ChangeType is present in the supplied changeTypes.
+     */
+    public boolean presentIn( int changeTypes )
+    {
+        return value == ( value & changeTypes );
+    }
+
+
+    /**
+     * Gets the changeType enumeration type for an integer value.
+     * 
+     * @param value the value to get the enumeration for
+     * @return the enueration type for the value if the value is valid
+     * @throws IllegalArgumentException if the value is undefined
+     */
+    public static ChangeType getChangeType( int value )
+    {
+        switch ( value )
+        {
+            case ( 1 ):
+                return ADD;
+            case ( 2 ):
+                return DELETE;
+            case ( 4 ):
+                return MODIFY;
+            case ( 8 ):
+                return MODDN;
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04055, value ) );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/EntryChange.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/EntryChange.java
new file mode 100644
index 0000000..704a7c1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/EntryChange.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * A response control that may be returned by Persistent Search entry responses.
+ * It contains addition change information to describe the exact change that
+ * occurred to an entry. The exact details of this control are covered in section
+ * 5 of this (yes) expired draft: <a
+ * href="http://www3.ietf.org/proceedings/01aug/I-D/draft-ietf-ldapext-psearch-03.txt">
+ * Persistent Search Draft v03</a> which is printed out below for convenience:
+ *
+ * <pre>
+ *    5.  Entry Change Notification Control
+ *
+ *    This control provides additional information about the change the caused
+ *    a particular entry to be returned as the result of a persistent search.
+ *    The controlType is &quot;2.16.840.1.113730.3.4.7&quot;.  If the client set the
+ *    returnECs boolean to TRUE in the PersistentSearch control, servers MUST
+ *    include an EntryChangeNotification control in the Controls portion of
+ *    each SearchResultEntry that is returned due to an entry being added,
+ *    deleted, or modified.
+ *
+ *               EntryChangeNotification ::= SEQUENCE
+ *               {
+ *                         changeType ENUMERATED
+ *                         {
+ *                                 add             (1),
+ *                                 delete          (2),
+ *                                 modify          (4),
+ *                                 modDN           (8)
+ *                         },
+ *                         previousDN   LDAPDN OPTIONAL,     -- modifyDN ops. only
+ *                         changeNumber INTEGER OPTIONAL     -- if supported
+ *               }
+ *
+ *    changeType indicates what LDAP operation caused the entry to be
+ *    returned.
+ *
+ *    previousDN is present only for modifyDN operations and gives the Dn of
+ *    the entry before it was renamed and/or moved.  Servers MUST include this
+ *    optional field only when returning change notifications as a result of
+ *    modifyDN operations.
+ *
+ *    changeNumber is the change number [CHANGELOG] assigned by a server for
+ *    the change.  If a server supports an LDAP Change Log it SHOULD include
+ *    this field.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface EntryChange extends Control
+{
+    int UNDEFINED_CHANGE_NUMBER = -1;
+
+    /** The EntryChange control */
+    String OID = "2.16.840.1.113730.3.4.7";
+
+
+    /**
+     * @return The ChangeType
+     */
+    ChangeType getChangeType();
+
+
+    /**
+     * Set the ChangeType
+     *
+     * @param changeType Add, Delete; Modify or ModifyDN
+     */
+    void setChangeType( ChangeType changeType );
+
+
+    Dn getPreviousDn();
+
+
+    void setPreviousDn( Dn previousDn );
+
+
+    long getChangeNumber();
+
+
+    void setChangeNumber( long changeNumber );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/EntryChangeImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/EntryChangeImpl.java
new file mode 100644
index 0000000..7685819
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/EntryChangeImpl.java
@@ -0,0 +1,146 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * A simple implementation of the EntryChange response control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EntryChangeImpl extends AbstractControl implements EntryChange
+{
+    /** The changeType */
+    private ChangeType changeType = ChangeType.ADD;
+
+    private long changeNumber = UNDEFINED_CHANGE_NUMBER;
+
+    /** The previous Dn */
+    private Dn previousDn = null;
+
+
+    /**
+     *
+     * Creates a new instance of EntryChangeControl.
+     *
+     */
+    public EntryChangeImpl()
+    {
+        super( OID );
+    }
+
+
+    public ChangeType getChangeType()
+    {
+        return changeType;
+    }
+
+
+    public void setChangeType( ChangeType changeType )
+    {
+        this.changeType = changeType;
+    }
+
+
+    public Dn getPreviousDn()
+    {
+        return previousDn;
+    }
+
+
+    public void setPreviousDn( Dn previousDn )
+    {
+        this.previousDn = previousDn;
+    }
+
+
+    public long getChangeNumber()
+    {
+        return changeNumber;
+    }
+
+
+    public void setChangeNumber( long changeNumber )
+    {
+        this.changeNumber = changeNumber;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    public int hashCode()
+    {
+        int h = super.hashCode();
+
+        h = h * 37 + Long.valueOf( changeNumber ).intValue();
+        h = h * 37 + ( changeType == null ? 0 : changeType.hashCode() );
+        h = h * 37 + ( previousDn == null ? 0 : previousDn.hashCode() );
+
+        return h;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        EntryChange otherControl = ( EntryChange ) o;
+
+        return ( changeNumber == otherControl.getChangeNumber() ) && ( changeType == otherControl.getChangeType() )
+            && ( previousDn.equals( otherControl.getPreviousDn() ) );
+    }
+
+
+    /**
+     * Return a String representing this EntryChangeControl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Entry Change Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        changeType   : '" ).append( changeType ).append( "'\n" );
+        sb.append( "        previousDN   : '" ).append( previousDn ).append( "'\n" );
+
+        if ( changeNumber == UNDEFINED_CHANGE_NUMBER )
+        {
+            sb.append( "        changeNumber : '" ).append( "UNDEFINED" ).append( "'\n" );
+        }
+        else
+        {
+            sb.append( "        changeNumber : '" ).append( changeNumber ).append( "'\n" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ManageDsaIT.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ManageDsaIT.java
new file mode 100644
index 0000000..edc07f6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ManageDsaIT.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * Control which allows for the management of referrals and other DSA specific
+ * entities without processing them: meaning the referrals are treated as
+ * regular entries using this control. More information is available in <a
+ * href="">RFC 3296</a>. Below we have included section 3 of the RFC describing
+ * this control:
+ *
+ * <pre>
+ *  3.  The ManageDsaIT Control
+ *
+ *   The client may provide the ManageDsaIT control with an operation to
+ *   indicate that the operation is intended to manage objects within the
+ *   DSA (server) Information Tree.  The control causes Directory-specific
+ *   entries (DSEs), regardless of type, to be treated as normal entries
+ *   allowing clients to interrogate and update these entries using LDAP
+ *   operations.
+ *
+ *   A client MAY specify the following control when issuing an add,
+ *   compare, delete, modify, modifyDN, search request or an extended
+ *   operation for which the control is defined.
+ *
+ *   The control type is 2.16.840.1.113730.3.4.2.  The control criticality
+ *   may be TRUE or, if FALSE, absent.  The control value is absent.
+ *
+ *   When the control is present in the request, the server SHALL NOT
+ *   generate a referral or continuation reference based upon information
+ *   held in referral objects and instead SHALL treat the referral object
+ *   as a normal entry.  The server, however, is still free to return
+ *   referrals for other reasons.  When not present, referral objects
+ *   SHALL be handled as described above.
+ *
+ *   The control MAY cause other objects to be treated as normal entries
+ *   as defined by subsequent documents.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ManageDsaIT extends Control
+{
+    /** This control OID */
+    String OID = "2.16.840.1.113730.3.4.2";
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ManageDsaITImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ManageDsaITImpl.java
new file mode 100644
index 0000000..e950e18
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ManageDsaITImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+/**
+ * Simple ManageDsaIT implementation class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ManageDsaITImpl extends AbstractControl implements ManageDsaIT
+{
+    /**
+     * Default constructor.
+     */
+    public ManageDsaITImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     * Creates instance and sets criticality at same time.
+     * 
+     * @param isCritical true if critical, false otherwise
+     */
+    public ManageDsaITImpl( boolean isCritical )
+    {
+        super( OID );
+        setCritical( isCritical );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/OpaqueControl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/OpaqueControl.java
new file mode 100644
index 0000000..b735d0e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/OpaqueControl.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A final {@link Control} implementation intended specifically for handling
+ * controls who's values cannot be encoded or decoded by the codec service.
+ * This situation results when no Control factory is found to be
+ * registered for this control's OID. Hence additional opaque value handling
+ * methods are included to manage the opaque control value.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class OpaqueControl extends AbstractControl implements Control
+{
+    /** The opaque encoded value */
+    private byte[] value;
+
+
+    /**
+     * Creates a Control with a specific OID.
+     *
+     * @param oid The OID of this Control.
+     */
+    public OpaqueControl( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Creates a Control with a specific OID, and criticality set.
+     *
+     * @param oid The OID of this Control.
+     * @param criticality true if this Control is critical, false otherwise.
+     */
+    public OpaqueControl( String oid, boolean criticality )
+    {
+        super( oid, criticality );
+    }
+
+
+    /**
+     * @return The encoded value
+     */
+    public byte[] getEncodedValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Stores an opaque value into the control.
+     * 
+     * @param value The opaque value to store
+     */
+    public void setEncodedValue( byte[] value )
+    {
+        this.value = Strings.copy( value );
+    }
+
+
+    /**
+     * Tells if the control has a stored value. Note that if the
+     * control has an empty value, this method will return true.
+     * 
+     * @return true if the control has a value
+     */
+    public boolean hasEncodedValue()
+    {
+        return value != null;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResults.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResults.java
new file mode 100644
index 0000000..4d1563c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResults.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A request/response control used to implement a simple paging of search
+ * results. This is an implementation of RFC 2696 :
+ * <a href="http://www.faqs.org/rfcs/rfc2696.html">LDAP Control Extension for Simple Paged Results Manipulation</a>
+ * <br/>
+ * <pre>
+ *    This control is included in the searchRequest and searchResultDone
+ *    messages as part of the controls field of the LDAPMessage, as defined
+ *    in Section 4.1.12 of [LDAPv3]. The structure of this control is as
+ *    follows:
+ *
+ * pagedResultsControl ::= SEQUENCE {
+ *         controlType     1.2.840.113556.1.4.319,
+ *         criticality     BOOLEAN DEFAULT FALSE,
+ *         controlValue    searchControlValue
+ * }
+ *
+ * The searchControlValue is an OCTET STRING wrapping the BER-encoded
+ * version of the following SEQUENCE:
+ *
+ * realSearchControlValue ::= SEQUENCE {
+ *         size            INTEGER (0..maxInt),
+ *                                 -- requested page size from client
+ *                                 -- result set size estimate from server
+ *         cookie          OCTET STRING
+ * }
+ *
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PagedResults extends Control
+{
+    /** The Paged Search Control OID */
+    String OID = "1.2.840.113556.1.4.319";
+
+
+    /**
+     * @return The requested or returned number of entries
+     */
+    int getSize();
+
+
+    /**
+     * Set the number of entry requested or returned
+     *
+     * @param size The number of entries
+     */
+    void setSize( int size );
+
+
+    /**
+     * @return The stored cookie
+     */
+    byte[] getCookie();
+
+
+    /**
+     * Set the cookie
+     *
+     * @param cookie The cookie to store in this control
+     */
+    void setCookie( byte[] cookie );
+
+
+    /**
+     * @return The integer value for the current cookie
+     */
+    int getCookieValue();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResultsImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResultsImpl.java
new file mode 100644
index 0000000..6126a0b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResultsImpl.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+
+import java.util.Arrays;
+
+
+/**
+ * A request/response control used to implement a simple paging of search
+ * results. This is an implementation of RFC 2696 :
+ * <a href="http://www.faqs.org/rfcs/rfc2696.html">LDAP Control Extension for Simple Paged Results Manipulation</a>
+ * <br/>
+ * <pre>
+ *    This control is included in the searchRequest and searchResultDone
+ *    messages as part of the controls field of the LDAPMessage, as defined
+ *    in Section 4.1.12 of [LDAPv3]. The structure of this control is as
+ *    follows:
+ *
+ * pagedResultsControl ::= SEQUENCE {
+ *         controlType     1.2.840.113556.1.4.319,
+ *         criticality     BOOLEAN DEFAULT FALSE,
+ *         controlValue    searchControlValue
+ * }
+ * 
+ * The searchControlValue is an OCTET STRING wrapping the BER-encoded
+ * version of the following SEQUENCE:
+ * 
+ * realSearchControlValue ::= SEQUENCE {
+ *         size            INTEGER (0..maxInt),
+ *                                 -- requested page size from client
+ *                                 -- result set size estimate from server
+ *         cookie          OCTET STRING
+ * }
+ * 
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PagedResultsImpl extends AbstractControl implements PagedResults
+{
+    /** The number of entries to return, or returned */
+    private int size;
+
+    /** The exchanged cookie */
+    private byte[] cookie = StringConstants.EMPTY_BYTES;
+
+
+    /**
+     * Creates a new instance of PagedResultsDecorator.
+     */
+    public PagedResultsImpl()
+    {
+        super( OID );
+    }
+
+
+    public int getSize()
+    {
+        return size;
+    }
+
+
+    public void setSize( int size )
+    {
+        this.size = size;
+    }
+
+
+    public byte[] getCookie()
+    {
+        return cookie;
+    }
+
+
+    public void setCookie( byte[] cookie )
+    {
+        this.cookie = cookie;
+    }
+
+
+    public int getCookieValue()
+    {
+        int value = 0;
+
+        switch ( cookie.length )
+        {
+            case 1:
+                value = cookie[0] & 0x00FF;
+                break;
+
+            case 2:
+                value = ( ( cookie[0] & 0x00FF ) << 8 ) + ( cookie[1] & 0x00FF );
+                break;
+
+            case 3:
+                value = ( ( cookie[0] & 0x00FF ) << 16 ) + ( ( cookie[1] & 0x00FF ) << 8 ) + ( cookie[2] & 0x00FF );
+                break;
+
+            case 4:
+                value = ( ( cookie[0] & 0x00FF ) << 24 ) + ( ( cookie[1] & 0x00FF ) << 16 )
+                    + ( ( cookie[2] & 0x00FF ) << 8 ) + ( cookie[3] & 0x00FF );
+                break;
+
+            default:
+                break;
+        }
+
+        return value;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = super.hashCode();
+
+        h = h * 37 + size;
+
+        if ( cookie != null )
+        {
+            for ( byte b : cookie )
+            {
+                h = h * 17 + b;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        PagedResults otherControl = ( PagedResults ) o;
+
+        return ( size == otherControl.getSize() ) && Arrays.equals( cookie, otherControl.getCookie() );
+    }
+
+
+    /**
+     * Return a String representing this PagedSearchControl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Paged Search Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        size   : '" ).append( size ).append( "'\n" );
+        sb.append( "        cookie   : '" ).append( Strings.dumpBytes( cookie ) ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PersistentSearch.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PersistentSearch.java
new file mode 100644
index 0000000..1824eff
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PersistentSearch.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A persistence search object
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface PersistentSearch extends Control
+{
+    /** This control OID */
+    String OID = "2.16.840.1.113730.3.4.3";
+
+    /** Min and Max values for the possible combined change types */
+    int CHANGE_TYPES_MIN = ChangeType.ADD.getValue();
+
+    int CHANGE_TYPES_MAX = ChangeType.ADD.getValue()
+        | ChangeType.DELETE.getValue()
+        | ChangeType.MODIFY.getValue()
+        | ChangeType.MODDN.getValue();
+
+
+    void setChangesOnly( boolean changesOnly );
+
+
+    boolean isChangesOnly();
+
+
+    void setReturnECs( boolean returnECs );
+
+
+    boolean isReturnECs();
+
+
+    void setChangeTypes( int changeTypes );
+
+
+    int getChangeTypes();
+
+
+    boolean isNotificationEnabled( ChangeType changeType );
+
+
+    void enableNotification( ChangeType changeType );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PersistentSearchImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PersistentSearchImpl.java
new file mode 100644
index 0000000..bf3b7e5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PersistentSearchImpl.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+/**
+ * A persistence search object
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PersistentSearchImpl extends AbstractControl implements PersistentSearch
+{
+
+    /**
+     * If changesOnly is TRUE, the server MUST NOT return any existing entries
+     * that match the search criteria. Entries are only returned when they are
+     * changed (added, modified, deleted, or subject to a modifyDN operation).
+     */
+    private boolean changesOnly = true;
+
+    /**
+     * If returnECs is TRUE, the server MUST return an Entry Change Notification
+     * control with each entry returned as the result of changes.
+     */
+    private boolean returnECs = false;
+
+    /**
+     * As changes are made to the server, the effected entries MUST be returned
+     * to the client if they match the standard search criteria and if the
+     * operation that caused the change is included in the changeTypes field.
+     * The changeTypes field is the logical OR of one or more of these values:
+     * add    (1),
+     * delete (2),
+     * modify (4),
+     * modDN  (8).
+     */
+    private int changeTypes = CHANGE_TYPES_MAX;
+
+
+    /**
+     * Default constructor
+     *
+     */
+    public PersistentSearchImpl()
+    {
+        super( OID );
+    }
+
+
+    public void setChangesOnly( boolean changesOnly )
+    {
+        this.changesOnly = changesOnly;
+    }
+
+
+    public boolean isChangesOnly()
+    {
+        return changesOnly;
+    }
+
+
+    public void setReturnECs( boolean returnECs )
+    {
+        this.returnECs = returnECs;
+    }
+
+
+    public boolean isReturnECs()
+    {
+        return returnECs;
+    }
+
+
+    public void setChangeTypes( int changeTypes )
+    {
+        this.changeTypes = changeTypes;
+    }
+
+
+    public int getChangeTypes()
+    {
+        return changeTypes;
+    }
+
+
+    public boolean isNotificationEnabled( ChangeType changeType )
+    {
+        return ( changeType.getValue() & changeTypes ) > 0;
+    }
+
+
+    public void enableNotification( ChangeType changeType )
+    {
+        changeTypes |= changeType.getValue();
+    }
+
+
+    /**
+     * Return a String representing this PSearchControl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Persistant Search Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        changeTypes : '" ).append( changeTypes ).append( "'\n" );
+        sb.append( "        changesOnly : '" ).append( changesOnly ).append( "'\n" );
+        sb.append( "        returnECs   : '" ).append( returnECs ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ProxiedAuthz.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ProxiedAuthz.java
new file mode 100644
index 0000000..a9a3474
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ProxiedAuthz.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * Control which defines the Proxy Authorization request. More information is available in <a
+ * href="https://tools.ietf.org/html/rfc4370">RFC 4370</a>. Below we have included section 3 of the RFC describing
+ * this control:
+ *
+ * <pre>
+ *  3. Proxy Authorization Control
+ *
+ *      A single Proxy Authorization Control may be included in any search,
+ *   compare, modify, add, delete, or modify Distinguished Name (DN) or
+ *   extended operation request message.  The exception is any extension
+ *   that causes a change in authentication, authorization, or data
+ *   confidentiality [RFC2829], such as Start TLS [LDAPTLS] as part of the
+ *   controls field of the LDAPMessage, as defined in [RFC2251].
+ *
+ *   The controlType of the proxy authorization control is
+ *   "2.16.840.1.113730.3.4.18".
+ *
+ *   The criticality MUST be present and MUST be TRUE.  This requirement
+ *   protects clients from submitting a request that is executed with an
+ *   unintended authorization identity.
+ *
+ *   Clients MUST include the criticality flag and MUST set it to TRUE.
+ *   Servers MUST reject any request containing a Proxy Authorization
+ *   Control without a criticality flag or with the flag set to FALSE with
+ *   a protocolError error.  These requirements protect clients from
+ *   submitting a request that is executed with an unintended
+ *   authorization identity.
+ *
+ *   The controlValue SHALL be present and SHALL either contain an authzId
+ *   [AUTH] representing the authorization identity for the request or be
+ *   empty if an anonymous association is to be used.
+ *
+ *   The mechanism for determining proxy access rights is specific to the
+ *   server's proxy authorization policy.
+ *
+ *   If the requested authorization identity is recognized by the server,
+ *   and the client is authorized to adopt the requested authorization
+ *   identity, the request will be executed as if submitted by the proxy
+ *   authorization identity; otherwise, the result code 123 is returned.
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ProxiedAuthz extends Control
+{
+    /** This control OID */
+    String OID = "2.16.840.1.113730.3.4.18";
+
+
+    /**
+     * @returns The authzId 
+     */
+    String getAuthzId();
+
+
+    /**
+     * @param authzId The authzId to set. Must be empty (not null), or a valid DN prefixed by 'dn:', or any
+     * user information prefixed by 'u:'
+     */
+    void setAuthzId( String authzId );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ProxiedAuthzImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ProxiedAuthzImpl.java
new file mode 100644
index 0000000..13ff17a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/ProxiedAuthzImpl.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Simple ProxiedAuthz implementation class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ProxiedAuthzImpl extends AbstractControl implements ProxiedAuthz
+{
+    /**
+     * The authzId used to authorize the user.
+     */
+    private String authzId;
+
+
+    /**
+     * Default constructor.
+     */
+    public ProxiedAuthzImpl()
+    {
+        super( OID );
+
+        // The criticality must be true
+        setCritical( true );
+    }
+
+
+    /**
+     * @return the authzId
+     */
+    public String getAuthzId()
+    {
+        return authzId;
+    }
+
+
+    /**
+     * The authzId syntax is given by the RFC 2829 :
+     * 
+     * <pre>
+     * authzId    = dnAuthzId / uAuthzId / <empty>
+     * dnAuthzId  = "dn:" dn
+     * dn         = utf8string
+     * uAuthzId   = "u:" userid
+     * userid     = utf8string
+     * </pre>
+     * @param authzId the authzId to set
+     */
+    public void setAuthzId( String authzId )
+    {
+        // We should have a valid authzId
+        if ( authzId == null )
+        {
+            throw new RuntimeException( "Invalid proxied authz value : cannot be null" );
+        }
+
+        if ( !Strings.isEmpty( authzId ) )
+        {
+            String lowercaseAuthzId = Strings.toLowerCase( authzId );
+
+            if ( lowercaseAuthzId.startsWith( "dn:" ) )
+            {
+                String dn = authzId.substring( 3 );
+
+                if ( !Dn.isValid( dn ) )
+                {
+                    throw new RuntimeException( "Invalid proxied authz value : the DN is not valid" );
+                }
+            }
+            else if ( !lowercaseAuthzId.startsWith( "u:" ) )
+            {
+                throw new RuntimeException( "Invalid proxied authz value : should start with 'dn:' or 'u:'" );
+            }
+        }
+
+        this.authzId = authzId;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = super.hashCode();
+
+        if ( authzId != null )
+        {
+            h = h * 37 + authzId.hashCode();
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        ProxiedAuthz otherControl = ( ProxiedAuthz ) o;
+
+        return ( authzId == otherControl.getAuthzId() )
+            || ( ( authzId != null ) && authzId.equals( otherControl.getAuthzId() ) );
+    }
+
+
+    /**
+     * Return a String representing this PagedSearchControl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Proxied Authz Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        authzid   : '" ).append( authzId ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortKey.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortKey.java
new file mode 100644
index 0000000..7cef037
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortKey.java
@@ -0,0 +1,163 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+/**
+ * Datastructure to store the Attribute name, matching rule ID of the attribute<br>
+ * and the sort order.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortKey
+{
+    /**
+     * The name/OID of AttributeType we want to use as a key for the sort
+     */
+    private String attributeTypeDesc;
+
+    /**
+     * The matching rule to use to order the result
+     */
+    private String matchingRuleId;
+
+    /**
+     * A flag to set to true to get the result in reverse order. Default to false
+     */
+    private boolean reverseOrder = false;
+
+
+    /**
+     * Create a new instance of a SortKey for a give AttributeType
+     * 
+     * @param attributeTypeDesc The AttributeType's name or OID to use
+     */
+    public SortKey( String attributeTypeDesc )
+    {
+        this( attributeTypeDesc, null );
+    }
+
+
+    /**
+     * Create a new instance of a SortKey for a give AttributeType
+     * 
+     * @param attributeTypeDesc The AttributeType's name or OID to use
+     * @param matchingRuleId The MatchingRule to use
+     */
+    public SortKey( String attributeTypeDesc, String matchingRuleId )
+    {
+        this( attributeTypeDesc, matchingRuleId, false );
+    }
+
+
+    /**
+     * Create a new instance of a SortKey for a give AttributeType
+     * 
+     * @param attributeTypeDesc The AttributeType OID to use
+     * @param matchingRuleId The MatchingRule to use
+     * @param reverseOrder The reverseOrder flag
+     */
+    public SortKey( String attributeTypeDesc, String matchingRuleId, boolean reverseOrder )
+    {
+        this.attributeTypeDesc = attributeTypeDesc;
+        this.matchingRuleId = matchingRuleId;
+        this.reverseOrder = reverseOrder;
+    }
+
+
+    /**
+     * @return the attributeType name or OID
+     */
+    public String getAttributeTypeDesc()
+    {
+        return attributeTypeDesc;
+    }
+
+
+    /**
+     * @param attributeType the attributeType to set
+     */
+    public void setAttributeTypeDesc( String attributeTypeDesc )
+    {
+        this.attributeTypeDesc = attributeTypeDesc;
+    }
+
+
+    /**
+     * @return the matchingRuleId
+     */
+    public String getMatchingRuleId()
+    {
+        return matchingRuleId;
+    }
+
+
+    /**
+     * @param matchingRuleId the matchingRuleId to set
+     */
+    public void setMatchingRuleId( String matchingRuleId )
+    {
+        this.matchingRuleId = matchingRuleId;
+    }
+
+
+    /**
+     * @return the reverseOrder
+     */
+    public boolean isReverseOrder()
+    {
+        return reverseOrder;
+    }
+
+
+    /**
+     * @param reverseOrder the reverseOrder to set
+     */
+    public void setReverseOrder( boolean reverseOrder )
+    {
+        this.reverseOrder = reverseOrder;
+    }
+
+
+    /**
+     * @see String#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "SortKey : [" );
+
+        sb.append( attributeTypeDesc );
+
+        if ( matchingRuleId != null )
+        {
+            sb.append( ", " ).append( matchingRuleId );
+        }
+
+        if ( reverseOrder )
+        {
+            sb.append( ", reverse" );
+        }
+
+        sb.append( ']' );
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortRequest.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortRequest.java
new file mode 100644
index 0000000..0e19db5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortRequest.java
@@ -0,0 +1,65 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * Implementation of Server Side Sort request control based on
+ * the <a href="http://tools.ietf.org/html/rfc2891">RFC 2891</a><br><br>
+ * 
+ *       SortKeyList ::= SEQUENCE OF SEQUENCE {<br>
+ *               attributeType   AttributeDescription,<br>
+ *               orderingRule    [0] MatchingRuleId OPTIONAL,<br>
+ *               reverseOrder    [1] BOOLEAN DEFAULT FALSE }<br>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SortRequest extends Control
+{
+    /** the sort request control's OID */
+    String OID = "1.2.840.113556.1.4.473";
+
+
+    /**
+     * sets the sort keys
+     *  
+     * @param sortKeys
+     */
+    void setSortKeys( List<SortKey> sortKeys );
+
+
+    /**
+     * @return the list of sort keys
+     */
+    List<SortKey> getSortKeys();
+
+
+    /**
+     * adds a sort key
+     * 
+     * @param sortKey
+     */
+    void addSortKey( SortKey sortKey );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortRequestControlImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortRequestControlImpl.java
new file mode 100644
index 0000000..0170bdc
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortRequestControlImpl.java
@@ -0,0 +1,80 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Implementation of SortRequestControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortRequestControlImpl extends AbstractControl implements SortRequest
+{
+    /**
+     * the list of sort keys
+     */
+    private List<SortKey> sortKeys;
+
+
+    public SortRequestControlImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     * @return the sortKeys
+     */
+    public List<SortKey> getSortKeys()
+    {
+        return sortKeys;
+    }
+
+
+    /**
+     * @param sortKeys the sortKeys to set
+     */
+    public void setSortKeys( List<SortKey> sortKeys )
+    {
+        this.sortKeys = sortKeys;
+    }
+
+
+    public void addSortKey( SortKey skey )
+    {
+        if ( sortKeys == null )
+        {
+            sortKeys = new ArrayList<SortKey>();
+        }
+
+        sortKeys.add( skey );
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return "SortRequestControlImpl [sortKeys=" + sortKeys + "]";
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResponse.java
new file mode 100644
index 0000000..28b1bb9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResponse.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+/**
+ * 
+ * <pre>SortResult ::= SEQUENCE {<br>
+ *           sortResult  ENUMERATED {<br>
+ *           success                   (0), -- results are sorted<br>
+ *           operationsError           (1), -- server internal failure<br>
+ *           timeLimitExceeded         (3), -- timelimit reached before sorting was completed<br>
+ *           strongAuthRequired        (8), -- refused to return sorted results via insecure protocol<br>
+ *           adminLimitExceeded       (11), -- too many matching entries for the server to sort<br>
+ *           noSuchAttribute          (16), -- unrecognized attribute type in sort key<br>
+ *           inappropriateMatching    (18), -- unrecognized or inappropriate matching rule in sort key<br>
+ *           insufficientAccessRights (50), -- refused to return sorted results to this client<br>
+ *           busy                     (51), -- too busy to process<br>
+ *           unwillingToPerform       (53), -- unable to sort<br>
+ *           other                    (80)<br>
+ *           },<br>
+ *       attributeType [0] AttributeDescription OPTIONAL }<br><pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SortResponse extends Control
+{
+    /** the OID of the response control */
+    String OID = "1.2.840.113556.1.4.474";
+    
+    /**
+     * sets the sort result
+     * 
+     * @param result
+     */
+    void setSortResult( SortResultCode result );
+    
+    
+    /**
+     * @return the sort result
+     */
+    SortResultCode getSortResult();
+
+    
+    /**
+     * sets the name of the first offending attribute
+     *  
+     * @param attributeName
+     */
+    // didn't name the method setAttribute*Type*
+    // cause in our internal terminology AttributeType is a java type
+    void setAttributeName( String attributeName );
+    
+    
+    /**
+     * @return the name of the first offending attribute
+     */
+    String getAttributeName();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResponseControlImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResponseControlImpl.java
new file mode 100644
index 0000000..ea978cf
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResponseControlImpl.java
@@ -0,0 +1,108 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+/**
+ * Implementation of SortResponseControl.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SortResponseControlImpl extends AbstractControl  implements SortResponse
+{
+    /** the sort operations result code */
+    private SortResultCode result;
+    
+    /** name of the first offending attribute */
+    private String attributeName;
+    
+    public SortResponseControlImpl()
+    {
+        super( OID );
+    }
+
+    @Override
+    public void setSortResult( SortResultCode result )
+    {
+        this.result = result;
+    }
+
+    @Override
+    public SortResultCode getSortResult()
+    {
+        return result;
+    }
+
+    @Override
+    public void setAttributeName( String attributeName )
+    {
+        this.attributeName = attributeName;
+    }
+
+    @Override
+    public String getAttributeName()
+    {
+        return attributeName;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int hash = super.hashCode();
+        hash = prime * hash + ( ( attributeName == null ) ? 0 : attributeName.hashCode() );
+        hash = prime * hash + ( ( this.result == null ) ? 0 : this.result.hashCode() );
+        
+        return hash;
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+        
+        SortResponse that = ( SortResponse ) o;
+        
+        if ( result != that.getSortResult() )
+        {
+            return false;
+        }
+        
+        if ( attributeName != null )
+        {
+            return ( attributeName.equalsIgnoreCase( that.getAttributeName() ) );
+        }
+        else if ( that.getAttributeName() == null )
+        {
+            return true;
+        }
+        
+        return false;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "SortResponseControlImpl [result=" + result + ", attributeName=" + attributeName + "]";
+    }
+    
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResultCode.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResultCode.java
new file mode 100644
index 0000000..0cc95b4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SortResultCode.java
@@ -0,0 +1,114 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+/**
+ * Enumeration of the result codes of a SortResult defined in <a href="http://tools.ietf.org/html/rfc2891">RFC 2891</a>
+ * for server side sort control.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SortResultCode
+{
+    SUCCESS( 0, "Results are sorted"),
+    
+    OPERATIONSERROR( 1, "Server internal failure"),
+    
+    TIMELIMITEXCEEDED( 3, "Timelimit reached before sorting was completed"),
+    
+    STRONGAUTHREQUIRED( 8, "Refused to return sorted results via insecure protocol"),
+    
+    ADMINLIMITEXCEEDED( 11, "Too many matching entries for the server to sort"),
+    
+    NOSUCHATTRIBUTE( 16, "Unrecognized attribute type in sort key"),
+    
+    INAPPROPRIATEMATCHING( 18, "Unrecognized or inappropriate matching rule in sort key"),
+    
+    INSUFFICIENTACCESSRIGHTS( 50, "Refused to return sorted results to this client"),
+    
+    BUSY( 51, "Too busy to process"),
+    
+    UNWILLINGTOPERFORM( 53, "Unable to sort"),
+    
+    OTHER( 80, "Other");
+    
+    int val;
+    String desc;
+    
+    private SortResultCode( int val, String desc )
+    {
+        this.val = val;
+        this.desc = desc;
+    }
+
+    public int getVal()
+    {
+        return val;
+    }
+    
+    /**
+     * returns the enum value representing the given code.
+     * 
+     * @param code the result code
+     * @return returns the corresponding ResultCode, throws IllegalArgumentException when there
+     *         is no matching ResultCode exists for the given value.
+     */
+    public static SortResultCode get( int code )
+    {
+        switch ( code )
+        {
+            case 0:
+                return SUCCESS;
+
+            case 1:
+                return OPERATIONSERROR;
+
+            case 3:
+                return TIMELIMITEXCEEDED;
+                
+            case 8:
+                return STRONGAUTHREQUIRED;
+
+            case 11:
+                return ADMINLIMITEXCEEDED;
+                
+            case 16:
+                return NOSUCHATTRIBUTE;
+                
+            case 18:
+                return INAPPROPRIATEMATCHING;
+                
+            case 50:
+                return INSUFFICIENTACCESSRIGHTS;
+                
+            case 51:
+                return BUSY;
+                
+            case 53:
+                return UNWILLINGTOPERFORM;
+                
+            case 80:
+                return OTHER;
+
+            default:
+                throw new IllegalArgumentException( "Unknown sort response result code " + code );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/Subentries.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/Subentries.java
new file mode 100644
index 0000000..3aa1e4e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/Subentries.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A simple Subentries Control. This control is described in RFC 3672 :
+ *    The subentries control MAY be sent with a searchRequest to control
+ *    the visibility of entries and subentries which are within scope.
+ *    Non-visible entries or subentries are not returned in response to the
+ *    request.
+ * 
+ *    The subentries control is an LDAP Control whose controlType is
+ *    1.3.6.1.4.1.4203.1.10.1, criticality is TRUE or FALSE (hence absent),
+ *    and controlValue contains a BER-encoded BOOLEAN indicating
+ *    visibility.  A controlValue containing the value TRUE indicates that
+ *    subentries are visible and normal entries are not.  A controlValue
+ *    containing the value FALSE indicates that normal entries are visible
+ *    and subentries are not.
+ * 
+ *    Note that TRUE visibility has the three octet encoding { 01 01 FF }
+ *    and FALSE visibility has the three octet encoding { 01 01 00 }.
+ * 
+ *    The controlValue SHALL NOT be absent.
+ * 
+ *    In absence of this control, subentries are not visible to singleLevel
+ *    and wholeSubtree scope Search requests but are visible to baseObject
+ *    scope Search requests.
+ * 
+ *    There is no corresponding response control.
+ * 
+ *    This control is not appropriate for non-Search operations.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Subentries extends Control
+{
+    /** The control OID */
+    String OID = "1.3.6.1.4.1.4203.1.10.1";
+
+
+    /**
+     * Check if the subEntry is visible
+     *
+     * @return true or false.
+     */
+    boolean isVisible();
+
+
+    /**
+     * Set the visibility flag
+     *
+     * @param visibility The visibility flag : true or false
+     */
+    void setVisibility( boolean visibility );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SubentriesImpl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SubentriesImpl.java
new file mode 100644
index 0000000..29e82a0
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/SubentriesImpl.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+/**
+ * A simple Subentries Control implementation. This control is described in 
+ * RFC 3672 :
+ *    The subentries control MAY be sent with a searchRequest to control
+ *    the visibility of entries and subentries which are within scope.
+ *    Non-visible entries or subentries are not returned in response to the
+ *    request.
+ * 
+ *    The subentries control is an LDAP Control whose controlType is
+ *    1.3.6.1.4.1.4203.1.10.1, criticality is TRUE or FALSE (hence absent),
+ *    and controlValue contains a BER-encoded BOOLEAN indicating
+ *    visibility.  A controlValue containing the value TRUE indicates that
+ *    subentries are visible and normal entries are not.  A controlValue
+ *    containing the value FALSE indicates that normal entries are visible
+ *    and subentries are not.
+ * 
+ *    Note that TRUE visibility has the three octet encoding { 01 01 FF }
+ *    and FALSE visibility has the three octet encoding { 01 01 00 }.
+ * 
+ *    The controlValue SHALL NOT be absent.
+ * 
+ *    In absence of this control, subentries are not visible to singleLevel
+ *    and wholeSubtree scope Search requests but are visible to baseObject
+ *    scope Search requests.
+ * 
+ *    There is no corresponding response control.
+ * 
+ *    This control is not appropriate for non-Search operations.
+ * 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubentriesImpl extends AbstractControl implements Subentries
+{
+    private boolean visibility = false;
+
+
+    /**
+     * Default constructor
+     */
+    public SubentriesImpl()
+    {
+        super( OID );
+    }
+
+
+    /**
+     * returns Tells if the Subentry values are visible or not
+     */
+    public boolean isVisible()
+    {
+        return visibility;
+    }
+
+
+    /**
+     * @param visibility Set the visibility flag
+     */
+    public void setVisibility( boolean visibility )
+    {
+        this.visibility = visibility;
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int h = super.hashCode();
+
+        h = h * 37 + ( visibility ? 1 : 0 );
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        Subentries otherDecorator = ( Subentries ) o;
+
+        return ( visibility == otherDecorator.isVisible() );
+    }
+
+
+    /**
+     * Return a String representing this EntryChangeControl.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( "    Subentries Control\n" );
+        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
+        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
+        sb.append( "        Visibility   : '" ).append( visibility ).append( "'\n" );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/AddNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/AddNoDResponse.java
new file mode 100644
index 0000000..7977616
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/AddNoDResponse.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.AddResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the Add response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class AddNoDResponse extends AddResponseImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final AddNoDResponse UNAVAILABLE = new AddNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final AddNoDResponse PROTOCOLERROR = new AddNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final AddNoDResponse STRONGAUTHREQUIRED = new AddNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private AddNoDResponse( ResultCodeEnum rcode )
+    {
+        super();
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/BindNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/BindNoDResponse.java
new file mode 100644
index 0000000..d36e539
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/BindNoDResponse.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the Bind response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class BindNoDResponse extends BindResponseImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final BindNoDResponse UNAVAILABLE = new BindNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final BindNoDResponse PROTOCOLERROR = new BindNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final BindNoDResponse STRONGAUTHREQUIRED = new BindNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private BindNoDResponse( ResultCodeEnum rcode )
+    {
+        super();
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/CompareNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/CompareNoDResponse.java
new file mode 100644
index 0000000..858f651
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/CompareNoDResponse.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the Compare response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class CompareNoDResponse extends CompareResponseImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final CompareNoDResponse UNAVAILABLE = new CompareNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final CompareNoDResponse PROTOCOLERROR = new CompareNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final CompareNoDResponse STRONGAUTHREQUIRED = new CompareNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private CompareNoDResponse( ResultCodeEnum rcode )
+    {
+        super();
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/DeleteNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/DeleteNoDResponse.java
new file mode 100644
index 0000000..45e2403
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/DeleteNoDResponse.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.DeleteResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the Delete response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DeleteNoDResponse extends DeleteResponseImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final DeleteNoDResponse UNAVAILABLE = new DeleteNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final DeleteNoDResponse PROTOCOLERROR = new DeleteNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final DeleteNoDResponse STRONGAUTHREQUIRED = new DeleteNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private DeleteNoDResponse( ResultCodeEnum rcode )
+    {
+        super();
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ExtendedNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ExtendedNoDResponse.java
new file mode 100644
index 0000000..3d93dbc
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ExtendedNoDResponse.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the Extended response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ExtendedNoDResponse extends ExtendedResponseImpl
+{
+    /** The serial version UID */
+    static final long serialVersionUID = 2L;
+
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final ExtendedNoDResponse UNAVAILABLE = new ExtendedNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final ExtendedNoDResponse PROTOCOLERROR = new ExtendedNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final ExtendedNoDResponse STRONGAUTHREQUIRED = new ExtendedNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private ExtendedNoDResponse( ResultCodeEnum rcode )
+    {
+        super( EXTENSION_OID );
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ModifyDnNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ModifyDnNoDResponse.java
new file mode 100644
index 0000000..883c974
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ModifyDnNoDResponse.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the ModifyDn response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ModifyDnNoDResponse extends ModifyDnResponseImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final ModifyDnNoDResponse UNAVAILABLE = new ModifyDnNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final ModifyDnNoDResponse PROTOCOLERROR = new ModifyDnNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final ModifyDnNoDResponse STRONGAUTHREQUIRED = new ModifyDnNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private ModifyDnNoDResponse( ResultCodeEnum rcode )
+    {
+        super();
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ModifyNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ModifyNoDResponse.java
new file mode 100644
index 0000000..c064224
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/ModifyNoDResponse.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the Modify response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ModifyNoDResponse extends ModifyResponseImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final ModifyNoDResponse UNAVAILABLE = new ModifyNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final ModifyNoDResponse PROTOCOLERROR = new ModifyNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final ModifyNoDResponse STRONGAUTHREQUIRED = new ModifyNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private ModifyNoDResponse( ResultCodeEnum rcode )
+    {
+        super();
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/NoticeOfDisconnect.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/NoticeOfDisconnect.java
new file mode 100644
index 0000000..5bbf4e0
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/NoticeOfDisconnect.java
@@ -0,0 +1,230 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection. Here's what <a
+ * href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251</a> has to say about
+ * it:
+ * 
+ * <pre>
+ *  Section 4.1.1 (Small snippet on sending NoD)
+ *  
+ *     If the server receives a PDU from the client in which the LDAPMessage
+ *     SEQUENCE tag cannot be recognized, the messageID cannot be parsed,
+ *     the tag of the protocolOp is not recognized as a request, or the
+ *     encoding structures or lengths of data fields are found to be
+ *     incorrect, then the server MUST return the notice of disconnection
+ *     described in section 4.4.1, with resultCode protocolError, and
+ *     immediately close the connection. In other cases that the server
+ *     cannot parse the request received by the client, the server MUST
+ *     return an appropriate response to the request, with the resultCode
+ *     set to protocolError.
+ *     
+ *  ...   
+ *     
+ *  4.4. Unsolicited Notification
+ *  
+ *     An unsolicited notification is an LDAPMessage sent from the server to
+ *     the client which is not in response to any LDAPMessage received by
+ *     the server. It is used to signal an extraordinary condition in the
+ *     server or in the connection between the client and the server.  The
+ *     notification is of an advisory nature, and the server will not expect
+ *     any response to be returned from the client.
+ *  
+ *     The unsolicited notification is structured as an LDAPMessage in which
+ *     the messageID is 0 and protocolOp is of the extendedResp form.  The
+ *     responseName field of the ExtendedResponse is present. The LDAPOID
+ *     value MUST be unique for this notification, and not be used in any
+ *     other situation.
+ *  
+ *     One unsolicited notification is defined in this document.
+ *  
+ *  4.4.1. Notice of Disconnection
+ *  
+ *     This notification may be used by the server to advise the client that
+ *     the server is about to close the connection due to an error
+ *     condition. Note that this notification is NOT a response to an
+ *     unbind requested by the client: the server MUST follow the procedures
+ *     of section 4.3. This notification is intended to assist clients in
+ *     distinguishing between an error condition and a transient network
+ *     failure. As with a connection close due to network failure, the
+ *     client MUST NOT assume that any outstanding requests which modified
+ *     the directory have succeeded or failed.
+ *  
+ *     The responseName is 1.3.6.1.4.1.1466.20036, the response field is
+ *     absent, and the resultCode is used to indicate the reason for the
+ *     disconnection.
+ *  
+ *     The following resultCode values are to be used in this notification:
+ *  
+ *     - protocolError: The server has received data from the client in
+ *       which the LDAPMessage structure could not be parsed.
+ *  
+ *     - strongAuthRequired: The server has detected that an established
+ *       underlying security association protecting communication between
+ *       the client and server has unexpectedly failed or been compromised.
+ *  
+ *     - unavailable: This server will stop accepting new connections and
+ *       operations on all existing connections, and be unavailable for an
+ *       extended period of time. The client may make use of an alternative
+ *       server.
+ *  
+ *     After sending this notice, the server MUST close the connection.
+ *     After receiving this notice, the client MUST NOT transmit any further
+ *     on the connection, and may abruptly close the connection.
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class NoticeOfDisconnect extends ExtendedResponseImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = "1.3.6.1.4.1.1466.20036";
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final NoticeOfDisconnect UNAVAILABLE = new NoticeOfDisconnect( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final NoticeOfDisconnect PROTOCOLERROR = new NoticeOfDisconnect( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final NoticeOfDisconnect STRONGAUTHREQUIRED = new NoticeOfDisconnect(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private NoticeOfDisconnect( ResultCodeEnum rcode )
+    {
+        super( 0, EXTENSION_OID );
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Sets the response OID specific encoded response values.
+     * 
+     * @param value the response specific encoded response values.
+     */
+    public void setResponse( byte[] value )
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04173 ) );
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+
+
+    /**
+     * Sets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @param oid
+     *            the OID of the extended response type.
+     */
+    public void setResponseName( String oid )
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_04168, EXTENSION_OID ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 37;
+        // Seems simple but look at the equals() method ...
+        hash = hash * 17 + getClass().getName().hashCode();
+
+        return hash;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        return ( obj instanceof NoticeOfDisconnect );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/SearchNoDResponse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/SearchNoDResponse.java
new file mode 100644
index 0000000..70a18c4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/extended/SearchNoDResponse.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message.extended;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.message.SearchResultDoneImpl;
+
+
+/**
+ * An extended operation intended for notifying clients of upcoming
+ * disconnection for the Search response. 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SearchNoDResponse extends SearchResultDoneImpl
+{
+    /** The OID of the NotiveOfDisconnect extended operation. */
+    public static final String EXTENSION_OID = NoticeOfDisconnect.EXTENSION_OID;
+
+    /** The empty response */
+    private static final byte[] EMPTY_RESPONSE = new byte[0];
+
+    /** The single instance with unavailable result code. */
+    public static final SearchNoDResponse UNAVAILABLE = new SearchNoDResponse( ResultCodeEnum.UNAVAILABLE );
+
+    /** The single instance with protocolError result code. */
+    public static final SearchNoDResponse PROTOCOLERROR = new SearchNoDResponse( ResultCodeEnum.PROTOCOL_ERROR );
+
+    /** The single instance with strongAuthRequired result code. */
+    public static final SearchNoDResponse STRONGAUTHREQUIRED = new SearchNoDResponse(
+        ResultCodeEnum.STRONG_AUTH_REQUIRED );
+
+
+    /**
+     * Creates a new instance of NoticeOfDisconnect.
+     */
+    private SearchNoDResponse( ResultCodeEnum rcode )
+    {
+        super();
+
+        switch ( rcode )
+        {
+            case UNAVAILABLE:
+                break;
+
+            case PROTOCOL_ERROR:
+                break;
+
+            case STRONG_AUTH_REQUIRED:
+                break;
+
+            default:
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04166, ResultCodeEnum.UNAVAILABLE,
+                    ResultCodeEnum.PROTOCOL_ERROR, ResultCodeEnum.STRONG_AUTH_REQUIRED ) );
+        }
+
+        super.getLdapResult().setDiagnosticMessage( rcode.toString() + ": The server will disconnect!" );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( rcode );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // ExtendedResponse Interface Method Implementations
+    // ------------------------------------------------------------------------
+    /**
+     * Gets the reponse OID specific encoded response values.
+     * 
+     * @return the response specific encoded response values.
+     */
+    public byte[] getResponse()
+    {
+        return EMPTY_RESPONSE;
+    }
+
+
+    /**
+     * Gets the OID uniquely identifying this extended response (a.k.a. its
+     * name).
+     * 
+     * @return the OID of the extended response type.
+     */
+    public String getResponseName()
+    {
+        return EXTENSION_OID;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Ava.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Ava.java
new file mode 100644
index 0000000..2fcdf62
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Ava.java
@@ -0,0 +1,1280 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Serialize;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Attribute Type And Value, which is the basis of all Rdn. It contains a
+ * type, and a value. The type must not be case sensitive. Superfluous leading
+ * and trailing spaces MUST have been trimmed before. The value MUST be in UTF8
+ * format, according to RFC 2253. If the type is in OID form, then the value
+ * must be a hexadecimal string prefixed by a '#' character. Otherwise, the
+ * string must respect the RC 2253 grammar.
+ *
+ * We will also keep a User Provided form of the AVA (Attribute Type And Value),
+ * called upName.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Ava implements Externalizable, Cloneable, Comparable<Ava>
+{
+    /**
+     * Declares the Serial Version Uid.
+     *
+     * @see <a
+     *      href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
+     *      Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /** The LoggerFactory used by this class */
+    private static final Logger LOG = LoggerFactory.getLogger( Ava.class );
+
+    /** The normalized Name type */
+    private String normType;
+
+    /** The user provided Name type */
+    private String upType;
+
+    /** The value. It can be a String or a byte array */
+    private Value<?> value;
+
+    /** The user provided Ava */
+    private String upName;
+
+    /** The attributeType if the Ava is schemaAware */
+    private AttributeType attributeType;
+
+    /** the schema manager */
+    private SchemaManager schemaManager;
+
+    /** The computed hashcode */
+    private volatile int h;
+
+
+    /**
+     * Constructs an empty Ava
+     */
+    public Ava()
+    {
+        this( null );
+    }
+
+
+    /**
+     * Constructs an empty schema aware Ava.
+     * 
+     * @param schemaManager The SchemaManager instance
+     */
+    public Ava( SchemaManager schemaManager )
+    {
+        normType = null;
+        upType = null;
+        value = null;
+        upName = "";
+        this.schemaManager = schemaManager;
+        this.attributeType = null;
+    }
+
+
+    /**
+     * Construct an Ava containing a binary value.
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolve
+     * to an empty string after having trimmed it.
+     *
+     * @param upType The User Provided type
+     * @param upValue The User Provided binary value
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    public Ava( String upType, byte[] upValue ) throws LdapInvalidDnException
+    {
+        this( null, upType, upValue );
+    }
+
+
+    /**
+     * Construct a schema aware Ava containing a binary value. The AttributeType
+     * and value will be normalized accordingly to the given SchemaManager.
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolve
+     * to an empty string after having trimmed it.
+     *
+     * @param schemaManager The SchemaManager instance
+     * @param upType The User Provided type
+     * @param upValue The User Provided binary value
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    public Ava( SchemaManager schemaManager, String upType, byte[] upValue ) throws LdapInvalidDnException
+    {
+        if ( schemaManager != null )
+        {
+            this.schemaManager = schemaManager;
+
+            try
+            {
+                attributeType = schemaManager.lookupAttributeTypeRegistry( upType );
+            }
+            catch ( LdapException le )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
+            }
+
+            try
+            {
+                createAva( schemaManager, upType, new BinaryValue( attributeType, upValue ) );
+            }
+            catch ( LdapInvalidAttributeValueException liave )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, liave );
+            }
+        }
+        else
+        {
+            createAva( upType, new BinaryValue( upValue ) );
+        }
+    }
+
+
+    /**
+     * Construct an Ava with a String value.
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolve
+     * to an empty string after having trimmed it.
+     *
+     * @param upType The User Provided type
+     * @param upValue The User Provided String value
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    public Ava( String upType, String upValue ) throws LdapInvalidDnException
+    {
+        this( null, upType, upValue );
+    }
+
+
+    /**
+     * Construct a schema aware Ava with a String value.
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolve
+     * to an empty string after having trimmed it.
+     *
+     * @param schemaManager The SchemaManager instance
+     * @param upType The User Provided type
+     * @param upValue The User Provided String value
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    public Ava( SchemaManager schemaManager, String upType, String upValue ) throws LdapInvalidDnException
+    {
+        if ( schemaManager != null )
+        {
+            this.schemaManager = schemaManager;
+
+            try
+            {
+                attributeType = schemaManager.lookupAttributeTypeRegistry( upType );
+            }
+            catch ( LdapException le )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
+            }
+
+            try
+            {
+                createAva( schemaManager, upType, new StringValue( attributeType, upValue ) );
+            }
+            catch ( LdapInvalidAttributeValueException liave )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, liave );
+            }
+        }
+        else
+        {
+            createAva( upType, new StringValue( upValue ) );
+        }
+    }
+
+
+    /**
+     * Construct a schema aware Ava. The AttributeType and value will be checked accordingly
+     * to the SchemaManager.
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolve
+     * to an empty string after having trimmed it.
+     *
+     * @param schemaManager The SchemaManager instance
+     * @param upType The User Provided type
+     * @param value The value
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    private void createAva( SchemaManager schemaManager, String upType, Value<?> value )
+        throws LdapInvalidDnException
+    {
+        normType = attributeType.getOid();
+        this.upType = upType;
+        this.value = value;
+        upName = this.upType + '=' + ( value == null ? "" : Rdn.escapeValue( value.getString() ) );
+        hashCode();
+    }
+
+
+    /**
+     * Construct an Ava. The type and value are normalized :
+     * <li> the type is trimmed and lowercased </li>
+     * <li> the value is trimmed </li>
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolved
+     * to an empty string after having trimmed it.
+     *
+     * @param upType The User Provided type
+     * @param upValue The User Provided value
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    private void createAva( String upType, Value<?> upValue ) throws LdapInvalidDnException
+    {
+        String upTypeTrimmed = Strings.trim( upType );
+        String normTypeTrimmed = Strings.trim( normType );
+
+        if ( Strings.isEmpty( upTypeTrimmed ) )
+        {
+            if ( Strings.isEmpty( normTypeTrimmed ) )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message );
+            }
+            else
+            {
+                // In this case, we will use the normType instead
+                this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
+                this.upType = normType;
+            }
+        }
+        else if ( Strings.isEmpty( normTypeTrimmed ) )
+        {
+            // In this case, we will use the upType instead
+            this.normType = Strings.lowerCaseAscii( upTypeTrimmed );
+            this.upType = upType;
+        }
+        else
+        {
+            this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
+            this.upType = upType;
+
+        }
+
+        value = upValue;
+
+        upName = this.upType + '=' + ( value == null ? "" : Rdn.escapeValue( value.getString() ) );
+        hashCode();
+    }
+
+
+    /**
+     * Construct an Ava. The type and value are normalized :
+     * <li> the type is trimmed and lowercased </li>
+     * <li> the value is trimmed </li>
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolved
+     * to an empty string after having trimmed it.
+     *
+     * @param schemaManager The SchemaManager
+     * @param upType The User Provided type
+     * @param normType The normalized type
+     * @param value The value
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    // WARNING : The protection level is left unspecified intentionally.
+    // We need this method to be visible from the DnParser class, but not
+    // from outside this package.
+    /* Unspecified protection */Ava( SchemaManager schemaManager, String upType, String normType, Value<?> value )
+        throws LdapInvalidDnException
+    {
+        this.upType = upType;
+        this.normType = normType;
+        this.value = value;
+        upName = this.upType + '=' + ( this.value == null ? "" : this.value.getString() );
+
+        if ( schemaManager != null )
+        {
+            apply( schemaManager );
+        }
+
+        hashCode();
+    }
+
+
+    /**
+     * Construct an Ava. The type and value are normalized :
+     * <li> the type is trimmed and lowercased </li>
+     * <li> the value is trimmed </li>
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolved
+     * to an empty string after having trimmed it.
+     *
+     * @param upType The User Provided type
+     * @param normType The normalized type
+     * @param value The User Provided value
+     * @param upName The User Provided name (may be escaped)
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    // WARNING : The protection level is left unspecified intentionally.
+    // We need this method to be visible from the DnParser class, but not
+    // from outside this package.
+    /* Unspecified protection */Ava( String upType, String normType, Value<?> value, String upName )
+        throws LdapInvalidDnException
+    {
+        this( null, upType, normType, value, upName );
+    }
+    
+    
+    /**
+     * Construct an Ava. The type and value are normalized :
+     * <li> the type is trimmed and lowercased </li>
+     * <li> the value is trimmed </li>
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolved
+     * to an empty string after having trimmed it.
+     *
+     * @param attributeType The AttributeType for this value
+     * @param upType The User Provided type
+     * @param normType The normalized type
+     * @param value The value
+     * @param upName The User Provided name (may be escaped)
+     * 
+     * @throws LdapInvalidDnException If the given type or value are invalid
+     */
+    // WARNING : The protection level is left unspecified intentionally.
+    // We need this method to be visible from the DnParser class, but not
+    // from outside this package.
+    /* Unspecified protection */Ava( AttributeType attributeType, String upType, String normType, Value<?> value, String upName )
+        throws LdapInvalidDnException
+    {
+        this.attributeType = attributeType;
+        String upTypeTrimmed = Strings.trim( upType );
+        String normTypeTrimmed = Strings.trim( normType );
+
+        if ( Strings.isEmpty( upTypeTrimmed ) )
+        {
+            if ( Strings.isEmpty( normTypeTrimmed ) )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message );
+            }
+            else
+            {
+                // In this case, we will use the normType instead
+                this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
+                this.upType = normType;
+            }
+        }
+        else if ( Strings.isEmpty( normTypeTrimmed ) )
+        {
+            // In this case, we will use the upType instead
+            this.normType = Strings.lowerCaseAscii( upTypeTrimmed );
+            this.upType = upType;
+        }
+        else
+        {
+            this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
+            this.upType = upType;
+        }
+
+        this.value = value;
+        this.upName = upName;
+        hashCode();
+    }
+
+
+    /**
+     * Apply a SchemaManager to the Ava. It will normalize the Ava.<br/>
+     * If the Ava already had a SchemaManager, then the new SchemaManager will be
+     * used instead.
+     * 
+     * @param schemaManager The SchemaManager instance to use
+     * @throws LdapInvalidDnException If the Ava can't be normalized accordingly
+     * to the given SchemaManager
+     */
+    public void apply( SchemaManager schemaManager ) throws LdapInvalidDnException
+    {
+        if ( schemaManager != null )
+        {
+            this.schemaManager = schemaManager;
+
+            AttributeType tmpAttributeType = null;
+
+            try
+            {
+                tmpAttributeType = schemaManager.lookupAttributeTypeRegistry( normType );
+            }
+            catch ( LdapException le )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
+            }
+
+            if ( this.attributeType == tmpAttributeType )
+            {
+                // No need to normalize again
+                return;
+            }
+            else
+            {
+                this.attributeType = tmpAttributeType;
+            }
+
+            normType = tmpAttributeType.getOid();
+
+            try
+            {
+                this.value.apply( tmpAttributeType );
+            }
+            catch ( LdapException le )
+            {
+                String message = I18n.err( I18n.ERR_04188 );
+                LOG.error( message );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
+            }
+
+            hashCode();
+        }
+    }
+
+
+    /**
+     * Get the normalized type of a Ava
+     *
+     * @return The normalized type
+     */
+    public String getNormType()
+    {
+        return normType;
+    }
+
+
+    /**
+     * Get the user provided type of a Ava
+     *
+     * @return The user provided type
+     */
+    public String getType()
+    {
+        return upType;
+    }
+
+
+    /**
+     * Get the Value of a Ava
+     *
+     * @return The value
+     */
+    public Value<?> getValue()
+    {
+        return value.clone();
+    }
+
+
+    /**
+     * Get the normalized Name of a Ava
+     *
+     * @return The name
+     */
+    public String getNormName()
+    {
+        return normalize();
+    }
+
+
+    /**
+     * Get the user provided form of this attribute type and value
+     *
+     * @return The user provided form of this ava
+     */
+    public String getName()
+    {
+        return upName;
+    }
+
+
+    /**
+     * Implements the cloning.
+     *
+     * @return a clone of this object
+     */
+    public Ava clone()
+    {
+        try
+        {
+            Ava clone = ( Ava ) super.clone();
+            clone.value = value.clone();
+
+            return clone;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            throw new Error( "Assertion failure", cnse );
+        }
+    }
+
+
+    /**
+     * A Normalized String representation of a Ava :
+     * <ul>
+     * <li>type is trimed and lowercased</li>
+     * <li>value is trimed and lowercased, and special characters are escaped if needed.</li>
+     * </ul>
+     *
+     * @return A normalized string representing an Ava
+     */
+    public String normalize()
+    {
+        if ( value.isHumanReadable() )
+        {
+            // The result will be gathered in a stringBuilder
+            StringBuilder sb = new StringBuilder();
+
+            // First, store the type and the '=' char
+            sb.append( normType ).append( '=' );
+
+            String normalizedValue = ( String ) value.getNormValue();
+
+            if ( ( normalizedValue != null ) && ( normalizedValue.length() > 0 ) )
+            {
+                sb.append( Rdn.escapeValue( normalizedValue ) );
+            }
+
+            return sb.toString();
+        }
+        else
+        {
+            return normType + "=#"
+                + Strings.dumpHexPairs( value.getBytes() );
+        }
+    }
+
+
+    /**
+     * Gets the hashcode of this object.
+     *
+     * @see java.lang.Object#hashCode()
+     * @return The instance hash code
+     */
+    public int hashCode()
+    {
+        if ( h == 0 )
+        {
+            h = 37;
+
+            h = h * 17 + ( normType != null ? normType.hashCode() : 0 );
+            h = h * 17 + ( value != null ? value.hashCode() : 0 );
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( !( obj instanceof Ava ) )
+        {
+            return false;
+        }
+
+        Ava instance = ( Ava ) obj;
+
+        // Compare the type
+        if ( normType == null )
+        {
+            if ( instance.normType != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !normType.equals( instance.normType ) )
+            {
+                return false;
+            }
+        }
+
+        // Compare the values
+        if ( value.isNull() )
+        {
+            return instance.value.isNull();
+        }
+        else
+        {
+            if ( schemaManager != null )
+            {
+                MatchingRule equalityMatchingRule = attributeType.getEquality();
+
+                if ( equalityMatchingRule != null )
+                {
+                    return equalityMatchingRule.getLdapComparator().compare( value.getValue(),
+                        instance.value.getValue() ) == 0;
+                }
+                else
+                {
+                    // No Equality MR, use a direct comparison
+                    if ( value instanceof BinaryValue )
+                    {
+                        return Arrays.equals( value.getBytes(), instance.value.getBytes() );
+                    }
+                    else
+                    {
+                        return value.getString().equals( instance.value.getString() );
+                    }
+                }
+            }
+            else
+            {
+                return value.equals( instance.value );
+            }
+        }
+    }
+
+
+    /**
+     * Serialize the AVA into a buffer at the given position.
+     * 
+     * @param buffer The buffer which will contain the serialized Ava
+     * @param pos The position in the buffer for the serialized value
+     * @return The new position in the buffer
+     */
+    public int serialize( byte[] buffer, int pos ) throws IOException
+    {
+        if ( Strings.isEmpty( upName )
+            || Strings.isEmpty( upType )
+            || Strings.isEmpty( normType )
+            || ( value.isNull() )
+            || ( value.isNull() ) )
+        {
+            String message = "Cannot serialize an wrong ATAV, ";
+
+            if ( Strings.isEmpty( upName ) )
+            {
+                message += "the upName should not be null or empty";
+            }
+            else if ( Strings.isEmpty( upType ) )
+            {
+                message += "the upType should not be null or empty";
+            }
+            else if ( Strings.isEmpty( normType ) )
+            {
+                message += "the normType should not be null or empty";
+            }
+            else if ( value.isNull() )
+            {
+                message += "the value should not be null";
+            }
+
+            LOG.error( message );
+            throw new IOException( message );
+        }
+
+        int length = 0;
+
+        // The upName
+        byte[] upNameBytes = null;
+
+        if ( upName != null )
+        {
+            upNameBytes = Strings.getBytesUtf8( upName );
+            length += 1 + 4 + upNameBytes.length;
+        }
+
+        // The upType
+        byte[] upTypeBytes = null;
+
+        if ( upType != null )
+        {
+            upTypeBytes = Strings.getBytesUtf8( upType );
+            length += 1 + 4 + upTypeBytes.length;
+        }
+
+        // The normType
+        byte[] normTypeBytes = null;
+
+        if ( normType != null )
+        {
+            normTypeBytes = Strings.getBytesUtf8( normType );
+            length += 1 + 4 + normTypeBytes.length;
+        }
+
+        // Is HR
+        length++;
+
+        // The hash code
+        length += 4;
+
+        // Check that we will be able to store the data in the buffer
+        if ( buffer.length - pos < length )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        // Write the upName
+        if ( upName != null )
+        {
+            buffer[pos++] = Serialize.TRUE;
+            pos = Serialize.serialize( upNameBytes, buffer, pos );
+        }
+        else
+        {
+            buffer[pos++] = Serialize.FALSE;
+        }
+
+        // Write the upType
+        if ( upType != null )
+        {
+            buffer[pos++] = Serialize.TRUE;
+            pos = Serialize.serialize( upTypeBytes, buffer, pos );
+        }
+        else
+        {
+            buffer[pos++] = Serialize.FALSE;
+        }
+
+        // Write the normType
+        if ( normType != null )
+        {
+            buffer[pos++] = Serialize.TRUE;
+            pos = Serialize.serialize( normTypeBytes, buffer, pos );
+        }
+        else
+        {
+            buffer[pos++] = Serialize.FALSE;
+        }
+
+        // Write the isHR flag
+        if ( value.isHumanReadable() )
+        {
+            buffer[pos++] = Serialize.TRUE;
+        }
+        else
+        {
+            buffer[pos++] = Serialize.FALSE;
+        }
+
+        // Write the upValue
+        if ( value.isHumanReadable() )
+        {
+            pos = ( ( StringValue ) value ).serialize( buffer, pos );
+        }
+
+        // Write the hash code
+        pos = Serialize.serialize( h, buffer, pos );
+
+        return pos;
+    }
+
+
+    /**
+     * Deserialize an AVA from a byte[], starting at a given position
+     * 
+     * @param buffer The buffer containing the AVA
+     * @param pos The position in the buffer
+     * @return The new position
+     * @throws IOException If the serialized value is not an AVA
+     * @throws LdapInvalidAttributeValueException If the serialized AVA is invalid
+     */
+    public int deserialize( byte[] buffer, int pos ) throws IOException, LdapInvalidAttributeValueException
+    {
+        if ( ( pos < 0 ) || ( pos >= buffer.length ) )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        // Read the upName value, if it's not null
+        boolean hasUpName = Serialize.deserializeBoolean( buffer, pos );
+        pos++;
+
+        if ( hasUpName )
+        {
+            byte[] wrappedValueBytes = Serialize.deserializeBytes( buffer, pos );
+            pos += 4 + wrappedValueBytes.length;
+            upName = Strings.utf8ToString( wrappedValueBytes );
+        }
+
+        // Read the upType value, if it's not null
+        boolean hasUpType = Serialize.deserializeBoolean( buffer, pos );
+        pos++;
+
+        if ( hasUpType )
+        {
+            byte[] upTypeBytes = Serialize.deserializeBytes( buffer, pos );
+            pos += 4 + upTypeBytes.length;
+            upType = Strings.utf8ToString( upTypeBytes );
+        }
+
+        // Read the normType value, if it's not null
+        boolean hasNormType = Serialize.deserializeBoolean( buffer, pos );
+        pos++;
+
+        if ( hasNormType )
+        {
+            byte[] normTypeBytes = Serialize.deserializeBytes( buffer, pos );
+            pos += 4 + normTypeBytes.length;
+            normType = Strings.utf8ToString( normTypeBytes );
+        }
+
+        // Update the AtributeType
+        if ( schemaManager != null )
+        {
+            if ( !Strings.isEmpty( upType ) )
+            {
+                attributeType = schemaManager.getAttributeType( upType );
+            }
+            else
+            {
+                attributeType = schemaManager.getAttributeType( normType );
+            }
+        }
+
+        // Read the isHR flag
+        boolean isHR = Serialize.deserializeBoolean( buffer, pos );
+        pos++;
+
+        if ( isHR )
+        {
+            // Read the upValue
+            value = new StringValue( attributeType );
+            pos = ( ( StringValue ) value ).deserialize( buffer, pos );
+        }
+
+        // Read the hashCode
+        h = Serialize.deserializeInt( buffer, pos );
+        pos += 4;
+
+        return pos;
+    }
+
+
+    /**
+     * 
+     * An Ava is composed of  a type and a value.
+     * The data are stored following the structure :
+     * <ul>
+     *   <li>
+     *     <b>upName</b> The User provided ATAV
+     *   </li>
+     *   <li>
+     *     <b>start</b> The position of this ATAV in the Dn
+     *   </li>
+     *   <li>
+     *     <b>length</b> The ATAV length
+     *   </li>
+     *   <li>
+     *     <b>upType</b> The user Provided Type
+     *   </li>
+     *   <li>
+     *     <b>normType</b> The normalized AttributeType
+     *   </li>
+     *   <li>
+     *     <b>isHR</b> Tells if the value is a String or not
+     *   </li>
+     * </ul>
+     * <br/>
+     * if the value is a String :
+     * <ul>
+     *   <li>
+     *     <b>value</b> The value
+     *   </li>
+     * </ul>
+     * <br/>
+     * if the value is binary :
+     * <ul>
+     *   <li>
+     *     <b>valueLength</b>
+     *   </li>
+     *   <li>
+     *     <b>value</b> The value
+     *   </li>
+     * </ul>
+     * 
+     * @see Externalizable#readExternal(ObjectInput)
+     * 
+     * @throws IoException If the Ava can't be written in the stream
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        if ( Strings.isEmpty( upName )
+            || Strings.isEmpty( upType )
+            || Strings.isEmpty( normType )
+            || ( value.isNull() ) )
+        {
+            String message = "Cannot serialize a wrong ATAV, ";
+
+            if ( Strings.isEmpty( upName ) )
+            {
+                message += "the upName should not be null or empty";
+            }
+            else if ( Strings.isEmpty( upType ) )
+            {
+                message += "the upType should not be null or empty";
+            }
+            else if ( Strings.isEmpty( normType ) )
+            {
+                message += "the normType should not be null or empty";
+            }
+            else if ( value.isNull() )
+            {
+                message += "the value should not be null";
+            }
+
+            LOG.error( message );
+            throw new IOException( message );
+        }
+
+        if ( upName != null )
+        {
+            out.writeBoolean( true );
+            out.writeUTF( upName );
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        if ( upType != null )
+        {
+            out.writeBoolean( true );
+            out.writeUTF( upType );
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        if ( normType != null )
+        {
+            out.writeBoolean( true );
+            out.writeUTF( normType );
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+
+        boolean isHR = value.isHumanReadable();
+
+        out.writeBoolean( isHR );
+
+        value.writeExternal( out );
+
+        // Write the hashCode
+        out.writeInt( h );
+
+        out.flush();
+    }
+
+
+    /**
+     * We read back the data to create a new ATAV. The structure
+     * read is exposed in the {@link Ava#writeExternal(ObjectOutput)}
+     * method
+     * 
+     * @see Externalizable#readExternal(ObjectInput)
+     * 
+     * @throws IOException If the Ava can't b written to the stream
+     * @throws ClassNotFoundException If we can't deserialize an Ava from the stream
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        boolean hasUpName = in.readBoolean();
+
+        if ( hasUpName )
+        {
+            upName = in.readUTF();
+        }
+
+        boolean hasUpType = in.readBoolean();
+
+        if ( hasUpType )
+        {
+            upType = in.readUTF();
+        }
+
+        boolean hasNormType = in.readBoolean();
+
+        if ( hasNormType )
+        {
+            normType = in.readUTF();
+        }
+
+        if ( schemaManager != null )
+        {
+            if ( !Strings.isEmpty( upType ) )
+            {
+                attributeType = schemaManager.getAttributeType( upType );
+            }
+            else
+            {
+                attributeType = schemaManager.getAttributeType( normType );
+            }
+        }
+
+        boolean isHR = in.readBoolean();
+
+        if ( isHR )
+        {
+            value = StringValue.deserialize( attributeType, in );
+        }
+        else
+        {
+            value = BinaryValue.deserialize( attributeType, in );
+        }
+
+        h = in.readInt();
+
+        if ( schemaManager != null )
+        {
+            attributeType = schemaManager.getAttributeType( upType );
+        }
+    }
+
+
+    /**
+     * Tells if the Ava is schema aware or not.
+     * 
+     * @return true if the Ava is schema aware
+     */
+    public boolean isSchemaAware()
+    {
+        return attributeType != null;
+    }
+
+
+    /**
+     * @return the attributeType
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    private int compareValues( Ava that )
+    {
+        int comp = 0;
+
+        if ( value.getNormValue() instanceof String )
+        {
+            comp = ( ( String ) value.getNormValue() ).compareTo( ( ( String ) that.value.getNormValue() ) );
+
+            return comp;
+        }
+        else
+        {
+            byte[] bytes1 = ( byte[] ) value.getNormValue();
+            byte[] bytes2 = ( byte[] ) that.value.getNormValue();
+
+            for ( int pos = 0; pos < bytes1.length; pos++ )
+            {
+                int v1 = ( bytes1[pos] & 0x00FF );
+                int v2 = ( bytes2[pos] & 0x00FF );
+
+                if ( v1 > v2 )
+                {
+                    return 1;
+                }
+                else if ( v2 > v1 )
+                {
+                    return -1;
+                }
+            }
+
+            return 0;
+        }
+
+    }
+
+
+    /**
+     * @see Comparable#compareTo(Object)
+     */
+    @SuppressWarnings("unchecked")
+    public int compareTo( Ava that )
+    {
+        if ( that == null )
+        {
+            return 1;
+        }
+
+        int comp = 0;
+
+        if ( schemaManager == null )
+        {
+            // Compare the ATs
+            comp = normType.compareTo( that.normType );
+
+            if ( comp != 0 )
+            {
+                return comp;
+            }
+
+            // and compare the values
+            if ( value == null )
+            {
+                if ( that.value == null )
+                {
+                    return 0;
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            else
+            {
+                if ( that.value == null )
+                {
+                    return 1;
+                }
+                else
+                {
+                    if ( value instanceof StringValue )
+                    {
+                        comp = ( ( StringValue ) value ).compareTo( ( StringValue ) that.value );
+
+                        return comp;
+                    }
+                    else
+                    {
+                        comp = ( ( BinaryValue ) value ).compareTo( ( BinaryValue ) that.value );
+
+                        return comp;
+                    }
+                }
+            }
+        }
+        else
+        {
+            if ( that.schemaManager == null )
+            {
+                // Problem : we will apply the current Ava SchemaManager to the given Ava
+                try
+                {
+                    that.apply( schemaManager );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    return 1;
+                }
+            }
+
+            // First compare the AT OID
+            comp = attributeType.getOid().compareTo( that.attributeType.getOid() );
+
+            if ( comp != 0 )
+            {
+                return comp;
+            }
+
+            // Now, compare the two values using the ordering matchingRule comparator, if any
+            MatchingRule orderingMR = attributeType.getOrdering();
+
+            if ( orderingMR != null )
+            {
+                LdapComparator<Object> comparator = ( LdapComparator<Object> ) orderingMR.getLdapComparator();
+
+                if ( comparator != null )
+                {
+                    comp = comparator.compare( value.getNormValue(), that.value.getNormValue() );
+
+                    return comp;
+                }
+                else
+                {
+                    comp = compareValues( that );
+
+                    return comp;
+                }
+            }
+            else
+            {
+                comp = compareValues( that );
+
+                return comp;
+            }
+        }
+    }
+    
+    
+    /**
+     * A String representation of an Ava, as provided by the user.
+     *
+     * @return A string representing an Ava
+     */
+    public String toString()
+    {
+        return upName;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/ComplexDnParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/ComplexDnParser.java
new file mode 100644
index 0000000..e21a0f4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/ComplexDnParser.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import java.io.StringReader;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A Dn parser that is able to parse complex DNs. This is an Antlr based parser.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No protection*/class ComplexDnParser
+{
+
+    /**
+     * Parses an Dn.
+     * 
+     * @param name the string representation of the distinguished name
+     * @param rdns the (empty) list where parsed RDNs are put to
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    /* No protection*/void parseDn( String name, List<Rdn> rdns ) throws LdapInvalidDnException
+    {
+        AntlrDnParser dnParser = new AntlrDnParser( new AntlrDnLexer( new StringReader( name ) ) );
+
+        try
+        {
+            dnParser.relativeDistinguishedNames( rdns );
+        }
+        catch ( Exception e )
+        {
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * Parses an Rdn.
+     * 
+     * @param name the string representationof the relative distinguished name
+     * @param rdn the (empty) Rdn where parsed ATAVs are put to
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    /* No protection*/void parseRdn( String name, Rdn rdn ) throws LdapInvalidDnException
+    {
+        AntlrDnParser dnParser = new AntlrDnParser( new AntlrDnLexer( new StringReader( name ) ) );
+
+        try
+        {
+            dnParser.relativeDistinguishedName( rdn );
+        }
+        catch ( Exception e )
+        {
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, e.getMessage(), e );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Dn.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Dn.java
new file mode 100644
index 0000000..080f507
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Dn.java
@@ -0,0 +1,1482 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.name;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.collections.list.UnmodifiableList;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The Dn class contains a Dn (Distinguished Name). This class is immutable.
+ * <br/>
+ * Its specification can be found in RFC 2253,
+ * "UTF-8 String Representation of Distinguished Names".
+ * <br/>
+ * We will store two representation of a Dn :
+ * <ul>
+ * <li>a user Provider representation, which is the parsed String given by a user</li>
+ * <li>an internal representation.</li>
+ * </ul>
+ *
+ * A Dn is formed of RDNs, in a specific order :<br/>
+ *  Rdn[n], Rdn[n-1], ... Rdn[1], Rdn[0]<br/>
+ *
+ * It represents a position in a hierarchy, in which the root is the last Rdn (Rdn[0]) and the leaf
+ * is the first Rdn (Rdn[n]).
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Dn implements Iterable<Rdn>, Externalizable
+{
+    /** The LoggerFactory used by this class */
+    protected static final Logger LOG = LoggerFactory.getLogger( Dn.class );
+
+    /**
+     * Declares the Serial Version Uid.
+     *
+     * @see <a
+     *      href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
+     *      Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /** Value returned by the compareTo method if values are not equals */
+    public static final int NOT_EQUAL = -1;
+
+    /** Value returned by the compareTo method if values are equals */
+    public static final int EQUAL = 0;
+
+    /**
+     *  The RDNs that are elements of the Dn<br/>
+     * NOTE THAT THESE ARE IN THE OPPOSITE ORDER FROM THAT IMPLIED BY THE JAVADOC!<br/>
+     * Rdn[0] is rdns.get(n) and Rdn[n] is rdns.get(0)
+     * <br>
+     * For instance,if the Dn is "dc=c, dc=b, dc=a", then the RDNs are stored as :
+     * <ul>
+     * <li>[0] : dc=c</li>
+     * <li>[1] : dc=b</li>
+     * <li>[2] : dc=a</li>
+     * </ul>
+     */
+    protected List<Rdn> rdns = new ArrayList<Rdn>( 5 );
+
+    /** The user provided name */
+    private String upName;
+
+    /** The normalized name */
+    private String normName;
+
+    /** The bytes representation of the normName */
+    private byte[] bytes;
+
+    /** A null Dn */
+    public static final Dn EMPTY_DN = new Dn();
+
+    /** The rootDSE */
+    public static final Dn ROOT_DSE = new Dn();
+
+    /** the schema manager */
+    private SchemaManager schemaManager;
+
+    /**
+     * An iterator over RDNs
+     */
+    private final class RdnIterator implements Iterator<Rdn>
+    {
+        // The current index
+        int index;
+
+
+        private RdnIterator()
+        {
+            index = rdns != null ? rdns.size() - 1 : -1;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean hasNext()
+        {
+            return index >= 0;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        public Rdn next()
+        {
+            return index >= 0 ? rdns.get( index-- ) : null;
+        }
+
+
+        /**
+         * {@inheritDoc}
+         */
+        public void remove()
+        {
+            // Not implemented
+        }
+    }
+
+
+    /**
+     * Construct an empty Dn object
+     */
+    public Dn()
+    {
+        this( ( SchemaManager ) null );
+    }
+
+
+    /**
+     * Construct an empty Schema aware Dn object
+     * 
+     *  @param schemaManager The SchemaManager to use
+     */
+    public Dn( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+        upName = "";
+        normName = "";
+    }
+
+
+    /**
+     * Creates a new instance of Dn, using varargs to declare the RDNs. Each
+     * String is either a full Rdn, or a couple of AttributeType DI and a value.
+     * If the String contains a '=' symbol, the the constructor will assume that
+     * the String arg contains afull Rdn, otherwise, it will consider that the
+     * following arg is the value.<br/>
+     * The created Dn is Schema aware.
+     * <br/><br/>
+     * An example of usage would be :
+     * <pre>
+     * String exampleName = "example";
+     * String baseDn = "dc=apache,dc=org";
+     *
+     * Dn dn = new Dn( DefaultSchemaManager.INSTANCE,
+     *     "cn=Test",
+     *     "ou", exampleName,
+     *     baseDn);
+     * </pre>
+     * 
+     * @param schemaManager the schema manager
+     * @param upRdns The list of String composing the Dn
+     * @throws LdapInvalidDnException If the resulting Dn is invalid
+     */
+    public Dn( String... upRdns ) throws LdapInvalidDnException
+    {
+        this( null, upRdns );
+    }
+
+
+    /**
+     * Creates a new instance of schema aware Dn, using varargs to declare the RDNs. Each
+     * String is either a full Rdn, or a couple of AttributeType DI and a value.
+     * If the String contains a '=' symbol, the the constructor will assume that
+     * the String arg contains afull Rdn, otherwise, it will consider that the
+     * following arg is the value.<br/>
+     * The created Dn is Schema aware.
+     * <br/><br/>
+     * An example of usage would be :
+     * <pre>
+     * String exampleName = "example";
+     * String baseDn = "dc=apache,dc=org";
+     *
+     * Dn dn = new Dn( DefaultSchemaManager.INSTANCE,
+     *     "cn=Test",
+     *     "ou", exampleName,
+     *     baseDn);
+     * </pre>
+     * 
+     * @param schemaManager the schema manager
+     * @param upRdns The list of String composing the Dn
+     * @throws LdapInvalidDnException If the resulting Dn is invalid
+     */
+    public Dn( SchemaManager schemaManager, String... upRdns ) throws LdapInvalidDnException
+    {
+        StringBuilder sb = new StringBuilder();
+        boolean valueExpected = false;
+        boolean isFirst = true;
+
+        for ( String upRdn : upRdns )
+        {
+            if ( Strings.isEmpty( upRdn ) )
+            {
+                continue;
+            }
+
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else if ( !valueExpected )
+            {
+                sb.append( ',' );
+            }
+
+            if ( !valueExpected )
+            {
+                sb.append( upRdn );
+
+                if ( upRdn.indexOf( '=' ) == -1 )
+                {
+                    valueExpected = true;
+                }
+            }
+            else
+            {
+                sb.append( "=" ).append( upRdn );
+
+                valueExpected = false;
+            }
+        }
+
+        if ( !isFirst && valueExpected )
+        {
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04202 ) );
+        }
+
+        // Stores the representations of a Dn : internal (as a string and as a
+        // byte[]) and external.
+        upName = sb.toString();
+        parseInternal( upName, rdns );
+
+        apply( schemaManager );
+    }
+
+
+    /**
+     * Create a schema aware Dn while deserializing it.
+     * <br/>
+     * Note : this constructor is used only by the deserialization method.
+     * 
+     * @param schemaManager the schema manager
+     * @param upName The user provided name
+     * @param normName the normalized name
+     * @param rdns the list of RDNs for this Dn
+     */
+    /* No protection */Dn( SchemaManager schemaManager, String upName, String normName, Rdn... rdns )
+    {
+        this.schemaManager = schemaManager;
+        this.upName = upName;
+        this.normName = normName;
+        bytes = Strings.getBytesUtf8Ascii( upName );
+        this.rdns = Arrays.asList( rdns );
+    }
+
+
+    /**
+     * Creates a Dn from a list of Rdns.
+     *
+     * @param rdns the list of Rdns to be used for the Dn
+     * @throws LdapInvalidDnException If the resulting Dn is invalid
+     */
+    public Dn( Rdn... rdns ) throws LdapInvalidDnException
+    {
+        if ( rdns == null )
+        {
+            return;
+        }
+
+        for ( Rdn rdn : rdns )
+        {
+            this.rdns.add( rdn );
+        }
+
+        apply( null );
+        toUpName();
+    }
+
+
+    /**
+     * Creates a Dn concatenating a Rdn and a Dn.
+     *
+     * @param rdn the Rdn to add to the Dn
+     * @param dn the Dn
+     * @throws LdapInvalidDnException If the resulting Dn is invalid
+     */
+    public Dn( Rdn rdn, Dn dn ) throws LdapInvalidDnException
+    {
+        if ( ( dn == null ) || ( rdn == null ) )
+        {
+            throw new IllegalArgumentException( "Either the dn or the rdn is null" );
+        }
+
+        for ( Rdn rdnParent : dn )
+        {
+            rdns.add( 0, rdnParent );
+        }
+
+        rdns.add( 0, rdn );
+
+        apply( dn.schemaManager );
+        toUpName();
+    }
+
+
+    /**
+     * Creates a Schema aware Dn from a list of Rdns.
+     *
+     * @param schemaManager The SchemaManager to use
+     * @param rdns the list of Rdns to be used for the Dn
+     * @throws LdapInvalidDnException If the resulting Dn is invalid
+     */
+    public Dn( SchemaManager schemaManager, Rdn... rdns ) throws LdapInvalidDnException
+    {
+        if ( rdns == null )
+        {
+            return;
+        }
+
+        for ( Rdn rdn : rdns )
+        {
+            this.rdns.add( rdn );
+        }
+
+        apply( schemaManager );
+        toUpName();
+    }
+
+
+    /**
+     * Get the associated SchemaManager if any.
+     * 
+     * @return The SchemaManager
+     */
+    public SchemaManager getSchemaManager()
+    {
+        return schemaManager;
+    }
+
+
+    /**
+     * Return the User Provided Dn as a String,
+     *
+     * @return A String representing the User Provided Dn
+     */
+    private String toUpName()
+    {
+        if ( rdns.size() == 0 )
+        {
+            upName = "";
+        }
+        else
+        {
+            StringBuffer sb = new StringBuffer();
+            boolean isFirst = true;
+
+            for ( Rdn rdn : rdns )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( ',' );
+                }
+
+                sb.append( rdn.getName() );
+            }
+
+            upName = sb.toString();
+        }
+
+        return upName;
+    }
+
+
+    /**
+     * Gets the hash code of this Dn.
+     *
+     * @see java.lang.Object#hashCode()
+     * @return the instance hash code
+     */
+    @Override
+    public int hashCode()
+    {
+        int result = 37;
+
+        for ( Rdn rdn : rdns )
+        {
+            result = result * 17 + rdn.hashCode();
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Get the user provided Dn
+     *
+     * @return The user provided Dn as a String
+     */
+    public String getName()
+    {
+        return ( upName == null ? "" : upName );
+    }
+
+
+    /**
+     * Sets the up name.
+     *
+     * Package private because Dn is immutable, only used by the Dn parser.
+     *
+     * @param upName the new up name
+     */
+    /* No qualifier */void setUpName( String upName )
+    {
+        this.upName = upName;
+    }
+
+
+    /**
+     * Get the normalized Dn. If the Dn is schema aware, the AttributeType
+     * will be represented using its OID :<br/>
+     * <pre>
+     * Dn dn = new Dn( schemaManager, "ou = Example , ou = com" );
+     * assert( "2.5.4.11=example,2.5.4.11=com".equals( dn.getNormName ) );
+     * </pre>
+     * Otherwise, it will return a Dn with the AttributeType in lower case
+     * and the value trimmed : <br/>
+     * <pre>
+     * Dn dn = new Dn( " CN = A   Test " );
+     * assertEquals( "cn=A   Test", dn.getNormName() );
+     * </pre>
+     *
+     * @return The normalized Dn as a String
+     */
+    public String getNormName()
+    {
+        return normName;
+    }
+
+
+    /**
+     * Get the number of RDNs present in the DN
+     * @return The umber of RDNs in the DN
+     */
+    public int size()
+    {
+        return rdns.size();
+    }
+
+
+    /**
+     * Get the number of bytes necessary to store this Dn
+
+     * @param dn The Dn.
+     * @return A integer, which is the size of the UTF-8 byte array
+     */
+    public static int getNbBytes( Dn dn )
+    {
+        return dn.bytes == null ? 0 : dn.bytes.length;
+    }
+
+
+    /**
+     * Get an UTF-8 representation of the normalized form of the Dn
+     *
+     * @param dn The Dn.
+     * @return A byte[] representation of the Dn
+     */
+    public static byte[] getBytes( Dn dn )
+    {
+        return dn == null ? null : dn.bytes;
+    }
+
+
+    /**
+     * Tells if the current Dn is a parent of another Dn.<br>
+     * For instance, <b>dc=com</b> is a ancestor
+     * of <b>dc=example, dc=com</b>
+     *
+     * @param dn The child
+     * @return true if the current Dn is a parent of the given Dn
+     */
+    public boolean isAncestorOf( String dn )
+    {
+        try
+        {
+            return isAncestorOf( new Dn( dn ) );
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Tells if the current Dn is a parent of another Dn.<br>
+     * For instance, <b>dc=com</b> is a ancestor
+     * of <b>dc=example, dc=com</b>
+     *
+     * @param dn The child
+     * @return true if the current Dn is a parent of the given Dn
+     */
+    public boolean isAncestorOf( Dn dn )
+    {
+        if ( dn == null )
+        {
+            return false;
+        }
+
+        return dn.isDescendantOf( this );
+    }
+
+
+    /**
+     * Tells if a Dn is a child of another Dn.<br>
+     * For instance, <b>dc=example, dc=com</b> is a descendant
+     * of <b>dc=com</b>
+     *
+     * @param dn The parent
+     * @return true if the current Dn is a child of the given Dn
+     */
+    public boolean isDescendantOf( String dn )
+    {
+        try
+        {
+            return isDescendantOf( new Dn( schemaManager, dn ) );
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Tells if a Dn is a child of another Dn.<br>
+     * For instance, <b>dc=example, dc=apache, dc=com</b> is a descendant
+     * of <b>dc=com</b>
+     *
+     * @param dn The parent
+     * @return true if the current Dn is a child of the given Dn
+     */
+    public boolean isDescendantOf( Dn dn )
+    {
+        if ( ( dn == null ) || dn.isRootDse() )
+        {
+            return true;
+        }
+
+        if ( dn.size() > size() )
+        {
+            // The name is longer than the current Dn.
+            return false;
+        }
+
+        // Ok, iterate through all the Rdn of the name,
+        // starting a the end of the current list.
+
+        for ( int i = dn.size() - 1; i >= 0; i-- )
+        {
+            Rdn nameRdn = dn.rdns.get( dn.rdns.size() - i - 1 );
+            Rdn ldapRdn = rdns.get( rdns.size() - i - 1 );
+
+            if ( !nameRdn.equals( ldapRdn ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Tells if the Dn contains no Rdn
+     *
+     * @return <code>true</code> if the Dn is empty
+     */
+    public boolean isEmpty()
+    {
+        return ( rdns.size() == 0 );
+    }
+
+
+    /**
+     * Tells if the Dn is the RootDSE Dn (ie, an empty Dn)
+     *
+     * @return <code>true</code> if the Dn is the RootDSE's Dn
+     */
+    public boolean isRootDse()
+    {
+        return ( rdns.size() == 0 );
+    }
+
+
+    /**
+     * Retrieves a component of this name.
+     *
+     * @param posn the 0-based index of the component to retrieve. Must be in the
+     *            range [0,size()).
+     * @return the component at index posn
+     * @throws ArrayIndexOutOfBoundsException
+     *             if posn is outside the specified range
+     */
+    public Rdn getRdn( int posn )
+    {
+        if ( rdns.size() == 0 )
+        {
+            return null;
+        }
+
+        if ( ( posn < 0 ) || ( posn >= rdns.size() ) )
+        {
+            throw new IllegalArgumentException( "Invalid position : " + posn );
+        }
+
+        Rdn rdn = rdns.get( posn );
+
+        return rdn;
+    }
+
+
+    /**
+     * Retrieves the last (leaf) component of this name.
+     *
+     * @return the last component of this Dn
+     */
+    public Rdn getRdn()
+    {
+        if ( isNullOrEmpty( this ) )
+        {
+            return Rdn.EMPTY_RDN;
+        }
+
+        return rdns.get( 0 );
+    }
+
+
+    /**
+     * Retrieves all the components of this name.
+     *
+     * @return All the components
+     */
+    @SuppressWarnings("unchecked")
+    public List<Rdn> getRdns()
+    {
+        return UnmodifiableList.decorate( rdns );
+    }
+
+
+    /**
+     * Get the descendant of a given DN, using the ancestr DN. Assuming that
+     * a DN has two parts :<br/>
+     * DN = [descendant DN][ancestor DN]<br/>
+     * To get back the descendant from the full DN, you just pass the ancestor DN
+     * as a parameter. Here is a working example :
+     * <pre>
+     * Dn dn = new Dn( "cn=test, dc=server, dc=directory, dc=apache, dc=org" );
+     * 
+     * Dn descendant = dn.getDescendantOf( "dc=apache, dc=org" );
+     * 
+     * // At this point, the descendant contains cn=test, dc=server, dc=directory"
+     * </pre>
+     */
+    public Dn getDescendantOf( String ancestor ) throws LdapInvalidDnException
+    {
+        return getDescendantOf( new Dn( schemaManager, ancestor ) );
+    }
+
+
+    /**
+     * Get the descendant of a given DN, using the ancestr DN. Assuming that
+     * a DN has two parts :<br/>
+     * DN = [descendant DN][ancestor DN]<br/>
+     * To get back the descendant from the full DN, you just pass the ancestor DN
+     * as a parameter. Here is a working example :
+     * <pre>
+     * Dn dn = new Dn( "cn=test, dc=server, dc=directory, dc=apache, dc=org" );
+     * 
+     * Dn descendant = dn.getDescendantOf( "dc=apache, dc=org" );
+     * 
+     * // At this point, the descendant contains cn=test, dc=server, dc=directory"
+     * </pre>
+     */
+    public Dn getDescendantOf( Dn ancestor ) throws LdapInvalidDnException
+    {
+        if ( ( ancestor == null ) || ( ancestor.size() == 0 ) )
+        {
+            return this;
+        }
+
+        if ( rdns.size() == 0 )
+        {
+            return EMPTY_DN;
+        }
+
+        int length = ancestor.size();
+
+        if ( length > rdns.size() )
+        {
+            String message = I18n.err( I18n.ERR_04206, length, rdns.size() );
+            LOG.error( message );
+            throw new ArrayIndexOutOfBoundsException( message );
+        }
+
+        Dn newDn = new Dn( schemaManager );
+        List<Rdn> rdnsAncestor = ancestor.getRdns();
+
+        for ( int i = 0; i < ancestor.size(); i++ )
+        {
+            Rdn rdn = rdns.get( size() - 1 - i );
+            Rdn rdnDescendant = rdnsAncestor.get( ancestor.size() - 1 - i );
+
+            if ( !rdn.equals( rdnDescendant ) )
+            {
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX );
+            }
+        }
+
+        for ( int i = 0; i < rdns.size() - length; i++ )
+        {
+            newDn.rdns.add( rdns.get( i ) );
+        }
+
+        newDn.toUpName();
+        newDn.apply( schemaManager, true );
+
+        return newDn;
+    }
+
+
+    /**
+     * Get the ancestor of a given DN, using the descendant DN. Assuming that
+     * a DN has two parts :<br/>
+     * DN = [descendant DN][ancestor DN]<br/>
+     * To get back the ancestor from the full DN, you just pass the descendant DN
+     * as a parameter. Here is a working example :
+     * <pre>
+     * Dn dn = new Dn( "cn=test, dc=server, dc=directory, dc=apache, dc=org" );
+     * 
+     * Dn ancestor = dn.getAncestorOf( "cn=test, dc=server, dc=directory" );
+     * 
+     * // At this point, the ancestor contains "dc=apache, dc=org"
+     * </pre>
+     */
+    public Dn getAncestorOf( String descendant ) throws LdapInvalidDnException
+    {
+        return getAncestorOf( new Dn( schemaManager, descendant ) );
+    }
+
+
+    /**
+     * Get the ancestor of a given DN, using the descendant DN. Assuming that
+     * a DN has two parts :<br/>
+     * DN = [descendant DN][ancestor DN]<br/>
+     * To get back the ancestor from the full DN, you just pass the descendant DN
+     * as a parameter. Here is a working example :
+     * <pre>
+     * Dn dn = new Dn( "cn=test, dc=server, dc=directory, dc=apache, dc=org" );
+     * 
+     * Dn ancestor = dn.getAncestorOf( new Dn( "cn=test, dc=server, dc=directory" ) );
+     * 
+     * // At this point, the ancestor contains "dc=apache, dc=org"
+     * </pre>
+     */
+    public Dn getAncestorOf( Dn descendant ) throws LdapInvalidDnException
+    {
+        if ( ( descendant == null ) || ( descendant.size() == 0 ) )
+        {
+            return this;
+        }
+
+        if ( rdns.size() == 0 )
+        {
+            return EMPTY_DN;
+        }
+
+        int length = descendant.size();
+
+        if ( length > rdns.size() )
+        {
+            String message = I18n.err( I18n.ERR_04206, length, rdns.size() );
+            LOG.error( message );
+            throw new ArrayIndexOutOfBoundsException( message );
+        }
+
+        Dn newDn = new Dn( schemaManager );
+        List<Rdn> rdnsDescendant = descendant.getRdns();
+
+        for ( int i = 0; i < descendant.size(); i++ )
+        {
+            Rdn rdn = rdns.get( i );
+            Rdn rdnDescendant = rdnsDescendant.get( i );
+
+            if ( !rdn.equals( rdnDescendant ) )
+            {
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX );
+            }
+        }
+
+        for ( int i = length; i < rdns.size(); i++ )
+        {
+            newDn.rdns.add( rdns.get( i ) );
+        }
+
+        newDn.toUpName();
+        newDn.apply( schemaManager, true );
+
+        return newDn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn add( Dn suffix ) throws LdapInvalidDnException
+    {
+        if ( ( suffix == null ) || ( suffix.size() == 0 ) )
+        {
+            return this;
+        }
+
+        Dn clonedDn = copy();
+
+        // Concatenate the rdns
+        clonedDn.rdns.addAll( 0, suffix.rdns );
+
+        // Regenerate the normalized name and the original string
+        if ( clonedDn.isSchemaAware() && suffix.isSchemaAware() )
+        {
+            if ( clonedDn.size() != 0 )
+            {
+                clonedDn.normName = suffix.getNormName() + "," + normName;
+                clonedDn.bytes = Strings.getBytesUtf8Ascii( normName );
+                clonedDn.upName = suffix.getName() + "," + upName;
+            }
+        }
+        else
+        {
+            clonedDn.apply( schemaManager, true );
+            clonedDn.toUpName();
+        }
+
+        return clonedDn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Dn add( String comp ) throws LdapInvalidDnException
+    {
+        if ( comp.length() == 0 )
+        {
+            return this;
+        }
+
+        Dn clonedDn = copy();
+
+        // We have to parse the nameComponent which is given as an argument
+        Rdn newRdn = new Rdn( schemaManager, comp );
+
+        clonedDn.rdns.add( 0, newRdn );
+
+        clonedDn.apply( schemaManager, true );
+        clonedDn.toUpName();
+
+        return clonedDn;
+    }
+
+
+    /**
+     * Adds a single Rdn to the (leaf) end of this name.
+     *
+     * @param newRdn the Rdn to add
+     * @return the updated cloned Dn
+     */
+    public Dn add( Rdn newRdn ) throws LdapInvalidDnException
+    {
+        if ( ( newRdn == null ) || ( newRdn.size() == 0 ) )
+        {
+            return this;
+        }
+
+        Dn clonedDn = copy();
+
+        clonedDn.rdns.add( 0, newRdn );
+        clonedDn.apply( schemaManager, true );
+        clonedDn.toUpName();
+
+        return clonedDn;
+    }
+
+
+    /**
+     * Gets the parent Dn of this Dn. Null if this Dn doesn't have a parent, i.e. because it
+     * is the empty Dn.<br/>
+     * The Parent is the right part of the Dn, when the Rdn has been removed.
+     *
+     * @return the parent Dn of this Dn
+     */
+    public Dn getParent()
+    {
+        if ( isNullOrEmpty( this ) )
+        {
+            return this;
+        }
+
+        int posn = rdns.size() - 1;
+
+        Dn newDn = new Dn( schemaManager );
+
+        for ( int i = rdns.size() - posn; i < rdns.size(); i++ )
+        {
+            newDn.rdns.add( rdns.get( i ) );
+        }
+
+        try
+        {
+            newDn.apply( schemaManager, true );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+        }
+
+        newDn.toUpName();
+
+        return newDn;
+    }
+
+
+    /**
+     * Create a copy of the current Dn
+     */
+    private Dn copy()
+    {
+        Dn dn = new Dn( schemaManager );
+        dn.rdns = new ArrayList<Rdn>();
+
+        for ( Rdn rdn : rdns )
+        {
+            dn.rdns.add( rdn );
+        }
+
+        return dn;
+    }
+
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     * @return <code>true</code> if the two instances are equals
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj instanceof String )
+        {
+            return normName.equals( obj );
+        }
+        else if ( obj instanceof Dn )
+        {
+            Dn name = ( Dn ) obj;
+
+            if ( name.getNormName().equals( normName ) )
+            {
+                return true;
+            }
+
+            if ( name.size() != this.size() )
+            {
+                return false;
+            }
+
+            for ( int i = 0; i < this.size(); i++ )
+            {
+                if ( !name.rdns.get( i ).equals( rdns.get( i ) ) )
+                {
+                    return false;
+                }
+            }
+
+            // All components matched so we return true
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Normalize the Ava
+     */
+    private static Ava atavOidToName( Ava atav, SchemaManager schemaManager )
+        throws LdapInvalidDnException
+    {
+        Map<String, OidNormalizer> oidsMap = schemaManager.getNormalizerMapping();
+        String type = Strings.trim( atav.getNormType() );
+
+        if ( ( type.startsWith( "oid." ) ) || ( type.startsWith( "OID." ) ) )
+        {
+            type = type.substring( 4 );
+        }
+
+        if ( Strings.isNotEmpty( type ) )
+        {
+            if ( oidsMap == null )
+            {
+                return atav;
+            }
+
+            type = Strings.toLowerCaseAscii( type );
+
+            // Check that we have an existing AttributeType for this type
+            if ( !oidsMap.containsKey( type ) )
+            {
+                // No AttributeType : this is an error
+                String msg = I18n.err( I18n.ERR_04268_OID_NOT_FOUND, atav.getType() );
+                LOG.error( msg );
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, msg );
+            }
+
+            OidNormalizer oidNormalizer = oidsMap.get( type );
+
+            if ( oidNormalizer != null )
+            {
+                try
+                {
+                    AttributeType attributeType = schemaManager.getAttributeType( type );
+                    Value<?> atavValue = null;
+                    Value<?> value = atav.getValue();
+                    
+                    if ( value instanceof StringValue )
+                    {
+                        if ( attributeType.getSyntax().isHumanReadable() )
+                        {
+                            atavValue = new StringValue( attributeType, value.getString() );
+                        }
+                        else
+                        {
+                            // This is a binary variable, transaform the StringValue to a BinaryValye
+                            atavValue = new BinaryValue( attributeType, value.getBytes() );
+                        }
+                    }
+                    else
+                    {
+                        atavValue = new BinaryValue( attributeType, atav.getValue().getBytes() );
+                    }
+                    
+                    Ava newAva = new Ava(
+                        attributeType,
+                        atav.getType(),
+                        oidNormalizer.getAttributeTypeOid(),
+                        atavValue,
+                        atav.getName() );
+
+                    return newAva;
+                }
+                catch ( LdapException le )
+                {
+                    throw new LdapInvalidDnException( le.getMessage(), le );
+                }
+            }
+            else
+            {
+                // We don't have a normalizer for this OID : just do nothing.
+                return atav;
+            }
+        }
+        else
+        {
+            // The type is empty : this is not possible...
+            String msg = I18n.err( I18n.ERR_04209_EMPTY_TYPE_NOT_ALLOWED );
+            LOG.error( msg );
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, msg );
+        }
+    }
+
+
+    /**
+     * Transform a Rdn by changing the value to its OID counterpart and
+     * normalizing the value accordingly to its type. We also sort the AVAs
+     *
+     * @param rdn The Rdn to modify.
+     * @param SchemaManager The schema manager
+     * @throws LdapInvalidDnException If the Rdn is invalid.
+     */
+    /** No qualifier */
+    static void rdnOidToName( Rdn rdn, SchemaManager schemaManager ) throws LdapInvalidDnException
+    {
+        // We have more than one ATAV for this Rdn. We will loop on all
+        // ATAVs
+        //Rdn rdnCopy = rdn.clone();
+        //rdn.clear();
+
+        if ( rdn.size() < 2 )
+        {
+            Ava newAtav = atavOidToName( rdn.getAva(), schemaManager );
+            rdn.replaceAva( newAtav, 0 );
+        }
+        else
+        {
+            Set<String> sortedOids = new TreeSet<String>();
+            Map<String, Ava> avas = new HashMap<String, Ava>();
+
+            // Sort the OIDs
+            for ( Ava val : rdn )
+            {
+                Ava newAtav = atavOidToName( val, schemaManager );
+                String oid = newAtav.getAttributeType().getOid();
+                sortedOids.add( oid );
+                avas.put( oid, newAtav );
+            }
+
+            // And create the Rdn
+            int pos = 0;
+
+            for ( String oid : sortedOids )
+            {
+                rdn.replaceAva( avas.get( oid ), pos++ );
+            }
+        }
+    }
+
+
+    /**
+     * Normalizes the Dn using the given the schema manager. If the flag is set to true,
+     * we will replace the inner SchemaManager by the provided one.
+     *
+     * @param schemaManager The schemaManagerto use to normalize the Dn
+     * @param force Tells if we should replace an existing SchemaManager by a new one
+     * @return The normalized Dn
+     * @throws LdapInvalidDnException If the Dn is invalid.
+     */
+    public Dn apply( SchemaManager schemaManager, boolean force ) throws LdapInvalidDnException
+    {
+        if ( ( this.schemaManager == null ) || force )
+        {
+            this.schemaManager = schemaManager;
+
+            if ( this.schemaManager != null )
+            {
+                synchronized ( this )
+                {
+                    if ( size() == 0 )
+                    {
+                        bytes = null;
+                        normName = "";
+
+                        return this;
+                    }
+
+                    StringBuilder sb = new StringBuilder();
+                    boolean isFirst = true;
+
+                    for ( Rdn rdn : rdns )
+                    {
+                        rdn.apply( schemaManager );
+
+                        if ( isFirst )
+                        {
+                            isFirst = false;
+                        }
+                        else
+                        {
+                            sb.append( ',' );
+                        }
+
+                        sb.append( rdn.getNormName() );
+                    }
+
+                    String newNormName = sb.toString();
+
+                    if ( ( normName == null ) || !normName.equals( newNormName ) )
+                    {
+                        bytes = Strings.getBytesUtf8Ascii( newNormName );
+                        normName = newNormName;
+                    }
+                }
+            }
+            else
+            {
+                if ( rdns.size() == 0 )
+                {
+                    bytes = null;
+                    normName = "";
+                }
+                else
+                {
+                    StringBuffer sb = new StringBuffer();
+                    boolean isFirst = true;
+
+                    for ( Rdn rdn : rdns )
+                    {
+                        if ( isFirst )
+                        {
+                            isFirst = false;
+                        }
+                        else
+                        {
+                            sb.append( ',' );
+                        }
+
+                        sb.append( rdn.getNormName() );
+                    }
+
+                    String newNormName = sb.toString();
+
+                    if ( ( normName == null ) || !normName.equals( newNormName ) )
+                    {
+                        bytes = Strings.getBytesUtf8Ascii( newNormName );
+                        normName = newNormName;
+                    }
+                }
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * Normalizes the Dn using the given the schema manager, unless the Dn is already normalized
+     *
+     * @param schemaManager The schemaManagerto use to normalize the Dn
+     * @return The normalized Dn
+     * @throws LdapInvalidDnException If the Dn is invalid.
+     */
+    public Dn apply( SchemaManager schemaManager ) throws LdapInvalidDnException
+    {
+        if ( this.schemaManager != null )
+        {
+            return this;
+        }
+        else
+        {
+            return apply( schemaManager, true );
+        }
+    }
+
+
+    /**
+     * Tells if the Dn is schema aware
+     *
+     * @return <code>true</code> if the Dn is schema aware.
+     */
+    public boolean isSchemaAware()
+    {
+        return schemaManager != null;
+    }
+
+
+    /**
+     * Iterate over the inner Rdn. The Rdn are returned from
+     * the rightmost to the leftmost. For instance, the following code :<br/>
+     * <pre>
+     * Dn dn = new Dn( "sn=test, dc=apache, dc=org );
+     * 
+     * for ( Rdn rdn : dn )
+     * {
+     *     System.out.println( rdn.toString() );
+     * }
+     * </pre>
+     * will produce this output : <br/>
+     * <pre>
+     * dc=org
+     * dc=apache
+     * sn=test
+     * </pre>
+     * 
+     */
+    public Iterator<Rdn> iterator()
+    {
+        return new RdnIterator();
+    }
+
+
+    /**
+     * Check if a DistinguishedName is null or empty.
+     *
+     * @param dn The Dn to check
+     * @return <code>true></code> if the Dn is null or empty, <code>false</code>
+     * otherwise
+     */
+    public static boolean isNullOrEmpty( Dn dn )
+    {
+        return ( dn == null ) || dn.isEmpty();
+    }
+
+
+    /**
+     * Check if a DistinguishedName is syntactically valid.
+     *
+     * @param dn The Dn to validate
+     * @return <code>true></code> if the Dn is valid, <code>false</code>
+     * otherwise
+     */
+    public static boolean isValid( String name )
+    {
+        Dn dn = new Dn();
+
+        try
+        {
+            parseInternal( name, dn.rdns );
+            return true;
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Parse a Dn.
+     *
+     * @param name The Dn to be parsed
+     * @param rdns The list that will contain the RDNs
+     * @throws LdapInvalidDnException If the Dn is invalid
+     */
+    private static void parseInternal( String name, List<Rdn> rdns ) throws LdapInvalidDnException
+    {
+        try
+        {
+            FastDnParser.parseDn( name, rdns );
+        }
+        catch ( TooComplexDnException e )
+        {
+            rdns.clear();
+            new ComplexDnParser().parseDn( name, rdns );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the UPName
+        upName = in.readUTF();
+
+        // Read the NormName
+        normName = in.readUTF();
+
+        if ( normName.length() == 0 )
+        {
+            // As the normName is equal to the upName,
+            // we didn't saved the nbnormName on disk.
+            // restore it by copying the upName.
+            normName = upName;
+        }
+
+        // Read the RDNs. Is it's null, the number will be -1.
+        int nbRdns = in.readInt();
+
+        rdns = new ArrayList<Rdn>( nbRdns );
+
+        for ( int i = 0; i < nbRdns; i++ )
+        {
+            Rdn rdn = new Rdn( schemaManager );
+            rdn.readExternal( in );
+            rdns.add( rdn );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        if ( upName == null )
+        {
+            String message = "Cannot serialize a NULL Dn";
+            LOG.error( message );
+            throw new IOException( message );
+        }
+
+        // Write the UPName
+        out.writeUTF( upName );
+
+        // Write the NormName if different
+        if ( upName.equals( normName ) )
+        {
+            out.writeUTF( "" );
+        }
+        else
+        {
+            out.writeUTF( normName );
+        }
+
+        // Write the RDNs.
+        // First the number of RDNs
+        out.writeInt( size() );
+
+        // Loop on the RDNs
+        for ( Rdn rdn : rdns )
+        {
+            rdn.writeExternal( out );
+        }
+
+        out.flush();
+    }
+
+
+    /**
+     * Return the user provided Dn as a String. It returns the same value as the
+     * getName method
+     *
+     * @return A String representing the user provided Dn
+     */
+    @Override
+    public String toString()
+    {
+        return getName();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/DnUtils.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/DnUtils.java
new file mode 100644
index 0000000..6d6504d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/DnUtils.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+/**
+ * Utility class used to manipulate Dn or Rdn elements.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DnUtils
+{
+    /**
+     * Gets the attributeType of a RDN (the left part of the RDN). The RDN is supposed
+     * to contain only one AVA.
+     *
+     * @param rdn the RDN
+     * @return the attributeType 
+     */
+    public static String getRdnAttributeType( String rdn )
+    {
+        int index = rdn.indexOf( '=' );
+        return rdn.substring( 0, index );
+    }
+
+
+    /**
+     * Gets the value of a RDN ( the right part of the RDN). The RDN is supposed
+     * to contain only one AVA.
+     *
+     * @param rdn the RDN
+     * @return the value of tpart of the RDN
+     */
+    public static String getRdnValue( String rdn )
+    {
+        int index = rdn.indexOf( '=' );
+        return rdn.substring( index + 1, rdn.length() );
+    }
+
+
+    private DnUtils()
+    {
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/FastDnParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/FastDnParser.java
new file mode 100644
index 0000000..6c555d1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/FastDnParser.java
@@ -0,0 +1,628 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.util.Position;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A fast LDAP Dn parser that handles only simple DNs. If the Dn contains
+ * any special character an {@link TooComplexException} is thrown.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+/* No protection*/enum FastDnParser
+{
+    INSTANCE;
+
+    /**
+     * Parses a Dn from a String
+     *
+     * @param name The Dn to parse
+     * @return A valid Dn
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If the Dn was invalid
+     */
+    /* No protection*/static Dn parse( String name ) throws LdapException
+    {
+        Dn dn = new Dn();
+        parseDn( name, dn );
+        return dn;
+    }
+
+
+    /**
+     * Parses the given name string and fills the given Dn object.
+     * 
+     * @param name the name to parse
+     * @param dn the Dn to fill
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    /* No protection*/static void parseDn( String name, Dn dn ) throws LdapInvalidDnException
+    {
+        parseDn( name, dn.rdns );
+        dn.setUpName( name );
+        dn.apply( null );
+    }
+
+
+    /* No protection*/static void parseDn( String name, List<Rdn> rdns ) throws LdapInvalidDnException
+    {
+        if ( ( name == null ) || ( name.trim().length() == 0 ) )
+        {
+            // We have an empty Dn, just get out of the function.
+            return;
+        }
+
+        Position pos = new Position();
+        char[] chars = name.toCharArray();
+
+        pos.start = 0;
+        pos.length = chars.length;
+
+        while ( true )
+        {
+            Rdn rdn = new Rdn();
+            parseRdnInternal( name, pos, rdn );
+            rdns.add( rdn );
+
+            if ( !hasMoreChars( pos ) )
+            {
+                // end of line reached
+                break;
+            }
+
+            char c = nextChar( chars, pos, true );
+
+            switch ( c )
+            {
+                case ',':
+                case ';':
+                    // another Rdn to parse
+                    break;
+
+                default:
+                    throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04192, c,
+                        pos.start ) );
+            }
+        }
+    }
+
+
+    /**
+     * Parses the given name string and fills the given Rdn object.
+     * 
+     * @param name the name to parse
+     * @param rdn the Rdn to fill
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    /* No protection*/static void parseRdn( String name, Rdn rdn ) throws LdapInvalidDnException
+    {
+        if ( name == null || name.length() == 0 )
+        {
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04193 ) );
+        }
+
+        if ( rdn == null )
+        {
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04194 ) );
+        }
+
+        Position pos = new Position();
+        pos.start = 0;
+        pos.length = name.length();
+
+        parseRdnInternal( name, pos, rdn );
+    }
+
+
+    private static void parseRdnInternal( String name, Position pos, Rdn rdn ) throws LdapInvalidDnException
+    {
+        int rdnStart = pos.start;
+        char[] chars = name.toCharArray();
+
+        // SPACE*
+        matchSpaces( chars, pos );
+
+        // attributeType: ALPHA (ALPHA|DIGIT|HYPEN) | NUMERICOID
+        String type = matchAttributeType( chars, pos );
+
+        // SPACE*
+        matchSpaces( chars, pos );
+
+        // EQUALS
+        matchEquals( chars, pos );
+
+        // SPACE*
+        matchSpaces( chars, pos );
+
+        // here we only match "simple" values
+        // stops at \ + # " -> Too Complex Exception
+        String upValue = matchValue( chars, pos );
+        String value = Strings.trimRight( upValue );
+        // TODO: trim, normalize, etc
+
+        // SPACE*
+        matchSpaces( chars, pos );
+
+        String upName = name.substring( rdnStart, pos.start );
+
+        Ava ava = new Ava( type, type, new StringValue( upValue ), upName );
+        rdn.addAVA( null, ava );
+
+        rdn.setUpName( upName );
+        rdn.normalize();
+    }
+
+
+    /**
+     * Matches and forgets optional spaces.
+     * 
+     * @param name the name
+     * @param pos the pos
+     * @throws LdapInvalidDnException 
+     */
+    private static void matchSpaces( char[] name, Position pos ) throws LdapInvalidDnException
+    {
+        while ( hasMoreChars( pos ) )
+        {
+            char c = nextChar( name, pos, true );
+
+            if ( c != ' ' )
+            {
+                pos.start--;
+                break;
+            }
+        }
+    }
+
+
+    /**
+     * Matches attribute type.
+     * 
+     * @param name the name
+     * @param pos the pos
+     * 
+     * @return the matched attribute type
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    private static String matchAttributeType( char[] name, Position pos ) throws LdapInvalidDnException
+    {
+        char c = nextChar( name, pos, false );
+
+        switch ( c )
+        {
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'G':
+            case 'H':
+            case 'I':
+            case 'J':
+            case 'K':
+            case 'L':
+            case 'M':
+            case 'N':
+            case 'O':
+            case 'P':
+            case 'Q':
+            case 'R':
+            case 'S':
+            case 'T':
+            case 'U':
+            case 'V':
+            case 'W':
+            case 'X':
+            case 'Y':
+            case 'Z':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+            case 'g':
+            case 'h':
+            case 'i':
+            case 'j':
+            case 'k':
+            case 'l':
+            case 'm':
+            case 'n':
+            case 'o':
+            case 'p':
+            case 'q':
+            case 'r':
+            case 's':
+            case 't':
+            case 'u':
+            case 'v':
+            case 'w':
+            case 'x':
+            case 'y':
+            case 'z':
+                // descr
+                return matchAttributeTypeDescr( name, pos );
+
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                // numericoid
+                return matchAttributeTypeNumericOid( name, pos );
+
+            default:
+                // error
+                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04195, c,
+                    pos.start ) );
+        }
+    }
+
+
+    /**
+     * Matches attribute type descr.
+     * 
+     * @param name the name
+     * @param pos the pos
+     * 
+     * @return the attribute type descr
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    private static String matchAttributeTypeDescr( char[] name, Position pos ) throws LdapInvalidDnException
+    {
+        int start = pos.start;
+
+        while ( hasMoreChars( pos ) )
+        {
+            char c = nextChar( name, pos, true );
+
+            switch ( c )
+            {
+                case 'A':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'E':
+                case 'F':
+                case 'G':
+                case 'H':
+                case 'I':
+                case 'J':
+                case 'K':
+                case 'L':
+                case 'M':
+                case 'N':
+                case 'O':
+                case 'P':
+                case 'Q':
+                case 'R':
+                case 'S':
+                case 'T':
+                case 'U':
+                case 'V':
+                case 'W':
+                case 'X':
+                case 'Y':
+                case 'Z':
+                case 'a':
+                case 'b':
+                case 'c':
+                case 'd':
+                case 'e':
+                case 'f':
+                case 'g':
+                case 'h':
+                case 'i':
+                case 'j':
+                case 'k':
+                case 'l':
+                case 'm':
+                case 'n':
+                case 'o':
+                case 'p':
+                case 'q':
+                case 'r':
+                case 's':
+                case 't':
+                case 'u':
+                case 'v':
+                case 'w':
+                case 'x':
+                case 'y':
+                case 'z':
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                case '-':
+                case '_':
+                    // Violation of the RFC, just because those idiots at Microsoft decided to support it...
+                    break;
+
+                case ' ':
+                case '=':
+                    pos.start--;
+                    return new String( name, start, pos.start - start );
+
+                case '.':
+                    // occurs for RDNs of form "oid.1.2.3=test"
+                    throw TooComplexDnException.INSTANCE;
+
+                default:
+                    // error
+                    throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04196, c,
+                        pos.start ) );
+            }
+        }
+
+        return new String( name, start, pos.start - start );
+    }
+
+
+    /**
+     * Matches attribute type numeric OID.
+     * 
+     * @param name the name
+     * @param pos the pos
+     * 
+     * @return the attribute type OID
+     * 
+     * @throws org.apache.directory.api.ldap.model.exception.LdapInvalidDnException the invalid name exception
+     */
+    private static String matchAttributeTypeNumericOid( char[] name, Position pos ) throws LdapInvalidDnException
+    {
+        int dotCount = 0;
+        int start = pos.start;
+
+        while ( true )
+        {
+            char c = nextChar( name, pos, true );
+
+            switch ( c )
+            {
+                case '0':
+                    // leading '0', no other digit may follow!
+                    c = nextChar( name, pos, true );
+
+                    switch ( c )
+                    {
+                        case '.':
+                            dotCount++;
+                            break;
+
+                        case ' ':
+                        case '=':
+                            pos.start--;
+                            break;
+
+                        default:
+                            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err(
+                                I18n.ERR_04197, c, pos.start ) );
+                    }
+
+                    break;
+
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    boolean inInnerLoop = true;
+
+                    while ( inInnerLoop )
+                    {
+                        c = nextChar( name, pos, true );
+
+                        switch ( c )
+                        {
+                            case ' ':
+                            case '=':
+                                inInnerLoop = false;
+                                pos.start--;
+                                break;
+
+                            case '.':
+                                inInnerLoop = false;
+                                dotCount++;
+                                // no break!
+                            case '0':
+                            case '1':
+                            case '2':
+                            case '3':
+                            case '4':
+                            case '5':
+                            case '6':
+                            case '7':
+                            case '8':
+                            case '9':
+                                break;
+
+                            default:
+                                throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err(
+                                    I18n.ERR_04197, c, pos.start ) );
+                        }
+                    }
+
+                    break;
+
+                case ' ':
+                case '=':
+                    pos.start--;
+
+                    if ( dotCount > 0 )
+                    {
+                        return new String( name, start, pos.start - start );
+                    }
+                    else
+                    {
+                        throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04198 ) );
+                    }
+
+                default:
+                    throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04199, c,
+                        pos.start ) );
+            }
+        }
+    }
+
+
+    /**
+     * Matches the equals character.
+     * 
+     * @param name the name
+     * @param pos the pos
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    private static void matchEquals( char[] name, Position pos ) throws LdapInvalidDnException
+    {
+        char c = nextChar( name, pos, true );
+
+        if ( c != '=' )
+        {
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04200, c, pos.start ) );
+        }
+    }
+
+
+    /**
+     * Matches the assertion value. This method only handles simple values.
+     * If we find any special character (BACKSLASH, PLUS, SHARP or DQUOTE),
+     * a TooComplexException will be thrown.
+     * 
+     * @param name the name
+     * @param pos the pos
+     * 
+     * @return the string
+     * 
+     * @throws LdapInvalidDnException the invalid name exception
+     */
+    private static String matchValue( char[] name, Position pos ) throws LdapInvalidDnException
+    {
+        //StringBuilder value = new StringBuilder();
+        int start = pos.start;
+        int numTrailingSpaces = 0;
+
+        while ( true )
+        {
+            if ( !hasMoreChars( pos ) )
+            {
+                pos.start -= numTrailingSpaces;
+                return new String( name, start, pos.start - start );
+            }
+
+            char c = nextChar( name, pos, true );
+
+            switch ( c )
+            {
+                case '\\':
+                case '+':
+                case '#':
+                case '"':
+                    throw TooComplexDnException.INSTANCE;
+
+                case ',':
+                case ';':
+                    pos.start--;
+                    pos.start -= numTrailingSpaces;
+                    return new String( name, start, pos.start - start );
+
+                case ' ':
+                    numTrailingSpaces++;
+                    break;
+
+                default:
+                    numTrailingSpaces = 0;
+            }
+        }
+    }
+
+
+    /**
+     * Gets the next character.
+     * 
+     * @param name the name
+     * @param pos the pos
+     * @param increment true to increment the position
+     * 
+     * @return the character
+     * @throws LdapInvalidDnException If no more characters are available
+     */
+    private static char nextChar( char[] name, Position pos, boolean increment ) throws LdapInvalidDnException
+    {
+        if ( !hasMoreChars( pos ) )
+        {
+            throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04201, pos.start ) );
+        }
+
+        char c = name[pos.start];
+
+        if ( increment )
+        {
+            pos.start++;
+        }
+
+        return c;
+    }
+
+
+    /**
+     * Checks if there are more characters.
+     * 
+     * @param pos the pos
+     * 
+     * @return true, if more characters are available
+     */
+    private static boolean hasMoreChars( Position pos )
+    {
+        return pos.start < pos.length;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Rdn.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Rdn.java
new file mode 100644
index 0000000..d838538
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/Rdn.java
@@ -0,0 +1,1908 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.collections.MultiMap;
+import org.apache.commons.collections.map.MultiValueMap;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Hex;
+import org.apache.directory.api.util.Serialize;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.Unicode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class store the name-component part or the following BNF grammar (as of
+ * RFC2253, par. 3, and RFC1779, fig. 1) : <br> - &lt;name-component&gt; ::=
+ * &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt;
+ * &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt; <br> -
+ * &lt;attributeTypeAndValues&gt; ::= &lt;spaces&gt; '+' &lt;spaces&gt;
+ * &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt;
+ * &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt; | e <br> -
+ * &lt;attributeType&gt; ::= [a-zA-Z] &lt;keychars&gt; | &lt;oidPrefix&gt; [0-9]
+ * &lt;digits&gt; &lt;oids&gt; | [0-9] &lt;digits&gt; &lt;oids&gt; <br> -
+ * &lt;keychars&gt; ::= [a-zA-Z] &lt;keychars&gt; | [0-9] &lt;keychars&gt; | '-'
+ * &lt;keychars&gt; | e <br> - &lt;oidPrefix&gt; ::= 'OID.' | 'oid.' | e <br> -
+ * &lt;oids&gt; ::= '.' [0-9] &lt;digits&gt; &lt;oids&gt; | e <br> -
+ * &lt;attributeValue&gt; ::= &lt;pairs-or-strings&gt; | '#' &lt;hexstring&gt;
+ * |'"' &lt;quotechar-or-pairs&gt; '"' <br> - &lt;pairs-or-strings&gt; ::= '\'
+ * &lt;pairchar&gt; &lt;pairs-or-strings&gt; | &lt;stringchar&gt;
+ * &lt;pairs-or-strings&gt; | e <br> - &lt;quotechar-or-pairs&gt; ::=
+ * &lt;quotechar&gt; &lt;quotechar-or-pairs&gt; | '\' &lt;pairchar&gt;
+ * &lt;quotechar-or-pairs&gt; | e <br> - &lt;pairchar&gt; ::= ',' | '=' | '+' |
+ * '&lt;' | '&gt;' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F] <br> -
+ * &lt;hexstring&gt; ::= [0-9a-fA-F] [0-9a-fA-F] &lt;hexpairs&gt; <br> -
+ * &lt;hexpairs&gt; ::= [0-9a-fA-F] [0-9a-fA-F] &lt;hexpairs&gt; | e <br> -
+ * &lt;digits&gt; ::= [0-9] &lt;digits&gt; | e <br> - &lt;stringchar&gt; ::=
+ * [0x00-0xFF] - [,=+&lt;&gt;#;\"\n\r] <br> - &lt;quotechar&gt; ::= [0x00-0xFF] -
+ * [\"] <br> - &lt;separator&gt; ::= ',' | ';' <br> - &lt;spaces&gt; ::= ' '
+ * &lt;spaces&gt; | e <br>
+ * <br>
+ * A Rdn is a part of a Dn. It can be composed of many types, as in the Rdn
+ * following Rdn :<br>
+ * ou=value + cn=other value<br>
+ * <br>
+ * or <br>
+ * ou=value + ou=another value<br>
+ * <br>
+ * In this case, we have to store an 'ou' and a 'cn' in the Rdn.<br>
+ * <br>
+ * The types are case insensitive. <br>
+ * Spaces before and after types and values are not stored.<br>
+ * Spaces before and after '+' are not stored.<br>
+ * <br>
+ * Thus, we can consider that the following RDNs are equals :<br>
+ * <br>
+ * 'ou=test 1'<br> ' ou=test 1'<br>
+ * 'ou =test 1'<br>
+ * 'ou= test 1'<br>
+ * 'ou=test 1 '<br> ' ou = test 1 '<br>
+ * <br>
+ * So are the following :<br>
+ * <br>
+ * 'ou=test 1+cn=test 2'<br>
+ * 'ou = test 1 + cn = test 2'<br> ' ou =test 1+ cn =test 2 ' <br>
+ * 'cn = test 2 +ou = test 1'<br>
+ * <br>
+ * but the following are not equal :<br>
+ * 'ou=test 1' <br>
+ * 'ou=test 1'<br>
+ * because we have more than one spaces inside the value.<br>
+ * <br>
+ * The Rdn is composed of one or more Ava. Those Avas
+ * are ordered in the alphabetical natural order : a < b < c ... < z As the type
+ * are not case sensitive, we can say that a = A
+ * <br>
+ * This class is immutable.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Rdn implements Cloneable, Externalizable, Iterable<Ava>, Comparable<Rdn>
+{
+    /** The LoggerFactory used by this class */
+    protected static final Logger LOG = LoggerFactory.getLogger( Rdn.class );
+
+    /** An empty Rdn */
+    public static final Rdn EMPTY_RDN = new Rdn();
+
+    /**
+    * Declares the Serial Version Uid.
+    *
+    * @see <a
+    *      href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
+    *      Declare Serial Version Uid</a>
+    */
+    private static final long serialVersionUID = 1L;
+
+    /** The User Provided Rdn */
+    private String upName = null;
+
+    /** The normalized Rdn */
+    private String normName = null;
+
+    /**
+     * Stores all couple type = value. We may have more than one type, if the
+     * '+' character appears in the Ava. This is a TreeSet,
+     * because we want the Avas to be sorted. An Ava may contain more than one
+     * value. In this case, the values are String stored in a List.
+     */
+    private List<Ava> avas = null;
+
+    /**
+     * We also keep a set of types, in order to use manipulations. A type is
+     * connected with the Ava it represents.
+     *
+     * Note : there is no Generic available classes in commons-collection...
+     */
+    private MultiMap avaTypes = new MultiValueMap();
+
+    /**
+     * We keep the type for a single valued Rdn, to avoid the creation of an HashMap
+     */
+    private String avaType = null;
+
+    /**
+     * A simple Ava is used to store the Rdn for the simple
+     * case where we only have a single type=value. This will be 99.99% the
+     * case. This avoids the creation of a HashMap.
+     */
+    protected Ava ava = null;
+
+    /**
+     * The number of Avas. We store this number here to avoid complex
+     * manipulation of Ava and Avas
+     */
+    private int nbAvas = 0;
+
+    /** CompareTo() results */
+    public static final int UNDEFINED = Integer.MAX_VALUE;
+
+    /** Constant used in comparisons */
+    public static final int SUPERIOR = 1;
+
+    /** Constant used in comparisons */
+    public static final int INFERIOR = -1;
+
+    /** Constant used in comparisons */
+    public static final int EQUAL = 0;
+
+    /** A flag used to tell if the Rdn has been normalized */
+    private boolean normalized = false;
+
+    /** the schema manager */
+    private SchemaManager schemaManager;
+
+    /** The computed hashcode */
+    private volatile int h;
+
+
+    /**
+     * A empty constructor.
+     */
+    public Rdn()
+    {
+        this( ( SchemaManager ) null );
+    }
+
+
+    /**
+     *
+     * Creates a new schema aware instance of Rdn.
+     *
+     * @param schemaManager the schema manager
+     */
+    public Rdn( SchemaManager schemaManager )
+    {
+        // Don't waste space... This is not so often we have multiple
+        // name-components in a Rdn... So we won't initialize the Map and the
+        // treeSet.
+        this.schemaManager = schemaManager;
+        upName = "";
+        normName = "";
+        normalized = false;
+        h = 0;
+    }
+
+
+    /**
+     *  A constructor that parse a String representing a schema aware Rdn.
+     *
+     * @param schemaManager the schema manager
+     * @param rdn the String containing the Rdn to parse
+     * @throws LdapInvalidDnException if the Rdn is invalid
+     */
+    public Rdn( SchemaManager schemaManager, String rdn ) throws LdapInvalidDnException
+    {
+        if ( Strings.isNotEmpty( rdn ) )
+        {
+            // Parse the string. The Rdn will be updated.
+            parse( rdn, this );
+
+            // create the internal normalized form
+            // and store the user provided form
+            if ( schemaManager != null )
+            {
+                this.schemaManager = schemaManager;
+                apply( schemaManager );
+                normalized = true;
+            }
+            else
+            {
+                normalize();
+                normalized = false;
+            }
+
+            if ( upName.length() < rdn.length() )
+            {
+                throw new LdapInvalidDnException( "Invalid RDN" );
+            }
+
+            upName = rdn;
+        }
+        else
+        {
+            upName = "";
+            normName = "";
+            normalized = false;
+        }
+
+        hashCode();
+    }
+
+
+    /**
+     * A constructor that parse a String representing a Rdn.
+     *
+     * @param rdn the String containing the Rdn to parse
+     * @throws LdapInvalidDnException if the Rdn is invalid
+     */
+    public Rdn( String rdn ) throws LdapInvalidDnException
+    {
+        this( ( SchemaManager ) null, rdn );
+    }
+
+
+    /**
+     * A constructor that constructs a schema aware Rdn from a type and a value.
+     * <p>
+     * The string attribute values are not interpreted as RFC 414 formatted Rdn
+     * strings. That is, the values are used literally (not parsed) and assumed
+     * to be un-escaped.
+      *
+     * @param schemaManager the schema manager
+     * @param upType the user provided type of the Rdn
+     * @param upValue the user provided value of the Rdn
+     * @throws LdapInvalidDnException if the Rdn is invalid
+     */
+    public Rdn( SchemaManager schemaManager, String upType, String upValue ) throws LdapInvalidDnException
+    {
+        addAVA( schemaManager, upType, upType, new StringValue( upValue ) );
+
+        upName = upType + '=' + upValue;
+
+        if ( schemaManager != null )
+        {
+            this.schemaManager = schemaManager;
+            apply( schemaManager );
+            normalized = true;
+        }
+        else
+        {
+            // create the internal normalized form
+            normalize();
+
+            // As strange as it seems, the Rdn is *not* normalized against the schema at this point
+            normalized = false;
+        }
+
+        hashCode();
+    }
+
+
+    /**
+     * A constructor that constructs a Rdn from a type and a value.
+     *
+     * @param upType the user provided type of the Rdn
+     * @param upValue the user provided value of the Rdn
+     * @throws LdapInvalidDnException if the Rdn is invalid
+     * @see #Rdn( SchemaManager, String, String )
+     */
+    public Rdn( String upType, String upValue ) throws LdapInvalidDnException
+    {
+        this( null, upType, upValue );
+    }
+
+
+    public Rdn( SchemaManager schemaManager, Ava... avas ) throws LdapInvalidDnException
+    {
+        StringBuilder buffer = new StringBuilder();
+        
+        for ( int i = 0; i < avas.length; i++ )
+        {
+            if ( i > 0 )
+            {
+                buffer.append( '+' );
+            }
+            
+            addAVA( schemaManager, avas[i] );
+            buffer.append( avas[i].getName() );
+        }
+        
+        setUpName( buffer.toString() );
+        normalize();
+    }
+
+
+    public Rdn( Ava... avas ) throws LdapInvalidDnException
+    {
+        this( null, avas );
+    }
+
+
+    /**
+     * Constructs an Rdn from the given rdn. The content of the rdn is simply
+     * copied into the newly created Rdn.
+     *
+     * @param rdn The non-null Rdn to be copied.
+     */
+    public Rdn( Rdn rdn )
+    {
+        nbAvas = rdn.size();
+        this.normName = rdn.normName;
+        this.upName = rdn.getName();
+        normalized = rdn.normalized;
+        schemaManager = rdn.schemaManager;
+
+        switch ( rdn.size() )
+        {
+            case 0:
+                hashCode();
+
+                return;
+
+            case 1:
+                this.ava = rdn.ava.clone();
+                hashCode();
+
+                return;
+
+            default:
+                // We must duplicate the treeSet and the hashMap
+                avas = new ArrayList<Ava>();
+                avaTypes = new MultiValueMap();
+
+                for ( Ava currentAva : rdn.avas )
+                {
+                    avas.add( currentAva.clone() );
+                    avaTypes.put( currentAva.getNormType(), currentAva );
+                }
+
+                hashCode();
+
+                return;
+        }
+    }
+
+
+    /**
+     * Transform the external representation of the current Rdn to an internal
+     * normalized form where :
+     * - types are trimmed and lower cased
+     * - values are trimmed and lower cased
+     */
+    // WARNING : The protection level is left unspecified on purpose.
+    // We need this method to be visible from the DnParser class, but not
+    // from outside this package.
+    /* Unspecified protection */void normalize()
+    {
+        switch ( nbAvas )
+        {
+            case 0:
+                // An empty Rdn
+                normName = "";
+                break;
+
+            case 1:
+                // We have a single Ava
+                // We will trim and lowercase type and value.
+                if ( ava.getValue().isHumanReadable() )
+                {
+                    normName = ava.getNormName();
+                }
+                else
+                {
+                    normName = ava.getNormType() + "=#" + Strings.dumpHexPairs( ava.getValue().getBytes() );
+                }
+
+                break;
+
+            default:
+                // We have more than one Ava
+                StringBuffer sb = new StringBuffer();
+
+                boolean isFirst = true;
+
+                for ( Ava ata : avas )
+                {
+                    if ( isFirst )
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        sb.append( '+' );
+                    }
+
+                    sb.append( ata.getNormName() );
+                }
+
+                normName = sb.toString();
+                break;
+        }
+
+        hashCode();
+    }
+
+
+    /**
+     * Transform a Rdn by changing the value to its OID counterpart and
+     * normalizing the value accordingly to its type. The modified Rdn is
+     * a new instance, as the Rdn class is immutable.
+     *
+     * @param schemaManager the SchemaManager
+     * @return this Rdn, normalized
+     * @throws LdapInvalidDnException if the Rdn is invalid
+     */
+    public Rdn apply( SchemaManager schemaManager ) throws LdapInvalidDnException
+    {
+        if ( normalized )
+        {
+            return this;
+        }
+
+        String savedUpName = getName();
+        Dn.rdnOidToName( this, schemaManager );
+        normalize();
+        this.upName = savedUpName;
+        normalized = true;
+        this.schemaManager = schemaManager;
+        hashCode();
+
+        return this;
+    }
+
+
+    /**
+     * Add an Ava to the current Rdn
+     *
+     * @param upType The user provided type of the added Rdn.
+     * @param type The normalized provided type of the added Rdn.
+     * @param upValue The user provided value of the added Rdn
+     * @param value The normalized provided value of the added Rdn
+     * @throws LdapInvalidDnException
+     *             If the Rdn is invalid
+     */
+    private void addAVA( SchemaManager schemaManager, String upType, String type, Value<?> value ) throws LdapInvalidDnException
+    {
+        // First, let's normalize the type
+        AttributeType attributeType = null;
+        String normalizedType = Strings.lowerCaseAscii( type );
+        this.schemaManager = schemaManager;
+
+        if ( schemaManager != null )
+        {
+            attributeType = schemaManager.getAttributeType( normalizedType );
+            
+            try
+            {
+                value.apply( attributeType );
+            }
+            catch ( LdapInvalidAttributeValueException liave )
+            {
+                throw new LdapInvalidDnException( liave.getMessage(), liave );
+            }
+        }
+
+        switch ( nbAvas )
+        {
+            case 0:
+                // This is the first Ava. Just stores it.
+                ava = new Ava( schemaManager, upType, normalizedType, value );
+                nbAvas = 1;
+                avaType = normalizedType;
+                hashCode();
+
+                return;
+
+            case 1:
+                // We already have an Ava. We have to put it in the HashMap
+                // before adding a new one.
+                // First, create the HashMap,
+                avas = new ArrayList<Ava>();
+
+                // and store the existing Ava into it.
+                avas.add( ava );
+                avaTypes = new MultiValueMap();
+                avaTypes.put( avaType, ava );
+
+                ava = null;
+
+                // Now, fall down to the commmon case
+                // NO BREAK !!!
+
+            default:
+                // add a new Ava
+                Ava newAva = new Ava( schemaManager, upType, normalizedType, value );
+                avas.add( newAva );
+                avaTypes.put( normalizedType, newAva );
+                nbAvas++;
+                hashCode();
+
+                return;
+
+        }
+    }
+
+
+    /**
+     * Replace an Ava into a Rdn at a given position
+     *
+     * @param value The modified Ava
+     * @param pos The position of the Ava in the Rdn
+     * @exception LdapInvalidDnException If the position is not valid
+     */
+    // WARNING : The protection level is left unspecified intentionally.
+    // We need this method to be visible from the DnParser class, but not
+    // from outside this package.
+    /* Unspecified protection */void replaceAva( Ava value, int pos ) throws LdapInvalidDnException
+    {
+        if ( ( pos < 0 ) || ( pos > nbAvas ) )
+        {
+            throw new LdapInvalidDnException( "Cannot set the AVA at position " + pos );
+        }
+
+        String normalizedType = value.getNormType();
+
+        switch ( nbAvas )
+        {
+            case 1:
+                // This is the first Ava. Just stores it.
+                ava = value;
+                avaType = normalizedType;
+
+                break;
+
+            default:
+                Ava oldAva = avas.get( pos );
+                avas.set( pos, value );
+                avaTypes.remove( oldAva.getType() );
+                avaTypes.put( normalizedType, value );
+
+                break;
+        }
+
+        h = 0;
+        hashCode();
+    }
+
+
+    /**
+     * Add an Ava to the current schema aware Rdn
+     *
+     * @param value The added Ava
+     */
+    // WARNING : The protection level is left unspecified intentionally.
+    // We need this method to be visible from the DnParser class, but not
+    // from outside this package.
+    /* Unspecified protection */void addAVA( SchemaManager schemaManager, Ava value ) throws LdapInvalidDnException
+    {
+        this.schemaManager = schemaManager;
+        String normalizedType = value.getNormType();
+
+        switch ( nbAvas )
+        {
+            case 0:
+                // This is the first Ava. Just stores it.
+                ava = value;
+                nbAvas = 1;
+                avaType = normalizedType;
+                hashCode();
+
+                return;
+
+            case 1:
+                // We already have an Ava. We have to put it in the HashMap
+                // before adding a new one.
+                // Check that the first AVA is not for the same attribute
+                if ( avaType.equals( normalizedType ) )
+                {
+                    throw new LdapInvalidDnException( "Invalid RDN: the " + normalizedType
+                        + " is already present in the RDN" );
+                }
+
+                // First, create the HashMap,
+                avas = new ArrayList<Ava>();
+
+                // and store the existing Ava into it.
+                avas.add( ava );
+                avaTypes = new MultiValueMap();
+                avaTypes.put( avaType, ava );
+
+                this.ava = null;
+
+                // Now, fall down to the commmon case
+                // NO BREAK !!!
+
+            default:
+                // Check that the AT is not already present
+                if ( avaTypes.containsKey( normalizedType ) )
+                {
+                    throw new LdapInvalidDnException( "Invalid RDN: the " + normalizedType
+                        + " is already present in the RDN" );
+                }
+
+                // add a new Ava
+                avas.add( value );
+                avaTypes.put( normalizedType, value );
+                nbAvas++;
+                hashCode();
+
+                break;
+        }
+    }
+
+
+    /**
+     * Clear the Rdn, removing all the Avas.
+     */
+    // WARNING : The protection level is left unspecified intentionally.
+    // We need this method to be visible from the DnParser class, but not
+    // from outside this package.
+    /* No protection */void clear()
+    {
+        ava = null;
+        avas = null;
+        avaType = null;
+        avaTypes.clear();
+        nbAvas = 0;
+        normName = "";
+        upName = "";
+        normalized = false;
+        h = 0;
+    }
+
+
+    /**
+     * Get the value of the Ava which type is given as an
+     * argument.
+     *
+     * @param type the type of the NameArgument
+     * @return the value to be returned, or null if none found.
+     * @throws LdapInvalidDnException if the Rdn is invalid
+     */
+    public Object getValue( String type ) throws LdapInvalidDnException
+    {
+        // First, let's normalize the type
+        String normalizedType = Strings.lowerCaseAscii( Strings.trim( type ) );
+
+        if ( schemaManager != null )
+        {
+            AttributeType attributeType = schemaManager.getAttributeType( normalizedType );
+
+            if ( attributeType != null )
+            {
+                normalizedType = attributeType.getOid();
+            }
+        }
+
+        switch ( nbAvas )
+        {
+            case 0:
+                return "";
+
+            case 1:
+                if ( Strings.equals( ava.getNormType(), normalizedType ) )
+                {
+                    return ava.getValue().getValue();
+                }
+
+                return "";
+
+            default:
+                if ( avaTypes.containsKey( normalizedType ) )
+                {
+                    @SuppressWarnings("unchecked")
+                    Collection<Ava> atavList = ( Collection<Ava> ) avaTypes.get( normalizedType );
+                    StringBuffer sb = new StringBuffer();
+                    boolean isFirst = true;
+
+                    for ( Ava elem : atavList )
+                    {
+                        if ( isFirst )
+                        {
+                            isFirst = false;
+                        }
+                        else
+                        {
+                            sb.append( ',' );
+                        }
+
+                        sb.append( elem.getValue() );
+                    }
+
+                    return sb.toString();
+                }
+
+                return "";
+        }
+    }
+
+
+    /**
+     * Get the normalized value of the Ava which type is given as an
+     * argument.
+     *
+     * @param type the type of the NameArgument
+     * @return the normalized value to be returned, or null if none found.
+     * @throws LdapInvalidDnException if the Rdn is invalid
+     */
+    public Object getNormValue( String type ) throws LdapInvalidDnException
+    {
+        // First, let's normalize the type
+        String normalizedType = Strings.lowerCaseAscii( Strings.trim( type ) );
+
+        if ( schemaManager != null )
+        {
+            AttributeType attributeType = schemaManager.getAttributeType( normalizedType );
+
+            if ( attributeType != null )
+            {
+                normalizedType = attributeType.getOid();
+            }
+        }
+
+        switch ( nbAvas )
+        {
+            case 0:
+                return "";
+
+            case 1:
+                if ( Strings.equals( ava.getNormType(), normalizedType ) )
+                {
+                    return ava.getValue().getNormValue();
+                }
+
+                return "";
+
+            default:
+                if ( avaTypes.containsKey( normalizedType ) )
+                {
+                    @SuppressWarnings("unchecked")
+                    Collection<Ava> atavList = ( Collection<Ava> ) avaTypes.get( normalizedType );
+                    StringBuffer sb = new StringBuffer();
+                    boolean isFirst = true;
+
+                    for ( Ava elem : atavList )
+                    {
+                        if ( isFirst )
+                        {
+                            isFirst = false;
+                        }
+                        else
+                        {
+                            sb.append( ',' );
+                        }
+
+                        sb.append( elem.getValue().getNormValue() );
+                    }
+
+                    return sb.toString();
+                }
+
+                return "";
+        }
+    }
+
+
+    /**
+     * Get the Ava which type is given as an argument. If we
+     * have more than one value associated with the type, we will return only
+     * the first one.
+     *
+     * @param type
+     *            The type of the NameArgument to be returned
+     * @return The Ava, of null if none is found.
+     */
+    public Ava getAva( String type )
+    {
+        // First, let's normalize the type
+        String normalizedType = Strings.lowerCaseAscii( Strings.trim( type ) );
+
+        switch ( nbAvas )
+        {
+            case 0:
+                return null;
+
+            case 1:
+                if ( ava.getNormType().equals( normalizedType ) )
+                {
+                    return ava;
+                }
+
+                return null;
+
+            default:
+                if ( avaTypes.containsKey( normalizedType ) )
+                {
+                    @SuppressWarnings("unchecked")
+                    Collection<Ava> atavList = ( Collection<Ava> ) avaTypes.get( normalizedType );
+                    return atavList.iterator().next();
+                }
+
+                return null;
+        }
+    }
+
+
+    /**
+     * Retrieves the components of this Rdn as an iterator of Avas.
+     * The effect on the iterator of updates to this Rdn is undefined. If the
+     * Rdn has zero components, an empty (non-null) iterator is returned.
+     *
+     * @return an iterator of the components of this Rdn, each an Ava
+     */
+    public Iterator<Ava> iterator()
+    {
+        if ( ( nbAvas == 1 ) || ( nbAvas == 0 ) )
+        {
+            return new Iterator<Ava>()
+            {
+                private boolean hasMoreElement = nbAvas == 1;
+
+
+                public boolean hasNext()
+                {
+                    return hasMoreElement;
+                }
+
+
+                public Ava next()
+                {
+                    Ava obj = ava;
+                    hasMoreElement = false;
+                    return obj;
+                }
+
+
+                public void remove()
+                {
+                    // nothing to do
+                }
+            };
+        }
+        else
+        {
+            return avas.iterator();
+        }
+    }
+
+
+    /**
+     * Clone the Rdn
+     *
+     * @return A clone of the current Rdn
+     */
+    public Rdn clone()
+    {
+        try
+        {
+            Rdn rdn = ( Rdn ) super.clone();
+            rdn.normalized = normalized;
+
+            // The Ava is immutable. We won't clone it
+
+            switch ( rdn.size() )
+            {
+                case 0:
+                    break;
+
+                case 1:
+                    rdn.ava = this.ava.clone();
+                    rdn.avaTypes = avaTypes;
+                    break;
+
+                default:
+                    // We must duplicate the treeSet and the hashMap
+                    rdn.avaTypes = new MultiValueMap();
+                    rdn.avas = new ArrayList<Ava>();
+
+                    for ( Ava currentAva : this.avas )
+                    {
+                        rdn.avas.add( currentAva.clone() );
+                        rdn.avaTypes.put( currentAva.getNormType(), currentAva );
+                    }
+
+                    break;
+            }
+
+            return rdn;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            throw new Error( "Assertion failure", cnse );
+        }
+    }
+
+
+    /**
+     * @return the user provided name
+     */
+    public String getName()
+    {
+        return upName;
+    }
+
+
+    /**
+     * @return The normalized name
+     */
+    public String getNormName()
+    {
+        return normName == null ? "" : normName;
+    }
+
+
+    /**
+     * Set the User Provided Name.
+     *
+     * Package private because Rdn is immutable, only used by the Dn parser.
+     *
+     * @param upName the User Provided dame
+     */
+    void setUpName( String upName )
+    {
+        this.upName = upName;
+    }
+
+
+    /**
+     * Return the unique Ava, or the first one of we have more
+     * than one
+     *
+     * @return The first Ava of this Rdn
+     */
+    public Ava getAva()
+    {
+        switch ( nbAvas )
+        {
+            case 0:
+                return null;
+
+            case 1:
+                return ava;
+
+            default:
+                return avas.get( 0 );
+        }
+    }
+
+
+    /**
+     * Return the user provided type, or the first one of we have more than one (the lowest)
+     *
+     * @return The first user provided type of this Rdn
+     */
+    public String getType()
+    {
+        switch ( nbAvas )
+        {
+            case 0:
+                return null;
+
+            case 1:
+                return ava.getType();
+
+            default:
+                return avas.get( 0 ).getType();
+        }
+    }
+
+
+    /**
+     * Return the normalized type, or the first one of we have more than one (the lowest)
+     *
+     * @return The first normalized type of this Rdn
+     */
+    public String getNormType()
+    {
+        switch ( nbAvas )
+        {
+            case 0:
+                return null;
+
+            case 1:
+                return ava.getNormType();
+
+            default:
+                return avas.get( 0 ).getNormType();
+        }
+    }
+
+
+    /**
+     * Return the User Provided value, as a String
+     *
+     * @return The first User provided value of this Rdn
+     */
+    public String getValue()
+    {
+        switch ( nbAvas )
+        {
+            case 0:
+                return null;
+
+            case 1:
+                return ava.getValue().getString();
+
+            default:
+                return avas.get( 0 ).getValue().getString();
+        }
+    }
+
+
+    /**
+     * Return the Normalized value, as a String
+     *
+     * @return The first Normalized value of this Rdn
+     */
+    public String getNormValue()
+    {
+        switch ( nbAvas )
+        {
+            case 0:
+                return null;
+
+            case 1:
+                return ava.getValue().getNormValue().toString();
+
+            default:
+                return avas.get( 0 ).getValue().getNormValue().toString();
+        }
+    }
+
+
+    /**
+     * Compares the specified Object with this Rdn for equality. Returns true if
+     * the given object is also a Rdn and the two Rdns represent the same
+     * attribute type and value mappings. The order of components in
+     * multi-valued Rdns is not significant.
+     *
+     * @param rdn
+     *            Rdn to be compared for equality with this Rdn
+     * @return true if the specified object is equal to this Rdn
+     */
+    public boolean equals( Object that )
+    {
+        if ( this == that )
+        {
+            return true;
+        }
+
+        if ( !( that instanceof Rdn ) )
+        {
+            return false;
+        }
+
+        Rdn rdn = ( Rdn ) that;
+
+        // Short cut : compare the normalized Rdn
+        if ( normName.equals( rdn.normName ) )
+        {
+            return true;
+        }
+
+        // Short cut : compare the normalized Rdn
+        if ( normName.equals( rdn.normName ) )
+        {
+            return true;
+        }
+
+        if ( rdn.nbAvas != nbAvas )
+        {
+            // We don't have the same number of Avas. The Rdn which
+            // has the higher number of Ava is the one which is
+            // superior
+            return false;
+        }
+
+        switch ( nbAvas )
+        {
+            case 0:
+                return true;
+
+            case 1:
+                return ava.equals( rdn.ava );
+
+            default:
+                // We have more than one value. We will
+                // go through all of them.
+
+                // the types are already normalized and sorted in the Avas Map
+                // so we could compare the first element with all of the second
+                // Ava elemnts, etc.
+                Iterator<Ava> localIterator = avas.iterator();
+
+                while ( localIterator.hasNext() )
+                {
+                    Iterator<Ava> paramIterator = rdn.avas.iterator();
+
+                    Ava localAva = localIterator.next();
+                    boolean equals = false;
+
+                    while ( paramIterator.hasNext() )
+                    {
+                        Ava paramAva = paramIterator.next();
+
+                        if ( localAva.equals( paramAva ) )
+                        {
+                            equals = true;
+                            break;
+                        }
+                    }
+
+                    if ( !equals )
+                    {
+                        return false;
+                    }
+                }
+
+                return true;
+        }
+    }
+
+
+    /**
+     * Get the number of Avas of this Rdn
+     *
+     * @return The number of Avas in this Rdn
+     */
+    public int size()
+    {
+        return nbAvas;
+    }
+
+
+    /**
+     * Unescape the given string according to RFC 2253 If in <string> form, a
+     * LDAP string representation asserted value can be obtained by replacing
+     * (left-to-right, non-recursively) each <pair> appearing in the <string> as
+     * follows: 
+     * <ul>
+     * <li>replace &lt;ESC&gt;&lt;ESC&gt; with &lt;ESC&gt;</li>
+     * <li>replace &lt;ESC&gt;&lt;special&gt; with &lt;special&gt;</li>
+     * <li>replace &lt;ESC&gt;&lt;hexpair&gt; with the octet indicated by the &lt;hexpair&gt;</li>
+     * </ul>
+     * If in &lt;hexstring&gt; form, a BER representation can be obtained
+     * from converting each &lt;hexpair&gt; of the &lt;hexstring&gt; to the octet indicated
+     * by the &lt;hexpair&gt;
+     *
+     * @param value The value to be unescaped
+     * @return Returns a string value as a String, and a binary value as a byte
+     *         array.
+     * @throws IllegalArgumentException When an Illegal value is provided.
+     */
+    public static Object unescapeValue( String value ) throws IllegalArgumentException
+    {
+        if ( Strings.isEmpty( value ) )
+        {
+            return "";
+        }
+
+        char[] chars = value.toCharArray();
+
+        // If the value is contained into double quotes, return it as is.
+        if ( ( chars[0] == '\"' ) && ( chars[chars.length - 1] == '\"' ) )
+        {
+            return new String( chars, 1, chars.length - 2 );
+        }
+
+        if ( chars[0] == '#' )
+        {
+            if ( chars.length == 1 )
+            {
+                // The value is only containing a #
+                return StringConstants.EMPTY_BYTES;
+            }
+
+            if ( ( chars.length % 2 ) != 1 )
+            {
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04213 ) );
+            }
+
+            // HexString form
+            byte[] hexValue = new byte[( chars.length - 1 ) / 2];
+            int pos = 0;
+
+            for ( int i = 1; i < chars.length; i += 2 )
+            {
+                if ( Chars.isHex( chars, i ) && Chars.isHex( chars, i + 1 ) )
+                {
+                    hexValue[pos++] = Hex.getHexValue( chars[i], chars[i + 1] );
+                }
+                else
+                {
+                    throw new IllegalArgumentException( I18n.err( I18n.ERR_04214 ) );
+                }
+            }
+
+            return hexValue;
+        }
+        else
+        {
+            boolean escaped = false;
+            boolean isHex = false;
+            byte pair = -1;
+            int pos = 0;
+
+            byte[] bytes = new byte[chars.length * 6];
+
+            for ( int i = 0; i < chars.length; i++ )
+            {
+                if ( escaped )
+                {
+                    escaped = false;
+
+                    switch ( chars[i] )
+                    {
+                        case '\\':
+                        case '"':
+                        case '+':
+                        case ',':
+                        case ';':
+                        case '<':
+                        case '>':
+                        case '#':
+                        case '=':
+                        case ' ':
+                            bytes[pos++] = ( byte ) chars[i];
+                            break;
+
+                        default:
+                            if ( Chars.isHex( chars, i ) )
+                            {
+                                isHex = true;
+                                pair = ( ( byte ) ( Hex.getHexValue( chars[i] ) << 4 ) );
+                            }
+
+                            break;
+                    }
+                }
+                else
+                {
+                    if ( isHex )
+                    {
+                        if ( Chars.isHex( chars, i ) )
+                        {
+                            pair += Hex.getHexValue( chars[i] );
+                            bytes[pos++] = pair;
+                            isHex = false;
+                            pair = 0;
+                        }
+                    }
+                    else
+                    {
+                        switch ( chars[i] )
+                        {
+                            case '\\':
+                                escaped = true;
+                                break;
+
+                            // We must not have a special char
+                            // Specials are : '"', '+', ',', ';', '<', '>', ' ',
+                            // '#' and '='
+                            case '"':
+                            case '+':
+                            case ',':
+                            case ';':
+                            case '<':
+                            case '>':
+                            case '#':
+                                if ( i != 0 )
+                                {
+                                    // '#' are allowed if not in first position
+                                    bytes[pos++] = '#';
+                                    break;
+                                }
+                            case '=':
+                                throw new IllegalArgumentException( I18n.err( I18n.ERR_04215 ) );
+
+                            case ' ':
+                                if ( ( i == 0 ) || ( i == chars.length - 1 ) )
+                                {
+                                    throw new IllegalArgumentException( I18n.err( I18n.ERR_04215 ) );
+                                }
+                                else
+                                {
+                                    bytes[pos++] = ' ';
+                                    break;
+                                }
+
+                            default:
+                                if ( chars[i] < 128 )
+                                {
+                                    bytes[pos++] = ( byte ) chars[i];
+                                }
+                                else
+                                {
+                                    byte[] result = Unicode.charToBytes( chars[i] );
+                                    System.arraycopy( result, 0, bytes, pos, result.length );
+                                    pos += result.length;
+                                }
+
+                                break;
+                        }
+                    }
+                }
+            }
+
+            return Strings.utf8ToString( bytes, pos );
+        }
+    }
+
+
+    /**
+     * Transform a value in a String, accordingly to RFC 2253
+     *
+     * @param value The attribute value to be escaped
+     * @return The escaped string value.
+     */
+    public static String escapeValue( String value )
+    {
+        if ( Strings.isEmpty( value ) )
+        {
+            return "";
+        }
+
+        char[] chars = value.toCharArray();
+        char[] newChars = new char[chars.length * 3];
+        int pos = 0;
+
+        for ( int i = 0; i < chars.length; i++ )
+        {
+            switch ( chars[i] )
+            {
+                case ' ':
+                    if ( ( i > 0 ) && ( i < chars.length - 1 ) )
+                    {
+                        newChars[pos++] = chars[i];
+                    }
+                    else
+                    {
+                        newChars[pos++] = '\\';
+                        newChars[pos++] = chars[i];
+                    }
+
+                    break;
+
+                case '#':
+                    if ( i != 0 )
+                    {
+                        newChars[pos++] = chars[i];
+                    }
+                    else
+                    {
+                        newChars[pos++] = '\\';
+                        newChars[pos++] = chars[i];
+                    }
+
+                    break;
+
+                case '"':
+                case '+':
+                case ',':
+                case ';':
+                case '=':
+                case '<':
+                case '>':
+                case '\\':
+                    newChars[pos++] = '\\';
+                    newChars[pos++] = chars[i];
+                    break;
+
+                case 0x7F:
+                    newChars[pos++] = '\\';
+                    newChars[pos++] = '7';
+                    newChars[pos++] = 'F';
+                    break;
+
+                case 0x00:
+                case 0x01:
+                case 0x02:
+                case 0x03:
+                case 0x04:
+                case 0x05:
+                case 0x06:
+                case 0x07:
+                case 0x08:
+                case 0x09:
+                case 0x0A:
+                case 0x0B:
+                case 0x0C:
+                case 0x0D:
+                case 0x0E:
+                case 0x0F:
+                    newChars[pos++] = '\\';
+                    newChars[pos++] = '0';
+                    newChars[pos++] = Strings.dumpHex( ( byte ) ( chars[i] & 0x0F ) );
+                    break;
+
+                case 0x10:
+                case 0x11:
+                case 0x12:
+                case 0x13:
+                case 0x14:
+                case 0x15:
+                case 0x16:
+                case 0x17:
+                case 0x18:
+                case 0x19:
+                case 0x1A:
+                case 0x1B:
+                case 0x1C:
+                case 0x1D:
+                case 0x1E:
+                case 0x1F:
+                    newChars[pos++] = '\\';
+                    newChars[pos++] = '1';
+                    newChars[pos++] = Strings.dumpHex( ( byte ) ( chars[i] & 0x0F ) );
+                    break;
+
+                default:
+                    newChars[pos++] = chars[i];
+                    break;
+            }
+        }
+
+        return new String( newChars, 0, pos );
+    }
+
+
+    /**
+     * Transform a value in a String, accordingly to RFC 2253
+     *
+     * @param attrValue
+     *            The attribute value to be escaped
+     * @return The escaped string value.
+     */
+    public static String escapeValue( byte[] attrValue )
+    {
+        if ( Strings.isEmpty( attrValue ) )
+        {
+            return "";
+        }
+
+        String value = Strings.utf8ToString( attrValue );
+
+        return escapeValue( value );
+    }
+
+
+    /**
+     * Tells if the Rdn is schema aware.
+     *
+     * @return <code>true</code> if the Rdn is schema aware
+     */
+    public boolean isSchemaAware()
+    {
+        return schemaManager != null;
+    }
+
+
+    /**
+     * Validate a NameComponent : <br>
+     * <p>
+     * &lt;name-component&gt; ::= &lt;attributeType&gt; &lt;spaces&gt; '='
+     * &lt;spaces&gt; &lt;attributeValue&gt; &lt;nameComponents&gt;
+     * </p>
+     *
+     * @param dn The string to parse
+     * @return <code>true</code> if the Rdn is valid
+     */
+    public static boolean isValid( String dn )
+    {
+        Rdn rdn = new Rdn();
+
+        try
+        {
+            parse( dn, rdn );
+
+            return true;
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Parse a NameComponent : <br>
+     * <p>
+     * &lt;name-component&gt; ::= &lt;attributeType&gt; &lt;spaces&gt; '='
+     * &lt;spaces&gt; &lt;attributeValue&gt; &lt;nameComponents&gt;
+     * </p>
+     *
+     * @param dn The String to parse
+     * @param rdn The Rdn to fill. Beware that if the Rdn is not empty, the new
+     *            AttributeTypeAndValue will be added.
+     * @throws LdapInvalidDnException If the NameComponent is invalid
+     */
+    private static void parse( String dn, Rdn rdn ) throws LdapInvalidDnException
+    {
+        try
+        {
+            FastDnParser.parseRdn( dn, rdn );
+        }
+        catch ( TooComplexDnException e )
+        {
+            rdn.clear();
+            new ComplexDnParser().parseRdn( dn, rdn );
+        }
+    }
+
+
+    /**
+      * Gets the hashcode of this rdn.
+      *
+      * @see java.lang.Object#hashCode()
+      * @return the instance's hash code
+      */
+    public int hashCode()
+    {
+        if ( h == 0 )
+        {
+            h = 37;
+
+            switch ( nbAvas )
+            {
+                case 0:
+                    // An empty Rdn
+                    break;
+
+                case 1:
+                    // We have a single Ava
+                    h = h * 17 + ava.hashCode();
+                    break;
+
+                default:
+                    // We have more than one Ava
+
+                    for ( Ava ata : avas )
+                    {
+                        h = h * 17 + ata.hashCode();
+                    }
+
+                    break;
+            }
+        }
+
+        return h;
+    }
+
+
+    /**
+     * Serialize a RDN into a byte[]
+     * 
+     * @return a byte[] containing a RDN
+     */
+    public int serialize( byte[] buffer, int pos ) throws IOException
+    {
+        // The nbAvas and the HashCode length
+        int length = 4 + 4;
+
+        // The NnbAvas
+        pos = Serialize.serialize( nbAvas, buffer, pos );
+
+        // The upName
+        byte[] upNameBytes = Strings.getBytesUtf8( upName );
+        length += 4 + upNameBytes.length;
+
+        byte[] normNameBytes = Strings.EMPTY_BYTES;
+        length += 4;
+
+        if ( !upName.equals( normName ) )
+        {
+            normNameBytes = Strings.getBytesUtf8( normName );
+            length += 4 + normNameBytes.length;
+        }
+
+        // Check that we will be able to store the data in the buffer
+        if ( buffer.length - pos < length )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        // Write the upName
+        pos = Serialize.serialize( upNameBytes, buffer, pos );
+
+        // Write the normName
+        pos = Serialize.serialize( normNameBytes, buffer, pos );
+
+        // Write the AVAs
+        switch ( nbAvas )
+        {
+            case 0:
+                break;
+
+            case 1:
+                pos = ava.serialize( buffer, pos );
+
+                break;
+
+            default:
+                for ( Ava localAva : avas )
+                {
+                    pos = localAva.serialize( buffer, pos );
+                }
+
+                break;
+        }
+
+        // The hash code
+        pos = Serialize.serialize( h, buffer, pos );
+
+        return pos;
+    }
+
+
+    /**
+     * Deserialize a RDN from a byte[], starting at a given position
+     * 
+     * @param buffer The buffer containing the RDN
+     * @param pos The position in the buffer
+     * @return The new position
+     * @throws IOException If the serialized value is not a RDN
+     * @throws LdapInvalidAttributeValueException If the serialized RDN is invalid
+     */
+    public int deserialize( byte[] buffer, int pos ) throws IOException, LdapInvalidAttributeValueException
+    {
+        if ( ( pos < 0 ) || ( pos >= buffer.length ) )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        // Read the nbAvas
+        nbAvas = Serialize.deserializeInt( buffer, pos );
+        pos += 4;
+
+        // Read the upName
+        byte[] upNameBytes = Serialize.deserializeBytes( buffer, pos );
+        pos += 4 + upNameBytes.length;
+        upName = Strings.utf8ToString( upNameBytes );
+
+        // Read the normName
+        byte[] normNameBytes = Serialize.deserializeBytes( buffer, pos );
+        pos += 4 + normNameBytes.length;
+
+        if ( normNameBytes.length == 0 )
+        {
+            normName = upName;
+        }
+        else
+        {
+            normName = Strings.utf8ToString( normNameBytes );
+        }
+
+        // Read the AVAs
+        switch ( nbAvas )
+        {
+            case 0:
+                break;
+
+            case 1:
+                ava = new Ava( schemaManager );
+                pos = ava.deserialize( buffer, pos );
+                avaType = ava.getNormType();
+
+                break;
+
+            default:
+                avas = new ArrayList<Ava>();
+
+                avaTypes = new MultiValueMap();
+
+                for ( int i = 0; i < nbAvas; i++ )
+                {
+                    Ava newAva = new Ava( schemaManager );
+                    pos = newAva.deserialize( buffer, pos );
+                    avas.add( newAva );
+                    avaTypes.put( newAva.getNormType(), newAva );
+                }
+
+                ava = null;
+                avaType = null;
+
+                break;
+        }
+
+        // Read the hashCode
+        h = Serialize.deserializeInt( buffer, pos );
+        pos += 4;
+
+        return pos;
+    }
+
+
+    /**
+     * A Rdn is composed of on to many Avas (AttributeType And Value).
+     * We should write all those Avas sequencially, following the
+     * structure :
+     * <ul>
+     *   <li>
+     *     <b>parentId</b> The parent entry's Id
+     *   </li>
+     *   <li>
+     *     <b>nbAvas</b> The number of Avas to write. Can't be 0.
+     *   </li>
+     *   <li>
+     *     <b>upName</b> The User provided Rdn
+     *   </li>
+     *   <li>
+     *     <b>normName</b> The normalized Rdn. It can be empty if the normalized
+     * name equals the upName.
+     *   </li>
+     *   <li>
+     *     <b>Avas</b>
+     *   </li>
+     * </ul>
+     * <br/>
+     * For each Ava :
+     * <ul>
+     *   <li>
+     *     <b>start</b> The position of this Ava in the upName string
+     *   </li>
+     *   <li>
+     *     <b>length</b> The Ava user provided length
+     *   </li>
+     *   <li>
+     *     <b>Call the Ava write method</b> The Ava itself
+     *   </li>
+     * </ul>
+     *
+     * @see Externalizable#readExternal(ObjectInput)
+     * @param out The stream into which the serialized Rdn will be put
+     * @throws IOException If the stream can't be written
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        out.writeInt( nbAvas );
+        out.writeUTF( upName );
+
+        if ( upName.equals( normName ) )
+        {
+            out.writeUTF( "" );
+        }
+        else
+        {
+            out.writeUTF( normName );
+        }
+
+        switch ( nbAvas )
+        {
+            case 0:
+                break;
+
+            case 1:
+                ava.writeExternal( out );
+                break;
+
+            default:
+                for ( Ava localAva : avas )
+                {
+                    localAva.writeExternal( out );
+                }
+
+                break;
+        }
+
+        out.writeInt( h );
+
+        out.flush();
+    }
+
+
+    /**
+     * We read back the data to create a new RDB. The structure
+     * read is exposed in the {@link Rdn#writeExternal(ObjectOutput)}
+     * method
+     *
+     * @see Externalizable#readExternal(ObjectInput)
+     * @param in The input stream from which the Rdn will be read
+     * @throws IOException If we can't read from the input stream
+     * @throws ClassNotFoundException If we can't create a new Rdn
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the Ava number
+        nbAvas = in.readInt();
+
+        // Read the UPName
+        upName = in.readUTF();
+
+        // Read the normName
+        normName = in.readUTF();
+
+        if ( Strings.isEmpty( normName ) )
+        {
+            normName = upName;
+        }
+
+        switch ( nbAvas )
+        {
+            case 0:
+                ava = null;
+                break;
+
+            case 1:
+                ava = new Ava( schemaManager );
+                ava.readExternal( in );
+                avaType = ava.getNormType();
+
+                break;
+
+            default:
+                avas = new ArrayList<Ava>();
+
+                avaTypes = new MultiValueMap();
+
+                for ( int i = 0; i < nbAvas; i++ )
+                {
+                    Ava newAva = new Ava( schemaManager );
+                    newAva.readExternal( in );
+                    avas.add( newAva );
+                    avaTypes.put( newAva.getNormType(), newAva );
+                }
+
+                ava = null;
+                avaType = null;
+
+                break;
+        }
+
+        h = in.readInt();
+    }
+
+
+    public int compareTo( Rdn arg0 )
+    {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+
+    /**
+     * @return a String representation of the Rdn. The caller will get back the user
+     * provided Rdn
+     */
+    public String toString()
+    {
+        return upName == null ? "" : upName;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/TooComplexDnException.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/TooComplexDnException.java
new file mode 100644
index 0000000..75d8be2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/name/TooComplexDnException.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+
+
+/**
+ * This exception is used to signal that the complex parser should be used.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TooComplexDnException extends LdapInvalidDnException
+{
+    // The defualt serila version ID
+    private static final long serialVersionUID = 4854240181901296414L;
+    
+    /** An instance of this exception to avoid creation a new one every time we need it */
+    public static final TooComplexDnException INSTANCE = new TooComplexDnException();
+
+    /**
+     * Creates a new instance of TooComplexException.
+     */
+    public TooComplexDnException()
+    {
+        super( ( String ) null );
+    }
+
+
+    /**
+     * Creates a new instance of TooComplexException.
+     * 
+     * @param message The associated message 
+     */
+    public TooComplexDnException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/EncryptionMethod.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/EncryptionMethod.java
new file mode 100644
index 0000000..3a81262
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/EncryptionMethod.java
@@ -0,0 +1,91 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.password;
+
+
+import org.apache.directory.api.ldap.model.constants.LdapSecurityConstants;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A class to store all informations about the existing
+ * password found in the cache or get from the backend.
+ *
+ * This is necessary as we have to compute :
+ * - the used algorithm
+ * - the salt if any
+ * - the password itself.
+ *
+ * If we have a on-way encrypted password, it is stored using this
+ * format :
+ * {<algorithm>}<encrypted password>
+ * where the encrypted password format can be :
+ * - MD5/SHA : base64(<password>)
+ * - SMD5/SSH/PKCS5S2 : base64(<salted-password-digest><salt (4 or 8 bytes)>)
+ * - crypt : <salt (2 btytes)><password>
+ *
+ * Algorithm are currently MD5, SMD5, SHA, SSHA, SHA2, SSHA-2 (except SHA-224), PKCS5S2, CRYPT and empty
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EncryptionMethod
+{
+    private byte[] salt;
+    private LdapSecurityConstants algorithm;
+
+
+    public EncryptionMethod( LdapSecurityConstants algorithm, byte[] salt )
+    {
+        this.algorithm = algorithm;
+        this.salt = salt;
+    }
+
+
+    public LdapSecurityConstants getAlgorithm()
+    {
+        return algorithm;
+    }
+
+
+    public byte[] getSalt()
+    {
+        return salt;
+    }
+
+
+    public void setSalt( byte[] salt )
+    {
+        // just to make this class immutable, though we have a setter
+        if ( this.salt != null )
+        {
+            throw new IllegalStateException( "salt will only be allowed to set once" );
+        }
+
+        this.salt = salt;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return "EncryptionMethod [algorithm=" + algorithm.getName().toUpperCase() + ", salt="
+            + Strings.dumpBytes( salt ) + "]";
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/PasswordUtil.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/PasswordUtil.java
new file mode 100644
index 0000000..4a72cd0
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/password/PasswordUtil.java
@@ -0,0 +1,634 @@
+/*
+ *   or more contributor license agreements.  See the NOTICE file
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.password;
+
+
+import java.io.UnsupportedEncodingException;
+import java.security.Key;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.KeySpec;
+import java.util.Date;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.apache.directory.api.ldap.model.constants.LdapSecurityConstants;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.DateUtils;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.UnixCrypt;
+
+
+/**
+ * A utility class containing methods related to processing passwords.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PasswordUtil
+{
+
+    /** The SHA1 hash length */
+    public static final int SHA1_LENGTH = 20;
+
+    /** The SHA256 hash length */
+    public static final int SHA256_LENGTH = 32;
+
+    /** The SHA384 hash length */
+    public static final int SHA384_LENGTH = 48;
+
+    /** The SHA512 hash length */
+    public static final int SHA512_LENGTH = 64;
+
+    /** The MD5 hash length */
+    public static final int MD5_LENGTH = 16;
+
+    /** The PKCS5S2 hash length */
+    public static final int PKCS5S2_LENGTH = 32;
+
+
+    private PasswordUtil()
+    {
+    }
+
+
+    /**
+     * Get the algorithm from the stored password. 
+     * It can be found on the beginning of the stored password, between 
+     * curly brackets.
+     * @param credentials the credentials of the user
+     * @return the name of the algorithm to use
+     */
+    public static LdapSecurityConstants findAlgorithm( byte[] credentials )
+    {
+        if ( ( credentials == null ) || ( credentials.length == 0 ) )
+        {
+            return null;
+        }
+
+        if ( credentials[0] == '{' )
+        {
+            // get the algorithm
+            int pos = 1;
+
+            while ( pos < credentials.length )
+            {
+                if ( credentials[pos] == '}' )
+                {
+                    break;
+                }
+
+                pos++;
+            }
+
+            if ( pos < credentials.length )
+            {
+                if ( pos == 1 )
+                {
+                    // We don't have an algorithm : return the credentials as is
+                    return null;
+                }
+
+                String algorithm = Strings.toLowerCase( Strings.utf8ToString( credentials, 1, pos - 1 ) );
+
+                return LdapSecurityConstants.getAlgorithm( algorithm );
+            }
+            else
+            {
+                // We don't have an algorithm
+                return null;
+            }
+        }
+        else
+        {
+            // No '{algo}' part
+            return null;
+        }
+    }
+
+
+    /**
+     * @see #createStoragePassword(byte[], LdapSecurityConstants)
+     */
+    public static byte[] createStoragePassword( String credentials, LdapSecurityConstants algorithm )
+    {
+        return createStoragePassword( Strings.getBytesUtf8( credentials ), algorithm );
+    }
+
+
+    /**
+     * create a hashed password in a format that can be stored in the server.
+     * If the specified algorithm requires a salt then a random salt of 8 byte size is used
+     *  
+     * @param credentials the plain text password
+     * @param algorithm the hashing algorithm to be applied
+     * @return the password after hashing with the given algorithm 
+     */
+    public static byte[] createStoragePassword( byte[] credentials, LdapSecurityConstants algorithm )
+    {
+        byte[] salt;
+
+        switch ( algorithm )
+        {
+            case HASH_METHOD_SSHA:
+            case HASH_METHOD_SSHA256:
+            case HASH_METHOD_SSHA384:
+            case HASH_METHOD_SSHA512:
+            case HASH_METHOD_SMD5:
+                // we use 8 byte salt always except for "crypt" which needs 2 byte salt
+                salt = new byte[8];
+                new SecureRandom().nextBytes( salt );
+                break;
+
+            case HASH_METHOD_PKCS5S2:
+                // we use 16 byte salt for PKCS5S2
+                salt = new byte[16];
+                new SecureRandom().nextBytes( salt );
+                break;
+
+            case HASH_METHOD_CRYPT:
+                salt = new byte[2];
+                SecureRandom sr = new SecureRandom();
+                int i1 = sr.nextInt( 64 );
+                int i2 = sr.nextInt( 64 );
+
+                salt[0] = ( byte ) ( i1 < 12 ? ( i1 + '.' ) : i1 < 38 ? ( i1 + 'A' - 12 ) : ( i1 + 'a' - 38 ) );
+                salt[1] = ( byte ) ( i2 < 12 ? ( i2 + '.' ) : i2 < 38 ? ( i2 + 'A' - 12 ) : ( i2 + 'a' - 38 ) );
+                break;
+
+            default:
+                salt = null;
+        }
+
+        byte[] hashedPassword = encryptPassword( credentials, algorithm, salt );
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( '{' ).append( algorithm.getPrefix().toUpperCase() ).append( '}' );
+
+        if ( algorithm == LdapSecurityConstants.HASH_METHOD_CRYPT )
+        {
+            sb.append( Strings.utf8ToString( salt ) );
+            sb.append( Strings.utf8ToString( hashedPassword ) );
+        }
+        else if ( salt != null )
+        {
+            byte[] hashedPasswordWithSaltBytes = new byte[hashedPassword.length + salt.length];
+
+            if ( algorithm == LdapSecurityConstants.HASH_METHOD_PKCS5S2 )
+            {
+                merge( hashedPasswordWithSaltBytes, salt, hashedPassword );
+            }
+            else
+            {
+                merge( hashedPasswordWithSaltBytes, hashedPassword, salt );
+            }
+
+            sb.append( String.valueOf( Base64.encode( hashedPasswordWithSaltBytes ) ) );
+        }
+        else
+        {
+            sb.append( String.valueOf( Base64.encode( hashedPassword ) ) );
+        }
+
+        return Strings.getBytesUtf8( sb.toString() );
+    }
+
+
+    /**
+     * 
+     * Compare the credentials.
+     * We have at least 6 algorithms to encrypt the password :
+     * <ul>
+     * <li>- SHA</li>
+     * <li>- SSHA (salted SHA)</li>
+     * <li>- SHA-2(256, 384 and 512 and their salted versions)</li>
+     * <li>- MD5</li>
+     * <li>- SMD5 (slated MD5)</li>
+     * <li>- PKCS5S2 (PBKDF2)</li>
+     * <li>- crypt (unix crypt)</li>
+     * <li>- plain text, ie no encryption.</li>
+     * </ul>
+     * <p>
+     *  If we get an encrypted password, it is prefixed by the used algorithm, between
+     *  brackets : {SSHA}password ...
+     *  </p>
+     *  If the password is using SSHA, SMD5 or crypt, some 'salt' is added to the password :
+     *  <ul>
+     *  <li>- length(password) - 20, starting at 21st position for SSHA</li>
+     *  <li>- length(password) - 16, starting at 16th position for SMD5</li>
+     *  <li>- length(password) - 2, starting at 3rd position for crypt</li>
+     *  </ul>
+     *  <p>
+     *  For (S)SHA, SHA-256 and (S)MD5, we have to transform the password from Base64 encoded text
+     *  to a byte[] before comparing the password with the stored one.
+     *  </p>
+     *  <p>
+     *  For PKCS5S2 the salt is stored in the beginning of the password
+     *  </p>
+     *  <p>
+     *  For crypt, we only have to remove the salt.
+     *  </p>
+     *  <p>
+     *  At the end, we use the digest() method for (S)SHA and (S)MD5, the crypt() method for
+     *  the CRYPT algorithm and a straight comparison for PLAIN TEXT passwords.
+     *  </p>
+     *  <p>
+     *  The stored password is always using the unsalted form, and is stored as a bytes array.
+     *  </p>
+     *
+     * @param receivedCredentials the credentials provided by user
+     * @param storedCredentials the credentials stored in the server
+     * @return true if they are equal, false otherwise
+     */
+    public static boolean compareCredentials( byte[] receivedCredentials, byte[] storedCredentials )
+    {
+        LdapSecurityConstants algorithm = findAlgorithm( storedCredentials );
+
+        if ( algorithm != null )
+        {
+            EncryptionMethod encryptionMethod = new EncryptionMethod( algorithm, null );
+
+            // Let's get the encrypted part of the stored password
+            // We should just keep the password, excluding the algorithm
+            // and the salt, if any.
+            // But we should also get the algorithm and salt to
+            // be able to encrypt the submitted user password in the next step
+            byte[] encryptedStored = PasswordUtil.splitCredentials( storedCredentials, encryptionMethod );
+
+            // Reuse the saltedPassword informations to construct the encrypted
+            // password given by the user.
+            byte[] userPassword = PasswordUtil.encryptPassword( receivedCredentials, encryptionMethod.getAlgorithm(),
+                encryptionMethod.getSalt() );
+
+            return compareBytes( userPassword, encryptedStored );
+        }
+        else
+        {
+            return compareBytes( receivedCredentials, storedCredentials );
+        }
+    }
+    
+    
+    /**
+     * Compare two byte[] in a constant time. This is necessary because using an Array.equals() is
+     * not Timing attack safe ([1], [2] and [3]), a breach that can be exploited to break some hashes.
+     * 
+     *  [1] https://en.wikipedia.org/wiki/Timing_attack
+     *  [2] http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/
+     *  [3] https://cryptocoding.net/index.php/Coding_rules
+     */
+    private static boolean compareBytes( byte[] provided, byte[] stored )
+    {
+        if ( stored == null )
+        {
+            return provided == null;
+        }
+        else if ( provided == null )
+        {
+            return false;
+        }
+        
+        // Now, compare the two passwords, using a constant time method
+        if ( stored.length != provided.length )
+        {
+            return false;
+        }
+        
+        // loop on *every* byte in both passwords, and at the end, if one char at least is different, return false.
+        int result = 0;
+        
+        for ( int i = 0; i < stored.length; i++ )
+        {
+            // If both bytes are equal, xor will be == 0, otherwise it will be != 0 and so will result.
+            result |= ( stored[i] ^ provided[i] );
+        }
+        
+        return result == 0;
+    }
+
+
+    /**
+     * encrypts the given credentials based on the algorithm name and optional salt
+     *
+     * @param credentials the credentials to be encrypted
+     * @param algorithm the algorithm to be used for encrypting the credentials
+     * @param salt value to be used as salt (optional)
+     * @return the encrypted credentials
+     */
+    public static byte[] encryptPassword( byte[] credentials, LdapSecurityConstants algorithm, byte[] salt )
+    {
+        switch ( algorithm )
+        {
+            case HASH_METHOD_SHA:
+            case HASH_METHOD_SSHA:
+                return digest( LdapSecurityConstants.HASH_METHOD_SHA, credentials, salt );
+
+            case HASH_METHOD_SHA256:
+            case HASH_METHOD_SSHA256:
+                return digest( LdapSecurityConstants.HASH_METHOD_SHA256, credentials, salt );
+
+            case HASH_METHOD_SHA384:
+            case HASH_METHOD_SSHA384:
+                return digest( LdapSecurityConstants.HASH_METHOD_SHA384, credentials, salt );
+
+            case HASH_METHOD_SHA512:
+            case HASH_METHOD_SSHA512:
+                return digest( LdapSecurityConstants.HASH_METHOD_SHA512, credentials, salt );
+
+            case HASH_METHOD_MD5:
+            case HASH_METHOD_SMD5:
+                return digest( LdapSecurityConstants.HASH_METHOD_MD5, credentials, salt );
+
+            case HASH_METHOD_CRYPT:
+                String saltWithCrypted = UnixCrypt.crypt( Strings.utf8ToString( credentials ), Strings
+                    .utf8ToString( salt ) );
+                String crypted = saltWithCrypted.substring( 2 );
+
+                return Strings.getBytesUtf8( crypted );
+
+            case HASH_METHOD_PKCS5S2:
+                return generatePbkdf2Hash( credentials, algorithm, salt );
+
+            default:
+                return credentials;
+        }
+    }
+
+
+    /**
+     * Compute the hashed password given an algorithm, the credentials and 
+     * an optional salt.
+     *
+     * @param algorithm the algorithm to use
+     * @param password the credentials
+     * @param salt the optional salt
+     * @return the digested credentials
+     */
+    private static byte[] digest( LdapSecurityConstants algorithm, byte[] password, byte[] salt )
+    {
+        MessageDigest digest;
+
+        try
+        {
+            digest = MessageDigest.getInstance( algorithm.getAlgorithm() );
+        }
+        catch ( NoSuchAlgorithmException e1 )
+        {
+            return null;
+        }
+
+        if ( salt != null )
+        {
+            digest.update( password );
+            digest.update( salt );
+            return digest.digest();
+        }
+        else
+        {
+            return digest.digest( password );
+        }
+    }
+
+
+    /**
+     * Decompose the stored password in an algorithm, an eventual salt
+     * and the password itself.
+     *
+     * If the algorithm is SHA, SSHA, MD5 or SMD5, the part following the algorithm
+     * is base64 encoded
+     *
+     * @param encryptionMethod The structure to feed
+     * @return The password
+     * @param credentials the credentials to split
+     */
+    public static byte[] splitCredentials( byte[] credentials, EncryptionMethod encryptionMethod )
+    {
+        int algoLength = encryptionMethod.getAlgorithm().getPrefix().length() + 2;
+
+        switch ( encryptionMethod.getAlgorithm() )
+        {
+            case HASH_METHOD_MD5:
+            case HASH_METHOD_SHA:
+                try
+                {
+                    // We just have the password just after the algorithm, base64 encoded.
+                    // Just decode the password and return it.
+                    return Base64
+                        .decode( new String( credentials, algoLength, credentials.length - algoLength, "UTF-8" )
+                            .toCharArray() );
+                }
+                catch ( UnsupportedEncodingException uee )
+                {
+                    // do nothing
+                    return credentials;
+                }
+
+            case HASH_METHOD_SMD5:
+                try
+                {
+                    // The password is associated with a salt. Decompose it
+                    // in two parts, after having decoded the password.
+                    // The salt will be stored into the EncryptionMethod structure
+                    // The salt is at the end of the credentials, and is 8 bytes long
+                    byte[] passwordAndSalt = Base64.decode( new String( credentials, algoLength, credentials.length
+                        - algoLength, "UTF-8" ).toCharArray() );
+
+                    int saltLength = passwordAndSalt.length - MD5_LENGTH;
+                    encryptionMethod.setSalt( new byte[saltLength] );
+                    byte[] password = new byte[MD5_LENGTH];
+                    split( passwordAndSalt, 0, password, encryptionMethod.getSalt() );
+
+                    return password;
+                }
+                catch ( UnsupportedEncodingException uee )
+                {
+                    // do nothing
+                    return credentials;
+                }
+
+            case HASH_METHOD_SSHA:
+                return getCredentials( credentials, algoLength, SHA1_LENGTH, encryptionMethod );
+
+            case HASH_METHOD_SHA256:
+            case HASH_METHOD_SSHA256:
+                return getCredentials( credentials, algoLength, SHA256_LENGTH, encryptionMethod );
+
+            case HASH_METHOD_SHA384:
+            case HASH_METHOD_SSHA384:
+                return getCredentials( credentials, algoLength, SHA384_LENGTH, encryptionMethod );
+
+            case HASH_METHOD_SHA512:
+            case HASH_METHOD_SSHA512:
+                return getCredentials( credentials, algoLength, SHA512_LENGTH, encryptionMethod );
+
+            case HASH_METHOD_PKCS5S2:
+                return getPbkdf2Credentials( credentials, algoLength, encryptionMethod );
+
+            case HASH_METHOD_CRYPT:
+                // The password is associated with a salt. Decompose it
+                // in two parts, storing the salt into the EncryptionMethod structure.
+                // The salt comes first, not like for SSHA and SMD5, and is 2 bytes long
+                encryptionMethod.setSalt( new byte[2] );
+                byte[] password = new byte[credentials.length - encryptionMethod.getSalt().length - algoLength];
+                split( credentials, algoLength, encryptionMethod.getSalt(), password );
+
+                return password;
+
+            default:
+                // unknown method
+                return credentials;
+
+        }
+    }
+
+
+    /**
+     * Compute the credentials
+     */
+    private static byte[] getCredentials( byte[] credentials, int algoLength, int hashLen,
+        EncryptionMethod encryptionMethod )
+    {
+        try
+        {
+            // The password is associated with a salt. Decompose it
+            // in two parts, after having decoded the password.
+            // The salt will be stored into the EncryptionMethod structure
+            // The salt is at the end of the credentials, and is 8 bytes long
+            byte[] passwordAndSalt = Base64.decode( new String( credentials, algoLength, credentials.length
+                - algoLength, "UTF-8" ).toCharArray() );
+
+            int saltLength = passwordAndSalt.length - hashLen;
+            encryptionMethod.setSalt( new byte[saltLength] );
+            byte[] password = new byte[hashLen];
+            split( passwordAndSalt, 0, password, encryptionMethod.getSalt() );
+
+            return password;
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // do nothing
+            return credentials;
+        }
+    }
+
+
+    private static void split( byte[] all, int offset, byte[] left, byte[] right )
+    {
+        System.arraycopy( all, offset, left, 0, left.length );
+        System.arraycopy( all, offset + left.length, right, 0, right.length );
+    }
+
+
+    private static void merge( byte[] all, byte[] left, byte[] right )
+    {
+        System.arraycopy( left, 0, all, 0, left.length );
+        System.arraycopy( right, 0, all, left.length, right.length );
+    }
+
+
+    /**
+     * checks if the given password's change time is older than the max age 
+     *
+     * @param pwdChangedZtime time when the password was last changed
+     * @param pwdMaxAgeSec the max age value in seconds
+     * @return true if expired, false otherwise
+     */
+    public static boolean isPwdExpired( String pwdChangedZtime, int pwdMaxAgeSec )
+    {
+        Date pwdChangeDate = DateUtils.getDate( pwdChangedZtime );
+
+        //DIRSERVER-1735
+        long time = pwdMaxAgeSec * 1000L;
+        time += pwdChangeDate.getTime();
+
+        Date expiryDate = DateUtils.getDate( DateUtils.getGeneralizedTime( time ) );
+        Date now = DateUtils.getDate( DateUtils.getGeneralizedTime() );
+
+        boolean expired = false;
+
+        if ( expiryDate.equals( now ) || expiryDate.before( now ) )
+        {
+            expired = true;
+        }
+
+        return expired;
+    }
+
+
+    /**
+     * generates a hash based on the <a href="http://en.wikipedia.org/wiki/PBKDF2">PKCS5S2 spec</a>
+     * 
+     * Note: this has been implemented to generate hashes compatible with what JIRA generates.
+     *       See the <a href="http://pythonhosted.org/passlib/lib/passlib.hash.atlassian_pbkdf2_sha1.html">JIRA's passlib</a>
+     * @param algorithm the algorithm to use
+     * @param password the credentials
+     * @param salt the optional salt
+     * @return the digested credentials
+     */
+    private static byte[] generatePbkdf2Hash( byte[] credentials, LdapSecurityConstants algorithm, byte[] salt )
+    {
+        try
+        {
+            SecretKeyFactory sk = SecretKeyFactory.getInstance( algorithm.getAlgorithm() );
+            char[] password = Strings.utf8ToString( credentials ).toCharArray();
+            KeySpec keySpec = new PBEKeySpec( password, salt, 10000, PKCS5S2_LENGTH * 8 );
+            Key key = sk.generateSecret( keySpec );
+            return key.getEncoded();
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * Gets the credentials from a PKCS5S2 hash.
+     * The salt for PKCS5S2 hash is prepended to the password
+     */
+    private static byte[] getPbkdf2Credentials( byte[] credentials, int algoLength, EncryptionMethod encryptionMethod )
+    {
+        try
+        {
+            // The password is associated with a salt. Decompose it
+            // in two parts, after having decoded the password.
+            // The salt will be stored into the EncryptionMethod structure
+            // The salt is at the *beginning* of the credentials, and is 16 bytes long
+            byte[] passwordAndSalt = Base64.decode( new String( credentials, algoLength, credentials.length
+                - algoLength, "UTF-8" ).toCharArray() );
+
+            int saltLength = passwordAndSalt.length - PKCS5S2_LENGTH;
+            encryptionMethod.setSalt( new byte[saltLength] );
+            byte[] password = new byte[PKCS5S2_LENGTH];
+
+            split( passwordAndSalt, 0, encryptionMethod.getSalt(), password );
+
+            return password;
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // do nothing
+            return credentials;
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AbstractSchemaObject.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AbstractSchemaObject.java
new file mode 100644
index 0000000..f401241
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AbstractSchemaObject.java
@@ -0,0 +1,986 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Most schema objects have some common attributes. This class
+ * contains the minimum set of properties exposed by a SchemaObject.<br>
+ * We have 11 types of SchemaObjects :
+ * <li> AttributeType
+ * <li> DitCOntentRule
+ * <li> DitStructureRule
+ * <li> LdapComparator (specific to ADS)
+ * <li> LdapSyntaxe
+ * <li> MatchingRule
+ * <li> MatchingRuleUse
+ * <li> NameForm
+ * <li> Normalizer (specific to ADS)
+ * <li> ObjectClass
+ * <li> SyntaxChecker (specific to ADS)
+ * <br>
+ * <br>
+ * This class provides accessors and setters for the following attributes,
+ * which are common to all those SchemaObjects :
+ * <li>oid : The numeric OID
+ * <li>description : The SchemaObject description
+ * <li>obsolete : Tells if the schema object is obsolete
+ * <li>extensions : The extensions, a key/Values map
+ * <li>schemaObjectType : The SchemaObject type (see upper)
+ * <li>schema : The schema the SchemaObject is associated with (it's an extension).
+ * Can be null
+ * <li>isEnabled : The SchemaObject status (it's related to the schema status)
+ * <li>isReadOnly : Tells if the SchemaObject can be modified or not
+ * <br><br>
+ * Some of those attributes are not used by some Schema elements, even if they should
+ * have been used. Here is the list :
+ * <b>name</b> : LdapSyntax, Comparator, Normalizer, SyntaxChecker
+ * <b>numericOid</b> : DitStructureRule,
+ * <b>obsolete</b> : LdapSyntax, Comparator, Normalizer, SyntaxChecker
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractSchemaObject implements SchemaObject, Serializable
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** The SchemaObject numeric OID */
+    protected String oid;
+
+    /** The optional names for this SchemaObject */
+    protected List<String> names;
+
+    /** Whether or not this SchemaObject is enabled */
+    protected boolean isEnabled = true;
+
+    /** Whether or not this SchemaObject can be modified */
+    protected boolean isReadOnly = false;
+
+    /** Whether or not this SchemaObject is obsolete */
+    protected boolean isObsolete = false;
+
+    /** A short description of this SchemaObject */
+    protected String description;
+
+    /** The SchemaObject specification */
+    protected String specification;
+
+    /** The name of the schema this object is associated with */
+    protected String schemaName;
+
+    /** The SchemaObjectType */
+    protected SchemaObjectType objectType;
+
+    /** A map containing the list of supported extensions */
+    protected Map<String, List<String>> extensions;
+
+    /** A locked to avoid modifications when set to true */
+    protected volatile boolean locked;
+
+    /** The hashcode for this schemaObject */
+    private int h;
+
+
+    /**
+     * A constructor for a SchemaObject instance. It must be
+     * invoked by the inherited class.
+     *
+     * @param objectType The SchemaObjectType to create
+     * @param oid the SchemaObject numeric OID
+     */
+    protected AbstractSchemaObject( SchemaObjectType objectType, String oid )
+    {
+        this.objectType = objectType;
+        this.oid = oid;
+        extensions = new HashMap<String, List<String>>();
+        names = new ArrayList<String>();
+    }
+
+
+    /**
+     * Constructor used when a generic reusable SchemaObject is assigned an
+     * OID after being instantiated.
+     * 
+     * @param objectType The SchemaObjectType to create
+     */
+    protected AbstractSchemaObject( SchemaObjectType objectType )
+    {
+        this.objectType = objectType;
+        extensions = new HashMap<String, List<String>>();
+        names = new ArrayList<String>();
+    }
+
+
+    /**
+     * Gets usually what is the numeric object identifier assigned to this
+     * SchemaObject. All schema objects except for MatchingRuleUses have an OID
+     * assigned specifically to then. A MatchingRuleUse's OID really is the OID
+     * of it's MatchingRule and not specific to the MatchingRuleUse. This
+     * effects how MatchingRuleUse objects are maintained by the system.
+     * 
+     * @return an OID for this SchemaObject or its MatchingRule if this
+     *         SchemaObject is a MatchingRuleUse object
+     */
+    public String getOid()
+    {
+        return oid;
+    }
+
+
+    /**
+     * A special method used when renaming an SchemaObject: we may have to
+     * change it's OID
+     * @param oid The new OID
+     */
+    public void setOid( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.oid = oid;
+    }
+
+
+    /**
+     * Gets short names for this SchemaObject if any exists for it, otherwise,
+     * returns an empty list.
+     * 
+     * @return the names for this SchemaObject
+     */
+    public List<String> getNames()
+    {
+        if ( names != null )
+        {
+            return Collections.unmodifiableList( names );
+        }
+        else
+        {
+            return Collections.emptyList();
+        }
+    }
+
+
+    /**
+     * Gets the first name in the set of short names for this SchemaObject if
+     * any exists for it.
+     * 
+     * @return the first of the names for this SchemaObject or the oid
+     * if one does not exist
+     */
+    public String getName()
+    {
+        if ( ( names != null ) && ( names.size() != 0 ) )
+        {
+            return names.get( 0 );
+        }
+        else
+        {
+            return oid;
+        }
+    }
+
+
+    /**
+     * Add a new name to the list of names for this SchemaObject. The name
+     * is lowercased and trimmed.
+     * 
+     * @param namesToAdd The names to add
+     */
+    public void addName( String... namesToAdd )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            // We must avoid duplicated names, as names are case insensitive
+            Set<String> lowerNames = new HashSet<String>();
+
+            // Fills a set with all the existing names
+            for ( String name : this.names )
+            {
+                lowerNames.add( Strings.toLowerCase( name ) );
+            }
+
+            for ( String name : namesToAdd )
+            {
+                if ( name != null )
+                {
+                    String lowerName = Strings.toLowerCase( name );
+                    // Check that the lower cased names is not already present
+                    if ( !lowerNames.contains( lowerName ) )
+                    {
+                        this.names.add( name );
+                        lowerNames.add( lowerName );
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Sets the list of names for this SchemaObject. The names are
+     * lowercased and trimmed.
+     * 
+     * @param names The list of names. Can be empty
+     */
+    public void setNames( List<String> names )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( names == null )
+        {
+            return;
+        }
+
+        if ( !isReadOnly )
+        {
+            this.names = new ArrayList<String>( names.size() );
+
+            for ( String name : names )
+            {
+                if ( name != null )
+                {
+                    this.names.add( name );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Sets the list of names for this SchemaObject. The names are
+     * lowercased and trimmed.
+     * 
+     * @param names The list of names.
+     */
+    public void setNames( String... names )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( names == null )
+        {
+            return;
+        }
+
+        if ( !isReadOnly )
+        {
+            this.names.clear();
+
+            for ( String name : names )
+            {
+                if ( name != null )
+                {
+                    this.names.add( name );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Gets a short description about this SchemaObject.
+     * 
+     * @return a short description about this SchemaObject
+     */
+    public String getDescription()
+    {
+        return description;
+    }
+
+
+    /**
+     * Sets the SchemaObject's description
+     * 
+     * @param description The SchemaObject's description
+     */
+    public void setDescription( String description )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.description = description;
+        }
+    }
+
+
+    /**
+     * Gets the SchemaObject specification.
+     * 
+     * @return the SchemaObject specification
+     */
+    public String getSpecification()
+    {
+        return specification;
+    }
+
+
+    /**
+     * Sets the SchemaObject's specification
+     * 
+     * @param specification The SchemaObject's specification
+     */
+    public void setSpecification( String specification )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.specification = specification;
+        }
+    }
+
+
+    /**
+     * Tells if this SchemaObject is enabled.
+     * 
+     * @return true if the SchemaObject is enabled, or if it depends on
+     * an enabled schema
+     */
+    public boolean isEnabled()
+    {
+        return isEnabled;
+    }
+
+
+    /**
+     * Tells if this SchemaObject is disabled.
+     * 
+     * @return true if the SchemaObject is disabled
+     */
+    public boolean isDisabled()
+    {
+        return !isEnabled;
+    }
+
+
+    /**
+     * Sets the SchemaObject state, either enabled or disabled.
+     * 
+     * @param enabled The current SchemaObject state
+     */
+    public void setEnabled( boolean enabled )
+    {
+        if ( !isReadOnly )
+        {
+            isEnabled = enabled;
+        }
+    }
+
+
+    /**
+     * Tells if this SchemaObject is ReadOnly.
+     * 
+     * @return true if the SchemaObject is not modifiable
+     */
+    public boolean isReadOnly()
+    {
+        return isReadOnly;
+    }
+
+
+    /**
+     * Sets the SchemaObject readOnly flag
+     * 
+     * @param readOnly The current SchemaObject ReadOnly status
+     */
+    public void setReadOnly( boolean readOnly )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.isReadOnly = readOnly;
+    }
+
+
+    /**
+     * Gets whether or not this SchemaObject has been inactivated. All
+     * SchemaObjects except Syntaxes allow for this parameter within their
+     * definition. For Syntaxes this property should always return false in
+     * which case it is never included in the description.
+     * 
+     * @return true if inactive, false if active
+     */
+    public boolean isObsolete()
+    {
+        return isObsolete;
+    }
+
+
+    /**
+     * Sets the Obsolete flag.
+     * 
+     * @param obsolete The Obsolete flag state
+     */
+    public void setObsolete( boolean obsolete )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.isObsolete = obsolete;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, List<String>> getExtensions()
+    {
+        return extensions;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasExtension( String extension )
+    {
+        return extensions.containsKey( Strings.toUpperCase( extension ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getExtension( String extension )
+    {
+        String name = Strings.toUpperCase( extension );
+
+        if ( hasExtension( name ) )
+        {
+            for ( Map.Entry<String, List<String>> entry : extensions.entrySet() )
+            {
+                String key = entry.getKey();
+                
+                if ( name.equalsIgnoreCase( key ) )
+                {
+                    return entry.getValue();
+                }
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Add an extension with its values
+     * @param key The extension key
+     * @param values The associated values
+     */
+    public void addExtension( String key, String... values )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            List<String> valueList = new ArrayList<String>();
+
+            for ( String value : values )
+            {
+                valueList.add( value );
+            }
+
+            extensions.put( Strings.toUpperCaseAscii( key ), valueList );
+        }
+    }
+
+
+    /**
+     * Add an extension with its values
+     * @param key The extension key
+     * @param values The associated values
+     */
+    public void addExtension( String key, List<String> values )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            extensions.put( Strings.toUpperCaseAscii( key ), values );
+        }
+    }
+
+
+    /**
+     * Add an extensions with their values. (Actually do a copy)
+     * 
+     * @param extensions The extensions map
+     */
+    public void setExtensions( Map<String, List<String>> extensions )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && ( extensions != null ) )
+        {
+            this.extensions = new HashMap<String, List<String>>();
+
+            for ( Map.Entry<String, List<String>> entry : extensions.entrySet() )
+            {
+                List<String> values = new ArrayList<String>();
+
+                for ( String value : entry.getValue() )
+                {
+                    values.add( value );
+                }
+
+                this.extensions.put( Strings.toUpperCaseAscii( entry.getKey() ), values );
+            }
+
+        }
+    }
+
+
+    /**
+     * The SchemaObject type :
+     * <ul>
+     *   <li> AttributeType
+     *   <li> DitCOntentRule
+     *   <li> DitStructureRule
+     *   <li> LdapComparator (specific to ADS)
+     *   <li> LdapSyntaxe
+     *   <li> MatchingRule
+     *   <li> MatchingRuleUse
+     *   <li> NameForm
+     *   <li> Normalizer (specific to ADS)
+     *   <li> ObjectClass
+     *   <li> SyntaxChecker (specific to ADS)
+     * </ul>
+     * 
+     * @return the SchemaObject type
+     */
+    public SchemaObjectType getObjectType()
+    {
+        return objectType;
+    }
+
+
+    /**
+     * Gets the name of the schema this SchemaObject is associated with.
+     *
+     * @return the name of the schema associated with this schemaObject
+     */
+    public String getSchemaName()
+    {
+        return schemaName;
+    }
+
+
+    /**
+     * Sets the name of the schema this SchemaObject is associated with.
+     * 
+     * @param schemaName the new schema name
+     */
+    public void setSchemaName( String schemaName )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.schemaName = schemaName;
+        }
+    }
+
+
+    /**
+     * This method is final to forbid the inherited classes to implement
+     * it. This has been done for performances reasons : the hashcode should
+     * be computed only once, and stored locally.
+     * 
+     * The hashcode is currently computed in the lock() method, which is a hack
+     * that should be fixed.
+     * 
+     * @return {@inheritDoc}
+     */
+    @Override
+    public final int hashCode()
+    {
+        return h;
+    }
+
+
+    /**
+     * @{@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o1 )
+    {
+        if ( this == o1 )
+        {
+            return true;
+        }
+
+        if ( !( o1 instanceof AbstractSchemaObject ) )
+        {
+            return false;
+        }
+
+        AbstractSchemaObject that = ( AbstractSchemaObject ) o1;
+
+        // Two schemaObject are equals if their oid is equal,
+        // their ObjectType is equal, their names are equals
+        // their schema name is the same, all their flags are equals,
+        // the description is the same and their extensions are equals
+        if ( !compareOid( oid, that.oid ) )
+        {
+            return false;
+        }
+
+        // Compare the names
+        if ( names == null )
+        {
+            if ( that.names != null )
+            {
+                return false;
+            }
+        }
+        else if ( that.names == null )
+        {
+            return false;
+        }
+        else
+        {
+            int nbNames = 0;
+
+            for ( String name : names )
+            {
+                if ( !that.names.contains( name ) )
+                {
+                    return false;
+                }
+
+                nbNames++;
+            }
+
+            if ( nbNames != names.size() )
+            {
+                return false;
+            }
+        }
+
+        if ( schemaName == null )
+        {
+            if ( that.schemaName != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( !schemaName.equalsIgnoreCase( that.schemaName ) )
+            {
+                return false;
+            }
+        }
+
+        if ( objectType != that.objectType )
+        {
+            return false;
+        }
+
+        if ( extensions != null )
+        {
+            if ( that.extensions == null )
+            {
+                return false;
+            }
+            else
+            {
+                for ( Map.Entry<String, List<String>> entry : extensions.entrySet() )
+                {
+                    String key = entry.getKey();
+                    
+                    if ( !that.extensions.containsKey( key ) )
+                    {
+                        return false;
+                    }
+
+                    List<String> thisValues = entry.getValue();
+                    List<String> thatValues = that.extensions.get( key );
+
+                    if ( thisValues != null )
+                    {
+                        if ( thatValues == null )
+                        {
+                            return false;
+                        }
+                        else
+                        {
+                            if ( thisValues.size() != thatValues.size() )
+                            {
+                                return false;
+                            }
+
+                            // TODO compare the values
+                        }
+                    }
+                    else if ( thatValues != null )
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+        else if ( that.extensions != null )
+        {
+            return false;
+        }
+
+        if ( this.isEnabled != that.isEnabled )
+        {
+            return false;
+        }
+
+        if ( this.isObsolete != that.isObsolete )
+        {
+            return false;
+        }
+
+        if ( this.isReadOnly != that.isReadOnly )
+        {
+            return false;
+        }
+
+        if ( this.description == null )
+        {
+            return that.description == null;
+        }
+        else
+        {
+            return this.description.equalsIgnoreCase( that.description );
+        }
+    }
+
+
+    /**
+     * Copy the current SchemaObject on place
+     *
+     * @return The copied SchemaObject
+     */
+    public abstract SchemaObject copy();
+
+
+    /**
+     * Compare two oids, and return true if they are both null or equal.
+     *
+     * @param oid1 the first OID
+     * @param oid2 the second OID
+     * @return <code>true</code> if both OIDs are null or equal
+     */
+    protected boolean compareOid( String oid1, String oid2 )
+    {
+        if ( oid1 == null )
+        {
+            return oid2 == null;
+        }
+        else
+        {
+            return oid1.equals( oid2 );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject copy( SchemaObject original )
+    {
+        // copy the description
+        description = original.getDescription();
+
+        // copy the flags
+        isEnabled = original.isEnabled();
+        isObsolete = original.isObsolete();
+        isReadOnly = original.isReadOnly();
+
+        // copy the names
+        names = new ArrayList<String>();
+
+        for ( String name : original.getNames() )
+        {
+            names.add( name );
+        }
+
+        // copy the extensions
+        extensions = new HashMap<String, List<String>>();
+
+        for ( String key : original.getExtensions().keySet() )
+        {
+            List<String> extensionValues = original.getExtension( key );
+
+            List<String> cloneExtension = new ArrayList<String>();
+
+            for ( String value : extensionValues )
+            {
+                cloneExtension.add( value );
+            }
+
+            extensions.put( key, cloneExtension );
+        }
+
+        // The SchemaName
+        schemaName = original.getSchemaName();
+
+        // The specification
+        specification = original.getSpecification();
+
+        return this;
+    }
+
+
+    /**
+     * Clear the current SchemaObject : remove all the references to other objects,
+     * and all the Maps.
+     */
+    public void clear()
+    {
+        // Clear the extensions
+        for ( Map.Entry<String, List<String>> entry : extensions.entrySet() )
+        {
+            List<String> extensionList = entry.getValue();
+
+            extensionList.clear();
+        }
+
+        extensions.clear();
+
+        // Clear the names
+        names.clear();
+    }
+
+
+    public void unlock()
+    {
+        locked = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final void lock()
+    {
+        if ( locked )
+        {
+            return;
+        }
+
+        h = 37;
+
+        // The OID
+        h += h * 17 + oid.hashCode();
+
+        // The SchemaObject type
+        h += h * 17 + objectType.getValue();
+
+        // The Names, if any
+        if ( ( names != null ) && ( names.size() != 0 ) )
+        {
+            for ( String name : names )
+            {
+                h += h * 17 + name.hashCode();
+            }
+        }
+
+        // The schemaName if any
+        if ( schemaName != null )
+        {
+            h += h * 17 + schemaName.hashCode();
+        }
+
+        h += h * 17 + ( isEnabled ? 1 : 0 );
+        h += h * 17 + ( isReadOnly ? 1 : 0 );
+
+        // The description, if any
+        if ( description != null )
+        {
+            h += h * 17 + description.hashCode();
+        }
+
+        // The extensions, if any
+        for ( Map.Entry<String, List<String>> entry : extensions.entrySet() )
+        {
+            String key = entry.getKey();
+            h += h * 17 + key.hashCode();
+
+            List<String> values = entry.getValue();
+
+            if ( values != null )
+            {
+                for ( String value : values )
+                {
+                    h += h * 17 + value.hashCode();
+                }
+            }
+        }
+
+        locked = true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributeType.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributeType.java
new file mode 100644
index 0000000..f6c775c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributeType.java
@@ -0,0 +1,735 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+/**
+ * An attributeType specification. attributeType specifications describe the
+ * nature of attributes within the directory. The attributeType specification's
+ * properties are accessible through this interface.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ *
+ * <pre>
+ *  4.1.2. Attribute Types
+ *
+ *    Attribute Type definitions are written according to the ABNF:
+ *
+ *      AttributeTypeDescription = LPAREN WSP
+ *          numericoid                   ; object identifier
+ *          [ SP &quot;NAME&quot; SP qdescrs ]     ; short names (descriptors)
+ *          [ SP &quot;DESC&quot; SP qdstring ]    ; description
+ *          [ SP &quot;OBSOLETE&quot; ]            ; not active
+ *          [ SP &quot;SUP&quot; SP oid ]          ; supertype
+ *          [ SP &quot;EQUALITY&quot; SP oid ]     ; equality matching rule
+ *          [ SP &quot;ORDERING&quot; SP oid ]     ; ordering matching rule
+ *          [ SP &quot;SUBSTR&quot; SP oid ]       ; substrings matching rule
+ *          [ SP &quot;SYNTAX&quot; SP noidlen ]   ; value syntax
+ *          [ SP &quot;SINGLE-VALUE&quot; ]        ; single-value
+ *          [ SP &quot;COLLECTIVE&quot; ]          ; collective
+ *          [ SP &quot;NO-USER-MODIFICATION&quot; ]; not user modifiable
+ *          [ SP &quot;USAGE&quot; SP usage ]      ; usage
+ *          extensions WSP RPAREN        ; extensions
+ *
+ *      usage = &quot;userApplications&quot;     / ; user
+ *              &quot;directoryOperation&quot;   / ; directory operational
+ *              &quot;distributedOperation&quot; / ; DSA-shared operational
+ *              &quot;dSAOperation&quot;           ; DSA-specific operational
+ *
+ *    where:
+ *      [numericoid] is object identifier assigned to this attribute type;
+ *      NAME [qdescrs] are short names (descriptors) identifying this
+ *          attribute type;
+ *      DESC [qdstring] is a short descriptive string;
+ *      OBSOLETE indicates this attribute type is not active;
+ *      SUP oid specifies the direct supertype of this type;
+ *      EQUALITY, ORDERING, SUBSTRING provide the oid of the equality,
+ *          ordering, and substrings matching rules, respectively;
+ *      SYNTAX identifies value syntax by object identifier and may suggest
+ *          a minimum upper bound;
+ *      COLLECTIVE indicates this attribute type is collective [X.501];
+ *      NO-USER-MODIFICATION indicates this attribute type is not user
+ *          modifiable;
+ *      USAGE indicates the application of this attribute type; and
+ *      [extensions] describe extensions.
+ *
+ *    Each attribute type description must contain at least one of the SUP
+ *    or SYNTAX fields.
+ *
+ *    Usage of userApplications, the default, indicates that attributes of
+ *    this type represent user information.  That is, they are user
+ *    attributes.
+ *
+ *    COLLECTIVE requires usage userApplications.  Use of collective
+ *    attribute types in LDAP is not discussed in this technical
+ *    specification.
+ *
+ *    A usage of directoryOperation, distributedOperation, or dSAOperation
+ *    indicates that attributes of this type represent operational and/or
+ *    administrative information.  That is, they are operational attributes.
+ *
+ *    directoryOperation usage indicates that the attribute of this type is
+ *    a directory operational attribute.  distributedOperation usage
+ *    indicates that the attribute of this DSA-shared usage operational
+ *    attribute.  dSAOperation usage indicates that the attribute of this
+ *    type is a DSA-specific operational attribute.
+ *
+ *    NO-USER-MODIFICATION requires an operational usage.
+ *
+ *    Note that the [AttributeTypeDescription] does not list the matching
+ *    rules which can be used with that attribute type in an extensibleMatch
+ *    search filter.  This is done using the 'matchingRuleUse' attribute
+ *    described in Section 4.1.4.
+ *
+ *    This document refines the schema description of X.501 by requiring
+ *    that the SYNTAX field in an [AttributeTypeDescription] be a string
+ *    representation of an object identifier for the LDAP string syntax
+ *    definition with an optional indication of the suggested minimum bound
+ *    of a value of this attribute.
+ *
+ *    A suggested minimum upper bound on the number of characters in a value
+ *    with a string-based syntax, or the number of bytes in a value for all
+ *    other syntaxes, may be indicated by appending this bound count inside
+ *    of curly braces following the syntax's OBJECT IDENTIFIER in an
+ *
+ *    Attribute Type Description.  This bound is not part of the syntax name
+ *    itself.  For instance, &quot;1.3.6.4.1.1466.0{64}&quot; suggests that server
+ *    implementations should allow a string to be 64 characters long,
+ *    although they may allow longer strings.  Note that a single character
+ *    of the Directory String syntax may be encoded in more than one octet
+ *    since UTF-8 is a variable-length encoding.
+ * </pre>
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.2</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">
+ *      ldapbis [MODELS]</a>
+ * @see DescriptionUtils#getDescription(AttributeType)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeType extends AbstractSchemaObject implements Cloneable
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** The syntax OID associated with this AttributeType */
+    protected String syntaxOid;
+
+    /** The syntax associated with the syntaxID */
+    protected LdapSyntax syntax;
+
+    /** The equality OID associated with this AttributeType */
+    protected String equalityOid;
+
+    /** The equality MatchingRule associated with the equalityID */
+    protected MatchingRule equality;
+
+    /** The substring OID associated with this AttributeType */
+    protected String substringOid;
+
+    /** The substring MatchingRule associated with the substringID */
+    protected MatchingRule substring;
+
+    /** The ordering OID associated with this AttributeType */
+    protected String orderingOid;
+
+    /** The ordering MatchingRule associated with the orderingID */
+    protected MatchingRule ordering;
+
+    /** The superior AttributeType OID */
+    protected String superiorOid;
+
+    /** The superior AttributeType */
+    protected AttributeType superior;
+
+    /** whether or not this type is single valued */
+    protected boolean isSingleValued = false;
+
+    /** whether or not this type is a collective attribute */
+    protected boolean isCollective = false;
+
+    /** whether or not this type can be modified by directory users */
+    protected boolean canUserModify = true;
+
+    /** the usage for this attributeType */
+    protected UsageEnum usage = UsageEnum.USER_APPLICATIONS;
+
+    /** the length of this attribute in bytes */
+    protected long syntaxLength = 0L;
+
+
+    /**
+     * Creates a AttributeType object using a unique OID.
+     *
+     * @param oid the OID for this AttributeType
+     */
+    public AttributeType( String oid )
+    {
+        super( SchemaObjectType.ATTRIBUTE_TYPE, oid );
+    }
+
+
+    /**
+     * Gets whether or not this AttributeType is single-valued.
+     *
+     * @return true if only one value can exist for this AttributeType, false
+     *         otherwise
+     */
+    public boolean isSingleValued()
+    {
+        return isSingleValued;
+    }
+
+
+    /**
+     * Gets whether or not this AttributeType can be modified by a user.
+     *
+     * @return true if users can modify it, false if only the directory can.
+     */
+    public boolean isUserModifiable()
+    {
+        return canUserModify;
+    }
+
+
+    /**
+     * Gets whether or not this AttributeType is a collective attribute.
+     *
+     * @return true if the attribute is collective, false otherwise
+     */
+    public boolean isCollective()
+    {
+        return isCollective;
+    }
+
+
+    /**
+     * Determines the usage for this AttributeType.
+     *
+     * @return a type safe UsageEnum
+     */
+    public UsageEnum getUsage()
+    {
+        return usage;
+    }
+
+
+    /**
+     * Gets a length limit for this AttributeType.
+     *
+     * @return the length of the attribute
+     */
+    public long getSyntaxLength()
+    {
+        return syntaxLength;
+    }
+
+
+    /**
+     * Gets the the superior AttributeType of this AttributeType.
+     *
+     * @return the superior AttributeType for this AttributeType
+     */
+    public AttributeType getSuperior()
+    {
+        return superior;
+    }
+
+
+    /**
+     * Gets the OID of the superior AttributeType for this AttributeType.
+     *
+     * @return The OID of the superior AttributeType for this AttributeType.
+     */
+    public String getSuperiorOid()
+    {
+        return superiorOid;
+    }
+
+
+    /**
+     * Gets the Name of the superior AttributeType for this AttributeType.
+     *
+     * @return The Name of the superior AttributeType for this AttributeType.
+     */
+    public String getSuperiorName()
+    {
+        if ( superior != null )
+        {
+            return superior.getName();
+        }
+        else
+        {
+            return superiorOid;
+        }
+    }
+
+
+    /**
+     * Gets the Syntax for this AttributeType's values.
+     *
+     * @return the value syntax
+     */
+    public LdapSyntax getSyntax()
+    {
+        return syntax;
+    }
+
+
+    /**
+     * Gets the Syntax name for this AttributeType's values.
+     *
+     * @return the value syntax name
+     */
+    public String getSyntaxName()
+    {
+        if ( syntax != null )
+        {
+            return syntax.getName();
+        }
+        else
+        {
+            return syntaxOid;
+        }
+    }
+
+
+    /**
+     * Gets the Syntax OID for this AttributeType's values.
+     *
+     * @return the value syntax's OID
+     */
+    public String getSyntaxOid()
+    {
+        return syntaxOid;
+    }
+
+
+    /**
+     * Gets the MatchingRule for this AttributeType used for equality matching.
+     *
+     * @return the equality matching rule
+     */
+    public MatchingRule getEquality()
+    {
+        return equality;
+    }
+
+
+    /**
+     * Gets the Equality OID for this AttributeType's values.
+     *
+     * @return the value Equality's OID
+     */
+    public String getEqualityOid()
+    {
+        return equalityOid;
+    }
+
+
+    /**
+     * Gets the Equality Name for this AttributeType's values.
+     *
+     * @return the value Equality's Name
+     */
+    public String getEqualityName()
+    {
+        if ( equality != null )
+        {
+            return equality.getName();
+        }
+        else
+        {
+            return equalityOid;
+        }
+    }
+
+
+    /**
+     * Gets the MatchingRule for this AttributeType used for Ordering matching.
+     *
+     * @return the Ordering matching rule
+     */
+    public MatchingRule getOrdering()
+    {
+        return ordering;
+    }
+
+
+    /**
+     * Gets the MatchingRule name for this AttributeType used for Ordering matching.
+     *
+     * @return the Ordering matching rule name
+     */
+    public String getOrderingName()
+    {
+        if ( ordering != null )
+        {
+            return ordering.getName();
+        }
+        else
+        {
+            return orderingOid;
+        }
+    }
+
+
+    /**
+     * Gets the Ordering OID for this AttributeType's values.
+     *
+     * @return the value Equality's OID
+     */
+    public String getOrderingOid()
+    {
+        return orderingOid;
+    }
+
+
+    /**
+     * Gets the MatchingRule for this AttributeType used for Substr matching.
+     *
+     * @return the Substr matching rule
+     */
+    public MatchingRule getSubstring()
+    {
+        return substring;
+    }
+
+
+    /**
+     * Gets the MatchingRule name for this AttributeType used for Substring matching.
+     *
+     * @return the Substring matching rule name
+     */
+    public String getSubstringName()
+    {
+        if ( substring != null )
+        {
+            return substring.getName();
+        }
+        else
+        {
+            return substringOid;
+        }
+    }
+
+
+    /**
+     * Gets the Substr OID for this AttributeType's values.
+     *
+     * @return the value Substr's OID
+     */
+    public String getSubstringOid()
+    {
+        return substringOid;
+    }
+
+
+    /**
+     * Tells if the attributeType is a USER attribute or not
+     * @return true if this is a USER attributeType
+     */
+    public boolean isUser()
+    {
+        return usage == UsageEnum.USER_APPLICATIONS;
+    }
+
+
+    /**
+     * Tells if the attributeType is an OPERATIONAL attribute or not
+     * @return true if this is an OPERATIONAL attributeType
+     */
+    public boolean isOperational()
+    {
+        return usage != UsageEnum.USER_APPLICATIONS;
+    }
+
+
+    /**
+     * Checks to see if this AttributeType is the ancestor of another
+     * attributeType.
+     *
+     * @param descendant the perspective descendant to check
+     * @return true if the descendant is truly a derived from this AttributeType
+     */
+    public boolean isAncestorOf( AttributeType descendant )
+    {
+        if ( ( descendant == null ) || this.equals( descendant ) )
+        {
+            return false;
+        }
+
+        return isAncestorOrEqual( this, descendant );
+    }
+
+
+    /**
+     * Checks to see if this AttributeType is the descendant of another
+     * attributeType.
+     *
+     * @param ancestor the perspective ancestor to check
+     * @return true if this AttributeType truly descends from the ancestor
+     */
+    public boolean isDescendantOf( AttributeType ancestor )
+    {
+        if ( ( ancestor == null ) || equals( ancestor ) )
+        {
+            return false;
+        }
+
+        return isAncestorOrEqual( ancestor, this );
+    }
+
+
+    /**
+     * Recursive method which checks to see if a descendant is really an ancestor or if the two
+     * are equal.
+     *
+     * @param ancestor the possible ancestor of the descendant
+     * @param descendant the possible descendant of the ancestor
+     * @return true if the ancestor equals the descendant or if the descendant is really
+     * a subtype of the ancestor. otherwise false
+     */
+    private boolean isAncestorOrEqual( AttributeType ancestor, AttributeType descendant )
+    {
+        if ( ( ancestor == null ) || ( descendant == null ) )
+        {
+            return false;
+        }
+
+        if ( ancestor.equals( descendant ) )
+        {
+            return true;
+        }
+
+        return isAncestorOrEqual( ancestor, descendant.getSuperior() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType copy()
+    {
+        MutableAttributeType copy = new MutableAttributeType( oid );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // Copy the canUserModify flag
+        copy.canUserModify = canUserModify;
+
+        // Copy the isCollective flag
+        copy.isCollective = isCollective;
+
+        // Copy the isSingleValue flag
+        copy.isSingleValued = isSingleValued;
+
+        // Copy the USAGE type
+        copy.usage = usage;
+
+        // All the references to other Registries object are set to null,
+        // all the OIDs are copied
+        // The EQUALITY MR
+        copy.equality = null;
+        copy.equalityOid = equalityOid;
+
+        // The ORDERING MR
+        copy.ordering = null;
+        copy.orderingOid = orderingOid;
+
+        // The SUBSTR MR
+        copy.substring = null;
+        copy.substringOid = substringOid;
+
+        // The SUP AT
+        copy.superior = null;
+        copy.superiorOid = superiorOid;
+
+        // The SYNTAX
+        copy.syntax = null;
+        copy.syntaxOid = syntaxOid;
+        copy.syntaxLength = syntaxLength;
+
+        return copy;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof AttributeType ) )
+        {
+            return false;
+        }
+
+        AttributeType that = ( AttributeType ) o;
+
+        // The COLLECTIVE
+        if ( isCollective != that.isCollective )
+        {
+            return false;
+        }
+
+        // The SINGLE_VALUE
+        if ( isSingleValued != that.isSingleValued )
+        {
+            return false;
+        }
+
+        // The NO_USER_MODIFICATION
+        if ( canUserModify != that.canUserModify )
+        {
+            return false;
+        }
+
+        // The USAGE
+        if ( usage != that.usage )
+        {
+            return false;
+        }
+
+        // The equality
+        if ( !compareOid( equalityOid, that.equalityOid ) )
+        {
+            return false;
+        }
+
+        if ( equality != null )
+        {
+            if ( !equality.equals( that.equality ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( that.equality != null )
+            {
+                return false;
+            }
+        }
+
+        // The ordering
+        if ( !compareOid( orderingOid, that.orderingOid ) )
+        {
+            return false;
+        }
+
+        if ( ordering != null )
+        {
+            if ( !ordering.equals( that.ordering ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( that.ordering != null )
+            {
+                return false;
+            }
+        }
+
+        // The substring
+        if ( !compareOid( substringOid, that.substringOid ) )
+        {
+            return false;
+        }
+
+        if ( substring != null )
+        {
+            if ( !substring.equals( that.substring ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( that.substring != null )
+            {
+                return false;
+            }
+        }
+
+        // The superior
+        if ( !compareOid( superiorOid, that.superiorOid ) )
+        {
+            return false;
+        }
+
+        if ( superior != null )
+        {
+            if ( !superior.equals( that.superior ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( that.superior != null )
+            {
+                return false;
+            }
+        }
+
+        // The syntax
+        if ( !compareOid( syntaxOid, that.syntaxOid ) )
+        {
+            return false;
+        }
+
+        if ( syntaxLength != that.syntaxLength )
+        {
+            return false;
+        }
+
+        if ( syntax == null )
+        {
+            return that.syntax == null;
+        }
+
+        if ( syntax.equals( that.syntax ) )
+        {
+            return syntaxLength == that.syntaxLength;
+        }
+        else
+        {
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributeTypeOptions.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributeTypeOptions.java
new file mode 100644
index 0000000..17b6069
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributeTypeOptions.java
@@ -0,0 +1,200 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * An structure containing a couple of attributeType and options. A search request
+ * can contain a list of attribute to return, those attribute could be associated
+ * with options.
+ * 
+ * Those options are stored into a Set.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeTypeOptions
+{
+    /** The attributeType */
+    private AttributeType attributeType;
+
+    /** The options, if any */
+    private Set<String> options;
+
+
+    /**
+     * Creates a new instance of AttributeTypeOptions, containing an attributeType, 
+     * but no options.
+     *
+     * @param attributeType The associated AttributeType
+     */
+    public AttributeTypeOptions( AttributeType attributeType )
+    {
+        this.attributeType = attributeType;
+    }
+
+
+    /**
+     * Creates a new instance of AttributeTypeOptions, containing an attributeType, 
+     * and options.
+     *
+     * @param attributeType the associated AttributeType
+     * @param options the associated options
+     */
+    public AttributeTypeOptions( AttributeType attributeType, Set<String> options )
+    {
+        this.attributeType = attributeType;
+        this.options = options;
+    }
+
+
+    /**
+     * @return the inner attributeType
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+
+
+    /**
+     * @return the associated options
+     */
+    public Set<String> getOptions()
+    {
+        return options;
+    }
+
+
+    /**
+     * @return <code>true</code> if the attributeType has at least one option
+     */
+    public boolean hasOption()
+    {
+        return ( options != null ) && ( options.size() != 0 );
+    }
+
+
+    /**
+     * @param option the option to check
+     * @return <code>true</code> if the attributeType has the given option
+     */
+    public boolean hasOption( String option )
+    {
+        if ( hasOption() )
+        {
+            return options.contains( Strings.toLowerCase( Strings.trim( option ) ) );
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Add a new option to the option set for this attributeType.
+     *
+     * @param option the option to add
+     */
+    public void addOption( String option )
+    {
+        if ( options == null )
+        {
+            options = new HashSet<String>();
+        }
+
+        options.add( Strings.toLowerCase( Strings.trim( option ) ) );
+    }
+
+
+    /**
+     * Add a set of optionS to the option set for this attributeType.
+     *
+     * @param optionsToAdd the options to add
+     */
+    public void addOptions( Set<String> optionsToAdd )
+    {
+        if ( this.options == null )
+        {
+            this.options = optionsToAdd;
+        }
+        else
+        {
+            this.options.addAll( optionsToAdd );
+        }
+    }
+
+
+    /**
+     * @see Object#hashCode()
+     */
+    public int hashCode()
+    {
+        return attributeType.hashCode();
+    }
+    
+    
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        // Short circuit
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof AttributeTypeOptions ) )
+        {
+            return false;
+        }
+
+        AttributeTypeOptions that = ( AttributeTypeOptions ) o;
+        
+        return attributeType.equals( that.attributeType );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "<" ).append( attributeType.getName() );
+
+        if ( hasOption() )
+        {
+            for ( String option : options )
+            {
+                sb.append( ";" ).append( option );
+            }
+        }
+
+        return sb.append( ">" ).toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributesFactory.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributesFactory.java
new file mode 100644
index 0000000..f8d6074
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/AttributesFactory.java
@@ -0,0 +1,473 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.util.DateUtils;
+
+
+/**
+ * A factory that generates an entry using the meta schema for schema
+ * elements.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributesFactory
+{
+    public Entry getAttributes( SchemaObject obj, Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        if ( obj instanceof LdapSyntax )
+        {
+            return convert( ( LdapSyntax ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof MatchingRule )
+        {
+            return convert( ( MatchingRule ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof AttributeType )
+        {
+            return convert( ( AttributeType ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof ObjectClass )
+        {
+            return convert( ( ObjectClass ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof MatchingRuleUse )
+        {
+            return convert( ( MatchingRuleUse ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof DitStructureRule )
+        {
+            return convert( ( DitStructureRule ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof DitContentRule )
+        {
+            return convert( ( DitContentRule ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof NameForm )
+        {
+            return convert( ( NameForm ) obj, schema, schemaManager );
+        }
+
+        throw new IllegalArgumentException( "nknown SchemaObject type: " + obj.getClass() );
+    }
+
+
+    /**
+     * Convert a Schema to Entry
+     * 
+     * @param schema The Schema to convert
+     * @param schemaManager The SchemaManager
+     * @return An Entry containing the converted Schema
+     * @throws LdapException If the conversion failed
+     */
+    public Entry convert( Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SCHEMA_OC );
+        entry.put( SchemaConstants.CN_AT, schema.getSchemaName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+
+        if ( schema.isDisabled() )
+        {
+            entry.put( MetaSchemaConstants.M_DISABLED_AT, "TRUE" );
+        }
+
+        String[] dependencies = schema.getDependencies();
+
+        if ( dependencies != null && dependencies.length > 0 )
+        {
+            Attribute attr = new DefaultAttribute(
+                schemaManager.getAttributeType( MetaSchemaConstants.M_DEPENDENCIES_AT ) );
+
+            for ( String dependency : dependencies )
+            {
+                attr.add( dependency );
+            }
+
+            entry.put( attr );
+        }
+
+        return entry;
+    }
+
+
+    public Entry convert( SyntaxChecker syntaxChecker, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SYNTAX_CHECKER_OC );
+        entry.put( MetaSchemaConstants.M_OID_AT, syntaxChecker.getOid() );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, syntaxChecker.getClass().getName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+
+        return entry;
+    }
+
+
+    public Entry convert( LdapSyntax syntax, Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SYNTAX_OC );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        injectCommon( syntax, entry, schemaManager );
+
+        return entry;
+    }
+
+
+    public Entry convert( String oid, Normalizer normalizer, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_NORMALIZER_OC );
+        entry.put( MetaSchemaConstants.M_OID_AT, oid );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, normalizer.getClass().getName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    public Entry convert( String oid, LdapComparator<? super Object> comparator, Schema schema,
+        SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_COMPARATOR_OC );
+        entry.put( MetaSchemaConstants.M_OID_AT, oid );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, comparator.getClass().getName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    /**
+     * 
+     * @param matchingRule
+     * @return Attributes
+     * @throws LdapException
+     */
+    public Entry convert( MatchingRule matchingRule, Schema schema, SchemaManager schemaManager )
+        throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_MATCHING_RULE_OC );
+        entry.put( MetaSchemaConstants.M_SYNTAX_AT, matchingRule.getSyntaxOid() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        injectCommon( matchingRule, entry, schemaManager );
+        return entry;
+    }
+
+
+    public Entry convert( MatchingRuleUse matchingRuleUse, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    public Entry convert( DitStructureRule ditStructureRule, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    public Entry convert( DitContentRule dITContentRule, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    public Entry convert( NameForm nameForm, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    /**
+     * <pre>
+     *    objectclass ( 1.3.6.1.4.1.18060.0.4.0.3.3
+     *       NAME 'metaAttributeType'
+     *       DESC 'meta definition of the AttributeType object'
+     *       SUP metaTop
+     *       STRUCTURAL
+     *       MUST ( m-name $ m-syntax )
+     *       MAY ( m-supAttributeType $ m-obsolete $ m-equality $ m-ordering $
+     *             m-substr $ m-singleValue $ m-collective $ m-noUserModification $
+     *             m-usage $ m-extensionAttributeType )
+     *    )
+     * </pre>
+     * 
+     * @param attributeType
+     * @return Attributes
+     * @throws LdapException
+     */
+    public Entry convert( AttributeType attributeType, Schema schema, SchemaManager schemaManager )
+        throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC );
+        entry.put( MetaSchemaConstants.M_COLLECTIVE_AT, getBoolean( attributeType.isCollective() ) );
+        entry.put( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT, getBoolean( !attributeType.isUserModifiable() ) );
+        entry.put( MetaSchemaConstants.M_SINGLE_VALUE_AT, getBoolean( attributeType.isSingleValued() ) );
+        entry.put( MetaSchemaConstants.M_USAGE_AT, attributeType.getUsage().toString() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+
+        injectCommon( attributeType, entry, schemaManager );
+
+        String superiorOid = attributeType.getSuperiorOid();
+
+        if ( superiorOid != null )
+        {
+            entry.put( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT, superiorOid );
+        }
+
+        if ( attributeType.getEqualityOid() != null )
+        {
+            entry.put( MetaSchemaConstants.M_EQUALITY_AT, attributeType.getEqualityOid() );
+        }
+
+        if ( attributeType.getSubstringOid() != null )
+        {
+            entry.put( MetaSchemaConstants.M_SUBSTR_AT, attributeType.getSubstringOid() );
+        }
+
+        if ( attributeType.getOrderingOid() != null )
+        {
+            entry.put( MetaSchemaConstants.M_ORDERING_AT, attributeType.getOrderingOid() );
+        }
+
+        if ( attributeType.getSyntaxOid() != null )
+        {
+            entry.put( MetaSchemaConstants.M_SYNTAX_AT, attributeType.getSyntaxOid() );
+        }
+
+        return entry;
+    }
+
+
+    /**
+     * Creates the attributes of an entry representing an objectClass.
+     * 
+     * <pre>
+     *  objectclass ( 1.3.6.1.4.1.18060.0.4.0.3.2
+     *      NAME 'metaObjectClass'
+     *      DESC 'meta definition of the objectclass object'
+     *      SUP metaTop
+     *      STRUCTURAL
+     *      MUST m-oid
+     *      MAY ( m-name $ m-obsolete $ m-supObjectClass $ m-typeObjectClass $ m-must $
+     *            m-may $ m-extensionObjectClass )
+     *  )
+     * </pre>
+     * 
+     * @param objectClass the objectClass to produce a meta schema entry for
+     * @return the attributes of the metaSchema entry representing the objectClass
+     * @throws LdapException if there are any problems
+     */
+    public Entry convert( ObjectClass objectClass, Schema schema, SchemaManager schemaManager )
+        throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_OBJECT_CLASS_OC );
+        entry.put( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT, objectClass.getType().toString() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+
+        injectCommon( objectClass, entry, schemaManager );
+        Attribute attr = null;
+
+        // handle the superior objectClasses
+        if ( objectClass.getSuperiorOids() != null && objectClass.getSuperiorOids().size() != 0 )
+        {
+            if ( schemaManager != null )
+            {
+                attr = new DefaultAttribute(
+                    schemaManager.getAttributeType( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT ) );
+            }
+            else
+            {
+                attr = new DefaultAttribute( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT );
+            }
+
+            for ( String superior : objectClass.getSuperiorOids() )
+            {
+                attr.add( superior );
+            }
+
+            entry.put( attr );
+        }
+
+        // add the must list
+        if ( objectClass.getMustAttributeTypeOids() != null && objectClass.getMustAttributeTypeOids().size() != 0 )
+        {
+            if ( schemaManager != null )
+            {
+                attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_MUST_AT ) );
+            }
+            else
+            {
+                attr = new DefaultAttribute( MetaSchemaConstants.M_MUST_AT );
+            }
+
+            for ( String mustOid : objectClass.getMustAttributeTypeOids() )
+            {
+                attr.add( mustOid );
+            }
+
+            entry.put( attr );
+        }
+
+        // add the may list
+        if ( objectClass.getMayAttributeTypeOids() != null && objectClass.getMayAttributeTypeOids().size() != 0 )
+        {
+            if ( schemaManager != null )
+            {
+                attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_MAY_AT ) );
+            }
+            else
+            {
+                attr = new DefaultAttribute( MetaSchemaConstants.M_MAY_AT );
+            }
+
+            for ( String mayOid : objectClass.getMayAttributeTypeOids() )
+            {
+                attr.add( mayOid );
+            }
+
+            entry.put( attr );
+        }
+
+        return entry;
+    }
+
+
+    private void injectCommon( SchemaObject object, Entry entry, SchemaManager schemaManager )
+        throws LdapException
+    {
+        injectNames( object.getNames(), entry, schemaManager );
+        entry.put( MetaSchemaConstants.M_OBSOLETE_AT, getBoolean( object.isObsolete() ) );
+        entry.put( MetaSchemaConstants.M_OID_AT, object.getOid() );
+
+        if ( object.getDescription() != null )
+        {
+            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, object.getDescription() );
+        }
+
+        // The extensions
+        Map<String, List<String>> extensions = object.getExtensions();
+
+        if ( extensions != null )
+        {
+            for ( Map.Entry<String, List<String>> mapEntry : extensions.entrySet() )
+            {
+                String key = mapEntry.getKey();
+                List<String> values = mapEntry.getValue();
+
+                for ( String value : values )
+                {
+                    entry.add( key, value );
+                }
+            }
+        }
+    }
+
+
+    private void injectNames( List<String> names, Entry entry, SchemaManager schemaManager ) throws LdapException
+    {
+        if ( ( names == null ) || ( names.size() == 0 ) )
+        {
+            return;
+        }
+
+        Attribute attr = null;
+
+        if ( schemaManager != null )
+        {
+            attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_NAME_AT ) );
+        }
+        else
+        {
+            attr = new DefaultAttribute( MetaSchemaConstants.M_NAME_AT );
+        }
+
+        for ( String name : names )
+        {
+            attr.add( name );
+        }
+
+        entry.put( attr );
+    }
+
+
+    private String getBoolean( boolean value )
+    {
+        if ( value )
+        {
+            return "TRUE";
+        }
+        else
+        {
+            return "FALSE";
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DescriptionUtils.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DescriptionUtils.java
new file mode 100644
index 0000000..385858c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DescriptionUtils.java
@@ -0,0 +1,224 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Utility class used to generate schema object specifications. Some of the
+ * latest work coming out of the LDAPBIS working body adds optional extensions
+ * to these syntaxes. Descriptions can be generated for
+ * the following objects:
+ * <ul>
+ * <li><a href="./AttributeType.html">AttributeType</a></li>
+ * <li><a href="./DitContentRule.html">DitContentRule</a></li>
+ * <li><a href="./DitContentRule.html">DitStructureRule</a></li>
+ * <li><a href="./LdapComparator.html">Syntax</a></li>
+ * <li><a href="./MatchingRule.html">MatchingRule</a></li>
+ * <li><a href="./MatchingRuleUse.html">MatchingRuleUse</a></li>
+ * <li><a href="./NameForm.html">NameForm</a></li>
+ * <li><a href="./Normalizer.html">Syntax</a></li>
+ * <li><a href="./ObjectClass.html">ObjectClass</a></li>
+ * <li><a href="./LdapSyntax.html">Syntax</a></li>
+ * <li><a href="./SyntaxChecker.html">Syntax</a></li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DescriptionUtils
+{
+    /**
+     * Private constructor.
+     */
+    private DescriptionUtils()
+    {
+    }
+
+
+    /**
+     * Generates the ComparatorDescription for a LdapComparator. Only the right 
+     * hand side of the description starting at the opening parenthesis is 
+     * generated: that is 'ComparatorDescription = ' is not generated.
+     * 
+     * <pre>
+     * ComparatorDescription = &quot;(&quot;
+     *     numericoid                          
+     *     [&quot;DESC&quot; qdstring ]
+     *     &quot;FQCN&quot; whsp fqcn
+     *     [&quot;BYTECODE&quot; whsp base64  ]
+     *     extensions 
+     *     &quot;)&quot;
+     * </pre>
+     * 
+     * @param comparator
+     *            the Comparator to generate the description for
+     * @return the ComparatorDescription string
+     */
+    public static String getDescription( LdapComparator<?> comparator )
+    {
+        return getLoadableDescription( comparator );
+    }
+
+
+    /**
+     * Generates the NormalizerDescription for a Normalizer. Only the right 
+     * hand side of the description starting at the opening parenthesis is 
+     * generated: that is 'NormalizerDescription = ' is not generated.
+     * 
+     * <pre>
+     * NormalizerDescription = &quot;(&quot;
+     *     numericoid                          
+     *     [&quot;DESC&quot; qdstring ]
+     *     &quot;FQCN&quot; whsp fqcn
+     *     [&quot;BYTECODE&quot; whsp base64  ]
+     *     extensions 
+     *     &quot;)&quot;
+     * </pre>
+     * 
+     * @param normalizer
+     *            the Normalizer to generate the description for
+     * @return the NormalizerDescription string
+     */
+    public static String getDescription( Normalizer normalizer )
+    {
+        return getLoadableDescription( normalizer );
+    }
+
+
+    /**
+     * Generates the SyntaxCheckerDescription for a SyntaxChecker. Only the right 
+     * hand side of the description starting at the opening parenthesis is 
+     * generated: that is 'SyntaxCheckerDescription = ' is not generated.
+     * 
+     * <pre>
+     * SyntaxCheckerDescription = &quot;(&quot;
+     *     numericoid                          
+     *     [&quot;DESC&quot; qdstring ]
+     *     &quot;FQCN&quot; whsp fqcn
+     *     [&quot;BYTECODE&quot; whsp base64  ]
+     *     extensions 
+     *     &quot;)&quot;
+     * </pre>
+     * 
+     * @param syntaxChecker
+     *            the SyntaxChecker to generate the description for
+     * @return the SyntaxCheckerDescription string
+     */
+    public static String getDescription( SyntaxChecker syntaxChecker )
+    {
+        return getLoadableDescription( syntaxChecker );
+    }
+
+
+    private static void getExtensions( StringBuilder sb, Map<String, List<String>> extensions )
+    {
+        for ( Map.Entry<String, List<String>> extension : extensions.entrySet() )
+        {
+            sb.append( ' ' ).append( extension.getKey() ).append( ' ' );
+
+            List<String> values = extension.getValue();
+
+            if ( ( values != null ) && ( values.size() != 0 ) )
+            {
+                if ( values.size() == 1 )
+                {
+                    sb.append( values.get( 0 ) );
+                }
+                else
+                {
+                    boolean isFirst = true;
+                    sb.append( "( " );
+
+                    for ( String value : values )
+                    {
+                        if ( isFirst )
+                        {
+                            isFirst = false;
+                        }
+                        else
+                        {
+                            sb.append( ' ' );
+                        }
+
+                        sb.append( value );
+                    }
+
+                    sb.append( " )" );
+                }
+            }
+
+            sb.append( '\n' );
+        }
+    }
+
+
+    /**
+     * Generate the description for Comparators, Normalizers and SyntaxCheckers.
+     */
+    private static String getLoadableDescription( LoadableSchemaObject schemaObject )
+    {
+        StringBuilder buf = new StringBuilder( "( " );
+        buf.append( schemaObject.getOid() );
+        buf.append( '\n' );
+
+        if ( schemaObject.getDescription() != null )
+        {
+            buf.append( " DESC " );
+            buf.append( schemaObject.getDescription() );
+            buf.append( '\n' );
+        }
+
+        if ( schemaObject.getFqcn() != null )
+        {
+            buf.append( " FQCN " );
+            buf.append( schemaObject.getFqcn() );
+            buf.append( '\n' );
+        }
+
+        if ( schemaObject.getBytecode() != null )
+        {
+            buf.append( " BYTECODE " );
+
+            // We will dump only the 16 first bytes
+            if ( schemaObject.getBytecode().length() > 16 )
+            {
+                buf.append( schemaObject.getBytecode().substring( 0, 16 ) );
+            }
+            else
+            {
+                buf.append( schemaObject.getBytecode() );
+            }
+
+            buf.append( '\n' );
+        }
+
+        if ( schemaObject.getExtensions() != null )
+        {
+            getExtensions( buf, schemaObject.getExtensions() );
+        }
+
+        buf.append( " ) " );
+
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DitContentRule.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DitContentRule.java
new file mode 100644
index 0000000..63cf696
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DitContentRule.java
@@ -0,0 +1,676 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A ditContentRule specification. ditContentRules identify the content of
+ * entries of a particular structural objectClass. They specify the AUXILIARY
+ * objectClasses and additional attribute types permitted to appear, or excluded
+ * from appearing in entries of the indicated STRUCTURAL objectClass.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ * 
+ * <pre>
+ *  4.1.6. DIT Content Rules
+ * 
+ *    A DIT content rule is a &quot;rule governing the content of entries of a
+ *    particular structural object class&quot; [X.501].
+ * 
+ *    For DIT entries of a particular structural object class, a DIT content
+ *    rule specifies which auxiliary object classes the entries are allowed
+ *    to belong to and which additional attributes (by type) are required,
+ *    allowed or not allowed to appear in the entries.
+ * 
+ *    The list of precluded attributes cannot include any attribute listed
+ *    as mandatory in rule, the structural object class, or any of the
+ *    allowed auxiliary object classes.
+ * 
+ *    Each content rule is identified by the object identifier, as well as
+ *    any short names (descriptors), of the structural object class it
+ *    applies to.
+ * 
+ *    An entry may only belong to auxiliary object classes listed in the
+ *    governing content rule.
+ * 
+ *    An entry must contain all attributes required by the object classes
+ *    the entry belongs to as well as all attributed required by the
+ *    governing content rule.
+ * 
+ *    An entry may contain any non-precluded attributes allowed by the
+ *    object classes the entry belongs to as well as all attributes allowed
+ *    by the governing content rule.
+ * 
+ *    An entry cannot include any attribute precluded by the governing
+ *    content rule.
+ * 
+ *    An entry is governed by (if present and active in the subschema) the
+ *    DIT content rule which applies to the structural object class of the
+ *    entry (see Section 2.4.2).  If no active rule is present for the
+ *    entry's structural object class, the entry's content is governed by
+ *    the structural object class (and possibly other aspects of user and
+ *    system schema).
+ * 
+ *    DIT content rule descriptions are written according to the ABNF:
+ * 
+ *      DITContentRuleDescription = LPAREN WSP
+ *          numericoid                ; object identifier
+ *          [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *          [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *          [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *          [ SP &quot;AUX&quot; SP oids ]      ; auxiliary object classes
+ *          [ SP &quot;MUST&quot; SP oids ]     ; attribute types
+ *          [ SP &quot;MAY&quot; SP oids ]      ; attribute types
+ *          [ SP &quot;NOT&quot; SP oids ]      ; attribute types
+ *          extensions WSP RPAREN     ; extensions
+ * 
+ *    where:
+ * 
+ *      [numericoid] is the object identifier of the structural object class
+ *          associated with this DIT content rule;
+ *      NAME [qdescrs] are short names (descriptors) identifying this DIT
+ *          content rule;
+ *      DESC [qdstring] is a short descriptive string;
+ *      OBSOLETE indicates this DIT content rule use is not active;
+ *      AUX specifies a list of auxiliary object classes which entries
+ *          subject to this DIT content rule may belong to;
+ *      MUST, MAY, and NOT specify lists of attribute types which are
+ *          required, allowed, or precluded, respectively, from appearing in
+ *          entries subject to this DIT content rule; and
+ *      [extensions] describe extensions.
+ * </pre>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 5.4.3</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see DescriptionUtils#getDescription(DitContentRule)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DitContentRule extends AbstractSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** The list of Auxiliary ObjectClass OIDs entries may belong to */
+    private List<String> auxObjectClassOids;
+
+    /** The list of Auxiliary ObjectClass entries may belong to */
+    private List<ObjectClass> auxObjectClasses;
+
+    /** The list of allowed AttributeType OIDs */
+    private List<String> mayAttributeTypeOids;
+
+    /** The list of allowed AttributeTypes */
+    private List<AttributeType> mayAttributeTypes;
+
+    /** The list of required AttributeType OIDs */
+    private List<String> mustAttributeTypeOids;
+
+    /** The list of required AttributeTypes */
+    private List<AttributeType> mustAttributeTypes;
+
+    /** The list of precluded AttributeType OIDs */
+    private List<String> notAttributeTypeOids;
+
+    /** The list of precluded AttributeTypes */
+    private List<AttributeType> notAttributeTypes;
+
+
+    /**
+     * Creates a DitContentRule object using a unique OID.
+     * 
+     * @param oid the OID for this DitContentRule
+     */
+    public DitContentRule( String oid )
+    {
+        super( SchemaObjectType.DIT_CONTENT_RULE, oid );
+
+        mayAttributeTypeOids = new ArrayList<String>();
+        mustAttributeTypeOids = new ArrayList<String>();
+        notAttributeTypeOids = new ArrayList<String>();
+        auxObjectClassOids = new ArrayList<String>();
+
+        mayAttributeTypes = new ArrayList<AttributeType>();
+        mustAttributeTypes = new ArrayList<AttributeType>();
+        notAttributeTypes = new ArrayList<AttributeType>();
+        auxObjectClasses = new ArrayList<ObjectClass>();
+    }
+
+
+    /**
+     * @return the auxObjectClassOids
+     */
+    public List<String> getAuxObjectClassOids()
+    {
+        return auxObjectClassOids;
+    }
+
+
+    /**
+     * Add an Auxiliary ObjectClass Oid
+     *
+     * @param oid The ObjectClass oid
+     */
+    public void addAuxObjectClassOidOids( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            auxObjectClassOids.add( oid );
+        }
+    }
+
+
+    /**
+     * Add an Auxiliary ObjectClass
+     *
+     * @param objectClass The ObjectClass
+     */
+    public void addAuxObjectClasses( ObjectClass objectClass )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !auxObjectClassOids.contains( objectClass.getOid() ) )
+        {
+            auxObjectClasses.add( objectClass );
+            auxObjectClassOids.add( objectClass.getOid() );
+        }
+    }
+
+
+    /**
+     * @param auxObjectClassOids the auxObjectClassOids to set
+     */
+    public void setAuxObjectClassOids( List<String> auxObjectClassOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.auxObjectClassOids = auxObjectClassOids;
+        }
+    }
+
+
+    /**
+     * @param auxObjectClasses the auxObjectClasses to set
+     */
+    public void setAuxObjectClasses( List<ObjectClass> auxObjectClasses )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.auxObjectClasses = auxObjectClasses;
+
+            // update the OIDS now
+            auxObjectClassOids.clear();
+
+            for ( ObjectClass oc : auxObjectClasses )
+            {
+                auxObjectClassOids.add( oc.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * @return the auxObjectClasses
+     */
+    public List<ObjectClass> getAuxObjectClasses()
+    {
+        return auxObjectClasses;
+    }
+
+
+    /**
+     * @return the mayAttributeTypeOids
+     */
+    public List<String> getMayAttributeTypeOids()
+    {
+        return mayAttributeTypeOids;
+    }
+
+
+    /**
+     * Add an allowed AttributeType
+     *
+     * @param oid The attributeType oid
+     */
+    public void addMayAttributeTypeOids( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            mayAttributeTypeOids.add( oid );
+        }
+    }
+
+
+    /**
+     * Add an allowed AttributeType
+     *
+     * @param attributeType The attributeType
+     */
+    public void addMayAttributeTypes( AttributeType attributeType )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !mayAttributeTypeOids.contains( attributeType.getOid() ) )
+        {
+            mayAttributeTypes.add( attributeType );
+            mayAttributeTypeOids.add( attributeType.getOid() );
+        }
+    }
+
+
+    /**
+     * @param mayAttributeTypeOids the mayAttributeTypeOids to set
+     */
+    public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mayAttributeTypeOids = mayAttributeTypeOids;
+        }
+    }
+
+
+    /**
+     * Sets the list of allowed AttributeTypes
+     *
+     * @param mayAttributeTypes the list of allowed AttributeTypes
+     */
+    public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mayAttributeTypes = mayAttributeTypes;
+
+            // update the OIDS now
+            mayAttributeTypeOids.clear();
+
+            for ( AttributeType may : mayAttributeTypes )
+            {
+                mayAttributeTypeOids.add( may.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * @return the mayAttributeTypes
+     */
+    public List<AttributeType> getMayAttributeTypes()
+    {
+        return mayAttributeTypes;
+    }
+
+
+    /**
+     * @return the mustAttributeTypeOids
+     */
+    public List<String> getMustAttributeTypeOids()
+    {
+        return mustAttributeTypeOids;
+    }
+
+
+    /**
+     * Add a required AttributeType OID
+     *
+     * @param oid The attributeType OID
+     */
+    public void addMustAttributeTypeOids( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            mustAttributeTypeOids.add( oid );
+        }
+    }
+
+
+    /**
+     * Add a required AttributeType
+     *
+     * @param attributeType The attributeType
+     */
+    public void addMustAttributeTypes( AttributeType attributeType )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !mustAttributeTypeOids.contains( attributeType.getOid() ) )
+        {
+            mustAttributeTypes.add( attributeType );
+            mustAttributeTypeOids.add( attributeType.getOid() );
+        }
+    }
+
+
+    /**
+     * @param mustAttributeTypeOids the mustAttributeTypeOids to set
+     */
+    public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mustAttributeTypeOids = mustAttributeTypeOids;
+        }
+    }
+
+
+    /**
+     * Sets the list of required AttributeTypes
+     *
+     * @param mustAttributeTypes the list of required AttributeTypes
+     */
+    public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mustAttributeTypes = mustAttributeTypes;
+
+            // update the OIDS now
+            mustAttributeTypeOids.clear();
+
+            for ( AttributeType may : mustAttributeTypes )
+            {
+                mustAttributeTypeOids.add( may.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * @return the mustAttributeTypes
+     */
+    public List<AttributeType> getMustAttributeTypes()
+    {
+        return mustAttributeTypes;
+    }
+
+
+    /**
+     * @return the notAttributeTypeOids
+     */
+    public List<String> getNotAttributeTypeOids()
+    {
+        return notAttributeTypeOids;
+    }
+
+
+    /**
+     * Add a precluded AttributeType
+     *
+     * @param oid The attributeType oid
+     */
+    public void addNotAttributeTypeOids( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            notAttributeTypeOids.add( oid );
+        }
+    }
+
+
+    /**
+     * Add a precluded AttributeType
+     *
+     * @param attributeType The attributeType
+     */
+    public void addNotAttributeTypes( AttributeType attributeType )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !notAttributeTypeOids.contains( attributeType.getOid() ) )
+        {
+            notAttributeTypes.add( attributeType );
+            notAttributeTypeOids.add( attributeType.getOid() );
+        }
+    }
+
+
+    /**
+     * @param notAttributeTypeOids the notAttributeTypeOids to set
+     */
+    public void setNotAttributeTypeOids( List<String> notAttributeTypeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.notAttributeTypeOids = notAttributeTypeOids;
+        }
+    }
+
+
+    /**
+     * Sets the list of precluded AttributeTypes
+     *
+     * @param notAttributeTypes the list of precluded AttributeTypes
+     */
+    public void setNotAttributeTypes( List<AttributeType> notAttributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.notAttributeTypes = notAttributeTypes;
+
+            // update the OIDS now
+            notAttributeTypeOids.clear();
+
+            for ( AttributeType not : notAttributeTypes )
+            {
+                notAttributeTypeOids.add( not.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * @return the notAttributeTypes
+     */
+    public List<AttributeType> getNotAttributeTypes()
+    {
+        return notAttributeTypes;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * Copy a DitContentRule
+     */
+    public DitContentRule copy()
+    {
+        DitContentRule copy = new DitContentRule( oid );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // copy the AUX ObjectClasses OIDs
+        copy.auxObjectClassOids = new ArrayList<String>();
+
+        for ( String oid : auxObjectClassOids )
+        {
+            copy.auxObjectClassOids.add( oid );
+        }
+
+        // copy the AUX ObjectClasses ( will be empty )
+        copy.auxObjectClasses = new ArrayList<ObjectClass>();
+
+        // Clone the MAY AttributeTypes OIDs
+        copy.mayAttributeTypeOids = new ArrayList<String>();
+
+        for ( String oid : mayAttributeTypeOids )
+        {
+            copy.mayAttributeTypeOids.add( oid );
+        }
+
+        // Clone the MAY AttributeTypes ( will be empty )
+        copy.mayAttributeTypes = new ArrayList<AttributeType>();
+
+        // Clone the MUST AttributeTypes OIDs
+        copy.mustAttributeTypeOids = new ArrayList<String>();
+
+        for ( String oid : mustAttributeTypeOids )
+        {
+            copy.mustAttributeTypeOids.add( oid );
+        }
+
+        // Clone the MUST AttributeTypes ( will be empty )
+        copy.mustAttributeTypes = new ArrayList<AttributeType>();
+
+        // Clone the NOT AttributeTypes OIDs
+        copy.notAttributeTypeOids = new ArrayList<String>();
+
+        for ( String oid : notAttributeTypeOids )
+        {
+            copy.notAttributeTypeOids.add( oid );
+        }
+
+        // Clone the NOT AttributeTypes ( will be empty )
+        copy.notAttributeTypes = new ArrayList<AttributeType>();
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof DitContentRule ) )
+        {
+            return false;
+        }
+
+        @SuppressWarnings("unused")
+        DitContentRule that = ( DitContentRule ) o;
+
+        // TODO : complete the check
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        auxObjectClasses.clear();
+        auxObjectClassOids.clear();
+        mayAttributeTypes.clear();
+        mayAttributeTypeOids.clear();
+        mustAttributeTypes.clear();
+        mustAttributeTypeOids.clear();
+        notAttributeTypes.clear();
+        notAttributeTypeOids.clear();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DitStructureRule.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DitStructureRule.java
new file mode 100644
index 0000000..042222d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/DitStructureRule.java
@@ -0,0 +1,292 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A dITStructureRule definition. A dITStructureRules is a rule governing the
+ * structure of the DIT by specifying a permitted superior to subordinate entry
+ * relationship. A structure rule relates a nameForm, and therefore a STRUCTURAL
+ * objectClass, to superior dITStructureRules. This permits entries of the
+ * STRUCTURAL objectClass identified by the nameForm to exist in the DIT as
+ * subordinates to entries governed by the indicated superior dITStructureRules.
+ * Hence dITStructureRules only apply to structural object classes.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ * 
+ * <pre>
+ *  DIT structure rule descriptions are written according to the ABNF:
+ *  
+ *    DITStructureRuleDescription = LPAREN WSP
+ *        ruleid                    ; rule identifier
+ *        [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *        [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *        [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *        SP &quot;FORM&quot; SP oid          ; NameForm
+ *        [ SP &quot;SUP&quot; ruleids ]      ; superior rules
+ *        extensions WSP RPAREN     ; extensions
+ * 
+ *    ruleids = ruleid / ( LPAREN WSP ruleidlist WSP RPAREN )
+ * 
+ *    ruleidlist = ruleid *( SP ruleid )
+ * 
+ *    ruleid = number
+ * 
+ *  where:
+ *    [ruleid] is the rule identifier of this DIT structure rule;
+ *    NAME [qdescrs] are short names (descriptors) identifying this DIT
+ *        structure rule;
+ *    DESC [qdstring] is a short descriptive string;
+ *    OBSOLETE indicates this DIT structure rule use is not active;
+ *    FORM is specifies the name form associated with this DIT structure
+ *        rule;
+ *    SUP identifies superior rules (by rule id); and
+ *    [extensions] describe extensions.
+ *  
+ *  If no superior rules are identified, the DIT structure rule applies
+ *  to an autonomous administrative point (e.g. the root vertex of the
+ *  subtree controlled by the subschema) [X.501].
+ * </pre>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC2252 Section 6.33</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see DescriptionUtils#getDescription(DitStructureRule)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DitStructureRule extends AbstractSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** The rule ID. A DSR does not have an OID */
+    private int ruleId;
+
+    /** The associated NameForm */
+    private String form;
+
+    /** The list of superiors rules */
+    private List<Integer> superRules;
+
+
+    /**
+     * Creates a new instance of DitStructureRule
+     */
+    public DitStructureRule( int ruleId )
+    {
+        super( SchemaObjectType.DIT_STRUCTURE_RULE, null );
+        this.ruleId = ruleId;
+        form = null;
+        superRules = new ArrayList<Integer>();
+    }
+
+
+    /**
+     *  @return The associated NameForm's OID
+     */
+    public String getForm()
+    {
+        return form;
+    }
+
+
+    /**
+     * Sets the associated NameForm's OID
+     *
+     * @param form The NameForm's OID
+     */
+    public void setForm( String form )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.form = form;
+        }
+    }
+
+
+    /**
+     * @return The Rule ID
+     */
+    public int getRuleId()
+    {
+        return ruleId;
+    }
+
+
+    /**
+     * Sets the rule identifier of this DIT structure rule;
+     *
+     * @param ruleId the rule identifier of this DIT structure rule;
+     */
+    public void setRuleId( int ruleId )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.ruleId = ruleId;
+        }
+    }
+
+
+    /**
+     * @return The list of superiors RuleIDs
+     */
+    public List<Integer> getSuperRules()
+    {
+        return superRules;
+    }
+
+
+    /**
+     * Sets the list of superior RuleIds
+     * 
+     * @param superRules the list of superior RuleIds
+     */
+    public void setSuperRules( List<Integer> superRules )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.superRules = superRules;
+        }
+    }
+
+
+    /**
+     * Adds a new superior RuleId
+     *
+     * @param superRule The superior RuleID to add
+     */
+    public void addSuperRule( Integer superRule )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        superRules.add( superRule );
+    }
+
+
+    /**
+     * The DIT structure rule does not have an OID
+     * 
+     * {@inheritDoc}
+     */
+    @Override
+    public String getOid()
+    {
+        // We cannot throw exception here. E.g. SchemaObjectWrapper will try to use this in hashcode.
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRule copy()
+    {
+        DitStructureRule copy = new DitStructureRule( ruleId );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // Copy the Superiors rules
+        copy.superRules = new ArrayList<Integer>();
+
+        // Copy the form
+        copy.form = form;
+
+        for ( int superRule : superRules )
+        {
+            copy.superRules.add( superRule );
+        }
+
+        return copy;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof DitStructureRule ) )
+        {
+            return false;
+        }
+
+        @SuppressWarnings("unused")
+        DitStructureRule that = ( DitStructureRule ) o;
+
+        // TODO : complete the test
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        superRules.clear();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LdapComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LdapComparator.java
new file mode 100644
index 0000000..58a389d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LdapComparator.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+
+/**
+ * An class used for Comparator. It inherits from the general AbstractAdsSchemaObject class. It
+ * also implements the Comparator interface
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class LdapComparator<T> extends LoadableSchemaObject implements Comparator<T>, Serializable
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+
+    /**
+     * Create a new instance of a Comparator
+     * @param oid The associated OID
+     */
+    protected LdapComparator( String oid )
+    {
+        super( SchemaObjectType.COMPARATOR, oid );
+    }
+
+
+    /**
+     * Store the SchemaManager in this instance. It may be necessary for some
+     * comparator which needs to have access to the oidNormalizer Map.
+     *
+     * @param schemaManager the schemaManager to store
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        // Do nothing (general case).
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        return o instanceof LdapComparator<?>;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return objectType + " " + DescriptionUtils.getDescription( this );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LdapSyntax.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LdapSyntax.java
new file mode 100644
index 0000000..bc355f1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LdapSyntax.java
@@ -0,0 +1,319 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+
+
+/**
+ * A syntax definition. Each attribute stored in a directory has a defined
+ * syntax (i.e. data type) which constrains the structure and format of its
+ * values. The description of each syntax specifies how attribute or assertion
+ * values conforming to the syntax are normally represented when transferred in
+ * LDAP operations. This representation is referred to as the LDAP-specific
+ * encoding to distinguish it from other methods of encoding attribute values.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ * 
+ * <pre>
+ *  4.1.5. LDAP Syntaxes
+ * 
+ *    LDAP Syntaxes of (attribute and assertion) values are described in
+ *    terms of ASN.1 [X.680] and, optionally, have an octet string encoding
+ *    known as the LDAP-specific encoding.  Commonly, the LDAP-specific
+ *    encoding is constrained to string of Universal Character Set (UCS)
+ *    [ISO10646] characters in UTF-8 [UTF-8] form.
+ * 
+ *    Each LDAP syntax is identified by an object identifier (OID).
+ * 
+ *    LDAP syntax definitions are written according to the ABNF:
+ * 
+ *      SyntaxDescription = LPAREN WSP
+ *          numericoid                ; object identifier
+ *          [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *          extensions WSP RPAREN     ; extensions
+ * 
+ *    where:
+ *      [numericoid] is object identifier assigned to this LDAP syntax;
+ *      DESC [qdstring] is a short descriptive string; and
+ *      [extensions] describe extensions.
+ * </pre>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html"> RFC2252 Section 4.3.3</a>
+ * @see <a href=
+ *      "http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-09.txt">
+ *      ldapbis [MODELS]</a>
+ * @see DescriptionUtils#getDescription(Syntax)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapSyntax extends AbstractSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** the human readable flag */
+    protected boolean isHumanReadable = false;
+
+    /** A flag set to true if the Syntax has a X-NOT-HUMAN-READABLE extension */
+    private boolean hasHumanReadableFlag = false;
+
+    /** The associated SyntaxChecker */
+    protected SyntaxChecker syntaxChecker;
+
+
+    /**
+     * Creates a Syntax object using a unique OID.
+     * 
+     * @param oid the OID for this Syntax
+     */
+    public LdapSyntax( String oid )
+    {
+        super( SchemaObjectType.LDAP_SYNTAX, oid );
+    }
+
+
+    /**
+     * Creates a Syntax object using a unique OID.
+     *
+     * @param oid the OID for this syntax
+     * @param description the description for this syntax
+     */
+    public LdapSyntax( String oid, String description )
+    {
+        super( SchemaObjectType.LDAP_SYNTAX, oid );
+        this.description = description;
+        this.hasHumanReadableFlag = false;
+    }
+
+
+    /**
+     * Creates a Syntax object using a unique OID.
+     *
+     * @param oid the OID for this syntax
+     * @param description the description for this syntax
+     * @param isHumanReadable true if this syntax is human readable
+     */
+    public LdapSyntax( String oid, String description, boolean isHumanReadable )
+    {
+        super( SchemaObjectType.LDAP_SYNTAX, oid );
+        this.description = description;
+        this.isHumanReadable = isHumanReadable;
+        this.hasHumanReadableFlag = true;
+    }
+
+
+    /**
+     * Gets whether or not the Syntax is human readable.
+     * 
+     * @return true if the syntax can be interpreted by humans, false otherwise
+     */
+    public boolean isHumanReadable()
+    {
+        if ( hasHumanReadableFlag )
+        {
+            return isHumanReadable;
+        }
+        else
+        {
+            List<String> values = getExtension( MetaSchemaConstants.X_NOT_HUMAN_READABLE_AT );
+
+            if ( ( values == null ) || ( values.size() == 0 ) )
+            {
+                // Default to String if the flag is not set
+                return true;
+            }
+            else
+            {
+                String value = values.get( 0 );
+                hasHumanReadableFlag = true;
+
+                if ( value.equalsIgnoreCase( "FALSE" ) )
+                {
+                    isHumanReadable = true;
+                    return true;
+                }
+                else
+                {
+                    isHumanReadable = false;
+                    return false;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Sets the human readable flag value.
+     * 
+     * @param humanReadable the human readable flag value to set
+     */
+    public void setHumanReadable( boolean humanReadable )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.isHumanReadable = humanReadable;
+            this.hasHumanReadableFlag = true;
+        }
+    }
+
+
+    /**
+     * Gets the SyntaxChecker used to validate values in accordance with this
+     * Syntax.
+     * 
+     * @return the SyntaxChecker
+     */
+    public SyntaxChecker getSyntaxChecker()
+    {
+        return syntaxChecker;
+    }
+
+
+    /**
+     * Sets the associated SyntaxChecker
+     *
+     * @param syntaxChecker The associated SyntaxChecker
+     */
+    public void setSyntaxChecker( SyntaxChecker syntaxChecker )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.syntaxChecker = syntaxChecker;
+        }
+    }
+
+
+    /**
+     * Update the associated SyntaxChecker, even if the SchemaObject is readOnly
+     *
+     * @param newSyntaxChecker The associated SyntaxChecker
+     */
+    public void updateSyntaxChecker( SyntaxChecker newSyntaxChecker )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.syntaxChecker = newSyntaxChecker;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapSyntax copy()
+    {
+        LdapSyntax copy = new LdapSyntax( oid );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // Copy the HR flag
+        copy.isHumanReadable = isHumanReadable;
+
+        // Copy the HR presence flag
+        copy.hasHumanReadableFlag = hasHumanReadableFlag;
+
+        // All the references to other Registries object are set to null.
+        copy.syntaxChecker = null;
+
+        return copy;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof LdapSyntax ) )
+        {
+            return false;
+        }
+
+        LdapSyntax that = ( LdapSyntax ) o;
+
+        // IsHR
+        if ( isHumanReadable != that.isHumanReadable )
+        {
+            return false;
+        }
+
+        // Check the SyntaxChecker (not a equals)
+        if ( syntaxChecker != null )
+        {
+            if ( that.syntaxChecker == null )
+            {
+                return false;
+            }
+
+            return syntaxChecker.getOid().equals( that.syntaxChecker.getOid() );
+        }
+        else
+        {
+            return that.syntaxChecker == null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        syntaxChecker = null;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LoadableSchemaObject.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LoadableSchemaObject.java
new file mode 100644
index 0000000..c60e5ea
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/LoadableSchemaObject.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * An abstract class used to manage the ADS specific SchemaObject, which can
+ * contain some compiled Java class to implement the specific logic.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class LoadableSchemaObject extends AbstractSchemaObject
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** The Full Qualified Class Name */
+    private String fqcn;
+
+    /** The base64 encoded bytecode for this schema */
+    private String bytecode;
+
+
+    /**
+     * Constructor to use when the OID is known in advance.
+     * 
+     * @param objectType The SchemaObject type
+     * @param oid The SchemaObject OID
+     */
+    protected LoadableSchemaObject( SchemaObjectType objectType, String oid )
+    {
+        super( objectType, oid );
+
+        fqcn = "";
+        bytecode = null;
+    }
+
+
+    /**
+     * Constructor to use when the OID is not known until after instantiation.
+     * 
+     * @param objectType The SchemaObject type
+     */
+    protected LoadableSchemaObject( SchemaObjectType objectType )
+    {
+        super( objectType );
+
+        fqcn = "";
+        bytecode = null;
+    }
+
+
+    /**
+     * @return The associated bytecode of this SchemaObject instance
+     */
+    public String getBytecode()
+    {
+        return bytecode;
+    }
+
+
+    /**
+     * Stores some bytecode representing the compiled Java class for this
+     * SchemaObject instance.
+     * 
+     * @param bytecode The bytecode to store
+     */
+    public void setBytecode( String bytecode )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.bytecode = bytecode;
+        }
+    }
+
+
+    /**
+     * @return The chemaObject instance Fully Qualified Class Name
+     */
+    public String getFqcn()
+    {
+        return fqcn;
+    }
+
+
+    /**
+     * Set the Fully Qualified Class Name for this SchemaObject instance
+     * class stored in the bytecode attribute
+     * @param fqcn The Fully Qualified Class Name
+     */
+    public void setFqcn( String fqcn )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.fqcn = fqcn;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LoadableSchemaObject copy()
+    {
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof LoadableSchemaObject ) )
+        {
+            return false;
+        }
+
+        LoadableSchemaObject that = ( LoadableSchemaObject ) o;
+
+        // Check the byteCode
+        // TODO
+
+        // Check the FQCN
+        if ( fqcn == null )
+        {
+            return that.fqcn == null;
+        }
+        else
+        {
+            return fqcn.equals( that.fqcn );
+        }
+    }
+
+
+    /**
+     * Test that the FQCN is equal to the instance's name. If the FQCN is
+     * empty, fill it with the instance's name
+     *
+     * @return true if the FQCN is correctly set
+     */
+    public boolean isValid()
+    {
+        String className = this.getClass().getName();
+
+        if ( Strings.isEmpty( fqcn ) )
+        {
+            fqcn = className;
+            return true;
+        }
+        else
+        {
+            return className.equals( fqcn );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRule.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRule.java
new file mode 100644
index 0000000..79c30e3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRule.java
@@ -0,0 +1,255 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+
+
+/**
+ * A matchingRule definition. MatchingRules associate a comparator and a
+ * normalizer, forming the basic tools necessary to assert actions against
+ * attribute values. MatchingRules are associated with a specific Syntax for the
+ * purpose of resolving a normalized form and for comparisons.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ * 
+ * <pre>
+ *  4.1.3. Matching Rules
+ * 
+ *    Matching rules are used by servers to compare attribute values against
+ *    assertion values when performing Search and Compare operations.  They
+ *    are also used to identify the value to be added or deleted when
+ *    modifying entries, and are used when comparing a purported
+ *    distinguished name with the name of an entry.
+ * 
+ *    A matching rule specifies the syntax of the assertion value.
+ * 
+ *    Each matching rule is identified by an object identifier (OID) and,
+ *    optionally, one or more short names (descriptors).
+ * 
+ *    Matching rule definitions are written according to the ABNF:
+ * 
+ *      MatchingRuleDescription = LPAREN WSP
+ *          numericoid                ; object identifier
+ *          [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *          [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *          [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *          SP &quot;SYNTAX&quot; SP numericoid ; assertion syntax
+ *          extensions WSP RPAREN     ; extensions
+ * 
+ *    where:
+ *      [numericoid] is object identifier assigned to this matching rule;
+ *      NAME [qdescrs] are short names (descriptors) identifying this
+ *          matching rule;
+ *      DESC [qdstring] is a short descriptive string;
+ *      OBSOLETE indicates this matching rule is not active;
+ *      SYNTAX identifies the assertion syntax by object identifier; and
+ *      [extensions] describe extensions.
+ * </pre>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.5</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see DescriptionUtils#getDescription(MatchingRule)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MatchingRule extends AbstractSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** The associated Comparator */
+    protected LdapComparator<? super Object> ldapComparator;
+
+    /** The associated Normalizer */
+    protected Normalizer normalizer;
+
+    /** The associated LdapSyntax */
+    protected LdapSyntax ldapSyntax;
+
+    /** The associated LdapSyntax OID */
+    protected String ldapSyntaxOid;
+
+
+    /**
+     * Creates a new instance of MatchingRule.
+     *
+     * @param oid The MatchingRule OID
+     */
+    public MatchingRule( String oid )
+    {
+        super( SchemaObjectType.MATCHING_RULE, oid );
+    }
+
+
+    /**
+     * Gets the LdapSyntax used by this MatchingRule.
+     * 
+     * @return the LdapSyntax of this MatchingRule
+     */
+    public LdapSyntax getSyntax()
+    {
+        return ldapSyntax;
+    }
+
+
+    /**
+     * Gets the LdapSyntax OID used by this MatchingRule.
+     * 
+     * @return the LdapSyntax of this MatchingRule
+     */
+    public String getSyntaxOid()
+    {
+        return ldapSyntaxOid;
+    }
+
+
+    /**
+     * Gets the LdapComparator enabling the use of this MatchingRule for ORDERING
+     * and sorted indexing.
+     * 
+     * @return the ordering LdapComparator
+     */
+    public LdapComparator<? super Object> getLdapComparator()
+    {
+        return ldapComparator;
+    }
+
+
+    /**
+     * Gets the Normalizer enabling the use of this MatchingRule for EQUALITY
+     * matching and indexing.
+     * 
+     * @return the associated normalizer
+     */
+    public Normalizer getNormalizer()
+    {
+        return normalizer;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * Copy an MatchingRule
+     */
+    public MatchingRule copy()
+    {
+        MatchingRule copy = new MutableMatchingRule( oid );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // All the references to other Registries object are set to null.
+        copy.ldapComparator = null;
+        copy.ldapSyntax = null;
+        copy.normalizer = null;
+
+        // Copy the syntax OID
+        copy.ldapSyntaxOid = ldapSyntaxOid;
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#equals()
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof MatchingRule ) )
+        {
+            return false;
+        }
+
+        MatchingRule that = ( MatchingRule ) o;
+
+        // Check the Comparator
+        if ( ldapComparator != null )
+        {
+            if ( !ldapComparator.equals( that.ldapComparator ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( that.ldapComparator != null )
+            {
+                return false;
+            }
+        }
+
+        // Check the Normalizer
+        if ( normalizer != null )
+        {
+            if ( !normalizer.equals( that.normalizer ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( that.normalizer != null )
+            {
+                return false;
+            }
+        }
+
+        // Check the Syntax OID
+        if ( !compareOid( ldapSyntaxOid, that.ldapSyntaxOid ) )
+        {
+            return false;
+        }
+
+        // Check the Syntax
+        if ( ldapSyntax != null )
+        {
+            if ( !ldapSyntax.equals( that.ldapSyntax ) )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( that.ldapSyntax != null )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRuleEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRuleEnum.java
new file mode 100644
index 0000000..e80feff
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRuleEnum.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+/**
+ * Type safe enum for a matching rule's comparator and normalizer component
+ * usage string. This can be take one of the following three values:
+ * <ul>
+ * <li>ORDERING</li>
+ * <li>EQUALITY</li>
+ * <li>SUBSTRING</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum MatchingRuleEnum
+{
+    /** value for ordering usage */
+    ORDERING(0),
+
+    /** value for equality usage */
+    EQUALITY(1),
+
+    /** value for substring usage */
+    SUBSTRING(2);
+
+    /** Stores the integer value of each element of the enumeration */
+    private int value;
+
+
+    /**
+     * Private constructor so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param value
+     *            the integer value of the enumeration.
+     */
+    private MatchingRuleEnum( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Gets the enumeration type for the usage string regardless of case.
+     * 
+     * @param matchingRule the usage string
+     * @return the matchingRule enumeration type
+     */
+    public static MatchingRuleEnum getUsage( String matchingRule )
+    {
+        return valueOf( matchingRule );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRuleUse.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRuleUse.java
new file mode 100644
index 0000000..2ebc852
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MatchingRuleUse.java
@@ -0,0 +1,282 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Represents an LDAP MatchingRuleUseDescription defined in RFC 2252.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ * 
+ * <pre>
+ *  Values of the matchingRuleUse list the attributes which are suitable
+ *  for use with an extensible matching rule.
+ * 
+ *    Matching rule use descriptions are written according to the following
+ *    ABNF:
+ * 
+ *      MatchingRuleUseDescription = LPAREN WSP
+ *          numericoid                ; object identifier
+ *          [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *          [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *          [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *          SP &quot;APPLIES&quot; SP oids      ; attribute types
+ *          extensions WSP RPAREN     ; extensions
+ * 
+ *    where:
+ *      [numericoid] is the object identifier of the matching rule
+ *          associated with this matching rule use description;
+ *      NAME [qdescrs] are short names (descriptors) identifying this
+ *          matching rule use;
+ *      DESC [qdstring] is a short descriptive string;
+ *      OBSOLETE indicates this matching rule use is not active;
+ *      APPLIES provides a list of attribute types the matching rule applies
+ *          to; and
+ *      [extensions] describe extensions.
+ * 
+ *  The matchingRule within the MatchingRuleUse definition can be used by an
+ *  extensible match assertion if the assertion is based on the attributes
+ *  listed within the MatchingRuleUse definition.  If an extensible match
+ *  assertion is based on attributes other than those listed within the
+ *  MatchingRuleUse definition then the assertion is deemed undefined.
+ * 
+ *  Also according to 3.3.20 of [SYNTAXES] (ldapbis working group):
+ * 
+ *  A value of the Matching Rule Use Description syntax indicates the
+ *  attribute types to which a matching rule may be applied in an
+ *  extensibleMatch search filter [PROT].  The LDAP-specific encoding of
+ *  a value of this syntax is defined by the &lt;MatchingRuleUseDescription&gt;
+ *  rule in [MODELS] above.
+ * </pre>
+ * 
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-syntaxes-09.txt">ldapbis
+ *      [SYNTAXES]</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MatchingRuleUse extends AbstractSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** The list of attributes types OID the matching rule applies to */
+    private List<String> applicableAttributeOids;
+
+    /** The list of attributes types the matching rule applies to */
+    private List<AttributeType> applicableAttributes;
+
+
+    /**
+     * Creates a new instance of MatchingRuleUseDescription
+     */
+    public MatchingRuleUse( String oid )
+    {
+        super( SchemaObjectType.MATCHING_RULE_USE, oid );
+
+        applicableAttributeOids = new ArrayList<String>();
+        applicableAttributes = new ArrayList<AttributeType>();
+    }
+
+
+    /**
+     * @return The matchingRule's list of AttributeType OIDs the MRU applies to
+     */
+    public List<String> getApplicableAttributeOids()
+    {
+        return applicableAttributeOids;
+    }
+
+
+    /**
+     * @return The matchingRule's list of AttributeType OIDs the MRU applies to
+     */
+    public List<AttributeType> getApplicableAttributes()
+    {
+        return applicableAttributes;
+    }
+
+
+    /**
+     * Set the matchingRule's AttributeType OIDs the MRU applies to.
+     *
+     * @param applicableAttributeOids The AttributeType OIDs list
+     */
+    public void setApplicableAttributeOids( List<String> applicableAttributeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.applicableAttributeOids = applicableAttributeOids;
+        }
+    }
+
+
+    /**
+     * Set the matchingRule's AttributeType the MRU applies to.
+     *
+     * @param applicableAttributes The AttributeType list
+     */
+    public void setApplicableAttributes( List<AttributeType> applicableAttributes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.applicableAttributes = applicableAttributes;
+
+            // update the OIDS now
+            applicableAttributeOids.clear();
+
+            for ( AttributeType at : applicableAttributes )
+            {
+                applicableAttributeOids.add( at.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * Add a matchingRule's AttributeType OIDs the MRU applies to.
+     *
+     * @param oid A matchingRule's AttributeType OIDs the MRU applies to
+     */
+    public void addApplicableAttributeOids( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !applicableAttributeOids.contains( oid ) )
+        {
+            applicableAttributeOids.add( oid );
+        }
+    }
+
+
+    /**
+     * Add a matchingRule's AttributeType the MRU applies to.
+     *
+     * @param attributeType A matchingRule's AttributeType the MRU applies to
+     */
+    public void addApplicableAttribute( AttributeType attributeType )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !applicableAttributeOids.contains( attributeType.getOid() ) )
+        {
+            applicableAttributes.add( attributeType );
+            applicableAttributeOids.add( attributeType.getOid() );
+        }
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * Copy an MatchingRuleUse
+     */
+    public MatchingRuleUse copy()
+    {
+        MatchingRuleUse copy = new MatchingRuleUse( oid );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // Clone the APPLY AttributeTypes
+        copy.applicableAttributeOids = new ArrayList<String>();
+
+        // Copy the APPLIES oid list
+        for ( String oid : applicableAttributeOids )
+        {
+            copy.applicableAttributeOids.add( oid );
+        }
+
+        // Copy the APPLIES list (will be empty)
+        copy.applicableAttributes = new ArrayList<AttributeType>();
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof MatchingRuleUse ) )
+        {
+            return false;
+        }
+
+        @SuppressWarnings("unused")
+        MatchingRuleUse that = ( MatchingRuleUse ) o;
+
+        // TODO : complete the checks
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        applicableAttributes.clear();
+        applicableAttributeOids.clear();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableAttributeType.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableAttributeType.java
new file mode 100644
index 0000000..a06a482
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableAttributeType.java
@@ -0,0 +1,604 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * An attributeType specification. attributeType specifications describe the
+ * nature of attributes within the directory. The attributeType specification's
+ * properties are accessible through this interface.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ *
+ * <pre>
+ *  4.1.2. Attribute Types
+ *
+ *    Attribute Type definitions are written according to the ABNF:
+ *
+ *      AttributeTypeDescription = LPAREN WSP
+ *          numericoid                   ; object identifier
+ *          [ SP &quot;NAME&quot; SP qdescrs ]     ; short names (descriptors)
+ *          [ SP &quot;DESC&quot; SP qdstring ]    ; description
+ *          [ SP &quot;OBSOLETE&quot; ]            ; not active
+ *          [ SP &quot;SUP&quot; SP oid ]          ; supertype
+ *          [ SP &quot;EQUALITY&quot; SP oid ]     ; equality matching rule
+ *          [ SP &quot;ORDERING&quot; SP oid ]     ; ordering matching rule
+ *          [ SP &quot;SUBSTR&quot; SP oid ]       ; substrings matching rule
+ *          [ SP &quot;SYNTAX&quot; SP noidlen ]   ; value syntax
+ *          [ SP &quot;SINGLE-VALUE&quot; ]        ; single-value
+ *          [ SP &quot;COLLECTIVE&quot; ]          ; collective
+ *          [ SP &quot;NO-USER-MODIFICATION&quot; ]; not user modifiable
+ *          [ SP &quot;USAGE&quot; SP usage ]      ; usage
+ *          extensions WSP RPAREN        ; extensions
+ *
+ *      usage = &quot;userApplications&quot;     / ; user
+ *              &quot;directoryOperation&quot;   / ; directory operational
+ *              &quot;distributedOperation&quot; / ; DSA-shared operational
+ *              &quot;dSAOperation&quot;           ; DSA-specific operational
+ *
+ *    where:
+ *      [numericoid] is object identifier assigned to this attribute type;
+ *      NAME [qdescrs] are short names (descriptors) identifying this
+ *          attribute type;
+ *      DESC [qdstring] is a short descriptive string;
+ *      OBSOLETE indicates this attribute type is not active;
+ *      SUP oid specifies the direct supertype of this type;
+ *      EQUALITY, ORDERING, SUBSTRING provide the oid of the equality,
+ *          ordering, and substrings matching rules, respectively;
+ *      SYNTAX identifies value syntax by object identifier and may suggest
+ *          a minimum upper bound;
+ *      COLLECTIVE indicates this attribute type is collective [X.501];
+ *      NO-USER-MODIFICATION indicates this attribute type is not user
+ *          modifiable;
+ *      USAGE indicates the application of this attribute type; and
+ *      [extensions] describe extensions.
+ *
+ *    Each attribute type description must contain at least one of the SUP
+ *    or SYNTAX fields.
+ *
+ *    Usage of userApplications, the default, indicates that attributes of
+ *    this type represent user information.  That is, they are user
+ *    attributes.
+ *
+ *    COLLECTIVE requires usage userApplications.  Use of collective
+ *    attribute types in LDAP is not discussed in this technical
+ *    specification.
+ *
+ *    A usage of directoryOperation, distributedOperation, or dSAOperation
+ *    indicates that attributes of this type represent operational and/or
+ *    administrative information.  That is, they are operational attributes.
+ *
+ *    directoryOperation usage indicates that the attribute of this type is
+ *    a directory operational attribute.  distributedOperation usage
+ *    indicates that the attribute of this DSA-shared usage operational
+ *    attribute.  dSAOperation usage indicates that the attribute of this
+ *    type is a DSA-specific operational attribute.
+ *
+ *    NO-USER-MODIFICATION requires an operational usage.
+ *
+ *    Note that the [AttributeTypeDescription] does not list the matching
+ *    rules which can be used with that attribute type in an extensibleMatch
+ *    search filter.  This is done using the 'matchingRuleUse' attribute
+ *    described in Section 4.1.4.
+ *
+ *    This document refines the schema description of X.501 by requiring
+ *    that the SYNTAX field in an [AttributeTypeDescription] be a string
+ *    representation of an object identifier for the LDAP string syntax
+ *    definition with an optional indication of the suggested minimum bound
+ *    of a value of this attribute.
+ *
+ *    A suggested minimum upper bound on the number of characters in a value
+ *    with a string-based syntax, or the number of bytes in a value for all
+ *    other syntaxes, may be indicated by appending this bound count inside
+ *    of curly braces following the syntax's OBJECT IDENTIFIER in an
+ *
+ *    Attribute Type Description.  This bound is not part of the syntax name
+ *    itself.  For instance, &quot;1.3.6.4.1.1466.0{64}&quot; suggests that server
+ *    implementations should allow a string to be 64 characters long,
+ *    although they may allow longer strings.  Note that a single character
+ *    of the Directory String syntax may be encoded in more than one octet
+ *    since UTF-8 is a variable-length encoding.
+ * </pre>
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.2</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">
+ *      ldapbis [MODELS]</a>
+ * @see DescriptionUtils#getDescription(MutableAttributeType)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MutableAttributeType extends AttributeType
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a AttributeType object using a unique OID.
+     *
+     * @param oid the OID for this AttributeType
+     */
+    public MutableAttributeType( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Tells if this AttributeType is Single Valued or not
+     *
+     * @param singleValued True if the AttributeType is single-valued
+     */
+    public void setSingleValued( boolean singleValued )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.isSingleValued = singleValued;
+        }
+    }
+
+
+    /**
+     * Tells if this AttributeType can be modified by a user or not
+     *
+     * @param userModifiable The flag to set
+     */
+    public void setUserModifiable( boolean userModifiable )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.canUserModify = userModifiable;
+        }
+    }
+
+
+    /**
+     * Updates the collective flag
+     *
+     * @param collective The new value to set
+     */
+    public void updateCollective( boolean collective )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.isCollective = collective;
+    }
+
+
+    /**
+     * Sets the collective flag
+     *
+     * @param collective The new value to set
+     */
+    public void setCollective( boolean collective )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.isCollective = collective;
+        }
+    }
+
+
+    /**
+     * Sets the AttributeType usage, one of :
+     * <ul>
+     *   <li>USER_APPLICATIONS</li>
+     *   <li>DIRECTORY_OPERATION</li>
+     *   <li>DISTRIBUTED_OPERATION</li>
+     *   <li>DSA_OPERATION</li>
+     * </ul>
+     * 
+     * @see UsageEnum
+     * @param usage The AttributeType usage
+     */
+    public void setUsage( UsageEnum usage )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.usage = usage;
+        }
+    }
+
+
+    /**
+     * Updates the AttributeType usage, one of :
+     * <ul>
+     *   <li>USER_APPLICATIONS</li>
+     *   <li>DIRECTORY_OPERATION</li>
+     *   <li>DISTRIBUTED_OPERATION</li>
+     *   <li>DSA_OPERATION</li>
+     * </ul>
+     * 
+     * @see UsageEnum
+     * @param newUsage The AttributeType usage
+     */
+    public void updateUsage( UsageEnum newUsage )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.usage = newUsage;
+    }
+
+
+    /**
+     * Sets the length limit of this AttributeType based on its associated
+     * syntax.
+     *
+     * @param length the new length to set
+     */
+    public void setSyntaxLength( long length )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.syntaxLength = length;
+        }
+    }
+
+
+    /**
+     * Sets the superior AttributeType OID of this AttributeType
+     *
+     * @param superiorOid The superior AttributeType OID of this AttributeType
+     */
+    public void setSuperiorOid( String superiorOid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.superiorOid = superiorOid;
+        }
+    }
+
+
+    /**
+     * Sets the superior for this AttributeType
+     *
+     * @param superior The superior for this AttributeType
+     */
+    public void setSuperior( MutableAttributeType superior )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.superior = superior;
+            this.superiorOid = superior.getOid();
+        }
+    }
+
+
+    /**
+     * Sets the superior oid for this AttributeType
+     *
+     * @param newSuperiorOid The superior oid for this AttributeType
+     */
+    public void setSuperior( String newSuperiorOid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.superiorOid = newSuperiorOid;
+        }
+    }
+
+
+    /**
+     * Update the associated Superior AttributeType, even if the SchemaObject is readOnly
+     *
+     * @param newSuperior The superior for this AttributeType
+     */
+    public void updateSuperior( MutableAttributeType newSuperior )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.superior = newSuperior;
+        this.superiorOid = newSuperior.getOid();
+    }
+
+
+    /**
+     * Sets the Syntax OID for this AttributeType
+     *
+     * @param syntaxOid The syntax OID for this AttributeType
+     */
+    public void setSyntaxOid( String syntaxOid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.syntaxOid = syntaxOid;
+        }
+    }
+
+
+    /**
+     * Sets the Syntax for this AttributeType
+     *
+     * @param syntax The Syntax for this AttributeType
+     */
+    public void setSyntax( LdapSyntax syntax )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.syntax = syntax;
+            this.syntaxOid = syntax.getOid();
+        }
+    }
+
+
+    /**
+     * Update the associated Syntax, even if the SchemaObject is readOnly
+     *
+     * @param newSyntax The Syntax for this AttributeType
+     */
+    public void updateSyntax( LdapSyntax newSyntax )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.syntax = newSyntax;
+        this.syntaxOid = newSyntax.getOid();
+    }
+
+
+    /**
+     * Sets the Equality OID for this AttributeType
+     *
+     * @param equalityOid The Equality OID for this AttributeType
+     */
+    public void setEqualityOid( String equalityOid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.equalityOid = equalityOid;
+        }
+    }
+
+
+    /**
+     * Sets the Equality MR for this AttributeType
+     *
+     * @param equality The Equality MR for this AttributeType
+     */
+    public void setEquality( MatchingRule equality )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.equality = equality;
+            this.equalityOid = equality.getOid();
+        }
+    }
+
+
+    /**
+     * Update the associated Equality MatchingRule, even if the SchemaObject is readOnly
+     *
+     * @param newEquality The Equality MR for this AttributeType
+     */
+    public void updateEquality( MatchingRule newEquality )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.equality = newEquality;
+        this.equalityOid = newEquality.getOid();
+    }
+
+
+    /**
+     * Sets the Ordering OID for this AttributeType
+     *
+     * @param orderingOid The Ordering OID for this AttributeType
+     */
+    public void setOrderingOid( String orderingOid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.orderingOid = orderingOid;
+        }
+    }
+
+
+    /**
+     * Sets the Ordering MR for this AttributeType
+     *
+     * @param ordering The Ordering MR for this AttributeType
+     */
+    public void setOrdering( MatchingRule ordering )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.ordering = ordering;
+            this.orderingOid = ordering.getOid();
+        }
+    }
+
+
+    /**
+     * Update the associated Ordering MatchingRule, even if the SchemaObject is readOnly
+     *
+     * @param newOrdering The Ordering MR for this AttributeType
+     */
+    public void updateOrdering( MatchingRule newOrdering )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.ordering = newOrdering;
+        this.orderingOid = newOrdering.getOid();
+    }
+
+
+    /**
+     * Sets the Substr OID for this AttributeType
+     *
+     * @param substrOid The Substr OID for this AttributeType
+     */
+    public void setSubstringOid( String substrOid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.substringOid = substrOid;
+        }
+    }
+
+
+    /**
+     * Sets the Substr MR for this AttributeType
+     *
+     * @param substring The Substr MR for this AttributeType
+     */
+    public void setSubstring( MatchingRule substring )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.substring = substring;
+            this.substringOid = substring.getOid();
+        }
+    }
+
+
+    /**
+     * Update the associated Substring MatchingRule, even if the SchemaObject is readOnly
+     *
+     * @param newSubstring The Substr MR for this AttributeType
+     */
+    public void updateSubstring( MatchingRule newSubstring )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.substring = newSubstring;
+        this.substringOid = newSubstring.getOid();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        equality = null;
+        ordering = null;
+        substring = null;
+        superior = null;
+        syntax = null;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableMatchingRule.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableMatchingRule.java
new file mode 100644
index 0000000..d00be76
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableMatchingRule.java
@@ -0,0 +1,234 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A matchingRule definition. MatchingRules associate a comparator and a
+ * normalizer, forming the basic tools necessary to assert actions against
+ * attribute values. MatchingRules are associated with a specific Syntax for the
+ * purpose of resolving a normalized form and for comparisons.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ * 
+ * <pre>
+ *  4.1.3. Matching Rules
+ * 
+ *    Matching rules are used by servers to compare attribute values against
+ *    assertion values when performing Search and Compare operations.  They
+ *    are also used to identify the value to be added or deleted when
+ *    modifying entries, and are used when comparing a purported
+ *    distinguished name with the name of an entry.
+ * 
+ *    A matching rule specifies the syntax of the assertion value.
+ * 
+ *    Each matching rule is identified by an object identifier (OID) and,
+ *    optionally, one or more short names (descriptors).
+ * 
+ *    Matching rule definitions are written according to the ABNF:
+ * 
+ *      MatchingRuleDescription = LPAREN WSP
+ *          numericoid                ; object identifier
+ *          [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *          [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *          [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *          SP &quot;SYNTAX&quot; SP numericoid ; assertion syntax
+ *          extensions WSP RPAREN     ; extensions
+ * 
+ *    where:
+ *      [numericoid] is object identifier assigned to this matching rule;
+ *      NAME [qdescrs] are short names (descriptors) identifying this
+ *          matching rule;
+ *      DESC [qdstring] is a short descriptive string;
+ *      OBSOLETE indicates this matching rule is not active;
+ *      SYNTAX identifies the assertion syntax by object identifier; and
+ *      [extensions] describe extensions.
+ * </pre>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC 2252 Section 4.5</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see DescriptionUtils#getDescription(MutableMatchingRule)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MutableMatchingRule extends MatchingRule
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of MatchingRule.
+     *
+     * @param oid The MatchingRule OID
+     */
+    public MutableMatchingRule( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Sets the Syntax's OID
+     *
+     * @param oid The Syntax's OID
+     */
+    public void setSyntaxOid( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.ldapSyntaxOid = oid;
+        }
+    }
+
+
+    /**
+     * Sets the Syntax
+     *
+     * @param ldapSyntax The Syntax
+     */
+    public void setSyntax( LdapSyntax ldapSyntax )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.ldapSyntax = ldapSyntax;
+            this.ldapSyntaxOid = ldapSyntax.getOid();
+        }
+    }
+
+
+    /**
+     * Update the associated Syntax, even if the SchemaObject is readOnly
+     *
+     * @param ldapSyntax The Syntax
+     */
+    public void updateSyntax( LdapSyntax ldapSyntax )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.ldapSyntax = ldapSyntax;
+        this.ldapSyntaxOid = ldapSyntax.getOid();
+    }
+
+
+    /**
+     * Sets the LdapComparator
+     *
+     * @param ldapComparator The LdapComparator
+     */
+    @SuppressWarnings("unchecked")
+    public void setLdapComparator( LdapComparator<?> ldapComparator )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.ldapComparator = ( LdapComparator<? super Object> ) ldapComparator;
+        }
+    }
+
+
+    /**
+     * Update the associated Comparator, even if the SchemaObject is readOnly
+     *
+     * @param ldapComparator The LdapComparator
+     */
+    @SuppressWarnings("unchecked")
+    public void updateLdapComparator( LdapComparator<?> ldapComparator )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.ldapComparator = ( LdapComparator<? super Object> ) ldapComparator;
+    }
+
+
+    /**
+     * Sets the Normalizer
+     *
+     * @param normalizer The Normalizer
+     */
+    public void setNormalizer( Normalizer normalizer )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.normalizer = normalizer;
+        }
+    }
+
+
+    /**
+     * Update the associated Normalizer, even if the SchemaObject is readOnly
+     *
+     * @param normalizer The Normalizer
+     */
+    public void updateNormalizer( Normalizer normalizer )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        this.normalizer = normalizer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        ldapComparator = null;
+        ldapSyntax = null;
+        normalizer = null;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableObjectClass.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableObjectClass.java
new file mode 100644
index 0000000..edae097
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/MutableObjectClass.java
@@ -0,0 +1,463 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * An objectClass definition.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ *
+ * <pre>
+ *  Object Class definitions are written according to the ABNF:
+ *
+ *    ObjectClassDescription = LPAREN WSP
+ *        numericoid                ; object identifier
+ *        [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *        [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *        [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *        [ SP &quot;SUP&quot; SP oids ]      ; superior object classes
+ *        [ SP kind ]               ; kind of class
+ *        [ SP &quot;MUST&quot; SP oids ]     ; attribute types
+ *        [ SP &quot;MAY&quot; SP oids ]      ; attribute types
+ *        extensions WSP RPAREN
+ *
+ *     kind = &quot;ABSTRACT&quot; / &quot;STRUCTURAL&quot; / &quot;AUXILIARY&quot;
+ *
+ *   where:
+ *     [numericoid] is object identifier assigned to this object class;
+ *     NAME [qdescrs] are short names (descriptors) identifying this object
+ *         class;
+ *     DESC [qdstring] is a short descriptive string;
+ *     OBSOLETE indicates this object class is not active;
+ *     SUP [oids] specifies the direct superclasses of this object class;
+ *     the kind of object class is indicated by one of ABSTRACT,
+ *         STRUCTURAL, or AUXILIARY, default is STRUCTURAL;
+ *     MUST and MAY specify the sets of required and allowed attribute
+ *         types, respectively; and
+ *    [extensions] describe extensions.
+ * </pre>
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC2252 Section 4.4</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see DescriptionUtils#getDescription(MutableObjectClass)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MutableObjectClass extends ObjectClass
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of MatchingRuleUseDescription
+     * @param oid the OID for this objectClass
+     */
+    public MutableObjectClass( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Add some allowed AttributeType
+     *
+     * @param oids The attributeType oids
+     */
+    public void addMayAttributeTypeOids( String... oids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            for ( String oid : oids )
+            {
+                mayAttributeTypeOids.add( oid );
+            }
+        }
+    }
+
+
+    /**
+     * Add some allowed AttributeTypes
+     *
+     * @param attributeTypes The attributeTypes
+     */
+    public void addMayAttributeTypes( AttributeType... attributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            for ( AttributeType attributeType : attributeTypes )
+            {
+                if ( !mayAttributeTypeOids.contains( attributeType.getOid() ) )
+                {
+                    mayAttributeTypes.add( attributeType );
+                    mayAttributeTypeOids.add( attributeType.getOid() );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * @param mayAttributeTypeOids the mayAttributeTypeOids to set
+     */
+    public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mayAttributeTypeOids = mayAttributeTypeOids;
+        }
+    }
+
+
+    /**
+     * Sets the list of allowed AttributeTypes
+     *
+     * @param mayAttributeTypes the list of allowed AttributeTypes
+     */
+    public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mayAttributeTypes = mayAttributeTypes;
+
+            // update the OIDS now
+            mayAttributeTypeOids.clear();
+
+            for ( AttributeType may : mayAttributeTypes )
+            {
+                mayAttributeTypeOids.add( may.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * Update the associated MAY AttributeType, even if the SchemaObject is readOnly
+     *
+     * @param mayAttributeTypes the list of allowed AttributeTypes
+     */
+    public void updateMayAttributeTypes( List<AttributeType> mayAttributeTypes )
+    {
+        this.mayAttributeTypes.clear();
+        this.mayAttributeTypes.addAll( mayAttributeTypes );
+
+        // update the OIDS now
+        mayAttributeTypeOids.clear();
+
+        for ( AttributeType may : mayAttributeTypes )
+        {
+            mayAttributeTypeOids.add( may.getOid() );
+        }
+    }
+
+
+    /**
+     * Add some required AttributeType OIDs
+     *
+     * @param oids The attributeType OIDs
+     */
+    public void addMustAttributeTypeOids( String... oids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            for ( String oid : oids )
+            {
+                mustAttributeTypeOids.add( oid );
+            }
+        }
+    }
+
+
+    /**
+     * Add some required AttributeTypes
+     *
+     * @param attributeTypes The attributeTypse
+     */
+    public void addMustAttributeTypes( AttributeType... attributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            for ( AttributeType attributeType : attributeTypes )
+            {
+                if ( !mustAttributeTypeOids.contains( attributeType.getOid() ) )
+                {
+                    mustAttributeTypes.add( attributeType );
+                    mustAttributeTypeOids.add( attributeType.getOid() );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * @param mustAttributeTypeOids the mustAttributeTypeOids to set
+     */
+    public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mustAttributeTypeOids = mustAttributeTypeOids;
+        }
+    }
+
+
+    /**
+     * Sets the list of required AttributeTypes
+     *
+     * @param mustAttributeTypes the list of required AttributeTypes
+     */
+    public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mustAttributeTypes = mustAttributeTypes;
+
+            // update the OIDS now
+            mustAttributeTypeOids.clear();
+
+            for ( AttributeType may : mustAttributeTypes )
+            {
+                mustAttributeTypeOids.add( may.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * Update the associated MUST AttributeType, even if the SchemaObject is readOnly
+     *
+     * @param mustAttributeTypes the list of allowed AttributeTypes
+     */
+    public void updateMustAttributeTypes( List<AttributeType> mustAttributeTypes )
+    {
+        this.mustAttributeTypes.clear();
+        this.mustAttributeTypes.addAll( mustAttributeTypes );
+
+        // update the OIDS now
+        mustAttributeTypeOids.clear();
+
+        for ( AttributeType must : mustAttributeTypes )
+        {
+            mustAttributeTypeOids.add( must.getOid() );
+        }
+    }
+
+
+    /**
+     * Add some superior ObjectClass OIDs
+     *
+     * @param oids The superior ObjectClass OIDs
+     */
+    public void addSuperiorOids( String... oids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            for ( String oid : oids )
+            {
+                if ( !superiorOids.contains( oid ) )
+                {
+                    superiorOids.add( oid );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Add some superior ObjectClasses
+     *
+     * @param objectClasses The superior ObjectClasses
+     */
+    public void addSuperior( MutableObjectClass... objectClasses )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            for ( MutableObjectClass objectClass : objectClasses )
+            {
+                if ( !superiorOids.contains( objectClass.getOid() ) )
+                {
+                    superiorOids.add( objectClass.getOid() );
+                    superiors.add( objectClass );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Sets the superior object classes
+     *
+     * @param superiors the object classes to set
+     */
+    public void setSuperiors( List<ObjectClass> superiors )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.superiors = superiors;
+
+            // update the OIDS now
+            superiorOids.clear();
+
+            for ( ObjectClass oc : superiors )
+            {
+                superiorOids.add( oc.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * Update the associated SUPERIORS ObjectClasses, even if the SchemaObject is readOnly
+     *
+     * @param superiors the object classes to set
+     */
+    public void updateSuperiors( List<ObjectClass> superiors )
+    {
+        this.superiors.clear();
+        this.superiors.addAll( superiors );
+
+        // update the OIDS now
+        superiorOids.clear();
+
+        for ( ObjectClass oc : superiors )
+        {
+            superiorOids.add( oc.getOid() );
+        }
+    }
+
+
+    /**
+     * Sets the superior object class OIDs
+     *
+     * @param superiorOids the object class OIDs to set
+     */
+    public void setSuperiorOids( List<String> superiorOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.superiorOids = superiorOids;
+        }
+    }
+
+
+    /**
+     * Set the ObjectClass type, one of ABSTRACT, AUXILIARY or STRUCTURAL.
+     *
+     * @param objectClassType The ObjectClassType value
+     */
+    public void setType( ObjectClassTypeEnum objectClassType )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.objectClassType = objectClassType;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        mayAttributeTypes.clear();
+        mayAttributeTypeOids.clear();
+        mustAttributeTypes.clear();
+        mustAttributeTypeOids.clear();
+        superiors.clear();
+        superiorOids.clear();
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/NameForm.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/NameForm.java
new file mode 100644
index 0000000..f90644f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/NameForm.java
@@ -0,0 +1,510 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A nameForm description. NameForms define the relationship between a
+ * STRUCTURAL objectClass definition and the attributeTypes allowed to be used
+ * for the naming of an Entry of that objectClass: it defines which attributes
+ * can be used for the Rdn.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ * 
+ * <pre>
+ *  4.1.7.2. Name Forms
+ * 
+ *   A name form &quot;specifies a permissible Rdn for entries of a particular
+ *   structural object class.  A name form identifies a named object
+ *   class and one or more attribute types to be used for naming (i.e.
+ *   for the Rdn).  Name forms are primitive pieces of specification
+ *   used in the definition of DIT structure rules&quot; [X.501].
+ * 
+ *   Each name form indicates the structural object class to be named,
+ *   a set of required attribute types, and a set of allowed attributes
+ *   types.  A particular attribute type cannot be listed in both sets.
+ * 
+ *   Entries governed by the form must be named using a value from each
+ *   required attribute type and zero or more values from the allowed
+ *   attribute types.
+ * 
+ *   Each name form is identified by an object identifier (OID) and,
+ *   optionally, one or more short names (descriptors).
+ * 
+ *   Name form descriptions are written according to the ABNF:
+ * 
+ *     NameFormDescription = LPAREN WSP
+ *         numericoid                ; object identifier
+ *         [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *         [ SP &quot;DESC&quot; SP qdstring ] ;String description
+ *         [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *         SP &quot;OC&quot; SP oid            ; structural object class
+ *         SP &quot;MUST&quot; SP oids         ; attribute types
+ *         [ SP &quot;MAY&quot; SP oids ]      ; attribute types
+ *         extensions WSP RPAREN     ; extensions
+ * 
+ *   where:
+ * 
+ *     [numericoid] is object identifier which identifies this name form;
+ *     NAME [qdescrs] are short names (descriptors) identifying this name
+ *         form;
+ *     DESC [qdstring] is a short descriptive string;
+ *     OBSOLETE indicates this name form is not active;
+ *     OC identifies the structural object class this rule applies to,
+ *     MUST and MAY specify the sets of required and allowed, respectively,
+ *         naming attributes for this name form; and
+ *     [extensions] describe extensions.
+ * 
+ *   All attribute types in the required (&quot;MUST&quot;) and allowed (&quot;MAY&quot;) lists
+ *   shall be different.
+ * </pre>
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc225String2.html">RFC2252 Section 6.22</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see DescriptionUtils#getDescription(NameForm)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NameForm extends AbstractSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** The structural object class OID this rule applies to */
+    private String structuralObjectClassOid;
+
+    /** The structural object class this rule applies to */
+    private ObjectClass structuralObjectClass;
+
+    /** The set of required attribute OIDs for this name form */
+    private List<String> mustAttributeTypeOids;
+
+    /** The set of required AttributeTypes for this name form */
+    private List<AttributeType> mustAttributeTypes;
+
+    /** The set of allowed attribute OIDs for this name form */
+    private List<String> mayAttributeTypeOids;
+
+    /** The set of allowed AttributeTypes for this name form */
+    private List<AttributeType> mayAttributeTypes;
+
+
+    /**
+     * Creates a new instance of MatchingRule.
+     *
+     * @param oid The MatchingRule OID
+     */
+    public NameForm( String oid )
+    {
+        super( SchemaObjectType.NAME_FORM, oid );
+
+        mustAttributeTypeOids = new ArrayList<String>();
+        mayAttributeTypeOids = new ArrayList<String>();
+
+        mustAttributeTypes = new ArrayList<AttributeType>();
+        mayAttributeTypes = new ArrayList<AttributeType>();
+    }
+
+
+    /**
+     * Gets the STRUCTURAL ObjectClass this name form specifies naming
+     * attributes for.
+     * 
+     * @return the ObjectClass's oid this NameForm is for
+     */
+    public String getStructuralObjectClassOid()
+    {
+        return structuralObjectClassOid;
+    }
+
+
+    /**
+     * Gets the STRUCTURAL ObjectClass this name form specifies naming
+     * attributes for.
+     * 
+     * @return the ObjectClass this NameForm is for
+     */
+    public ObjectClass getStructuralObjectClass()
+    {
+        return structuralObjectClass;
+    }
+
+
+    /**
+     * Sets the structural object class this rule applies to
+     * 
+     * @param structuralObjectClassOid the structural object class to set
+     */
+    public void setStructuralObjectClassOid( String structuralObjectClassOid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.structuralObjectClassOid = structuralObjectClassOid;
+        }
+    }
+
+
+    /**
+     * Sets the structural object class this rule applies to
+     * 
+     * @param structuralObjectClass the structural object class to set
+     */
+    public void setStructuralObjectClass( ObjectClass structuralObjectClass )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.structuralObjectClass = structuralObjectClass;
+            this.structuralObjectClassOid = structuralObjectClass.getOid();
+        }
+    }
+
+
+    /**
+     * Gets all the AttributeTypes OIDs of the attributes this NameForm specifies as
+     * having to be used in the given objectClass for naming: as part of the
+     * Rdn.
+     * 
+     * @return the AttributeTypes OIDs of the must use attributes
+     */
+    public List<String> getMustAttributeTypeOids()
+    {
+        return Collections.unmodifiableList( mustAttributeTypeOids );
+    }
+
+
+    /**
+     * Gets all the AttributeTypes of the attributes this NameForm specifies as
+     * having to be used in the given objectClass for naming: as part of the
+     * Rdn.
+     * 
+     * @return the AttributeTypes of the must use attributes
+     */
+    public List<AttributeType> getMustAttributeTypes()
+    {
+        return Collections.unmodifiableList( mustAttributeTypes );
+    }
+
+
+    /**
+     * Sets the list of required AttributeTypes OIDs
+     *
+     * @param mustAttributeTypeOids the list of required AttributeTypes OIDs
+     */
+    public void setMustAttributeTypeOids( List<String> mustAttributeTypeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mustAttributeTypeOids = mustAttributeTypeOids;
+        }
+    }
+
+
+    /**
+     * Sets the list of required AttributeTypes
+     *
+     * @param mustAttributeTypes the list of required AttributeTypes
+     */
+    public void setMustAttributeTypes( List<AttributeType> mustAttributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mustAttributeTypes = mustAttributeTypes;
+
+            // update the OIDS now
+            mustAttributeTypeOids.clear();
+
+            for ( AttributeType may : mustAttributeTypes )
+            {
+                mustAttributeTypeOids.add( may.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * Add a required AttributeType OID
+     *
+     * @param oid The attributeType OID
+     */
+    public void addMustAttributeTypeOids( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            mustAttributeTypeOids.add( oid );
+        }
+    }
+
+
+    /**
+     * Add a required AttributeType
+     *
+     * @param attributeType The attributeType
+     */
+    public void addMustAttributeTypes( AttributeType attributeType )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !mustAttributeTypeOids.contains( attributeType.getOid() ) )
+        {
+            mustAttributeTypes.add( attributeType );
+            mustAttributeTypeOids.add( attributeType.getOid() );
+        }
+    }
+
+
+    /**
+     * Gets all the AttributeTypes OIDs of the attribute this NameForm specifies as
+     * being usable without requirement in the given objectClass for naming: as
+     * part of the Rdn.
+     * 
+     * @return the AttributeTypes OIDs of the may use attributes
+     */
+    public List<String> getMayAttributeTypeOids()
+    {
+        return Collections.unmodifiableList( mayAttributeTypeOids );
+    }
+
+
+    /**
+     * Gets all the AttributeTypes of the attribute this NameForm specifies as
+     * being useable without requirement in the given objectClass for naming: as
+     * part of the Rdn.
+     * 
+     * @return the AttributeTypes of the may use attributes
+     */
+    public List<AttributeType> getMayAttributeTypes()
+    {
+        return Collections.unmodifiableList( mayAttributeTypes );
+    }
+
+
+    /**
+     * Sets the list of allowed AttributeTypes
+     *
+     * @param mayAttributeTypeOids the list of allowed AttributeTypes
+     */
+    public void setMayAttributeTypeOids( List<String> mayAttributeTypeOids )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mayAttributeTypeOids = mayAttributeTypeOids;
+        }
+    }
+
+
+    /**
+     * Sets the list of allowed AttributeTypes
+     *
+     * @param mayAttributeTypes the list of allowed AttributeTypes
+     */
+    public void setMayAttributeTypes( List<AttributeType> mayAttributeTypes )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            this.mayAttributeTypes = mayAttributeTypes;
+
+            // update the OIDS now
+            mayAttributeTypeOids.clear();
+
+            for ( AttributeType may : mayAttributeTypes )
+            {
+                mayAttributeTypeOids.add( may.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * Add an allowed AttributeType
+     *
+     * @param oid The attributeType oid
+     */
+    public void addMayAttributeTypeOids( String oid )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly )
+        {
+            mayAttributeTypeOids.add( oid );
+        }
+    }
+
+
+    /**
+     * Add an allowed AttributeType
+     *
+     * @param attributeType The attributeType
+     */
+    public void addMayAttributeTypes( AttributeType attributeType )
+    {
+        if ( locked )
+        {
+            throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
+        }
+
+        if ( !isReadOnly && !mayAttributeTypeOids.contains( attributeType.getOid() ) )
+        {
+            mayAttributeTypes.add( attributeType );
+            mayAttributeTypeOids.add( attributeType.getOid() );
+        }
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * Copy a NameForm
+     */
+    public NameForm copy()
+    {
+        NameForm copy = new NameForm( oid );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // Copy the MAY AttributeTypes OIDs
+        copy.mayAttributeTypeOids = new ArrayList<String>();
+
+        for ( String oid : mayAttributeTypeOids )
+        {
+            copy.mayAttributeTypeOids.add( oid );
+        }
+
+        // Copy the MAY AttributeTypes (will be empty)
+        copy.mayAttributeTypes = new ArrayList<AttributeType>();
+
+        // Copy the MUST AttributeTypes OIDs
+        copy.mustAttributeTypeOids = new ArrayList<String>();
+
+        for ( String oid : mustAttributeTypeOids )
+        {
+            copy.mustAttributeTypeOids.add( oid );
+        }
+
+        // Copy the MUST AttributeTypes ( will be empty )
+        copy.mustAttributeTypes = new ArrayList<AttributeType>();
+
+        // Copy the Structural ObjectClass OID
+        copy.structuralObjectClassOid = structuralObjectClassOid;
+
+        // All the references to other Registries object are set to null.
+        copy.structuralObjectClass = null;
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof NameForm ) )
+        {
+            return false;
+        }
+
+        @SuppressWarnings("unused")
+        NameForm that = ( NameForm ) o;
+
+        // TODO : complete the checks
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the common elements
+        super.clear();
+
+        // Clear the references
+        mayAttributeTypes.clear();
+        mayAttributeTypeOids.clear();
+        mustAttributeTypes.clear();
+        mustAttributeTypeOids.clear();
+        structuralObjectClass = null;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/Normalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/Normalizer.java
new file mode 100644
index 0000000..71011f9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/Normalizer.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * Converts attribute values to a canonical form.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class Normalizer extends LoadableSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * The Normalizer base constructor. We use it's MR OID to
+     * initialize the SchemaObject instance
+     * 
+     * @param oid The associated OID. It's the element's MR OID
+     */
+    protected Normalizer( String oid )
+    {
+        super( SchemaObjectType.NORMALIZER, oid );
+    }
+
+
+    /**
+     * Use this default constructor when the Normalizer must be instantiated
+     * before setting the OID.
+     */
+    protected Normalizer()
+    {
+        super( SchemaObjectType.NORMALIZER );
+    }
+
+
+    /**
+     * Gets the normalized value.
+     * 
+     * @param value the value to normalize. It must *not* be null !
+     * @return the normalized form for a value
+     * @throws LdapException if an error results during normalization
+     */
+    public abstract Value<?> normalize( Value<?> value ) throws LdapException;
+
+
+    /**
+     * Gets the normalized value.
+     * 
+     * @param value the value to normalize. It must *not* be null !
+     * @return the normalized form for a value
+     * @throws LdapException if an error results during normalization
+     */
+    public abstract String normalize( String value ) throws LdapException;
+
+
+    /**
+     * Store the SchemaManager in this instance. It may be necessary for some
+     * normalizer which needs to have access to the oidNormalizer Map.
+     *
+     * @param schemaManager the schemaManager to store
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        // Do nothing (general case).
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        return o instanceof Normalizer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return objectType + " " + DescriptionUtils.getDescription( this );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/NormalizerMappingResolver.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/NormalizerMappingResolver.java
new file mode 100644
index 0000000..76aafab
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/NormalizerMappingResolver.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.Map;
+
+
+/**
+ * A class is used to resolve the normalizer mapping hash used for normalization.
+ * This interface is implemented and passed into several kinds of parsers that
+ * need to handle the normalization of LDAP name strings.
+ * 
+ * Why you may ask are we doing this?  Why not just pass in the map of 
+ * normalizers to these parsers and let them use that?  First off this mapping
+ * will not be static when dynamic updates are enabled to schema.  So if
+ * we just passed in the map then there would be no way to set a new map or
+ * trigger the change of the map when schema changes.  Secondly we cannot just
+ * pass server side objects that return this mapping because these parsers may
+ * and will be used in client side applications.  They will not have access to
+ * these server side objects that generate these mappings.  Instead when a 
+ * resolver is used we can create mock or almost right implementations.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface NormalizerMappingResolver<E extends Normalizer>
+{
+    Map<String, E> getNormalizerMapping() throws Exception;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/ObjectClass.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/ObjectClass.java
new file mode 100644
index 0000000..44aca14
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/ObjectClass.java
@@ -0,0 +1,447 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * An objectClass definition.
+ * <p>
+ * According to ldapbis [MODELS]:
+ * </p>
+ *
+ * <pre>
+ *  Object Class definitions are written according to the ABNF:
+ *
+ *    ObjectClassDescription = LPAREN WSP
+ *        numericoid                ; object identifier
+ *        [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
+ *        [ SP &quot;DESC&quot; SP qdstring ] ; description
+ *        [ SP &quot;OBSOLETE&quot; ]         ; not active
+ *        [ SP &quot;SUP&quot; SP oids ]      ; superior object classes
+ *        [ SP kind ]               ; kind of class
+ *        [ SP &quot;MUST&quot; SP oids ]     ; attribute types
+ *        [ SP &quot;MAY&quot; SP oids ]      ; attribute types
+ *        extensions WSP RPAREN
+ *
+ *     kind = &quot;ABSTRACT&quot; / &quot;STRUCTURAL&quot; / &quot;AUXILIARY&quot;
+ *
+ *   where:
+ *     [numericoid] is object identifier assigned to this object class;
+ *     NAME [qdescrs] are short names (descriptors) identifying this object
+ *         class;
+ *     DESC [qdstring] is a short descriptive string;
+ *     OBSOLETE indicates this object class is not active;
+ *     SUP [oids] specifies the direct superclasses of this object class;
+ *     the kind of object class is indicated by one of ABSTRACT,
+ *         STRUCTURAL, or AUXILIARY, default is STRUCTURAL;
+ *     MUST and MAY specify the sets of required and allowed attribute
+ *         types, respectively; and
+ *    [extensions] describe extensions.
+ * </pre>
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC2252 Section 4.4</a>
+ * @see <a
+ *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
+ *      [MODELS]</a>
+ * @see DescriptionUtils#getDescription(ObjectClass)
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ObjectClass extends AbstractSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+    /** The ObjectClass type : ABSTRACT, AUXILIARY or STRUCTURAL */
+    protected ObjectClassTypeEnum objectClassType = ObjectClassTypeEnum.STRUCTURAL;
+
+    /** The ObjectClass superior OIDs */
+    protected List<String> superiorOids;
+
+    /** The ObjectClass superiors */
+    protected List<ObjectClass> superiors;
+
+    /** The list of allowed AttributeType OIDs */
+    protected List<String> mayAttributeTypeOids;
+
+    /** The list of allowed AttributeTypes */
+    protected List<AttributeType> mayAttributeTypes;
+
+    /** The list of required AttributeType OIDs */
+    protected List<String> mustAttributeTypeOids;
+
+    /** The list of required AttributeTypes */
+    protected List<AttributeType> mustAttributeTypes;
+
+
+    /**
+     * Creates a new instance of MatchingRuleUseDescription
+     * @param oid the OID for this objectClass
+     */
+    public ObjectClass( String oid )
+    {
+        super( SchemaObjectType.OBJECT_CLASS, oid );
+
+        mayAttributeTypeOids = new ArrayList<String>();
+        mustAttributeTypeOids = new ArrayList<String>();
+        superiorOids = new ArrayList<String>();
+
+        mayAttributeTypes = new ArrayList<AttributeType>();
+        mustAttributeTypes = new ArrayList<AttributeType>();
+        superiors = new ArrayList<ObjectClass>();
+        objectClassType = ObjectClassTypeEnum.STRUCTURAL;
+    }
+
+
+    /**
+     * @return the mayAttributeTypeOids
+     */
+    public List<String> getMayAttributeTypeOids()
+    {
+        return mayAttributeTypeOids;
+    }
+
+
+    /**
+     * @return the mayAttributeTypes
+     */
+    public List<AttributeType> getMayAttributeTypes()
+    {
+        return mayAttributeTypes;
+    }
+
+
+    /**
+     * @return the mustAttributeTypeOids
+     */
+    public List<String> getMustAttributeTypeOids()
+    {
+        return mustAttributeTypeOids;
+    }
+
+
+    /**
+     * @return the mustAttributeTypes
+     */
+    public List<AttributeType> getMustAttributeTypes()
+    {
+        return mustAttributeTypes;
+    }
+
+
+    /**
+     * Gets the superclasses of this ObjectClass.
+     *
+     * @return the superclasses
+     */
+    public List<ObjectClass> getSuperiors()
+    {
+        return superiors;
+    }
+
+
+    /**
+     * Gets the superclasses OIDsof this ObjectClass.
+     *
+     * @return the superclasses OIDs
+     */
+    public List<String> getSuperiorOids()
+    {
+        return superiorOids;
+    }
+
+
+    /**
+     * Gets the type of this ObjectClass as a type safe enum.
+     *
+     * @return the ObjectClass type as an enum
+     */
+    public ObjectClassTypeEnum getType()
+    {
+        return objectClassType;
+    }
+
+
+    /**
+     * Tells if the current ObjectClass is STRUCTURAL
+     *
+     * @return <code>true</code> if the ObjectClass is STRUCTURAL
+     */
+    public boolean isStructural()
+    {
+        return objectClassType == ObjectClassTypeEnum.STRUCTURAL;
+    }
+
+
+    /**
+     * Tells if the current ObjectClass is ABSTRACT
+     *
+     * @return <code>true</code> if the ObjectClass is ABSTRACT
+     */
+    public boolean isAbstract()
+    {
+        return objectClassType == ObjectClassTypeEnum.ABSTRACT;
+    }
+
+
+    /**
+     * Tells if the current ObjectClass is AUXILIARY
+     *
+     * @return <code>true</code> if the ObjectClass is AUXILIARY
+     */
+    public boolean isAuxiliary()
+    {
+        return objectClassType == ObjectClassTypeEnum.AUXILIARY;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
+    }
+
+
+    /**
+     * Copy an ObjectClass
+     */
+    public ObjectClass copy()
+    {
+        ObjectClass copy = new ObjectClass( oid );
+
+        // Copy the SchemaObject common data
+        copy.copy( this );
+
+        // Copy the ObjectClass type
+        copy.objectClassType = objectClassType;
+
+        // Copy the Superiors ObjectClasses OIDs
+        copy.superiorOids = new ArrayList<String>();
+
+        for ( String oid : superiorOids )
+        {
+            copy.superiorOids.add( oid );
+        }
+
+        // Copy the Superiors ObjectClasses ( will be empty )
+        copy.superiors = new ArrayList<ObjectClass>();
+
+        // Copy the MAY AttributeTypes OIDs
+        copy.mayAttributeTypeOids = new ArrayList<String>();
+
+        for ( String oid : mayAttributeTypeOids )
+        {
+            copy.mayAttributeTypeOids.add( oid );
+        }
+
+        // Copy the MAY AttributeTypes ( will be empty )
+        copy.mayAttributeTypes = new ArrayList<AttributeType>();
+
+        // Copy the MUST AttributeTypes OIDs
+        copy.mustAttributeTypeOids = new ArrayList<String>();
+
+        for ( String oid : mustAttributeTypeOids )
+        {
+            copy.mustAttributeTypeOids.add( oid );
+        }
+
+        // Copy the MUST AttributeTypes ( will be empty )
+        copy.mustAttributeTypes = new ArrayList<AttributeType>();
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        if ( !( o instanceof ObjectClass ) )
+        {
+            return false;
+        }
+
+        ObjectClass that = ( ObjectClass ) o;
+
+        // The ObjectClassType
+        if ( objectClassType != that.objectClassType )
+        {
+            return false;
+        }
+
+        // The Superiors OIDs
+        if ( superiorOids.size() != that.superiorOids.size() )
+        {
+            return false;
+        }
+
+        // One way
+        for ( String oid : superiorOids )
+        {
+            if ( !that.superiorOids.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The other way
+        for ( String oid : that.superiorOids )
+        {
+            if ( !superiorOids.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The Superiors
+        if ( superiors.size() != that.superiors.size() )
+        {
+            return false;
+        }
+
+        // One way
+        for ( ObjectClass oid : superiors )
+        {
+            if ( !that.superiors.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The other way
+        for ( ObjectClass oid : that.superiors )
+        {
+            if ( !superiors.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The MAY OIDs
+        if ( mayAttributeTypeOids.size() != that.mayAttributeTypeOids.size() )
+        {
+            return false;
+        }
+
+        // One way
+        for ( String oid : mayAttributeTypeOids )
+        {
+            if ( !that.mayAttributeTypeOids.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The other way
+        for ( String oid : that.mayAttributeTypeOids )
+        {
+            if ( !mayAttributeTypeOids.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The MAY
+        if ( mayAttributeTypes.size() != that.mayAttributeTypes.size() )
+        {
+            return false;
+        }
+
+        // One way
+        for ( AttributeType oid : mayAttributeTypes )
+        {
+            if ( !that.mayAttributeTypes.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The other way
+        for ( AttributeType oid : that.mayAttributeTypes )
+        {
+            if ( !mayAttributeTypes.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The MUST OIDs
+        if ( mustAttributeTypeOids.size() != that.mustAttributeTypeOids.size() )
+        {
+            return false;
+        }
+
+        // One way
+        for ( String oid : mustAttributeTypeOids )
+        {
+            if ( !that.mustAttributeTypeOids.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The other way
+        for ( String oid : that.mustAttributeTypeOids )
+        {
+            if ( !mustAttributeTypeOids.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The MUST
+        if ( mustAttributeTypes.size() != that.mustAttributeTypes.size() )
+        {
+            return false;
+        }
+
+        // One way
+        for ( AttributeType oid : mustAttributeTypes )
+        {
+            if ( !that.mustAttributeTypes.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        // The other way
+        for ( AttributeType oid : that.mustAttributeTypes )
+        {
+            if ( !mustAttributeTypes.contains( oid ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/ObjectClassTypeEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/ObjectClassTypeEnum.java
new file mode 100644
index 0000000..51c1812
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/ObjectClassTypeEnum.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Type safe enumerations for an objectClass' type. An ObjectClass type can be
+ * one of the following types:
+ * <ul>
+ * <li>ABSTRACT</li>
+ * <li>AUXILIARY</li>
+ * <li>STRUCTURAL</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum ObjectClassTypeEnum
+{
+    /** The enumeration constant value for the abstract objectClasses */
+    ABSTRACT(0),
+
+    /** The enumeration constant value for the auxillary objectClasses */
+    AUXILIARY(1),
+
+    /** The enumeration constant value for the structural objectClasses */
+    STRUCTURAL(2);
+
+    /** The int constant value for the abstract objectClasses */
+    public static final int ABSTRACT_VAL = 0;
+
+    /** The int constant value for the auxillary objectClasses */
+    public static final int AUXILIARY_VAL = 1;
+
+    /** The int constant value for the structural objectClasses */
+    public static final int STRUCTURAL_VAL = 2;
+
+    /** Stores the integer value of each element of the enumeration */
+    private int value;
+
+
+    /**
+     * Private constructor so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param name
+     *            a string name for the enumeration value.
+     * @param value
+     *            the integer value of the enumeration.
+     */
+    private ObjectClassTypeEnum( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Gets the objectClass type enumeration of AUXILIARY, STRUCTURAL, or,
+     * ABSTRACT.
+     * 
+     * @param name options are AUXILIARY, STRUCTURAL, or, ABSTRACT
+     * 
+     * @return the type safe enumeration for the objectClass type
+     */
+    public static ObjectClassTypeEnum getClassType( String name )
+    {
+        String upperCase = name.trim().toUpperCase();
+
+        if ( upperCase.equals( "STRUCTURAL" ) )
+        {
+            return STRUCTURAL;
+        }
+        else if ( upperCase.equals( "AUXILIARY" ) )
+        {
+            return AUXILIARY;
+        }
+        else if ( upperCase.equals( "ABSTRACT" ) )
+        {
+            return ABSTRACT;
+        }
+
+        throw new IllegalArgumentException( I18n.err( I18n.ERR_04327, name ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/PrepareString.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/PrepareString.java
new file mode 100644
index 0000000..d59f30c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/PrepareString.java
@@ -0,0 +1,5355 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.exception.InvalidCharacterException;
+
+
+/**
+ * 
+ * This class implements the 6 steps described in RFC 4518
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class PrepareString
+{
+    /** A flag used to lowercase chars during the map process */
+    private static final boolean CASE_SENSITIVE = true;
+
+    /** A flag used to keep casing during the map process */
+    private static final boolean IGNORE_CASE = false;
+
+    /** All the possible combining marks */
+    private static final char[][] COMBINING_MARKS = new char[][]
+        {
+            { 0x0300, 0x034F },
+            { 0x0360, 0x036F },
+            { 0x0483, 0x0486 },
+            { 0x0488, 0x0489 },
+            { 0x0591, 0x05A1 },
+            { 0x05A3, 0x05B9 },
+            { 0x05BB, 0x05BC },
+            { 0x05BF, 0x05BF },
+            { 0x05C1, 0x05C2 },
+            { 0x05C4, 0x05C4 },
+            { 0x064B, 0x0655 },
+            { 0x0670, 0x0670 },
+            { 0x06D6, 0x06DC },
+            { 0x06DE, 0x06E4 },
+            { 0x06E7, 0x06E8 },
+            { 0x06EA, 0x06ED },
+            { 0x0711, 0x0711 },
+            { 0x0730, 0x074A },
+            { 0x07A6, 0x07B0 },
+            { 0x0901, 0x0903 },
+            { 0x093C, 0x093C },
+            { 0x093E, 0x094F },
+            { 0x0951, 0x0954 },
+            { 0x0962, 0x0963 },
+            { 0x0981, 0x0983 },
+            { 0x09BC, 0x09BC },
+            { 0x09BE, 0x09C4 },
+            { 0x09C7, 0x09C8 },
+            { 0x09CB, 0x09CD },
+            { 0x09D7, 0x09D7 },
+            { 0x09E2, 0x09E3 },
+            { 0x0A02, 0x0A02 },
+            { 0x0A3C, 0x0A3C },
+            { 0x0A3E, 0x0A42 },
+            { 0x0A47, 0x0A48 },
+            { 0x0A4B, 0x0A4D },
+            { 0x0A70, 0x0A71 },
+            { 0x0A81, 0x0A83 },
+            { 0x0ABC, 0x0ABC },
+            { 0x0ABE, 0x0AC5 },
+            { 0x0AC7, 0x0AC9 },
+            { 0x0ACB, 0x0ACD },
+            { 0x0B01, 0x0B03 },
+            { 0x0B3C, 0x0B3C },
+            { 0x0B3E, 0x0B43 },
+            { 0x0B47, 0x0B48 },
+            { 0x0B4B, 0x0B4D },
+            { 0x0B56, 0x0B57 },
+            { 0x0B82, 0x0B82 },
+            { 0x0BBE, 0x0BC2 },
+            { 0x0BC6, 0x0BC8 },
+            { 0x0BCA, 0x0BCD },
+            { 0x0BD7, 0x0BD7 },
+            { 0x0C01, 0x0C03 },
+            { 0x0C3E, 0x0C44 },
+            { 0x0C46, 0x0C48 },
+            { 0x0C4A, 0x0C4D },
+            { 0x0C55, 0x0C56 },
+            { 0x0C82, 0x0C83 },
+            { 0x0CBE, 0x0CC4 },
+            { 0x0CC6, 0x0CC8 },
+            { 0x0CCA, 0x0CCD },
+            { 0x0CD5, 0x0CD6 },
+            { 0x0D02, 0x0D03 },
+            { 0x0D3E, 0x0D43 },
+            { 0x0D46, 0x0D48 },
+            { 0x0D4A, 0x0D4D },
+            { 0x0D57, 0x0D57 },
+            { 0x0D82, 0x0D83 },
+            { 0x0DCA, 0x0DCA },
+            { 0x0DCF, 0x0DD4 },
+            { 0x0DD6, 0x0DD6 },
+            { 0x0DD8, 0x0DDF },
+            { 0x0DF2, 0x0DF3 },
+            { 0x0E31, 0x0E31 },
+            { 0x0E34, 0x0E3A },
+            { 0x0E47, 0x0E4E },
+            { 0x0EB1, 0x0EB1 },
+            { 0x0EB4, 0x0EB9 },
+            { 0x0EBB, 0x0EBC },
+            { 0x0EC8, 0x0ECD },
+            { 0x0F18, 0x0F19 },
+            { 0x0F35, 0x0F35 },
+            { 0x0F37, 0x0F37 },
+            { 0x0F39, 0x0F39 },
+            { 0x0F3E, 0x0F3F },
+            { 0x0F71, 0x0F84 },
+            { 0x0F86, 0x0F87 },
+            { 0x0F90, 0x0F97 },
+            { 0x0F99, 0x0FBC },
+            { 0x0FC6, 0x0FC6 },
+            { 0x102C, 0x1032 },
+            { 0x1036, 0x1039 },
+            { 0x1056, 0x1059 },
+            { 0x1712, 0x1714 },
+            { 0x1732, 0x1734 },
+            { 0x1752, 0x1753 },
+            { 0x1772, 0x1773 },
+            { 0x17B4, 0x17D3 },
+            { 0x180B, 0x180D },
+            { 0x18A9, 0x18A9 },
+            { 0x20D0, 0x20EA },
+            { 0x302A, 0x302F },
+            { 0x3099, 0x309A },
+            { 0xFB1E, 0xFB1E },
+            { 0xFE00, 0xFE0F },
+            { 0xFE20, 0xFE23 }
+    };
+
+    /**
+     * The type of String we have to normalize
+     */
+    public enum StringType
+    {
+        NOT_STRING,
+        NUMERIC_STRING,
+        CASE_EXACT,
+        CASE_EXACT_IA5,
+        CASE_IGNORE_IA5,
+        CASE_IGNORE_LIST,
+        CASE_IGNORE,
+        DIRECTORY_STRING,
+        TELEPHONE_NUMBER,
+        WORD
+    }
+
+
+    /**
+     * A private constructor, to avoid instance creation of this static class.
+     */
+    private PrepareString()
+    {
+        // Do nothing
+    }
+
+
+    /**
+     * Tells if a char is a combining mark.
+     *
+     * @param c The char to check
+     * @return true if the char is a combining mark, false otherwise
+     */
+    private static boolean isCombiningMark( char c )
+    {
+        if ( c < COMBINING_MARKS[0][0] )
+        {
+            return false;
+        }
+
+        for ( char[] interval : COMBINING_MARKS )
+        {
+            if ( ( c >= interval[0] ) && ( c <= interval[1] ) )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+    *
+    * We have to go through 6 steps :
+    *
+    * 1) Transcode
+    * 2) Map
+    * 3) Normalize
+    * 4) Prohibit
+    * 5) Bidi
+    * 6) Insignifiant Character Handling
+    *
+    * The first step is already done, the step (3) is not done.
+    *
+    * @param str The String to normalize
+    * @param type The string type
+    * @return A normalized string.
+    * @throws IOException
+    */
+    public static String normalize( String str, StringType type ) throws IOException
+    {
+        switch ( type )
+        {
+            case NUMERIC_STRING:
+                return insignifiantCharNumericString( str );
+
+            case TELEPHONE_NUMBER:
+                return insignifiantCharTelephoneNumber( str );
+
+            case CASE_EXACT:
+            case CASE_EXACT_IA5:
+            case DIRECTORY_STRING:
+                try
+                {
+                    return insignifiantSpacesStringAscii( str, CASE_SENSITIVE );
+                }
+                catch ( Exception e )
+                {
+                    return insignifiantSpacesString( str, CASE_SENSITIVE );
+                }
+
+            case CASE_IGNORE_IA5:
+            case CASE_IGNORE_LIST:
+            case CASE_IGNORE:
+                try
+                {
+                    return insignifiantSpacesStringAscii( str, IGNORE_CASE );
+                }
+                catch ( Exception e )
+                {
+                    return insignifiantSpacesString( str, IGNORE_CASE );
+                }
+
+            case WORD:
+                return str;
+
+            default:
+                return str;
+
+        }
+    }
+
+
+    /**
+     * Execute the mapping step of the string preparation :
+     * - suppress useless chars
+     * - transform to spaces
+     * - lowercase
+     * 
+     * @param c The char to map
+     * @param array The array which will collect the transformed char
+     * @param pos The current position in the target
+     * @param lowerCase A mask to lowercase the char, if necessary
+     * @return The transformed StringBuilder
+     */
+    // CHECKSTYLE:OFF
+    private static int map( char[] src, char[] target, char lowerCase )
+    {
+        int limit = 0;
+
+        for ( char c : src )
+        {
+            switch ( c )
+            {
+                case 0x0000:
+                case 0x0001:
+                case 0x0002:
+                case 0x0003:
+                case 0x0004:
+                case 0x0005:
+                case 0x0006:
+                case 0x0007:
+                case 0x0008:
+                    break;
+
+                case 0x0009:
+                case 0x000A:
+                case 0x000B:
+                case 0x000C:
+                case 0x000D:
+                    target[limit++] = ( char ) 0x20;
+                    break;
+
+                case 0x000E:
+                case 0x000F:
+                case 0x0010:
+                case 0x0011:
+                case 0x0012:
+                case 0x0013:
+                case 0x0014:
+                case 0x0015:
+                case 0x0016:
+                case 0x0017:
+                case 0x0018:
+                case 0x0019:
+                case 0x001A:
+                case 0x001B:
+                case 0x001C:
+                case 0x001D:
+                case 0x001E:
+                case 0x001F:
+                    break;
+
+                case 0x0041:
+                case 0x0042:
+                case 0x0043:
+                case 0x0044:
+                case 0x0045:
+                case 0x0046:
+                case 0x0047:
+                case 0x0048:
+                case 0x0049:
+                case 0x004A:
+                case 0x004B:
+                case 0x004C:
+                case 0x004D:
+                case 0x004E:
+                case 0x004F:
+                case 0x0050:
+                case 0x0051:
+                case 0x0052:
+                case 0x0053:
+                case 0x0054:
+                case 0x0055:
+                case 0x0056:
+                case 0x0057:
+                case 0x0058:
+                case 0x0059:
+                case 0x005A:
+                    target[limit++] = ( char ) ( c | lowerCase );
+                    break;
+
+                case 0x007F:
+                case 0x0080:
+                case 0x0081:
+                case 0x0082:
+                case 0x0083:
+                case 0x0084:
+                    break;
+
+                case 0x0085:
+                    target[limit] = ( char ) 0x20;
+                    break;
+
+                case 0x0086:
+                case 0x0087:
+                case 0x0088:
+                case 0x0089:
+                case 0x008A:
+                case 0x008B:
+                case 0x008C:
+                case 0x008D:
+                case 0x008E:
+                case 0x008F:
+                case 0x0090:
+                case 0x0091:
+                case 0x0092:
+                case 0x0093:
+                case 0x0094:
+                case 0x0095:
+                case 0x0096:
+                case 0x0097:
+                case 0x0098:
+                case 0x0099:
+                case 0x009A:
+                case 0x009B:
+                case 0x009C:
+                case 0x009D:
+                case 0x009E:
+                case 0x009F:
+                    break;
+
+                case 0x00A0:
+                    target[limit++] = ( char ) 0x20;
+                    break;
+
+                case 0x00AD:
+                    break;
+
+                case 0x00B5:
+                    target[limit++] = ( char ) 0x03BC;
+                    break;
+
+                case 0x00C0:
+                case 0x00C1:
+                case 0x00C2:
+                case 0x00C3:
+                case 0x00C4:
+                case 0x00C5:
+                case 0x00C6:
+                case 0x00C7:
+                case 0x00C8:
+                case 0x00C9:
+                case 0x00CA:
+                case 0x00CB:
+                case 0x00CC:
+                case 0x00CD:
+                case 0x00CE:
+                case 0x00CF:
+                case 0x00D0:
+                case 0x00D1:
+                case 0x00D2:
+                case 0x00D3:
+                case 0x00D4:
+                case 0x00D5:
+                case 0x00D6:
+                case 0x00D8:
+                case 0x00D9:
+                case 0x00DA:
+                case 0x00DB:
+                case 0x00DC:
+                case 0x00DD:
+                case 0x00DE:
+                    target[limit++] = ( char ) ( c | lowerCase );
+                    break;
+
+                case 0x00DF:
+                    target[limit++] = ( char ) 0x0073;
+                    target[limit++] = ( char ) 0x0073;
+                    break;
+
+                case 0x0100:
+                    target[limit++] = ( char ) 0x0101;
+                    break;
+
+                case 0x0102:
+                    target[limit++] = ( char ) 0x0103;
+                    break;
+
+                case 0x0104:
+                    target[limit++] = 0x0105;
+                    break;
+
+                case 0x0106:
+                    target[limit++] = 0x0107;
+                    break;
+
+                case 0x0108:
+                    target[limit++] = 0x0109;
+                    break;
+
+                case 0x010A:
+                    target[limit++] = 0x010B;
+                    break;
+
+                case 0x010C:
+                    target[limit++] = 0x010D;
+                    break;
+
+                case 0x010E:
+                    target[limit++] = 0x010F;
+                    break;
+
+                case 0x0110:
+                    target[limit++] = 0x0111;
+                    break;
+
+                case 0x0112:
+                    target[limit++] = 0x0113;
+                    break;
+
+                case 0x0114:
+                    target[limit++] = 0x0115;
+                    break;
+
+                case 0x0116:
+                    target[limit++] = 0x0117;
+                    break;
+
+                case 0x0118:
+                    target[limit++] = 0x0119;
+                    break;
+
+                case 0x011A:
+                    target[limit++] = 0x011B;
+                    break;
+
+                case 0x011C:
+                    target[limit++] = 0x011D;
+                    break;
+
+                case 0x011E:
+                    target[limit++] = 0x011F;
+                    break;
+
+                case 0x0120:
+                    target[limit++] = 0x0121;
+                    break;
+
+                case 0x0122:
+                    target[limit++] = 0x0123;
+                    break;
+
+                case 0x0124:
+                    target[limit++] = 0x0125;
+                    break;
+
+                case 0x0126:
+                    target[limit++] = 0x0127;
+                    break;
+
+                case 0x0128:
+                    target[limit++] = 0x0129;
+                    break;
+
+                case 0x012A:
+                    target[limit++] = 0x012B;
+                    break;
+
+                case 0x012C:
+                    target[limit++] = 0x012D;
+                    break;
+
+                case 0x012E:
+                    target[limit++] = 0x012F;
+                    break;
+
+                case 0x0130:
+                    target[limit++] = 0x0069;
+                    target[limit++] = 0x0307;
+                    break;
+
+                case 0x0132:
+                    target[limit++] = 0x0133;
+                    break;
+
+                case 0x0134:
+                    target[limit++] = 0x0135;
+                    break;
+
+                case 0x0136:
+                    target[limit++] = 0x0137;
+                    break;
+
+                case 0x0139:
+                    target[limit++] = 0x013A;
+                    break;
+
+                case 0x013B:
+                    target[limit++] = 0x013C;
+                    break;
+
+                case 0x013D:
+                    target[limit++] = 0x013E;
+                    break;
+
+                case 0x013F:
+                    target[limit++] = 0x0140;
+                    break;
+
+                case 0x0141:
+                    target[limit++] = 0x0142;
+                    break;
+
+                case 0x0143:
+                    target[limit++] = 0x0144;
+                    break;
+
+                case 0x0145:
+                    target[limit++] = 0x0146;
+                    break;
+
+                case 0x0147:
+                    target[limit++] = 0x0148;
+                    break;
+
+                case 0x0149:
+                    target[limit++] = 0x02BC;
+                    target[limit++] = 0x006E;
+                    break;
+
+                case 0x014A:
+                    target[limit++] = 0x014B;
+                    break;
+
+                case 0x014C:
+                    target[limit++] = 0x014D;
+                    break;
+
+                case 0x014E:
+                    target[limit++] = 0x014F;
+                    break;
+
+                case 0x0150:
+                    target[limit++] = 0x0151;
+                    break;
+
+                case 0x0152:
+                    target[limit++] = 0x0153;
+                    break;
+
+                case 0x0154:
+                    target[limit++] = 0x0155;
+                    break;
+
+                case 0x0156:
+                    target[limit++] = 0x0157;
+                    break;
+
+                case 0x0158:
+                    target[limit++] = 0x0159;
+                    break;
+
+                case 0x015A:
+                    target[limit++] = 0x015B;
+                    break;
+
+                case 0x015C:
+                    target[limit++] = 0x015D;
+                    break;
+
+                case 0x015E:
+                    target[limit++] = 0x015F;
+                    break;
+
+                case 0x0160:
+                    target[limit++] = 0x0161;
+                    break;
+
+                case 0x0162:
+                    target[limit++] = 0x0163;
+                    break;
+
+                case 0x0164:
+                    target[limit++] = 0x0165;
+                    break;
+
+                case 0x0166:
+                    target[limit++] = 0x0167;
+                    break;
+
+                case 0x0168:
+                    target[limit++] = 0x0169;
+                    break;
+
+                case 0x016A:
+                    target[limit++] = 0x016B;
+                    break;
+
+                case 0x016C:
+                    target[limit++] = 0x016D;
+                    break;
+
+                case 0x016E:
+                    target[limit++] = 0x016F;
+                    break;
+
+                case 0x0170:
+                    target[limit++] = 0x0171;
+                    break;
+
+                case 0x0172:
+                    target[limit++] = 0x0173;
+                    break;
+
+                case 0x0174:
+                    target[limit++] = 0x0175;
+                    break;
+
+                case 0x0176:
+                    target[limit++] = 0x0177;
+                    break;
+
+                case 0x0178:
+                    target[limit++] = 0x00FF;
+                    break;
+
+                case 0x0179:
+                    target[limit++] = 0x017A;
+                    break;
+
+                case 0x017B:
+                    target[limit++] = 0x017C;
+                    break;
+
+                case 0x017D:
+                    target[limit++] = 0x017E;
+                    break;
+
+                case 0x017F:
+                    target[limit++] = 0x0073;
+                    break;
+
+                case 0x0181:
+                    target[limit++] = 0x0253;
+                    break;
+
+                case 0x0182:
+                    target[limit++] = 0x0183;
+                    break;
+
+                case 0x0184:
+                    target[limit++] = 0x0185;
+                    break;
+
+                case 0x0186:
+                    target[limit++] = 0x0254;
+                    break;
+
+                case 0x0187:
+                    target[limit++] = 0x0188;
+                    break;
+
+                case 0x0189:
+                    target[limit++] = 0x0256;
+                    break;
+
+                case 0x018A:
+                    target[limit++] = 0x0257;
+                    break;
+
+                case 0x018B:
+                    target[limit++] = 0x018C;
+                    break;
+
+                case 0x018E:
+                    target[limit++] = 0x01DD;
+                    break;
+
+                case 0x018F:
+                    target[limit++] = 0x0259;
+                    break;
+
+                case 0x0190:
+                    target[limit++] = 0x025B;
+                    break;
+
+                case 0x0191:
+                    target[limit++] = 0x0192;
+                    break;
+
+                case 0x0193:
+                    target[limit++] = 0x0260;
+                    break;
+
+                case 0x0194:
+                    target[limit++] = 0x0263;
+                    break;
+
+                case 0x0196:
+                    target[limit++] = 0x0269;
+                    break;
+
+                case 0x0197:
+                    target[limit++] = 0x0268;
+                    break;
+
+                case 0x0198:
+                    target[limit++] = 0x0199;
+                    break;
+
+                case 0x019C:
+                    target[limit++] = 0x026F;
+                    break;
+
+                case 0x019D:
+                    target[limit++] = 0x0272;
+                    break;
+
+                case 0x019F:
+                    target[limit++] = 0x0275;
+                    break;
+
+                case 0x01A0:
+                    target[limit++] = 0x01A1;
+                    break;
+
+                case 0x01A2:
+                    target[limit++] = 0x01A3;
+                    break;
+
+                case 0x01A4:
+                    target[limit++] = 0x01A5;
+                    break;
+
+                case 0x01A6:
+                    target[limit++] = 0x0280;
+                    break;
+
+                case 0x01A7:
+                    target[limit++] = 0x01A8;
+                    break;
+
+                case 0x01A9:
+                    target[limit++] = 0x0283;
+                    break;
+
+                case 0x01AC:
+                    target[limit++] = 0x01AD;
+                    break;
+
+                case 0x01AE:
+                    target[limit++] = 0x0288;
+                    break;
+
+                case 0x01AF:
+                    target[limit++] = 0x01B0;
+                    break;
+
+                case 0x01B1:
+                    target[limit++] = 0x028A;
+                    break;
+
+                case 0x01B2:
+                    target[limit++] = 0x028B;
+                    break;
+
+                case 0x01B3:
+                    target[limit++] = 0x01B4;
+                    break;
+
+                case 0x01B5:
+                    target[limit++] = 0x01B6;
+                    break;
+
+                case 0x01B7:
+                    target[limit++] = 0x0292;
+                    break;
+
+                case 0x01B8:
+                    target[limit++] = 0x01B9;
+                    break;
+
+                case 0x01BC:
+                    target[limit++] = 0x01BD;
+                    break;
+
+                case 0x01C4:
+                    target[limit++] = 0x01C6;
+                    break;
+
+                case 0x01C5:
+                    target[limit++] = 0x01C6;
+                    break;
+
+                case 0x01C7:
+                    target[limit++] = 0x01C9;
+                    break;
+
+                case 0x01C8:
+                    target[limit++] = 0x01C9;
+                    break;
+
+                case 0x01CA:
+                    target[limit++] = 0x01CC;
+                    break;
+
+                case 0x01CB:
+                    target[limit++] = 0x01CC;
+                    break;
+
+                case 0x01CD:
+                    target[limit++] = 0x01CE;
+                    break;
+
+                case 0x01CF:
+                    target[limit++] = 0x01D0;
+                    break;
+
+                case 0x01D1:
+                    target[limit++] = 0x01D2;
+                    break;
+
+                case 0x01D3:
+                    target[limit++] = 0x01D4;
+                    break;
+
+                case 0x01D5:
+                    target[limit++] = 0x01D6;
+                    break;
+
+                case 0x01D7:
+                    target[limit++] = 0x01D8;
+                    break;
+
+                case 0x01D9:
+                    target[limit++] = 0x01DA;
+                    break;
+
+                case 0x01DB:
+                    target[limit++] = 0x01DC;
+                    break;
+
+                case 0x01DE:
+                    target[limit++] = 0x01DF;
+                    break;
+
+                case 0x01E0:
+                    target[limit++] = 0x01E1;
+                    break;
+
+                case 0x01E2:
+                    target[limit++] = 0x01E3;
+                    break;
+
+                case 0x01E4:
+                    target[limit++] = 0x01E5;
+                    break;
+
+                case 0x01E6:
+                    target[limit++] = 0x01E7;
+                    break;
+
+                case 0x01E8:
+                    target[limit++] = 0x01E9;
+                    break;
+
+                case 0x01EA:
+                    target[limit++] = 0x01EB;
+                    break;
+
+                case 0x01EC:
+                    target[limit++] = 0x01ED;
+                    break;
+
+                case 0x01EE:
+                    target[limit++] = 0x01EF;
+                    break;
+
+                case 0x01F0:
+                    target[limit++] = 0x006A;
+                    target[limit++] = 0x030C;
+                    break;
+
+                case 0x01F1:
+                    target[limit++] = 0x01F3;
+                    break;
+
+                case 0x01F2:
+                    target[limit++] = 0x01F3;
+                    break;
+
+                case 0x01F4:
+                    target[limit++] = 0x01F5;
+                    break;
+
+                case 0x01F6:
+                    target[limit++] = 0x0195;
+                    break;
+
+                case 0x01F7:
+                    target[limit++] = 0x01BF;
+                    break;
+
+                case 0x01F8:
+                    target[limit++] = 0x01F9;
+                    break;
+
+                case 0x01FA:
+                    target[limit++] = 0x01FB;
+                    break;
+
+                case 0x01FC:
+                    target[limit++] = 0x01FD;
+                    break;
+
+                case 0x01FE:
+                    target[limit++] = 0x01FF;
+                    break;
+
+                case 0x0200:
+                    target[limit++] = 0x0201;
+                    break;
+
+                case 0x0202:
+                    target[limit++] = 0x0203;
+                    break;
+
+                case 0x0204:
+                    target[limit++] = 0x0205;
+                    break;
+
+                case 0x0206:
+                    target[limit++] = 0x0207;
+                    break;
+
+                case 0x0208:
+                    target[limit++] = 0x0209;
+                    break;
+
+                case 0x020A:
+                    target[limit++] = 0x020B;
+                    break;
+
+                case 0x020C:
+                    target[limit++] = 0x020D;
+                    break;
+
+                case 0x020E:
+                    target[limit++] = 0x020F;
+                    break;
+
+                case 0x0210:
+                    target[limit++] = 0x0211;
+                    break;
+
+                case 0x0212:
+                    target[limit++] = 0x0213;
+                    break;
+
+                case 0x0214:
+                    target[limit++] = 0x0215;
+                    break;
+
+                case 0x0216:
+                    target[limit++] = 0x0217;
+                    break;
+
+                case 0x0218:
+                    target[limit++] = 0x0219;
+                    break;
+
+                case 0x021A:
+                    target[limit++] = 0x021B;
+                    break;
+
+                case 0x021C:
+                    target[limit++] = 0x021D;
+                    break;
+
+                case 0x021E:
+                    target[limit++] = 0x021F;
+                    break;
+
+                case 0x0220:
+                    target[limit++] = 0x019E;
+                    break;
+
+                case 0x0222:
+                    target[limit++] = 0x0223;
+                    break;
+
+                case 0x0224:
+                    target[limit++] = 0x0225;
+                    break;
+
+                case 0x0226:
+                    target[limit++] = 0x0227;
+                    break;
+
+                case 0x0228:
+                    target[limit++] = 0x0229;
+                    break;
+
+                case 0x022A:
+                    target[limit++] = 0x022B;
+                    break;
+
+                case 0x022C:
+                    target[limit++] = 0x022D;
+                    break;
+
+                case 0x022E:
+                    target[limit++] = 0x022F;
+                    break;
+
+                case 0x0230:
+                    target[limit++] = 0x0231;
+                    break;
+
+                case 0x0232:
+                    target[limit++] = 0x0233;
+                    break;
+
+                case 0x0345:
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x034F:
+                    break;
+
+                case 0x037A:
+                    target[limit++] = 0x0020;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x0386:
+                    target[limit++] = 0x03AC;
+                    break;
+
+                case 0x0388:
+                    target[limit++] = 0x03AD;
+                    break;
+
+                case 0x0389:
+                    target[limit++] = 0x03AE;
+                    break;
+
+                case 0x038A:
+                    target[limit++] = 0x03AF;
+                    break;
+
+                case 0x038C:
+                    target[limit++] = 0x03CC;
+                    break;
+
+                case 0x038E:
+                    target[limit++] = 0x03CD;
+                    break;
+
+                case 0x038F:
+                    target[limit++] = 0x03CE;
+                    break;
+
+                case 0x0390:
+                    target[limit++] = 0x03B9;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0301;
+                    break;
+
+                case 0x0391:
+                    target[limit++] = 0x03B1;
+                    break;
+
+                case 0x0392:
+                    target[limit++] = 0x03B2;
+                    break;
+
+                case 0x0393:
+                    target[limit++] = 0x03B3;
+                    break;
+
+                case 0x0394:
+                    target[limit++] = 0x03B4;
+                    break;
+
+                case 0x0395:
+                    target[limit++] = 0x03B5;
+                    break;
+
+                case 0x0396:
+                    target[limit++] = 0x03B6;
+                    break;
+
+                case 0x0397:
+                    target[limit++] = 0x03B7;
+                    break;
+
+                case 0x0398:
+                    target[limit++] = 0x03B8;
+                    break;
+
+                case 0x0399:
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x039A:
+                    target[limit++] = 0x03BA;
+                    break;
+
+                case 0x039B:
+                    target[limit++] = 0x03BB;
+                    break;
+
+                case 0x039C:
+                    target[limit++] = 0x03BC;
+                    break;
+
+                case 0x039D:
+                    target[limit++] = 0x03BD;
+                    break;
+
+                case 0x039E:
+                    target[limit++] = 0x03BE;
+                    break;
+
+                case 0x039F:
+                    target[limit++] = 0x03BF;
+                    break;
+
+                case 0x03A0:
+                    target[limit++] = 0x03C0;
+                    break;
+
+                case 0x03A1:
+                    target[limit++] = 0x03C1;
+                    break;
+
+                case 0x03A3:
+                    target[limit++] = 0x03C3;
+                    break;
+
+                case 0x03A4:
+                    target[limit++] = 0x03C4;
+                    break;
+
+                case 0x03A5:
+                    target[limit++] = 0x03C5;
+                    break;
+
+                case 0x03A6:
+                    target[limit++] = 0x03C6;
+                    break;
+
+                case 0x03A7:
+                    target[limit++] = 0x03C7;
+                    break;
+
+                case 0x03A8:
+                    target[limit++] = 0x03C8;
+                    break;
+
+                case 0x03A9:
+                    target[limit++] = 0x03C9;
+                    break;
+
+                case 0x03AA:
+                    target[limit++] = 0x03CA;
+                    break;
+
+                case 0x03AB:
+                    target[limit++] = 0x03CB;
+                    break;
+
+                case 0x03B0:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0301;
+                    break;
+
+                case 0x03C2:
+                    target[limit++] = 0x03C3;
+                    break;
+
+                case 0x03D0:
+                    target[limit++] = 0x03B2;
+                    break;
+
+                case 0x03D1:
+                    target[limit++] = 0x03B8;
+                    break;
+
+                case 0x03D2:
+                    target[limit++] = 0x03C5;
+                    break;
+
+                case 0x03D3:
+                    target[limit++] = 0x03CD;
+                    break;
+
+                case 0x03D4:
+                    target[limit++] = 0x03CB;
+                    break;
+
+                case 0x03D5:
+                    target[limit++] = 0x03C6;
+                    break;
+
+                case 0x03D6:
+                    target[limit++] = 0x03C0;
+                    break;
+
+                case 0x03D8:
+                    target[limit++] = 0x03D9;
+                    break;
+
+                case 0x03DA:
+                    target[limit++] = 0x03DB;
+                    break;
+
+                case 0x03DC:
+                    target[limit++] = 0x03DD;
+                    break;
+
+                case 0x03DE:
+                    target[limit++] = 0x03DF;
+                    break;
+
+                case 0x03E0:
+                    target[limit++] = 0x03E1;
+                    break;
+
+                case 0x03E2:
+                    target[limit++] = 0x03E3;
+                    break;
+
+                case 0x03E4:
+                    target[limit++] = 0x03E5;
+                    break;
+
+                case 0x03E6:
+                    target[limit++] = 0x03E7;
+                    break;
+
+                case 0x03E8:
+                    target[limit++] = 0x03E9;
+                    break;
+
+                case 0x03EA:
+                    target[limit++] = 0x03EB;
+                    break;
+
+                case 0x03EC:
+                    target[limit++] = 0x03ED;
+                    break;
+
+                case 0x03EE:
+                    target[limit++] = 0x03EF;
+                    break;
+
+                case 0x03F0:
+                    target[limit++] = 0x03BA;
+                    break;
+
+                case 0x03F1:
+                    target[limit++] = 0x03C1;
+                    break;
+
+                case 0x03F2:
+                    target[limit++] = 0x03C3;
+                    break;
+
+                case 0x03F4:
+                    target[limit++] = 0x03B8;
+                    break;
+
+                case 0x03F5:
+                    target[limit++] = 0x03B5;
+                    break;
+
+                case 0x0400:
+                    target[limit++] = 0x0450;
+                    break;
+
+                case 0x0401:
+                    target[limit++] = 0x0451;
+                    break;
+
+                case 0x0402:
+                    target[limit++] = 0x0452;
+                    break;
+
+                case 0x0403:
+                    target[limit++] = 0x0453;
+                    break;
+
+                case 0x0404:
+                    target[limit++] = 0x0454;
+                    break;
+
+                case 0x0405:
+                    target[limit++] = 0x0455;
+                    break;
+
+                case 0x0406:
+                    target[limit++] = 0x0456;
+                    break;
+
+                case 0x0407:
+                    target[limit++] = 0x0457;
+                    break;
+
+                case 0x0408:
+                    target[limit++] = 0x0458;
+                    break;
+
+                case 0x0409:
+                    target[limit++] = 0x0459;
+                    break;
+
+                case 0x040A:
+                    target[limit++] = 0x045A;
+                    break;
+
+                case 0x040B:
+                    target[limit++] = 0x045B;
+                    break;
+
+                case 0x040C:
+                    target[limit++] = 0x045C;
+                    break;
+
+                case 0x040D:
+                    target[limit++] = 0x045D;
+                    break;
+
+                case 0x040E:
+                    target[limit++] = 0x045E;
+                    break;
+
+                case 0x040F:
+                    target[limit++] = 0x045F;
+                    break;
+
+                case 0x0410:
+                    target[limit++] = 0x0430;
+                    break;
+
+                case 0x0411:
+                    target[limit++] = 0x0431;
+                    break;
+
+                case 0x0412:
+                    target[limit++] = 0x0432;
+                    break;
+
+                case 0x0413:
+                    target[limit++] = 0x0433;
+                    break;
+
+                case 0x0414:
+                    target[limit++] = 0x0434;
+                    break;
+
+                case 0x0415:
+                    target[limit++] = 0x0435;
+                    break;
+
+                case 0x0416:
+                    target[limit++] = 0x0436;
+                    break;
+
+                case 0x0417:
+                    target[limit++] = 0x0437;
+                    break;
+
+                case 0x0418:
+                    target[limit++] = 0x0438;
+                    break;
+
+                case 0x0419:
+                    target[limit++] = 0x0439;
+                    break;
+
+                case 0x041A:
+                    target[limit++] = 0x043A;
+                    break;
+
+                case 0x041B:
+                    target[limit++] = 0x043B;
+                    break;
+
+                case 0x041C:
+                    target[limit++] = 0x043C;
+                    break;
+
+                case 0x041D:
+                    target[limit++] = 0x043D;
+                    break;
+
+                case 0x041E:
+                    target[limit++] = 0x043E;
+                    break;
+
+                case 0x041F:
+                    target[limit++] = 0x043F;
+                    break;
+
+                case 0x0420:
+                    target[limit++] = 0x0440;
+                    break;
+
+                case 0x0421:
+                    target[limit++] = 0x0441;
+                    break;
+
+                case 0x0422:
+                    target[limit++] = 0x0442;
+                    break;
+
+                case 0x0423:
+                    target[limit++] = 0x0443;
+                    break;
+
+                case 0x0424:
+                    target[limit++] = 0x0444;
+                    break;
+
+                case 0x0425:
+                    target[limit++] = 0x0445;
+                    break;
+
+                case 0x0426:
+                    target[limit++] = 0x0446;
+                    break;
+
+                case 0x0427:
+                    target[limit++] = 0x0447;
+                    break;
+
+                case 0x0428:
+                    target[limit++] = 0x0448;
+                    break;
+
+                case 0x0429:
+                    target[limit++] = 0x0449;
+                    break;
+
+                case 0x042A:
+                    target[limit++] = 0x044A;
+                    break;
+
+                case 0x042B:
+                    target[limit++] = 0x044B;
+                    break;
+
+                case 0x042C:
+                    target[limit++] = 0x044C;
+                    break;
+
+                case 0x042D:
+                    target[limit++] = 0x044D;
+                    break;
+
+                case 0x042E:
+                    target[limit++] = 0x044E;
+                    break;
+
+                case 0x042F:
+                    target[limit++] = 0x044F;
+                    break;
+
+                case 0x0460:
+                    target[limit++] = 0x0461;
+                    break;
+
+                case 0x0462:
+                    target[limit++] = 0x0463;
+                    break;
+
+                case 0x0464:
+                    target[limit++] = 0x0465;
+                    break;
+
+                case 0x0466:
+                    target[limit++] = 0x0467;
+                    break;
+
+                case 0x0468:
+                    target[limit++] = 0x0469;
+                    break;
+
+                case 0x046A:
+                    target[limit++] = 0x046B;
+                    break;
+
+                case 0x046C:
+                    target[limit++] = 0x046D;
+                    break;
+
+                case 0x046E:
+                    target[limit++] = 0x046F;
+                    break;
+
+                case 0x0470:
+                    target[limit++] = 0x0471;
+                    break;
+
+                case 0x0472:
+                    target[limit++] = 0x0473;
+                    break;
+
+                case 0x0474:
+                    target[limit++] = 0x0475;
+                    break;
+
+                case 0x0476:
+                    target[limit++] = 0x0477;
+                    break;
+
+                case 0x0478:
+                    target[limit++] = 0x0479;
+                    break;
+
+                case 0x047A:
+                    target[limit++] = 0x047B;
+                    break;
+
+                case 0x047C:
+                    target[limit++] = 0x047D;
+                    break;
+
+                case 0x047E:
+                    target[limit++] = 0x047F;
+                    break;
+
+                case 0x0480:
+                    target[limit++] = 0x0481;
+                    break;
+
+                case 0x048A:
+                    target[limit++] = 0x048B;
+                    break;
+
+                case 0x048C:
+                    target[limit++] = 0x048D;
+                    break;
+
+                case 0x048E:
+                    target[limit++] = 0x048F;
+                    break;
+
+                case 0x0490:
+                    target[limit++] = 0x0491;
+                    break;
+
+                case 0x0492:
+                    target[limit++] = 0x0493;
+                    break;
+
+                case 0x0494:
+                    target[limit++] = 0x0495;
+                    break;
+
+                case 0x0496:
+                    target[limit++] = 0x0497;
+                    break;
+
+                case 0x0498:
+                    target[limit++] = 0x0499;
+                    break;
+
+                case 0x049A:
+                    target[limit++] = 0x049B;
+                    break;
+
+                case 0x049C:
+                    target[limit++] = 0x049D;
+                    break;
+
+                case 0x049E:
+                    target[limit++] = 0x049F;
+                    break;
+
+                case 0x04A0:
+                    target[limit++] = 0x04A1;
+                    break;
+
+                case 0x04A2:
+                    target[limit++] = 0x04A3;
+                    break;
+
+                case 0x04A4:
+                    target[limit++] = 0x04A5;
+                    break;
+
+                case 0x04A6:
+                    target[limit++] = 0x04A7;
+                    break;
+
+                case 0x04A8:
+                    target[limit++] = 0x04A9;
+                    break;
+
+                case 0x04AA:
+                    target[limit++] = 0x04AB;
+                    break;
+
+                case 0x04AC:
+                    target[limit++] = 0x04AD;
+                    break;
+
+                case 0x04AE:
+                    target[limit++] = 0x04AF;
+                    break;
+
+                case 0x04B0:
+                    target[limit++] = 0x04B1;
+                    break;
+
+                case 0x04B2:
+                    target[limit++] = 0x04B3;
+                    break;
+
+                case 0x04B4:
+                    target[limit++] = 0x04B5;
+                    break;
+
+                case 0x04B6:
+                    target[limit++] = 0x04B7;
+                    break;
+
+                case 0x04B8:
+                    target[limit++] = 0x04B9;
+                    break;
+
+                case 0x04BA:
+                    target[limit++] = 0x04BB;
+                    break;
+
+                case 0x04BC:
+                    target[limit++] = 0x04BD;
+                    break;
+
+                case 0x04BE:
+                    target[limit++] = 0x04BF;
+                    break;
+
+                case 0x04C1:
+                    target[limit++] = 0x04C2;
+                    break;
+
+                case 0x04C3:
+                    target[limit++] = 0x04C4;
+                    break;
+
+                case 0x04C5:
+                    target[limit++] = 0x04C6;
+                    break;
+
+                case 0x04C7:
+                    target[limit++] = 0x04C8;
+                    break;
+
+                case 0x04C9:
+                    target[limit++] = 0x04CA;
+                    break;
+
+                case 0x04CB:
+                    target[limit++] = 0x04CC;
+                    break;
+
+                case 0x04CD:
+                    target[limit++] = 0x04CE;
+                    break;
+
+                case 0x04D0:
+                    target[limit++] = 0x04D1;
+                    break;
+
+                case 0x04D2:
+                    target[limit++] = 0x04D3;
+                    break;
+
+                case 0x04D4:
+                    target[limit++] = 0x04D5;
+                    break;
+
+                case 0x04D6:
+                    target[limit++] = 0x04D7;
+                    break;
+
+                case 0x04D8:
+                    target[limit++] = 0x04D9;
+                    break;
+
+                case 0x04DA:
+                    target[limit++] = 0x04DB;
+                    break;
+
+                case 0x04DC:
+                    target[limit++] = 0x04DD;
+                    break;
+
+                case 0x04DE:
+                    target[limit++] = 0x04DF;
+                    break;
+
+                case 0x04E0:
+                    target[limit++] = 0x04E1;
+                    break;
+
+                case 0x04E2:
+                    target[limit++] = 0x04E3;
+                    break;
+
+                case 0x04E4:
+                    target[limit++] = 0x04E5;
+                    break;
+
+                case 0x04E6:
+                    target[limit++] = 0x04E7;
+                    break;
+
+                case 0x04E8:
+                    target[limit++] = 0x04E9;
+                    break;
+
+                case 0x04EA:
+                    target[limit++] = 0x04EB;
+                    break;
+
+                case 0x04EC:
+                    target[limit++] = 0x04ED;
+                    break;
+
+                case 0x04EE:
+                    target[limit++] = 0x04EF;
+                    break;
+
+                case 0x04F0:
+                    target[limit++] = 0x04F1;
+                    break;
+
+                case 0x04F2:
+                    target[limit++] = 0x04F3;
+                    break;
+
+                case 0x04F4:
+                    target[limit++] = 0x04F5;
+                    break;
+
+                case 0x04F8:
+                    target[limit++] = 0x04F9;
+                    break;
+
+                case 0x0500:
+                    target[limit++] = 0x0501;
+                    break;
+
+                case 0x0502:
+                    target[limit++] = 0x0503;
+                    break;
+
+                case 0x0504:
+                    target[limit++] = 0x0505;
+                    break;
+
+                case 0x0506:
+                    target[limit++] = 0x0507;
+                    break;
+
+                case 0x0508:
+                    target[limit++] = 0x0509;
+                    break;
+
+                case 0x050A:
+                    target[limit++] = 0x050B;
+                    break;
+
+                case 0x050C:
+                    target[limit++] = 0x050D;
+                    break;
+
+                case 0x050E:
+                    target[limit++] = 0x050F;
+                    break;
+
+                case 0x0531:
+                    target[limit++] = 0x0561;
+                    break;
+
+                case 0x0532:
+                    target[limit++] = 0x0562;
+                    break;
+
+                case 0x0533:
+                    target[limit++] = 0x0563;
+                    break;
+
+                case 0x0534:
+                    target[limit++] = 0x0564;
+                    break;
+
+                case 0x0535:
+                    target[limit++] = 0x0565;
+                    break;
+
+                case 0x0536:
+                    target[limit++] = 0x0566;
+                    break;
+
+                case 0x0537:
+                    target[limit++] = 0x0567;
+                    break;
+
+                case 0x0538:
+                    target[limit++] = 0x0568;
+                    break;
+
+                case 0x0539:
+                    target[limit++] = 0x0569;
+                    break;
+
+                case 0x053A:
+                    target[limit++] = 0x056A;
+                    break;
+
+                case 0x053B:
+                    target[limit++] = 0x056B;
+                    break;
+
+                case 0x053C:
+                    target[limit++] = 0x056C;
+                    break;
+
+                case 0x053D:
+                    target[limit++] = 0x056D;
+                    break;
+
+                case 0x053E:
+                    target[limit++] = 0x056E;
+                    break;
+
+                case 0x053F:
+                    target[limit++] = 0x056F;
+                    break;
+
+                case 0x0540:
+                    target[limit++] = 0x0570;
+                    break;
+
+                case 0x0541:
+                    target[limit++] = 0x0571;
+                    break;
+
+                case 0x0542:
+                    target[limit++] = 0x0572;
+                    break;
+
+                case 0x0543:
+                    target[limit++] = 0x0573;
+                    break;
+
+                case 0x0544:
+                    target[limit++] = 0x0574;
+                    break;
+
+                case 0x0545:
+                    target[limit++] = 0x0575;
+                    break;
+
+                case 0x0546:
+                    target[limit++] = 0x0576;
+                    break;
+
+                case 0x0547:
+                    target[limit++] = 0x0577;
+                    break;
+
+                case 0x0548:
+                    target[limit++] = 0x0578;
+                    break;
+
+                case 0x0549:
+                    target[limit++] = 0x0579;
+                    break;
+
+                case 0x054A:
+                    target[limit++] = 0x057A;
+                    break;
+
+                case 0x054B:
+                    target[limit++] = 0x057B;
+                    break;
+
+                case 0x054C:
+                    target[limit++] = 0x057C;
+                    break;
+
+                case 0x054D:
+                    target[limit++] = 0x057D;
+                    break;
+
+                case 0x054E:
+                    target[limit++] = 0x057E;
+                    break;
+
+                case 0x054F:
+                    target[limit++] = 0x057F;
+                    break;
+
+                case 0x0550:
+                    target[limit++] = 0x0580;
+                    break;
+
+                case 0x0551:
+                    target[limit++] = 0x0581;
+                    break;
+
+                case 0x0552:
+                    target[limit++] = 0x0582;
+                    break;
+
+                case 0x0553:
+                    target[limit++] = 0x0583;
+                    break;
+
+                case 0x0554:
+                    target[limit++] = 0x0584;
+                    break;
+
+                case 0x0555:
+                    target[limit++] = 0x0585;
+                    break;
+
+                case 0x0556:
+                    target[limit++] = 0x0586;
+                    break;
+
+                case 0x0587:
+                    target[limit++] = 0x0565;
+                    target[limit++] = 0x0582;
+                    break;
+
+                case 0x06DD:
+                    break;
+
+                case 0x070F:
+                    break;
+
+                case 0x1680:
+                    target[limit++] = 0x0020;
+                    break;
+
+                case 0x1806:
+                    break;
+
+                case 0x180B:
+                case 0x180C:
+                case 0x180D:
+                case 0x180E:
+                    break;
+
+                case 0x1E00:
+                    target[limit++] = 0x1E01;
+                    break;
+
+                case 0x1E02:
+                    target[limit++] = 0x1E03;
+                    break;
+
+                case 0x1E04:
+                    target[limit++] = 0x1E05;
+                    break;
+
+                case 0x1E06:
+                    target[limit++] = 0x1E07;
+                    break;
+
+                case 0x1E08:
+                    target[limit++] = 0x1E09;
+                    break;
+
+                case 0x1E0A:
+                    target[limit++] = 0x1E0B;
+                    break;
+
+                case 0x1E0C:
+                    target[limit++] = 0x1E0D;
+                    break;
+
+                case 0x1E0E:
+                    target[limit++] = 0x1E0F;
+                    break;
+
+                case 0x1E10:
+                    target[limit++] = 0x1E11;
+                    break;
+
+                case 0x1E12:
+                    target[limit++] = 0x1E13;
+                    break;
+
+                case 0x1E14:
+                    target[limit++] = 0x1E15;
+                    break;
+
+                case 0x1E16:
+                    target[limit++] = 0x1E17;
+                    break;
+
+                case 0x1E18:
+                    target[limit++] = 0x1E19;
+                    break;
+
+                case 0x1E1A:
+                    target[limit++] = 0x1E1B;
+                    break;
+
+                case 0x1E1C:
+                    target[limit++] = 0x1E1D;
+                    break;
+
+                case 0x1E1E:
+                    target[limit++] = 0x1E1F;
+                    break;
+
+                case 0x1E20:
+                    target[limit++] = 0x1E21;
+                    break;
+
+                case 0x1E22:
+                    target[limit++] = 0x1E23;
+                    break;
+
+                case 0x1E24:
+                    target[limit++] = 0x1E25;
+                    break;
+
+                case 0x1E26:
+                    target[limit++] = 0x1E27;
+                    break;
+
+                case 0x1E28:
+                    target[limit++] = 0x1E29;
+                    break;
+
+                case 0x1E2A:
+                    target[limit++] = 0x1E2B;
+                    break;
+
+                case 0x1E2C:
+                    target[limit++] = 0x1E2D;
+                    break;
+
+                case 0x1E2E:
+                    target[limit++] = 0x1E2F;
+                    break;
+
+                case 0x1E30:
+                    target[limit++] = 0x1E31;
+                    break;
+
+                case 0x1E32:
+                    target[limit++] = 0x1E33;
+                    break;
+
+                case 0x1E34:
+                    target[limit++] = 0x1E35;
+                    break;
+
+                case 0x1E36:
+                    target[limit++] = 0x1E37;
+                    break;
+
+                case 0x1E38:
+                    target[limit++] = 0x1E39;
+                    break;
+
+                case 0x1E3A:
+                    target[limit++] = 0x1E3B;
+                    break;
+
+                case 0x1E3C:
+                    target[limit++] = 0x1E3D;
+                    break;
+
+                case 0x1E3E:
+                    target[limit++] = 0x1E3F;
+                    break;
+
+                case 0x1E40:
+                    target[limit++] = 0x1E41;
+                    break;
+
+                case 0x1E42:
+                    target[limit++] = 0x1E43;
+                    break;
+
+                case 0x1E44:
+                    target[limit++] = 0x1E45;
+                    break;
+
+                case 0x1E46:
+                    target[limit++] = 0x1E47;
+                    break;
+
+                case 0x1E48:
+                    target[limit++] = 0x1E49;
+                    break;
+
+                case 0x1E4A:
+                    target[limit++] = 0x1E4B;
+                    break;
+
+                case 0x1E4C:
+                    target[limit++] = 0x1E4D;
+                    break;
+
+                case 0x1E4E:
+                    target[limit++] = 0x1E4F;
+                    break;
+
+                case 0x1E50:
+                    target[limit++] = 0x1E51;
+                    break;
+
+                case 0x1E52:
+                    target[limit++] = 0x1E53;
+                    break;
+
+                case 0x1E54:
+                    target[limit++] = 0x1E55;
+                    break;
+
+                case 0x1E56:
+                    target[limit++] = 0x1E57;
+                    break;
+
+                case 0x1E58:
+                    target[limit++] = 0x1E59;
+                    break;
+
+                case 0x1E5A:
+                    target[limit++] = 0x1E5B;
+                    break;
+
+                case 0x1E5C:
+                    target[limit++] = 0x1E5D;
+                    break;
+
+                case 0x1E5E:
+                    target[limit++] = 0x1E5F;
+                    break;
+
+                case 0x1E60:
+                    target[limit++] = 0x1E61;
+                    break;
+
+                case 0x1E62:
+                    target[limit++] = 0x1E63;
+                    break;
+
+                case 0x1E64:
+                    target[limit++] = 0x1E65;
+                    break;
+
+                case 0x1E66:
+                    target[limit++] = 0x1E67;
+                    break;
+
+                case 0x1E68:
+                    target[limit++] = 0x1E69;
+                    break;
+
+                case 0x1E6A:
+                    target[limit++] = 0x1E6B;
+                    break;
+
+                case 0x1E6C:
+                    target[limit++] = 0x1E6D;
+                    break;
+
+                case 0x1E6E:
+                    target[limit++] = 0x1E6F;
+                    break;
+
+                case 0x1E70:
+                    target[limit++] = 0x1E71;
+                    break;
+
+                case 0x1E72:
+                    target[limit++] = 0x1E73;
+                    break;
+
+                case 0x1E74:
+                    target[limit++] = 0x1E75;
+                    break;
+
+                case 0x1E76:
+                    target[limit++] = 0x1E77;
+                    break;
+
+                case 0x1E78:
+                    target[limit++] = 0x1E79;
+                    break;
+
+                case 0x1E7A:
+                    target[limit++] = 0x1E7B;
+                    break;
+
+                case 0x1E7C:
+                    target[limit++] = 0x1E7D;
+                    break;
+
+                case 0x1E7E:
+                    target[limit++] = 0x1E7F;
+                    break;
+
+                case 0x1E80:
+                    target[limit++] = 0x1E81;
+                    break;
+
+                case 0x1E82:
+                    target[limit++] = 0x1E83;
+                    break;
+
+                case 0x1E84:
+                    target[limit++] = 0x1E85;
+                    break;
+
+                case 0x1E86:
+                    target[limit++] = 0x1E87;
+                    break;
+
+                case 0x1E88:
+                    target[limit++] = 0x1E89;
+                    break;
+
+                case 0x1E8A:
+                    target[limit++] = 0x1E8B;
+                    break;
+
+                case 0x1E8C:
+                    target[limit++] = 0x1E8D;
+                    break;
+
+                case 0x1E8E:
+                    target[limit++] = 0x1E8F;
+                    break;
+
+                case 0x1E90:
+                    target[limit++] = 0x1E91;
+                    break;
+
+                case 0x1E92:
+                    target[limit++] = 0x1E93;
+                    break;
+
+                case 0x1E94:
+                    target[limit++] = 0x1E95;
+                    break;
+
+                case 0x1E96:
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x0331;
+                    break;
+
+                case 0x1E97:
+                    target[limit++] = 0x0074;
+                    target[limit++] = 0x0308;
+                    break;
+
+                case 0x1E98:
+                    target[limit++] = 0x0077;
+                    target[limit++] = 0x030A;
+                    break;
+
+                case 0x1E99:
+                    target[limit++] = 0x0079;
+                    target[limit++] = 0x030A;
+                    break;
+
+                case 0x1E9A:
+                    target[limit++] = 0x0061;
+                    target[limit++] = 0x02BE;
+                    break;
+
+                case 0x1E9B:
+                    target[limit++] = 0x1E61;
+                    break;
+
+                case 0x1EA0:
+                    target[limit++] = 0x1EA1;
+                    break;
+
+                case 0x1EA2:
+                    target[limit++] = 0x1EA3;
+                    break;
+
+                case 0x1EA4:
+                    target[limit++] = 0x1EA5;
+                    break;
+
+                case 0x1EA6:
+                    target[limit++] = 0x1EA7;
+                    break;
+
+                case 0x1EA8:
+                    target[limit++] = 0x1EA9;
+                    break;
+
+                case 0x1EAA:
+                    target[limit++] = 0x1EAB;
+                    break;
+
+                case 0x1EAC:
+                    target[limit++] = 0x1EAD;
+                    break;
+
+                case 0x1EAE:
+                    target[limit++] = 0x1EAF;
+                    break;
+
+                case 0x1EB0:
+                    target[limit++] = 0x1EB1;
+                    break;
+
+                case 0x1EB2:
+                    target[limit++] = 0x1EB3;
+                    break;
+
+                case 0x1EB4:
+                    target[limit++] = 0x1EB5;
+                    break;
+
+                case 0x1EB6:
+                    target[limit++] = 0x1EB7;
+                    break;
+
+                case 0x1EB8:
+                    target[limit++] = 0x1EB9;
+                    break;
+
+                case 0x1EBA:
+                    target[limit++] = 0x1EBB;
+                    break;
+
+                case 0x1EBC:
+                    target[limit++] = 0x1EBD;
+                    break;
+
+                case 0x1EBE:
+                    target[limit++] = 0x1EBF;
+                    break;
+
+                case 0x1EC0:
+                    target[limit++] = 0x1EC1;
+                    break;
+
+                case 0x1EC2:
+                    target[limit++] = 0x1EC3;
+                    break;
+
+                case 0x1EC4:
+                    target[limit++] = 0x1EC5;
+                    break;
+
+                case 0x1EC6:
+                    target[limit++] = 0x1EC7;
+                    break;
+
+                case 0x1EC8:
+                    target[limit++] = 0x1EC9;
+                    break;
+
+                case 0x1ECA:
+                    target[limit++] = 0x1ECB;
+                    break;
+
+                case 0x1ECC:
+                    target[limit++] = 0x1ECD;
+                    break;
+
+                case 0x1ECE:
+                    target[limit++] = 0x1ECF;
+                    break;
+
+                case 0x1ED0:
+                    target[limit++] = 0x1ED1;
+                    break;
+
+                case 0x1ED2:
+                    target[limit++] = 0x1ED3;
+                    break;
+
+                case 0x1ED4:
+                    target[limit++] = 0x1ED5;
+                    break;
+
+                case 0x1ED6:
+                    target[limit++] = 0x1ED7;
+                    break;
+
+                case 0x1ED8:
+                    target[limit++] = 0x1ED9;
+                    break;
+
+                case 0x1EDA:
+                    target[limit++] = 0x1EDB;
+                    break;
+
+                case 0x1EDC:
+                    target[limit++] = 0x1EDD;
+                    break;
+
+                case 0x1EDE:
+                    target[limit++] = 0x1EDF;
+                    break;
+
+                case 0x1EE0:
+                    target[limit++] = 0x1EE1;
+                    break;
+
+                case 0x1EE2:
+                    target[limit++] = 0x1EE3;
+                    break;
+
+                case 0x1EE4:
+                    target[limit++] = 0x1EE5;
+                    break;
+
+                case 0x1EE6:
+                    target[limit++] = 0x1EE7;
+                    break;
+
+                case 0x1EE8:
+                    target[limit++] = 0x1EE9;
+                    break;
+
+                case 0x1EEA:
+                    target[limit++] = 0x1EEB;
+                    break;
+
+                case 0x1EEC:
+                    target[limit++] = 0x1EED;
+                    break;
+
+                case 0x1EEE:
+                    target[limit++] = 0x1EEF;
+                    break;
+
+                case 0x1EF0:
+                    target[limit++] = 0x1EF1;
+                    break;
+
+                case 0x1EF2:
+                    target[limit++] = 0x1EF3;
+                    break;
+
+                case 0x1EF4:
+                    target[limit++] = 0x1EF5;
+                    break;
+
+                case 0x1EF6:
+                    target[limit++] = 0x1EF7;
+                    break;
+
+                case 0x1EF8:
+                    target[limit++] = 0x1EF9;
+                    break;
+
+                case 0x1F08:
+                    target[limit++] = 0x1F00;
+                    break;
+
+                case 0x1F09:
+                    target[limit++] = 0x1F01;
+                    break;
+
+                case 0x1F0A:
+                    target[limit++] = 0x1F02;
+                    break;
+
+                case 0x1F0B:
+                    target[limit++] = 0x1F03;
+                    break;
+
+                case 0x1F0C:
+                    target[limit++] = 0x1F04;
+                    break;
+
+                case 0x1F0D:
+                    target[limit++] = 0x1F05;
+                    break;
+
+                case 0x1F0E:
+                    target[limit++] = 0x1F06;
+                    break;
+
+                case 0x1F0F:
+                    target[limit++] = 0x1F07;
+                    break;
+
+                case 0x1F18:
+                    target[limit++] = 0x1F10;
+                    break;
+
+                case 0x1F19:
+                    target[limit++] = 0x1F11;
+                    break;
+
+                case 0x1F1A:
+                    target[limit++] = 0x1F12;
+                    break;
+
+                case 0x1F1B:
+                    target[limit++] = 0x1F13;
+                    break;
+
+                case 0x1F1C:
+                    target[limit++] = 0x1F14;
+                    break;
+
+                case 0x1F1D:
+                    target[limit++] = 0x1F15;
+                    break;
+
+                case 0x1F28:
+                    target[limit++] = 0x1F20;
+                    break;
+
+                case 0x1F29:
+                    target[limit++] = 0x1F21;
+                    break;
+
+                case 0x1F2A:
+                    target[limit++] = 0x1F22;
+                    break;
+
+                case 0x1F2B:
+                    target[limit++] = 0x1F23;
+                    break;
+
+                case 0x1F2C:
+                    target[limit++] = 0x1F24;
+                    break;
+
+                case 0x1F2D:
+                    target[limit++] = 0x1F25;
+                    break;
+
+                case 0x1F2E:
+                    target[limit++] = 0x1F26;
+                    break;
+
+                case 0x1F2F:
+                    target[limit++] = 0x1F27;
+                    break;
+
+                case 0x1F38:
+                    target[limit++] = 0x1F30;
+                    break;
+
+                case 0x1F39:
+                    target[limit++] = 0x1F31;
+                    break;
+
+                case 0x1F3A:
+                    target[limit++] = 0x1F32;
+                    break;
+
+                case 0x1F3B:
+                    target[limit++] = 0x1F33;
+                    break;
+
+                case 0x1F3C:
+                    target[limit++] = 0x1F34;
+                    break;
+
+                case 0x1F3D:
+                    target[limit++] = 0x1F35;
+                    break;
+
+                case 0x1F3E:
+                    target[limit++] = 0x1F36;
+                    break;
+
+                case 0x1F3F:
+                    target[limit++] = 0x1F37;
+                    break;
+
+                case 0x1F48:
+                    target[limit++] = 0x1F40;
+                    break;
+
+                case 0x1F49:
+                    target[limit++] = 0x1F41;
+                    break;
+
+                case 0x1F4A:
+                    target[limit++] = 0x1F42;
+                    break;
+
+                case 0x1F4B:
+                    target[limit++] = 0x1F43;
+                    break;
+
+                case 0x1F4C:
+                    target[limit++] = 0x1F44;
+                    break;
+
+                case 0x1F4D:
+                    target[limit++] = 0x1F45;
+                    break;
+
+                case 0x1F50:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0313;
+                    break;
+
+                case 0x1F52:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0313;
+                    target[limit++] = 0x0300;
+                    break;
+
+                case 0x1F54:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0313;
+                    target[limit++] = 0x0301;
+                    break;
+
+                case 0x1F56:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0313;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1F59:
+                    target[limit++] = 0x1F51;
+                    break;
+
+                case 0x1F5B:
+                    target[limit++] = 0x1F53;
+                    break;
+
+                case 0x1F5D:
+                    target[limit++] = 0x1F55;
+                    break;
+
+                case 0x1F5F:
+                    target[limit++] = 0x1F57;
+                    break;
+
+                case 0x1F68:
+                    target[limit++] = 0x1F60;
+                    break;
+
+                case 0x1F69:
+                    target[limit++] = 0x1F61;
+                    break;
+
+                case 0x1F6A:
+                    target[limit++] = 0x1F62;
+                    break;
+
+                case 0x1F6B:
+                    target[limit++] = 0x1F63;
+                    break;
+
+                case 0x1F6C:
+                    target[limit++] = 0x1F64;
+                    break;
+
+                case 0x1F6D:
+                    target[limit++] = 0x1F65;
+                    break;
+
+                case 0x1F6E:
+                    target[limit++] = 0x1F66;
+                    break;
+
+                case 0x1F6F:
+                    target[limit++] = 0x1F67;
+                    break;
+
+                case 0x1F80:
+                    target[limit++] = 0x1F00;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F81:
+                    target[limit++] = 0x1F01;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F82:
+                    target[limit++] = 0x1F02;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F83:
+                    target[limit++] = 0x1F03;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F84:
+                    target[limit++] = 0x1F04;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F85:
+                    target[limit++] = 0x1F05;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F86:
+                    target[limit++] = 0x1F06;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F87:
+                    target[limit++] = 0x1F07;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F88:
+                    target[limit++] = 0x1F00;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F89:
+                    target[limit++] = 0x1F01;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F8A:
+                    target[limit++] = 0x1F02;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F8B:
+                    target[limit++] = 0x1F03;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F8C:
+                    target[limit++] = 0x1F04;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F8D:
+                    target[limit++] = 0x1F05;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F8E:
+                    target[limit++] = 0x1F06;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F8F:
+                    target[limit++] = 0x1F07;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F90:
+                    target[limit++] = 0x1F20;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F91:
+                    target[limit++] = 0x1F21;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F92:
+                    target[limit++] = 0x1F22;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F93:
+                    target[limit++] = 0x1F23;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F94:
+                    target[limit++] = 0x1F24;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F95:
+                    target[limit++] = 0x1F25;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F96:
+                    target[limit++] = 0x1F26;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F97:
+                    target[limit++] = 0x1F27;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F98:
+                    target[limit++] = 0x1F20;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F99:
+                    target[limit++] = 0x1F21;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F9A:
+                    target[limit++] = 0x1F22;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F9B:
+                    target[limit++] = 0x1F23;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F9C:
+                    target[limit++] = 0x1F24;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F9D:
+                    target[limit++] = 0x1F25;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F9E:
+                    target[limit++] = 0x1F26;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1F9F:
+                    target[limit++] = 0x1F27;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA0:
+                    target[limit++] = 0x1F60;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA1:
+                    target[limit++] = 0x1F61;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA2:
+                    target[limit++] = 0x1F62;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA3:
+                    target[limit++] = 0x1F63;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA4:
+                    target[limit++] = 0x1F64;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA5:
+                    target[limit++] = 0x1F65;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA6:
+                    target[limit++] = 0x1F66;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA7:
+                    target[limit++] = 0x1F67;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA8:
+                    target[limit++] = 0x1F60;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FA9:
+                    target[limit++] = 0x1F61;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FAA:
+                    target[limit++] = 0x1F62;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FAB:
+                    target[limit++] = 0x1F63;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FAC:
+                    target[limit++] = 0x1F64;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FAD:
+                    target[limit++] = 0x1F65;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FAE:
+                    target[limit++] = 0x1F66;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FAF:
+                    target[limit++] = 0x1F67;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FB2:
+                    target[limit++] = 0x1F70;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FB3:
+                    target[limit++] = 0x03B1;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FB4:
+                    target[limit++] = 0x03AC;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FB6:
+                    target[limit++] = 0x03B1;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1FB7:
+                    target[limit++] = 0x03B1;
+                    target[limit++] = 0x0342;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FB8:
+                    target[limit++] = 0x1FB0;
+                    break;
+
+                case 0x1FB9:
+                    target[limit++] = 0x1FB1;
+                    break;
+
+                case 0x1FBA:
+                    target[limit++] = 0x1F70;
+                    break;
+
+                case 0x1FBB:
+                    target[limit++] = 0x1F71;
+                    break;
+
+                case 0x1FBC:
+                    target[limit++] = 0x03B1;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FBE:
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FC2:
+                    target[limit++] = 0x1F74;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FC3:
+                    target[limit++] = 0x03B7;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FC4:
+                    target[limit++] = 0x03AE;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FC6:
+                    target[limit++] = 0x03B7;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1FC7:
+                    target[limit++] = 0x03B7;
+                    target[limit++] = 0x0342;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FC8:
+                    target[limit++] = 0x1F72;
+                    break;
+
+                case 0x1FC9:
+                    target[limit++] = 0x1F73;
+                    break;
+
+                case 0x1FCA:
+                    target[limit++] = 0x1F74;
+                    break;
+
+                case 0x1FCB:
+                    target[limit++] = 0x1F75;
+                    break;
+
+                case 0x1FCC:
+                    target[limit++] = 0x03B7;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FD2:
+                    target[limit++] = 0x03B9;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0300;
+                    break;
+
+                case 0x1FD3:
+                    target[limit++] = 0x03B9;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0301;
+                    break;
+
+                case 0x1FD6:
+                    target[limit++] = 0x03B9;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1FD7:
+                    target[limit++] = 0x03B9;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1FD8:
+                    target[limit++] = 0x1FD0;
+                    break;
+
+                case 0x1FD9:
+                    target[limit++] = 0x1FD1;
+                    break;
+
+                case 0x1FDA:
+                    target[limit++] = 0x1F76;
+                    break;
+
+                case 0x1FDB:
+                    target[limit++] = 0x1F77;
+                    break;
+
+                case 0x1FE2:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0300;
+                    break;
+
+                case 0x1FE3:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0301;
+                    break;
+
+                case 0x1FE4:
+                    target[limit++] = 0x03C1;
+                    target[limit++] = 0x0313;
+                    break;
+
+                case 0x1FE6:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1FE7:
+                    target[limit++] = 0x03C5;
+                    target[limit++] = 0x0308;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1FE8:
+                    target[limit++] = 0x1FE0;
+                    break;
+
+                case 0x1FE9:
+                    target[limit++] = 0x1FE1;
+                    break;
+
+                case 0x1FEA:
+                    target[limit++] = 0x1F7A;
+                    break;
+
+                case 0x1FEB:
+                    target[limit++] = 0x1F7B;
+                    break;
+
+                case 0x1FEC:
+                    target[limit++] = 0x1FE5;
+                    break;
+
+                case 0x1FF2:
+                    target[limit++] = 0x1F7C;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FF3:
+                    target[limit++] = 0x03C9;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FF4:
+                    target[limit++] = 0x03CE;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FF6:
+                    target[limit++] = 0x03C9;
+                    target[limit++] = 0x0342;
+                    break;
+
+                case 0x1FF7:
+                    target[limit++] = 0x03C9;
+                    target[limit++] = 0x0342;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x1FF8:
+                    target[limit++] = 0x1F78;
+                    break;
+
+                case 0x1FF9:
+                    target[limit++] = 0x1F79;
+                    break;
+
+                case 0x1FFA:
+                    target[limit++] = 0x1F7C;
+                    break;
+
+                case 0x1FFB:
+                    target[limit++] = 0x1F7D;
+                    break;
+
+                case 0x1FFC:
+                    target[limit++] = 0x03C9;
+                    target[limit++] = 0x03B9;
+                    break;
+
+                case 0x2000:
+                case 0x2001:
+                case 0x2002:
+                case 0x2003:
+                case 0x2004:
+                case 0x2005:
+                case 0x2006:
+                case 0x2007:
+                case 0x2008:
+                case 0x2009:
+                case 0x200A:
+                    target[limit++] = 0x0020;
+                    break;
+
+                case 0x200B:
+                case 0x200C:
+                case 0x200D:
+                case 0x200E:
+                case 0x200F:
+                    break;
+
+                case 0x2028:
+                case 0x2029:
+                    target[limit++] = 0x0020;
+                    break;
+
+                case 0x202A:
+                case 0x202B:
+                case 0x202C:
+                case 0x202D:
+                case 0x202E:
+                    break;
+
+                case 0x202F:
+                    target[limit++] = 0x0020;
+                    break;
+
+                case 0x205F:
+                    target[limit++] = 0x0020;
+                    break;
+
+                case 0x2060:
+                case 0x2061:
+                case 0x2062:
+                case 0x2063:
+                    break;
+
+                case 0x206A:
+                case 0x206B:
+                case 0x206C:
+                case 0x206D:
+                case 0x206E:
+                case 0x206F:
+                    break;
+
+                case 0x20A8:
+                    target[limit++] = 0x0072;
+                    target[limit++] = 0x0073;
+                    break;
+
+                case 0x2102:
+                    target[limit++] = 0x0063;
+                    break;
+
+                case 0x2103:
+                    target[limit++] = 0x00B0;
+                    target[limit++] = 0x0063;
+                    break;
+
+                case 0x2107:
+                    target[limit++] = 0x025B;
+                    break;
+
+                case 0x2109:
+                    target[limit++] = 0x00B0;
+                    target[limit++] = 0x0066;
+                    break;
+
+                case 0x210B:
+                    target[limit++] = 0x0068;
+                    break;
+
+                case 0x210C:
+                    target[limit++] = 0x0068;
+                    break;
+
+                case 0x210D:
+                    target[limit++] = 0x0068;
+                    break;
+
+                case 0x2110:
+                    target[limit++] = 0x0069;
+                    break;
+
+                case 0x2111:
+                    target[limit++] = 0x0069;
+                    break;
+
+                case 0x2112:
+                    target[limit++] = 0x006C;
+                    break;
+
+                case 0x2115:
+                    target[limit++] = 0x006E;
+                    break;
+
+                case 0x2116:
+                    target[limit++] = 0x006E;
+                    target[limit++] = 0x006F;
+                    break;
+
+                case 0x2119:
+                    target[limit++] = 0x0070;
+                    break;
+
+                case 0x211A:
+                    target[limit++] = 0x0071;
+                    break;
+
+                case 0x211B:
+                    target[limit++] = 0x0072;
+                    break;
+
+                case 0x211C:
+                    target[limit++] = 0x0072;
+                    break;
+
+                case 0x211D:
+                    target[limit++] = 0x0072;
+                    break;
+
+                case 0x2120:
+                    target[limit++] = 0x0073;
+                    target[limit++] = 0x006D;
+                    break;
+
+                case 0x2121:
+                    target[limit++] = 0x0074;
+                    target[limit++] = 0x0065;
+                    target[limit++] = 0x006C;
+                    break;
+
+                case 0x2122:
+                    target[limit++] = 0x0074;
+                    target[limit++] = 0x006D;
+                    break;
+
+                case 0x2124:
+                    target[limit++] = 0x007A;
+                    break;
+
+                case 0x2126:
+                    target[limit++] = 0x03C9;
+                    break;
+
+                case 0x2128:
+                    target[limit++] = 0x007A;
+                    break;
+
+                case 0x212A:
+                    target[limit++] = 0x006B;
+                    break;
+
+                case 0x212B:
+                    target[limit++] = 0x00E5;
+                    break;
+
+                case 0x212C:
+                    target[limit++] = 0x0062;
+                    break;
+
+                case 0x212D:
+                    target[limit++] = 0x0063;
+                    break;
+
+                case 0x2130:
+                    target[limit++] = 0x0065;
+                    break;
+
+                case 0x2131:
+                    target[limit++] = 0x0066;
+                    break;
+
+                case 0x2133:
+                    target[limit++] = 0x006D;
+                    break;
+
+                case 0x213E:
+                    target[limit++] = 0x03B3;
+                    break;
+
+                case 0x213F:
+                    target[limit++] = 0x03C0;
+                    break;
+
+                case 0x2145:
+                    target[limit++] = 0x0064;
+                    break;
+
+                case 0x2160:
+                    target[limit++] = 0x2170;
+                    break;
+
+                case 0x2161:
+                    target[limit++] = 0x2171;
+                    break;
+
+                case 0x2162:
+                    target[limit++] = 0x2172;
+                    break;
+
+                case 0x2163:
+                    target[limit++] = 0x2173;
+                    break;
+
+                case 0x2164:
+                    target[limit++] = 0x2174;
+                    break;
+
+                case 0x2165:
+                    target[limit++] = 0x2175;
+                    break;
+
+                case 0x2166:
+                    target[limit++] = 0x2176;
+                    break;
+
+                case 0x2167:
+                    target[limit++] = 0x2177;
+                    break;
+
+                case 0x2168:
+                    target[limit++] = 0x2178;
+                    break;
+
+                case 0x2169:
+                    target[limit++] = 0x2179;
+                    break;
+
+                case 0x216A:
+                    target[limit++] = 0x217A;
+                    break;
+
+                case 0x216B:
+                    target[limit++] = 0x217B;
+                    break;
+
+                case 0x216C:
+                    target[limit++] = 0x217C;
+                    break;
+
+                case 0x216D:
+                    target[limit++] = 0x217D;
+                    break;
+
+                case 0x216E:
+                    target[limit++] = 0x217E;
+                    break;
+
+                case 0x216F:
+                    target[limit++] = 0x217F;
+                    break;
+
+                case 0x24B6:
+                    target[limit++] = 0x24D0;
+                    break;
+
+                case 0x24B7:
+                    target[limit++] = 0x24D1;
+                    break;
+
+                case 0x24B8:
+                    target[limit++] = 0x24D2;
+                    break;
+
+                case 0x24B9:
+                    target[limit++] = 0x24D3;
+                    break;
+
+                case 0x24BA:
+                    target[limit++] = 0x24D4;
+                    break;
+
+                case 0x24BB:
+                    target[limit++] = 0x24D5;
+                    break;
+
+                case 0x24BC:
+                    target[limit++] = 0x24D6;
+                    break;
+
+                case 0x24BD:
+                    target[limit++] = 0x24D7;
+                    break;
+
+                case 0x24BE:
+                    target[limit++] = 0x24D8;
+                    break;
+
+                case 0x24BF:
+                    target[limit++] = 0x24D9;
+                    break;
+
+                case 0x24C0:
+                    target[limit++] = 0x24DA;
+                    break;
+
+                case 0x24C1:
+                    target[limit++] = 0x24DB;
+                    break;
+
+                case 0x24C2:
+                    target[limit++] = 0x24DC;
+                    break;
+
+                case 0x24C3:
+                    target[limit++] = 0x24DD;
+                    break;
+
+                case 0x24C4:
+                    target[limit++] = 0x24DE;
+                    break;
+
+                case 0x24C5:
+                    target[limit++] = 0x24DF;
+                    break;
+
+                case 0x24C6:
+                    target[limit++] = 0x24E0;
+                    break;
+
+                case 0x24C7:
+                    target[limit++] = 0x24E1;
+                    break;
+
+                case 0x24C8:
+                    target[limit++] = 0x24E2;
+                    break;
+
+                case 0x24C9:
+                    target[limit++] = 0x24E3;
+                    break;
+
+                case 0x24CA:
+                    target[limit++] = 0x24E4;
+                    break;
+
+                case 0x24CB:
+                    target[limit++] = 0x24E5;
+                    break;
+
+                case 0x24CC:
+                    target[limit++] = 0x24E6;
+                    break;
+
+                case 0x24CD:
+                    target[limit++] = 0x24E7;
+                    break;
+
+                case 0x24CE:
+                    target[limit++] = 0x24E8;
+                    break;
+
+                case 0x24CF:
+                    target[limit++] = 0x24E9;
+                    break;
+
+                case 0x3000:
+                    target[limit++] = 0x0020;
+                    break;
+
+                case 0x3371:
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x3373:
+                    target[limit++] = 0x0061;
+                    target[limit++] = 0x0075;
+                    break;
+
+                case 0x3375:
+                    target[limit++] = 0x006F;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x3380:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x3381:
+                    target[limit++] = 0x006E;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x3382:
+                    target[limit++] = 0x03BC;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x3383:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x3384:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x3385:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x0062;
+                    break;
+
+                case 0x3386:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0062;
+                    break;
+
+                case 0x3387:
+                    target[limit++] = 0x0067;
+                    target[limit++] = 0x0062;
+                    break;
+
+                case 0x338A:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0066;
+                    break;
+
+                case 0x338B:
+                    target[limit++] = 0x006E;
+                    target[limit++] = 0x0066;
+                    break;
+
+                case 0x338C:
+                    target[limit++] = 0x03BC;
+                    target[limit++] = 0x0066;
+                    break;
+
+                case 0x3390:
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x007A;
+                    break;
+
+                case 0x3391:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x007A;
+                    break;
+
+                case 0x3392:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x007A;
+                    break;
+
+                case 0x3393:
+                    target[limit++] = 0x0067;
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x007A;
+                    break;
+
+                case 0x3394:
+                    target[limit++] = 0x0074;
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x007A;
+                    break;
+
+                case 0x33A9:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x33AA:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x33AB:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x33AC:
+                    target[limit++] = 0x0067;
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0061;
+                    break;
+
+                case 0x33B4:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x33B5:
+                    target[limit++] = 0x006E;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x33B6:
+                    target[limit++] = 0x03BC;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x33B7:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x33B8:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x33B9:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x33BA:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0077;
+                    break;
+
+                case 0x33BB:
+                    target[limit++] = 0x006E;
+                    target[limit++] = 0x0077;
+                    break;
+
+                case 0x33BC:
+                    target[limit++] = 0x03BC;
+                    target[limit++] = 0x0077;
+                    break;
+
+                case 0x33BD:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0077;
+                    break;
+
+                case 0x33BE:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x0077;
+                    break;
+
+                case 0x33BF:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x0077;
+                    break;
+
+                case 0x33C0:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x03C9;
+                    break;
+
+                case 0x33C1:
+                    target[limit++] = 0x006D;
+                    target[limit++] = 0x03C9;
+                    break;
+
+                case 0x33C3:
+                    target[limit++] = 0x0062;
+                    target[limit++] = 0x0071;
+                    break;
+
+                case 0x33C6:
+                    target[limit++] = 0x0063;
+                    target[limit++] = 0x2215;
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x0067;
+                    break;
+
+                case 0x33C7:
+                    target[limit++] = 0x0063;
+                    target[limit++] = 0x006F;
+                    target[limit++] = 0x002E;
+                    break;
+
+                case 0x33C8:
+                    target[limit++] = 0x0064;
+                    target[limit++] = 0x0062;
+                    break;
+
+                case 0x33C9:
+                    target[limit++] = 0x0067;
+                    target[limit++] = 0x0079;
+                    break;
+
+                case 0x33CB:
+                    target[limit++] = 0x0068;
+                    target[limit++] = 0x0070;
+                    break;
+
+                case 0x33CD:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x006B;
+                    break;
+
+                case 0x33CE:
+                    target[limit++] = 0x006B;
+                    target[limit++] = 0x006D;
+                    break;
+
+                case 0x33D7:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0068;
+                    break;
+
+                case 0x33D9:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x006D;
+                    break;
+
+                case 0x33DA:
+                    target[limit++] = 0x0070;
+                    target[limit++] = 0x0072;
+                    break;
+
+                case 0x33DC:
+                    target[limit++] = 0x0073;
+                    target[limit++] = 0x0076;
+                    break;
+
+                case 0x33DD:
+                    target[limit++] = 0x0077;
+                    target[limit++] = 0x0062;
+                    break;
+
+                case 0xFB00:
+                    target[limit++] = 0x0066;
+                    target[limit++] = 0x0066;
+                    break;
+
+                case 0xFB01:
+                    target[limit++] = 0x0066;
+                    target[limit++] = 0x0069;
+                    break;
+
+                case 0xFB02:
+                    target[limit++] = 0x0066;
+                    target[limit++] = 0x006C;
+                    break;
+
+                case 0xFB03:
+                    target[limit++] = 0x0066;
+                    target[limit++] = 0x0066;
+                    target[limit++] = 0x0069;
+                    break;
+
+                case 0xFB04:
+                    target[limit++] = 0x0066;
+                    target[limit++] = 0x0066;
+                    target[limit++] = 0x006C;
+                    break;
+
+                case 0xFB05:
+                    target[limit++] = 0x0073;
+                    target[limit++] = 0x0074;
+                    break;
+
+                case 0xFB06:
+                    target[limit++] = 0x0073;
+                    target[limit++] = 0x0074;
+                    break;
+
+                case 0xFB13:
+                    target[limit++] = 0x0574;
+                    target[limit++] = 0x0576;
+                    break;
+
+                case 0xFB14:
+                    target[limit++] = 0x0574;
+                    target[limit++] = 0x0565;
+                    break;
+
+                case 0xFB15:
+                    target[limit++] = 0x0574;
+                    target[limit++] = 0x056B;
+                    break;
+
+                case 0xFB16:
+                    target[limit++] = 0x057E;
+                    target[limit++] = 0x0576;
+                    break;
+
+                case 0xFB17:
+                    target[limit++] = 0x0574;
+                    target[limit++] = 0x056D;
+                    break;
+
+                case 0xFE00:
+                case 0xFE01:
+                case 0xFE02:
+                case 0xFE03:
+                case 0xFE04:
+                case 0xFE05:
+                case 0xFE06:
+                case 0xFE07:
+                case 0xFE08:
+                case 0xFE09:
+                case 0xFE0A:
+                case 0xFE0B:
+                case 0xFE0C:
+                case 0xFE0D:
+                case 0xFE0E:
+                case 0xFE0F:
+                    break;
+
+                case 0xFEFF:
+                    break;
+
+                case 0xFF21:
+                    target[limit++] = 0xFF41;
+                    break;
+
+                case 0xFF22:
+                    target[limit++] = 0xFF42;
+                    break;
+
+                case 0xFF23:
+                    target[limit++] = 0xFF43;
+                    break;
+
+                case 0xFF24:
+                    target[limit++] = 0xFF44;
+                    break;
+
+                case 0xFF25:
+                    target[limit++] = 0xFF45;
+                    break;
+
+                case 0xFF26:
+                    target[limit++] = 0xFF46;
+                    break;
+
+                case 0xFF27:
+                    target[limit++] = 0xFF47;
+                    break;
+
+                case 0xFF28:
+                    target[limit++] = 0xFF48;
+                    break;
+
+                case 0xFF29:
+                    target[limit++] = 0xFF49;
+                    break;
+
+                case 0xFF2A:
+                    target[limit++] = 0xFF4A;
+                    break;
+
+                case 0xFF2B:
+                    target[limit++] = 0xFF4B;
+                    break;
+
+                case 0xFF2C:
+                    target[limit++] = 0xFF4C;
+                    break;
+
+                case 0xFF2D:
+                    target[limit++] = 0xFF4D;
+                    break;
+
+                case 0xFF2E:
+                    target[limit++] = 0xFF4E;
+                    break;
+
+                case 0xFF2F:
+                    target[limit++] = 0xFF4F;
+                    break;
+
+                case 0xFF30:
+                    target[limit++] = 0xFF50;
+                    break;
+
+                case 0xFF31:
+                    target[limit++] = 0xFF51;
+                    break;
+
+                case 0xFF32:
+                    target[limit++] = 0xFF52;
+                    break;
+
+                case 0xFF33:
+                    target[limit++] = 0xFF53;
+                    break;
+
+                case 0xFF34:
+                    target[limit++] = 0xFF54;
+                    break;
+
+                case 0xFF35:
+                    target[limit++] = 0xFF55;
+                    break;
+
+                case 0xFF36:
+                    target[limit++] = 0xFF56;
+                    break;
+
+                case 0xFF37:
+                    target[limit++] = 0xFF57;
+                    break;
+
+                case 0xFF38:
+                    target[limit++] = 0xFF58;
+                    break;
+
+                case 0xFF39:
+                    target[limit++] = 0xFF59;
+                    break;
+
+                case 0xFF3A:
+                    target[limit++] = 0xFF5A;
+                    break;
+
+                case 0xFFF9:
+                case 0xFFFA:
+                case 0xFFFB:
+                case 0xFFFC:
+                    break;
+
+                default:
+                    // First, eliminate surrogates, and replace them by FFFD char
+                    if ( ( c >= 0xD800 ) && ( c <= 0xDFFF ) )
+                    {
+                        target[limit++] = ( char ) 0xFFFD;
+                        break;
+                    }
+
+                    target[limit++] = c;
+                    break;
+            }
+        }
+
+        return limit;
+    }
+
+
+    /**
+     * 
+     * Prohibit characters described in RFC 4518 :
+     *  - Table A.1 of RFC 3454
+     *  - Table C.3 of RFC 3454
+     *  - Table C.4 of RFC 3454
+     *  - Table C.5 of RFC 3454
+     *  - Table C.8 of RFC 3454
+     *  - character U-FFFD
+     *
+     * @param c The char to analyze
+     * @throws InvalidCharacterException If any character is prohibited
+     */
+    private static void checkProhibited( char c ) throws InvalidCharacterException
+    {
+        // Shortcut chars above 0x0221
+        if ( c < 0x221 )
+        {
+            return;
+        }
+
+        // RFC 3454, Table A.1
+        switch ( c )
+        {
+            case 0x0221:
+            case 0x038B:
+            case 0x038D:
+            case 0x03A2:
+            case 0x03CF:
+            case 0x0487:
+            case 0x04CF:
+            case 0x0560:
+            case 0x0588:
+            case 0x05A2:
+            case 0x05BA:
+            case 0x0620:
+            case 0x06FF:
+            case 0x070E:
+            case 0x0904:
+            case 0x0984:
+            case 0x09A9:
+            case 0x09B1:
+            case 0x09BD:
+            case 0x09DE:
+            case 0x0A29:
+            case 0x0A31:
+            case 0x0A34:
+            case 0x0A37:
+            case 0x0A3D:
+            case 0x0A5D:
+            case 0x0A84:
+            case 0x0A8C:
+            case 0x0A8E:
+            case 0x0A92:
+            case 0x0AA9:
+            case 0x0AB1:
+            case 0x0AB4:
+            case 0x0AC6:
+            case 0x0ACA:
+            case 0x0B04:
+            case 0x0B29:
+            case 0x0B31:
+            case 0x0B5E:
+            case 0x0B84:
+            case 0x0B91:
+            case 0x0B9B:
+            case 0x0B9D:
+            case 0x0BB6:
+            case 0x0BC9:
+            case 0x0C04:
+            case 0x0C0D:
+            case 0x0C11:
+            case 0x0C29:
+            case 0x0C34:
+            case 0x0C45:
+            case 0x0C49:
+            case 0x0C84:
+            case 0x0C8D:
+            case 0x0C91:
+            case 0x0CA9:
+            case 0x0CB4:
+            case 0x0CC5:
+            case 0x0CC9:
+            case 0x0CDF:
+            case 0x0D04:
+            case 0x0D0D:
+            case 0x0D11:
+            case 0x0D29:
+            case 0x0D49:
+            case 0x0D84:
+            case 0x0DB2:
+            case 0x0DBC:
+            case 0x0DD5:
+            case 0x0DD7:
+            case 0x0E83:
+            case 0x0E89:
+            case 0x0E98:
+            case 0x0EA0:
+            case 0x0EA4:
+            case 0x0EA6:
+            case 0x0EAC:
+            case 0x0EBA:
+            case 0x0EC5:
+            case 0x0EC7:
+            case 0x0F48:
+            case 0x0F98:
+            case 0x0FBD:
+            case 0x1022:
+            case 0x1028:
+            case 0x102B:
+            case 0x1207:
+            case 0x1247:
+            case 0x1249:
+            case 0x1257:
+            case 0x1259:
+            case 0x1287:
+            case 0x1289:
+            case 0x12AF:
+            case 0x12B1:
+            case 0x12BF:
+            case 0x12C1:
+            case 0x12CF:
+            case 0x12D7:
+            case 0x12EF:
+            case 0x130F:
+            case 0x1311:
+            case 0x131F:
+            case 0x1347:
+            case 0x170D:
+            case 0x176D:
+            case 0x1771:
+            case 0x180F:
+            case 0x1F58:
+            case 0x1F5A:
+            case 0x1F5C:
+            case 0x1F5E:
+            case 0x1FB5:
+            case 0x1FC5:
+            case 0x1FDC:
+            case 0x1FF5:
+            case 0x1FFF:
+            case 0x24FF:
+            case 0x2618:
+            case 0x2705:
+            case 0x2728:
+            case 0x274C:
+            case 0x274E:
+            case 0x2757:
+            case 0x27B0:
+            case 0x2E9A:
+            case 0x3040:
+            case 0x318F:
+            case 0x32FF:
+            case 0x33FF:
+            case 0xFB37:
+            case 0xFB3D:
+            case 0xFB3F:
+            case 0xFB42:
+            case 0xFB45:
+            case 0xFE53:
+            case 0xFE67:
+            case 0xFE75:
+            case 0xFF00:
+            case 0xFFE7:
+                throw new InvalidCharacterException( c );
+            default:
+                break;
+        }
+
+        // RFC 3454, Table A.1, intervals
+        if ( ( c >= 0x0234 ) && ( c <= 0x024F ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x02AE ) && ( c <= 0x02AF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x02EF ) && ( c <= 0x02FF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0350 ) && ( c <= 0x035F ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0370 ) && ( c <= 0x0373 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0376 ) && ( c <= 0x0379 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x037B ) && ( c <= 0x037D ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x037F ) && ( c <= 0x0383 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x03F7 ) && ( c <= 0x03FF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x04F6 ) && ( c <= 0x04F7 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x04FA ) && ( c <= 0x04FF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0510 ) && ( c <= 0x0530 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0557 ) && ( c <= 0x0558 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x058B ) && ( c <= 0x0590 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x05C5 ) && ( c <= 0x05CF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x05EB ) && ( c <= 0x05EF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x05F5 ) && ( c <= 0x060B ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x060D ) && ( c <= 0x061A ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x061C ) && ( c <= 0x061E ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x063B ) && ( c <= 0x063F ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0656 ) && ( c <= 0x065F ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x06EE ) && ( c <= 0x06EF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x072D ) && ( c <= 0x072F ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x074B ) && ( c <= 0x077F ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x07B2 ) && ( c <= 0x0900 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x093A ) && ( c <= 0x093B ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x094E ) && ( c <= 0x094F ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0955 ) && ( c <= 0x0957 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0971 ) && ( c <= 0x0980 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x098D ) && ( c <= 0x098E ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0991 ) && ( c <= 0x0992 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09B3 ) && ( c <= 0x09B5 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09BA ) && ( c <= 0x09BB ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09C5 ) && ( c <= 0x09C6 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09C9 ) && ( c <= 0x09CA ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09CE ) && ( c <= 0x09D6 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09D8 ) && ( c <= 0x09DB ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09E4 ) && ( c <= 0x09E5 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x09FB ) && ( c <= 0x0A01 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A03 ) && ( c <= 0x0A04 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A0B ) && ( c <= 0x0A0E ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A11 ) && ( c <= 0x0A12 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A3A ) && ( c <= 0x0A3B ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A43 ) && ( c <= 0x0A46 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A49 ) && ( c <= 0x0A4A ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A4E ) && ( c <= 0x0A58 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A5F ) && ( c <= 0x0A65 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0A75 ) && ( c <= 0x0A80 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0ABA ) && ( c <= 0x0ABB ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0ACE ) && ( c <= 0x0ACF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0AD1 ) && ( c <= 0x0ADF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0AE1 ) && ( c <= 0x0AE5 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0AF0 ) && ( c <= 0x0B00 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B0D ) && ( c <= 0x0B0E ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B11 ) && ( c <= 0x0B12 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B34 ) && ( c <= 0x0B35 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B3A ) && ( c <= 0x0B3B ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B44 ) && ( c <= 0x0B46 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B49 ) && ( c <= 0x0B4A ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B4E ) && ( c <= 0x0B55 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B58 ) && ( c <= 0x0B5B ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B62 ) && ( c <= 0x0B65 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B71 ) && ( c <= 0x0B81 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B8B ) && ( c <= 0x0B8D ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0B96 ) && ( c <= 0x0B98 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BA0 ) && ( c <= 0x0BA2 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BA5 ) && ( c <= 0x0BA7 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BAB ) && ( c <= 0x0BAD ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BBA ) && ( c <= 0x0BBD ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BC3 ) && ( c <= 0x0BC5 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BCE ) && ( c <= 0x0BD6 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BD8 ) && ( c <= 0x0BE6 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c >= 0x0BF3 ) && ( c <= 0x0C00 ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        // RFC 3454, Table C.3
+        if ( ( c >= 0xE000 ) && ( c <= 0xF8FF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        // RFC 3454, Table C.4
+        if ( ( c >= 0xFDD0 ) && ( c <= 0xFDEF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        if ( ( c == 0xFFFE ) || ( c == 0xFFFF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        // RFC 3454, Table C.5 (Surrogates)
+        if ( ( c >= 0xD800 ) && ( c <= 0xDFFF ) )
+        {
+            throw new InvalidCharacterException( c );
+        }
+
+        // RFC 3454, Table C.8 
+        switch ( c )
+        {
+            case 0x0340: // COMBINING GRAVE TONE MARK
+            case 0x0341: // COMBINING ACUTE TONE MARK
+            case 0x200E: // LEFT-TO-RIGHT MARK
+            case 0x200F: // RIGHT-TO-LEFT MARK
+            case 0x202A: // LEFT-TO-RIGHT EMBEDDING
+            case 0x202B: // RIGHT-TO-LEFT EMBEDDING
+            case 0x202C: // POP DIRECTIONAL FORMATTING
+            case 0x202D: // LEFT-TO-RIGHT OVERRIDE
+            case 0x202E: // RIGHT-TO-LEFT OVERRIDE
+            case 0x206A: // INHIBIT SYMMETRIC SWAPPING
+            case 0x206B: // ACTIVATE SYMMETRIC SWAPPING
+            case 0x206C: // INHIBIT ARABIC FORM SHAPING
+            case 0x206D: // ACTIVATE ARABIC FORM SHAPING
+            case 0x206E: // NATIONAL DIGIT SHAPES
+            case 0x206F: // NOMINAL DIGIT SHAPES
+                throw new InvalidCharacterException( c );
+            default:
+                break;
+        }
+
+        if ( c == 0xFFFD )
+        {
+            throw new InvalidCharacterException( c );
+        }
+    }
+
+
+    /**
+     * 
+     * Remove all bidirectionnal chars. This is not really clear in RFC 4518
+     * what we should do with bidi chars :
+     * "Bidirectional characters are ignored."
+     * 
+     * But it's not explained what is a bidi chars...
+     * 
+     * So this method just do nothing atm.
+     *
+     * @param str The string where bidi chars are to be removed
+     * @return The cleaned string
+     */
+    public static String bidi( String str )
+    {
+        return str;
+    }
+
+
+    /**
+     * 
+     * Remove all bidirectionnal chars. This is not really clear in RFC 4518
+     * what we should do with bidi chars :
+     * "Bidirectional characters are ignored."
+     * 
+     * But it's not explained what is a bidi chars...
+     * 
+     * So this method just do nothing atm.
+     *
+     * @param array The char array where bidi chars are to be removed
+     * @return The cleaned StringBuilder
+     */
+    public static StringBuilder bidi( char[] array )
+    {
+        StringBuilder sb = new StringBuilder( array == null ? 0 : array.length );
+
+        if ( array != null )
+        {
+            sb.append( array );
+        }
+
+        return sb;
+    }
+
+
+    /**
+     * 
+     * Remove all insignifiant chars in a Telephone Number :
+     * Hyphen and spaces. 
+     * 
+     * For instance, the following telephone number :
+     * "+ (33) 1-123--456  789"
+     * will be trasnformed to :
+     * "+(33)1123456789"
+     *
+     * @param str The telephone number
+     * @return The modified telephone number String
+     */
+    private static String insignifiantCharTelephoneNumber( String str )
+    {
+        if ( Strings.isEmpty( str ) )
+        {
+            return "";
+        }
+
+        char[] array = str.toCharArray();
+
+        boolean isSpaceOrHyphen = false;
+        char soh = '\0';
+        int pos = 0;
+
+        for ( char c : array )
+        {
+            switch ( c )
+            {
+                case 0x0020: // SPACE
+                case 0x002D: // HYPHEN-MINUS
+                case 0x058A: // ARMENIAN HYPHEN
+                case 0x2010: // HYPHEN
+                case 0x2011: // NON-BREAKING HYPHEN
+                case 0x2212: // MINUS SIGN
+                case 0xFE63: // SMALL HYPHEN-MINUS
+                case 0xFF0D: // FULLWIDTH HYPHEN-MINUS
+                    soh = c;
+                    break;
+
+                default:
+                    if ( isSpaceOrHyphen && isCombiningMark( c ) )
+                    {
+                        array[pos++] = soh;
+                        isSpaceOrHyphen = false;
+                    }
+
+                    array[pos++] = c;
+                    break;
+            }
+        }
+
+        return new String( array, 0, pos );
+    }
+
+
+    /**
+     * 
+     * Remove all insignifiant spaces in a numeric string. For
+     * instance, the following numeric string :
+     * "  123  456  789  "
+     * will be transformed to :
+     * "123456789"
+     *
+     * @param str The numeric String
+     * @return The modified numeric StringBuilder
+     */
+    private static String insignifiantCharNumericString( String str )
+    {
+        if ( Strings.isEmpty( str ) )
+        {
+            return "";
+        }
+
+        char[] array = str.toCharArray();
+
+        boolean isSpace = false;
+        int pos = 0;
+
+        for ( char c : array )
+        {
+            if ( c != 0x20 )
+            {
+                if ( isSpace && isCombiningMark( c ) )
+                {
+                    array[pos++] = ' ';
+                    isSpace = false;
+                }
+
+                array[pos++] = c;
+            }
+            else
+            {
+                isSpace = true;
+            }
+        }
+
+        return new String( array, 0, pos );
+    }
+
+
+    /**
+     * Remove all insignificant spaces in a string.
+     * 
+     * This method use a finite state machine to parse
+     * the text.
+     * 
+     * @param str The String to modify
+     * @param caseSensitive A flag telling if the chars must be lower cased
+     * @return The modified StringBuilder
+     * @throws InvalidCharacterException If an invalid character is found in the String
+     */
+    private static String insignifiantSpacesString( String str, boolean caseSensitive )
+        throws InvalidCharacterException
+    {
+        if ( Strings.isEmpty( str ) )
+        {
+            // Special case : an empty strings is replaced by 2 spaces
+            return "";
+        }
+
+        char[] array = str.toCharArray();
+
+        // Create a target char array which is 3 times bigger than the original size. 
+        // We have to do that because the map phase may transform a char to
+        // three chars.
+        // TODO : we have to find a way to prevent this waste of space.
+        char[] target = new char[str.length() * 3 + 2];
+        
+        int pos = 0;
+        char lowerCase = ( char ) ( caseSensitive ? 0x00 : 0x20 );
+
+        // First pass to map the chars. This will copy the array into the target
+        int limit = map( array, target, lowerCase );
+        pos = 0;
+
+        // Second pass to remove spaces. We work on the target
+        int start = 0;
+        char c = '\0';
+
+        // First remove starting spaces
+        for ( int i = 0; i < limit; i++ )
+        {
+            c = target[i];
+
+            if ( c != ' ' )
+            {
+                checkProhibited( c );
+                break;
+            }
+            
+            start++;
+        }
+
+        // We will just handle the special case of a combining character
+        if ( start == limit )
+        {
+            // we only have spaces, we keep only one
+            return " ";
+        }
+        else if ( isCombiningMark( c ) )
+        {
+            if ( start == 0 )
+            {
+                // The first char can't be a combining char
+                throw new InvalidCharacterException( c );
+            }
+            else
+            {
+                target[pos++] = ' ';
+                target[pos++] = c;
+                start++;
+            }
+        }
+        else
+        {
+            target[pos++] = c;
+            start++;
+        }
+
+        // Now remove the spaces at the end
+        int i = 0;
+        
+        for ( i = limit - 1; i >= start; i-- )
+        {
+            if ( target[i] == ' ' )
+            {
+                // Check if we have a preceding '\' 
+                if ( i - 1 >= start )
+                {
+                    // Break only if the space is preceded by a single ESC
+                    if ( i - 2 >= start )
+                    {
+                        if ( ( target[i - 1] == '\\' ) && ( target[i - 2] != '\\' ) )
+                        {
+                            target[i - 1] = ' ';
+                            i--;
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        if ( target[i - 1] == '\\' )
+                        {
+                            target[i - 1] = ' ';
+                            i--;
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        limit = i + 1;
+
+        // Remove the " around the string if any
+        if ( target[start] == '"' )
+        {
+            start++;
+            limit--;
+        }
+
+        boolean spaceSeen = false;
+        boolean escapeSeen = false;
+
+        for ( i = start; i < limit; i++ )
+        {
+            c = target[i];
+
+            checkProhibited( c );
+
+            if ( c == ' ' )
+            {
+                if ( escapeSeen )
+                {
+                    target[pos++] = ' ';
+                }
+                else
+                {
+                    spaceSeen = true;
+                }
+
+                escapeSeen = false;
+            }
+            else if ( c == '\\' )
+            {
+                if ( escapeSeen )
+                {
+                    target[pos++] = '\\';
+                    target[pos++] = '\\';
+                }
+                else if ( spaceSeen )
+                {
+                    target[pos++] = ' ';
+                }
+                
+                escapeSeen = !escapeSeen;
+                spaceSeen = false;
+            }
+            else
+            {
+                if ( spaceSeen )
+                {
+                    target[pos++] = ' ';
+                    spaceSeen = false;
+                }
+                else if ( escapeSeen )
+                {
+                    target[pos++] = '\\';
+                }
+                
+                target[pos++] = c;
+                escapeSeen = false;
+            }
+        }
+
+        // A special case : we have seen a space at the end of the array : it must be added back
+        // because it's an escaped space, otherwise it would have been discarded by the previous 
+        // end of String's space removal
+        if ( spaceSeen )
+        {
+            target[pos++] = ' ';
+        }
+        // Same for the escape
+        else if ( escapeSeen )
+        {
+            target[pos++] = '\\';
+        }
+        // Ends by unescaping the escaped elements
+        String result = unescape( target, pos );
+
+        return result;
+    }
+
+
+    /**
+     * Remove all insignificant spaces in a Ascii string. We don't remove escaped spaces.
+     * 
+     * This method use a finite state machine to parse
+     * the text.
+     * 
+     * @param str The String to modify
+     * @param caseSensitive A flag telling if the chars must be lower cased
+     * @return The modified StringBuilder
+     * @throws InvalidCharacterException If an invalid character is found in the String
+     */
+    private static String insignifiantSpacesStringAscii( String str, boolean caseSensitive )
+        throws InvalidCharacterException
+    {
+        if ( Strings.isEmpty( str ) )
+        {
+            // Special case : an empty strings is replaced by 2 spaces
+            return "";
+        }
+        
+        char[] array = str.toCharArray();
+
+        int pos = 0;
+        char lowerCase = ( char ) ( caseSensitive ? 0x00 : 0x20 );
+
+        // First pass to map the chars
+        int limit = map( array, array, lowerCase );
+        pos = 0;
+
+        // Second pass to remove spaces (except the escaped ones). We work on the target
+        int start = 0;
+        char c = '\0';
+
+        // First remove starting spaces
+        for ( int i = 0; i < limit; i++ )
+        {
+            c = array[i];
+
+            if ( c != ' ' )
+            {
+                checkProhibited( c );
+                break;
+            }
+            
+            start++;
+        }
+
+        // We will just handle the special case of a combining character
+        if ( start == limit )
+        {
+            // we only have spaces, we keep only one
+            return " ";
+        }
+        else if ( isCombiningMark( c ) )
+        {
+            if ( start == 0 )
+            {
+                // The first char can't be a combining char
+                throw new InvalidCharacterException( c );
+            }
+            else
+            {
+                throw new InvalidCharacterException( c );
+            }
+        }
+
+        // Now remove the spaces at the end
+        int i = 0;
+        
+        for ( i = limit - 1; i >= start; i-- )
+        {
+            if ( array[i] == ' ' )
+            {
+                // Check if we have a preceding '\' 
+                if ( i - 1 >= start )
+                {
+                    // Break only if the space is preceded by a single ESC
+                    if ( i - 2 >= start )
+                    {
+                        if ( ( array[i - 1] == '\\' ) && ( array[i - 2] != '\\' ) )
+                        {
+                            array[i - 1] = ' ';
+                            i--;
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        if ( array[i - 1] == '\\' )
+                        {
+                            array[i - 1] = ' ';
+                            i--;
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        limit = i + 1;
+
+        // Remove the " around the string if any
+        if ( array[start] == '"' )
+        {
+            start++;
+            limit--;
+        }
+        
+        boolean spaceSeen = false;
+        boolean escapeSeen = false;
+
+        for ( i = start; i < limit; i++ )
+        {
+            c = array[i];
+
+            checkProhibited( c );
+
+            /*if ( isCombiningMark( c ) )
+            {
+                throw new InvalidCharacterException( c );
+            }
+            else*/ if ( c == ' ' )
+            {
+                if ( escapeSeen )
+                {
+                    array[pos++] = ' ';
+                }
+                else
+                {
+                    spaceSeen = true;
+                }
+
+                escapeSeen = false;
+            }
+            else if ( c == '\\' )
+            {
+                if ( escapeSeen )
+                {
+                    array[pos++] = '\\';
+                    array[pos++] = '\\';
+                }
+                else if ( spaceSeen )
+                {
+                    array[pos++] = ' ';
+                }
+                
+                escapeSeen = !escapeSeen;
+                spaceSeen = false;
+            }
+            else
+            {
+                if ( spaceSeen )
+                {
+                    array[pos++] = ' ';
+                    spaceSeen = false;
+                }
+                else if ( escapeSeen )
+                {
+                    array[pos++] = '\\';
+                }
+                
+                array[pos++] = c;
+                escapeSeen = false;
+            }
+        }
+
+        // A special case : we have seen a space at the end of the array : it must be added back
+        // because it's an escaped space, otherwise it would have been discarded by the previous 
+        // end of String's space removal
+        if ( spaceSeen )
+        {
+            array[pos++] = ' ';
+        }
+        // Same for the escape
+        else if ( escapeSeen )
+        {
+            array[pos++] = '\\';
+        }
+        
+        // Ends by unescaping the escaped elements
+        String result = unescape( array, pos );
+        
+        return result;
+    }
+    
+    
+    private static String unescape( char[] array, int end )
+    {
+        byte[] bytes = new byte[end * 3];
+        boolean escapeSeen = false;
+        int pos = 0;
+            
+        for ( int i = 0; i < end; i++ )
+        {
+            char c = array[i];
+            
+            if ( c == '\\' )
+            {
+                if ( escapeSeen )
+                {
+                    bytes[pos++] = '\\';
+                }
+                
+                escapeSeen = !escapeSeen;
+            }
+            else
+            {
+                if ( escapeSeen )
+                {
+                    switch ( c )
+                    {
+                        // Various form of space
+                        case 0x0A :
+                        case 0x0B :
+                        case 0x0C :
+                        case 0x0D :
+                        case 0x85 :
+                        case 0xA0 :
+                        case ' ' :
+                            bytes[pos++] = ' ';
+                            break;
+                        
+                        // Special chars
+                        case '#' :
+                        case '=' :
+                        case '+' :
+                        case '"' :
+                        case ',' :
+                        case ';' :
+                        case '<' :
+                        case '>' : 
+                            bytes[pos++] = ( byte ) c;
+                            break;
+                        
+                        // Hexpair
+                        case '0' :
+                        case '1' :
+                        case '2' :
+                        case '3' :
+                        case '4' :
+                        case '5' :
+                        case '6' :
+                        case '7' :
+                        case '8' :
+                        case '9' :
+                            bytes[pos++] = ( byte ) ( ( ( byte ) ( array[i] - '0' ) << 4 ) + toByte( array[i + 1] ) );
+                            i++;
+                            break;
+                            
+                        case 'a' :
+                        case 'b' :
+                        case 'c' :
+                        case 'd' :
+                        case 'e' :
+                        case 'f' :
+                            bytes[pos++] = ( byte ) ( ( ( byte ) ( array[i] - 'a' + 10 ) << 4 ) + toByte( array[i + 1] ) );
+                            i++;
+                            break;
+                            
+                        case 'A' :
+                        case 'B' :
+                        case 'C' :
+                        case 'D' :
+                        case 'E' :
+                        case 'F' :
+                            bytes[pos++] = ( byte ) ( ( ( byte ) ( array[i] - 'A' + 10 ) << 4 ) + toByte( array[i + 1] ) );
+                            i++;
+                            break;
+                            
+                        default :
+                            break;
+                    }
+                    
+                    escapeSeen = false;
+                }
+                else
+                {
+                    // We might have a UTF-8 char
+                    if ( ( c & 0x007F ) == c )
+                    {
+                        // Single byte char
+                        bytes[pos++] = ( byte ) c;
+                    }
+                    else if ( ( c & 0x07FF ) == c )
+                    {
+                        bytes[pos++] = ( byte ) ( 0x00C0 | ( c >> 6 ) );
+                        bytes[pos++] = ( byte ) ( 0x0080 | ( c & 0x003F ) );
+                    }
+                    else
+                    {
+                        bytes[pos++] = ( byte ) ( 0x00E0 | ( c >> 12 ) );
+                        bytes[pos++] = ( byte ) ( 0x0080 | ( ( c >> 6 ) & 0x3F ) );
+                        bytes[pos++] = ( byte ) ( 0x0080 | ( c & 0x003F ) );
+                    }
+                }
+            }
+        }
+        
+        // Deal with the special case where we have one single escape
+        if ( escapeSeen )
+        {
+            bytes[pos++] = '\\';
+        }
+        
+        String result = Strings.utf8ToString( bytes, pos );
+        
+        return result;
+    }
+    
+    
+    private static byte toByte( char c )
+    {
+        switch ( c )
+        {
+            case '0' :
+            case '1' :
+            case '2' :
+            case '3' :
+            case '4' :
+            case '5' :
+            case '6' :
+            case '7' :
+            case '8' :
+            case '9' :
+                return ( byte ) ( c - '0' );
+                
+            case 'a' :
+            case 'b' :
+            case 'c' :
+            case 'd' :
+            case 'e' :
+            case 'f' :
+                return ( byte ) ( c - 'a' + 10 );
+                
+            case 'A' :
+            case 'B' :
+            case 'C' :
+            case 'D' :
+            case 'E' :
+            case 'F' :
+                return ( byte ) ( c - 'A' + 10 );
+                
+            default :
+                break;
+        }
+        
+        return 0;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaManager.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaManager.java
new file mode 100644
index 0000000..0d115e6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaManager.java
@@ -0,0 +1,846 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ComparatorRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.DitContentRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.DitStructureRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.LdapSyntaxRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleUseRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.NameFormRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.NormalizerRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.OidRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
+import org.apache.directory.api.ldap.model.schema.registries.SyntaxCheckerRegistry;
+
+
+/**
+ * A class used to manage access to the Schemas and Registries. It's associated 
+ * with a SchemaLoader, in charge of loading the schemas from the disk.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SchemaManager
+{
+    /** Two flags for RELAXED and STRICT, this is STRICT */
+    boolean STRICT = false;
+
+    /** Two flags for RELAXED and STRICT, this is RELAXED */
+    boolean RELAXED = true;
+
+    //---------------------------------------------------------------------------------
+    // Schema loading methods
+    //---------------------------------------------------------------------------------
+    /**
+     * Load some Schemas into the registries. The Registries is checked after the 
+     * schemas have been loaded, and if there is an error, the method returns false
+     * and the registries is kept intact.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas to load
+     * @return true if the schemas have been loaded and the registries is consistent
+     * @throws Exception @TODO 
+     */
+    boolean load( Schema... schemas ) throws LdapException;
+
+
+    /**
+     * Load some Schemas into the registries. The Registries is checked after the 
+     * schemas have been loaded, and if there is an error, the method returns false
+     * and the registries is kept intact.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas' name to load
+     * @return true if the schemas have been loaded and the registries is consistent
+     * @throws Exception @TODO 
+     */
+    boolean load( String... schemas ) throws Exception;
+
+
+    /**
+     * Load some Schemas into the registries, and loads all of the schemas they depend
+     * on. The Registries is checked after the schemas have been loaded, and if there 
+     * is an error, the method returns false and the registries is kept intact.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas to load
+     * @return true if the schemas have been loaded and the registries is consistent
+     * @throws Exception @TODO 
+     */
+    boolean loadWithDeps( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Load some Schemas into the registries, and loads all of the schemas they depend
+     * on. The Registries is checked after the schemas have been loaded, and if there 
+     * is an error, the method returns false and the registries is kept intact.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas' name to load
+     * @return true if the schemas have been loaded and the registries is consistent
+     * @throws Exception @TODO 
+     */
+    boolean loadWithDeps( String... schemas ) throws Exception;
+
+
+    /**
+     * Load Schemas into the registries, even if there are some errors in the schemas. 
+     * The Registries is checked after the schemas have been loaded. Even if we have 
+     * errors, the registries will be updated.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas to load, if enabled
+     * @return true if the schemas have been loaded
+     * @throws Exception @TODO 
+     */
+    boolean loadRelaxed( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Load Schemas into the registries, even if there are some errors in the schemas. 
+     * The Registries is checked after the schemas have been loaded. Even if we have 
+     * errors, the registries will be updated.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas' name to load, if enabled
+     * @return true if the schemas have been loaded and the registries is consistent
+     * @throws Exception @TODO 
+     */
+    boolean loadRelaxed( String... schemas ) throws Exception;
+
+
+    /**
+     * Load some Schemas into the registries, and loads all of the schemas they depend
+     * on. The Registries is checked after the schemas have been loaded. Even if we have 
+     * errors, the registries will be updated.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas to load
+     * @return true if the schemas have been loaded
+     * @throws Exception @TODO 
+     */
+    boolean loadWithDepsRelaxed( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Load some Schemas into the registries, and loads all of the schemas they depend
+     * on. The Registries is checked after the schemas have been loaded. Even if we have 
+     * errors, the registries will be updated.
+     * <br>
+     * The Schemas must be enabled, and only enabled SchemaObject will be loaded.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     * 
+     * @param schemas the Schemas' name to load
+     * @return true if the schemas have been loaded
+     * @throws Exception @TODO 
+     */
+    boolean loadWithDepsRelaxed( String... schemas ) throws Exception;
+
+
+    /**
+     * Load Schemas into the Registries, even if they are disabled. The disabled
+     * SchemaObject from an enabled schema will also be loaded. The Registries will
+     * be checked after the schemas have been loaded. Even if we have errors, the
+     * Registries will be updated.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     *
+     * @param schemas The Schemas to load
+     * @return true if the schemas have been loaded
+     * @throws Exception @TODO 
+     */
+    boolean loadDisabled( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Load Schemas into the Registries, even if they are disabled. The disabled
+     * SchemaObject from an enabled schema will also be loaded. The Registries will
+     * be checked after the schemas have been loaded. Even if we have errors, the
+     * Registries will be updated.
+     * <br>
+     * If any error was met, the {@link #getErrors} method will contain them
+     *
+     * @param schemas The Schemas' name to load
+     * @return true if the schemas have been loaded
+     * @throws Exception @TODO 
+     */
+    boolean loadDisabled( String... schemas ) throws LdapException;
+
+
+    /**
+     * Load all the enabled schema into the Registries. The Registries is strict,
+     * any inconsistent schema will be rejected. 
+     *
+     * @return true if the schemas have been loaded
+     * @throws Exception @TODO
+     */
+    boolean loadAllEnabled() throws Exception;
+
+
+    /**
+     * Load all the enabled schema into the Registries. The Registries is relaxed,
+     * even inconsistent schema will be loaded. 
+     *
+     * @return true if the schemas have been loaded
+     * @throws Exception @TODO
+     */
+    boolean loadAllEnabledRelaxed() throws Exception;
+
+
+    /**
+     * Unload the given set of Schemas
+     *
+     * @param schemas The list of Schema to unload
+     * @return True if all the schemas have been unloaded
+     */
+    boolean unload( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Unload the given set of Schemas
+     *
+     * @param schemas The list of Schema to unload
+     * @return True if all the schemas have been unloaded
+     */
+    boolean unload( String... schemas ) throws LdapException;
+
+
+    //---------------------------------------------------------------------------------
+    // Other Schema methods
+    //---------------------------------------------------------------------------------
+    /**
+     * Enables a set of Schemas, and returns true if all the schema have been
+     * enabled, with all the dependent schemas, and if the registries is 
+     * still consistent.
+     * 
+     * If the modification is ok, the Registries will be updated. 
+     * 
+     *  @param schemas The list of schemas to enable
+     *  @return true if the Registries is still consistent, false otherwise.
+     *  @throws If something went wrong
+     */
+    boolean enable( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Enables a set of Schemas, and returns true if all the schema have been
+     * enabled, with all the dependent schemas, and if the registries is 
+     * still consistent.
+     * 
+     * If the modification is ok, the Registries will be updated.
+     *  
+     *  @param schemas The list of schema name to enable
+     *  @return true if the Registries is still consistent, false otherwise.
+     *  @throws If something went wrong
+     */
+    boolean enable( String... schemas ) throws LdapException;
+
+
+    /**
+     * Enables a set of Schemas, and returns true if all the schema have been
+     * enabled, with all the dependent schemas. No check is done, the Registries
+     * might become inconsistent after this operation.
+     * 
+     *  @param schemas The list of schemas to enable
+     *  @return true if all the schemas have been enabled
+     */
+    boolean enableRelaxed( Schema... schemas );
+
+
+    /**
+     * Enables a set of Schemas, and returns true if all the schema have been
+     * enabled, with all the dependent schemas. No check is done, the Registries
+     * might become inconsistent after this operation.
+     * 
+     *  @param schemas The list of schema names to enable
+     *  @return true if all the schemas have been enabled
+     */
+    boolean enableRelaxed( String... schemas );
+
+
+    /**
+     * @return the list of all the enabled schema
+     */
+    List<Schema> getEnabled();
+
+
+    /**
+     * Tells if the given Schema is enabled
+     *
+     * @param schemaName The schema name
+     * @return true if the schema is enabled
+     */
+    boolean isEnabled( String schemaName );
+
+
+    /**
+     * Tells if the given Schema is enabled
+     *
+     * @param schema The schema
+     * @return true if the schema is enabled
+     */
+    boolean isEnabled( Schema schema );
+
+
+    /**
+     * Disables a set of Schemas, and returns true if all the schema have been
+     * disabled, with all the dependent schemas, and if the registries is 
+     * still consistent.
+     * 
+     * If the modification is ok, the Registries will be updated. 
+     * 
+     *  @param schemas The list of schemas to disable
+     *  @return true if the Registries is still consistent, false otherwise.
+     *  @throws If something went wrong
+     */
+    boolean disable( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Disables a set of Schemas, and returns true if all the schema have been
+     * disabled, with all the dependent schemas, and if the registries is 
+     * still consistent.
+     * 
+     * If the modification is ok, the Registries will be updated. 
+     * 
+     *  @param schemas The list of schema names to disable
+     *  @return true if the Registries is still consistent, false otherwise.
+     *  @throws If something went wrong
+     */
+    boolean disable( String... schemas ) throws LdapException;
+
+
+    /**
+     * Disables a set of Schemas, and returns true if all the schema have been
+     * disabled, with all the dependent schemas. The Registries is not checked
+     * and can be inconsistent after this operation
+     * 
+     * If the modification is ok, the Registries will be updated. 
+     * 
+     *  @param schemas The list of schemas to disable
+     *  @return true if all the schemas have been disabled
+     */
+    boolean disabledRelaxed( Schema... schemas );
+
+
+    /**
+     * Disables a set of Schemas, and returns true if all the schema have been
+     * disabled, with all the dependent schemas. The Registries is not checked
+     * and can be inconsistent after this operation
+     * 
+     * If the modification is ok, the Registries will be updated. 
+     * 
+     *  @param schemas The list of schema names to disable
+     *  @return true if all the schemas have been disabled
+     */
+    boolean disabledRelaxed( String... schemas );
+
+
+    /**
+     * @return the list of all the disabled schema
+     */
+    List<Schema> getDisabled();
+
+
+    /**
+     * Tells if the given Schema is disabled
+     *
+     * @param schemaName The schema name
+     * @return true if the schema is disabled
+     */
+    boolean isDisabled( String schemaName );
+
+
+    /**
+     * Tells if the given Schema is disabled
+     *
+     * @param schema The schema
+     * @return true if the schema is disabled
+     */
+    boolean isDisabled( Schema schema );
+
+    /**
+     * Tells if the SchemaManager is permissive or if it must be checked
+     * against inconsistencies.
+     *
+     * @return True if SchemaObjects can be added even if they break the consistency
+     */
+    boolean isRelaxed();
+
+
+    /**
+     * Set the SchemaManager to a RELAXED mode
+     */
+    void setRelaxed();
+
+    /**
+     * Tells if the SchemaManager is strict.
+     *
+     * @return True if SchemaObjects cannot be added if they break the consistency
+     */
+    boolean isStrict();
+
+    /**
+     * Set the SchemaManager to a STRICT mode
+     */
+    void setStrict();
+    
+    /**
+     * Check that the Schemas are consistent regarding the current Registries.
+     * 
+     * @param schemas The schemas to check
+     * @return true if the schemas can be loaded in the registries
+     * @throws Exception if something went wrong
+     */
+    boolean verify( Schema... schemas ) throws Exception;
+
+
+    /**
+     * Check that the Schemas are consistent regarding the current Registries.
+     * 
+     * @param schemas The schema names to check
+     * @return true if the schemas can be loaded in the registries
+     * @throws Exception if something went wrong
+     */
+    boolean verify( String... schemas ) throws Exception;
+
+
+    /**
+     * @return The Registries
+     */
+    Registries getRegistries();
+
+
+    /**
+     * Lookup for an AttributeType in the AttributeType registry
+     * 
+     * @param oid the OID we are looking for
+     * @return The found AttributeType 
+     * @throws LdapException if the OID is not found in the AttributeType registry
+     */
+    AttributeType lookupAttributeTypeRegistry( String oid ) throws LdapException;
+
+
+    /**
+     * Get an AttributeType in the AttributeType registry. This method won't
+     * throw an exception if the AttributeTyp is not found, it will just return
+     * null.
+     * 
+     * @param oid the OID we are looking for
+     * @return The found AttributeType, or null if not found
+     */
+    AttributeType getAttributeType( String oid );
+
+
+    /**
+     * Lookup for a Comparator in the Comparator registry
+     * 
+     * @param oid the OID we are looking for
+     * @return The found Comparator 
+     * @throws LdapException if the OID is not found in the Comparator registry
+     */
+    LdapComparator<?> lookupComparatorRegistry( String oid ) throws LdapException;
+
+
+    /**
+     * Lookup for a MatchingRule in the MatchingRule registry
+     * 
+     * @param oid the OID we are looking for
+     * @return The found MatchingRule 
+     * @throws LdapException if the OID is not found in the MatchingRule registry
+     */
+    MatchingRule lookupMatchingRuleRegistry( String oid ) throws LdapException;
+
+
+    /**
+     * Lookup for a Normalizer in the Normalizer registry
+     * 
+     * @param oid the OID we are looking for
+     * @return The found Normalizer 
+     * @throws LdapException if the OID is not found in the Normalizer registry
+     */
+    Normalizer lookupNormalizerRegistry( String oid ) throws LdapException;
+
+
+    /**
+     * Lookup for a ObjectClass in the ObjectClass registry
+     * 
+     * @param oid the OID we are looking for
+     * @return The found ObjectClass 
+     * @throws LdapException if the OID is not found in the ObjectClass registry
+     */
+    ObjectClass lookupObjectClassRegistry( String oid ) throws LdapException;
+
+
+    /**
+     * Lookup for an LdapSyntax in the LdapSyntax registry
+     * 
+     * @param oid the OID we are looking for
+     * @return The found LdapSyntax 
+     * @throws LdapException if the OID is not found in the LdapSyntax registry
+     */
+    LdapSyntax lookupLdapSyntaxRegistry( String oid ) throws LdapException;
+
+
+    /**
+     * Lookup for a SyntaxChecker in the SyntaxChecker registry
+     * 
+     * @param oid the OID we are looking for
+     * @return The found SyntaxChecker 
+     * @throws LdapException if the OID is not found in the SyntaxChecker registry
+     */
+    SyntaxChecker lookupSyntaxCheckerRegistry( String oid ) throws LdapException;
+
+
+    /**
+     * Get an immutable reference on the AttributeType registry
+     * 
+     * @return A reference to the AttributeType registry.
+     */
+    AttributeTypeRegistry getAttributeTypeRegistry();
+
+
+    /**
+     * Get an immutable reference on the Comparator registry
+     * 
+     * @return A reference to the Comparator registry.
+     */
+    ComparatorRegistry getComparatorRegistry();
+
+
+    /**
+     * Get an immutable reference on the DitContentRule registry
+     * 
+     * @return A reference to the DitContentRule registry.
+     */
+    DitContentRuleRegistry getDITContentRuleRegistry();
+
+
+    /**
+     * Get an immutable reference on the DitStructureRule registry
+     * 
+     * @return A reference to the DitStructureRule registry.
+     */
+    DitStructureRuleRegistry getDITStructureRuleRegistry();
+
+
+    /**
+     * Get an immutable reference on the MatchingRule registry
+     * 
+     * @return A reference to the MatchingRule registry.
+     */
+    MatchingRuleRegistry getMatchingRuleRegistry();
+
+
+    /**
+     * Get an immutable reference on the MatchingRuleUse registry
+     * 
+     * @return A reference to the MatchingRuleUse registry.
+     */
+    MatchingRuleUseRegistry getMatchingRuleUseRegistry();
+
+
+    /**
+     * Get an immutable reference on the Normalizer registry
+     * 
+     * @return A reference to the Normalizer registry.
+     */
+    NormalizerRegistry getNormalizerRegistry();
+
+
+    /**
+     * Get an immutable reference on the NameForm registry
+     * 
+     * @return A reference to the NameForm registry.
+     */
+    NameFormRegistry getNameFormRegistry();
+
+
+    /**
+     * Get an immutable reference on the ObjectClass registry
+     * 
+     * @return A reference to the ObjectClass registry.
+     */
+    ObjectClassRegistry getObjectClassRegistry();
+
+
+    /**
+     * Get an immutable reference on the LdapSyntax registry
+     * 
+     * @return A reference to the LdapSyntax registry.
+     */
+    LdapSyntaxRegistry getLdapSyntaxRegistry();
+
+
+    /**
+     * Get an immutable reference on the SyntaxChecker registry
+     * 
+     * @return A reference to the SyntaxChecker registry.
+     */
+    SyntaxCheckerRegistry getSyntaxCheckerRegistry();
+
+
+    /**
+     * Get an immutable reference on the Normalizer mapping
+     * 
+     * @return A reference to the Normalizer mapping
+     */
+    Map<String, OidNormalizer> getNormalizerMapping();
+
+
+    /**
+     * Associate a new Registries to the SchemaManager
+     *
+     * @param registries The new Registries
+     */
+    void setRegistries( Registries registries );
+
+
+    /**
+     * @return The errors obtained when checking the registries
+     */
+    List<Throwable> getErrors();
+
+
+    /**
+     * Associate a Schema loader to this SchemaManager
+     *
+     * @param schemaLoader The schema loader to use
+     */
+    void setSchemaLoader( SchemaLoader schemaLoader );
+
+
+    /**
+     * @return the namingContext
+     */
+    Dn getNamingContext();
+
+
+    /**
+     * Initializes the SchemaService
+     *
+     * @throws Exception If the initialization fails
+     */
+    void initialize() throws Exception;
+
+
+    /**
+     * @return The used loader
+     */
+    SchemaLoader getLoader();
+
+
+    /**
+     * Registers a new SchemaObject. The registries will be updated only if it's
+     * consistent after this addition, if the SchemaManager is in Strict mode.
+     * If something went wrong during this operation, the 
+     * SchemaManager.getErrors() will give the list of generated errors.
+     *
+     * @param schemaObject the SchemaObject to register
+     * @return true if the addition has been made, false if there were some errors
+     * @throws LdapException if the SchemaObject is already registered or
+     * the registration operation is not supported
+     */
+    boolean add( SchemaObject schemaObject ) throws LdapException;
+
+
+    /**
+     * Unregisters a new SchemaObject. The registries will be updated only if it's
+     * consistent after this deletion, if the SchemaManager is in Strict mode.
+     * If something went wrong during this operation, the 
+     * SchemaManager.getErrors() will give the list of generated errors.
+     *
+     * @param schemaObject the SchemaObject to unregister
+     * @return true if the deletion has been made, false if there were some errors
+     * @throws Exception if the SchemaObject is not registered or
+     * the deletion operation is not supported
+     */
+    boolean delete( SchemaObject schemaObject ) throws LdapException;
+
+
+    /**
+     * Removes the registered attributeType from the attributeTypeRegistry 
+     * 
+     * @param attributeTypeOid the attributeType OID to unregister
+     * @throws LdapException if the attributeType is invalid
+     */
+    SchemaObject unregisterAttributeType( String attributeTypeOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered Comparator from the ComparatorRegistry 
+     * 
+     * @param comparatorOid the Comparator OID to unregister
+     * @throws LdapException if the Comparator is invalid
+     */
+    SchemaObject unregisterComparator( String comparatorOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered DitControlRule from the DitControlRuleRegistry 
+     * 
+     * @param ditControlRuleOid the DitControlRule OID to unregister
+     * @throws LdapException if the DitControlRule is invalid
+     */
+    SchemaObject unregisterDitControlRule( String ditControlRuleOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered DitStructureRule from the DitStructureRuleRegistry 
+     * 
+     * @param ditStructureRuleOid the DitStructureRule OID to unregister
+     * @throws LdapException if the DitStructureRule is invalid
+     */
+    SchemaObject unregisterDitStructureRule( String ditStructureRuleOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered MatchingRule from the MatchingRuleRegistry 
+     * 
+     * @param matchingRuleOid the MatchingRuleRule OID to unregister
+     * @throws LdapException if the MatchingRule is invalid
+     */
+    SchemaObject unregisterMatchingRule( String matchingRuleOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered MatchingRuleUse from the MatchingRuleUseRegistry 
+     * 
+     * @param matchingRuleUseOid the MatchingRuleUse OID to unregister
+     * @throws LdapException if the MatchingRuleUse is invalid
+     */
+    SchemaObject unregisterMatchingRuleUse( String matchingRuleUseOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered NameForm from the NameFormRegistry 
+     * 
+     * @param nameFormOid the NameForm OID to unregister
+     * @throws LdapException if the NameForm is invalid
+     */
+    SchemaObject unregisterNameForm( String nameFormOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered Normalizer from the NormalizerRegistry 
+     * 
+     * @param normalizerOid the Normalizer OID to unregister
+     * @throws LdapException if the Normalizer is invalid
+     */
+    SchemaObject unregisterNormalizer( String normalizerOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered ObjectClass from the ObjectClassRegistry 
+     * 
+     * @param objectClassOid the ObjectClass OID to unregister
+     * @throws LdapException if the ObjectClass is invalid
+     */
+    SchemaObject unregisterObjectClass( String objectClassOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered LdapSyntax from the LdapSyntaxRegistry 
+     * 
+     * @param ldapSyntaxOid the LdapSyntax OID to unregister
+     * @throws LdapException if the LdapSyntax is invalid
+     */
+    SchemaObject unregisterLdapSyntax( String ldapSyntaxOid ) throws LdapException;
+
+
+    /**
+     * Removes the registered SyntaxChecker from the SyntaxCheckerRegistry 
+     * 
+     * @param syntaxCheckerOid the SyntaxChecker OID to unregister
+     * @throws LdapException if the SyntaxChecker is invalid
+     */
+    SchemaObject unregisterSyntaxChecker( String syntaxCheckerOid ) throws LdapException;
+
+
+    /**
+     * Returns a reference to the global OidRegistry
+     *
+     * @return The the global OidRegistry
+     */
+    @SuppressWarnings("rawtypes")
+    OidRegistry getGlobalOidRegistry();
+
+
+    /**
+     * Gets a schema that has been loaded into these Registries.
+     * 
+     * @param schemaName the name of the schema to lookup
+     * @return the loaded Schema if one corresponding to the name exists
+     */
+    Schema getLoadedSchema( String schemaName );
+
+
+    /**
+     * Tells if the specific schema is loaded
+     *
+     * @param schemaName The schema we want to check
+     * @return true if the schema is laoded
+     */
+    boolean isSchemaLoaded( String schemaName );
+
+
+    /**
+     * Get the list of Schema names which has the given schema name as a dependence
+     *
+     * @param schemaName The Schema name for which we want to get the list of dependent schemas
+     * @return The list of dependent schemas
+     */
+    Set<String> listDependentSchemaNames( String schemaName );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObject.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObject.java
new file mode 100644
index 0000000..c42dd16
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObject.java
@@ -0,0 +1,340 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Most schema objects have some common attributes. This class
+ * contains the minimum set of properties exposed by a SchemaObject.<br>
+ * We have 11 types of SchemaObjects :
+ * <li> AttributeType
+ * <li> DitCOntentRule
+ * <li> DitStructureRule
+ * <li> LdapComparator (specific to ADS)
+ * <li> LdapSyntaxe
+ * <li> MatchingRule
+ * <li> MatchingRuleUse
+ * <li> NameForm
+ * <li> Normalizer (specific to ADS)
+ * <li> ObjectClass
+ * <li> SyntaxChecker (specific to ADS)
+ * <br>
+ * <br>
+ * This class provides accessors and setters for the following attributes,
+ * which are common to all those SchemaObjects :
+ * <li>oid : The numeric OID
+ * <li>description : The SchemaObject description
+ * <li>obsolete : Tells if the schema object is obsolete
+ * <li>extensions : The extensions, a key/Values map
+ * <li>schemaObjectType : The SchemaObject type (see upper)
+ * <li>schema : The schema the SchemaObject is associated with (it's an extension).
+ * Can be null
+ * <li>isEnabled : The SchemaObject status (it's related to the schema status)
+ * <li>isReadOnly : Tells if the SchemaObject can be modified or not
+ * <br><br>
+ * Some of those attributes are not used by some Schema elements, even if they should
+ * have been used. Here is the list :
+ * <b>name</b> : LdapSyntax, Comparator, Normalizer, SyntaxChecker
+ * <b>numericOid</b> : DitStructureRule,
+ * <b>obsolete</b> : LdapSyntax, Comparator, Normalizer, SyntaxChecker
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SchemaObject
+{
+    /**
+     * Gets usually what is the numeric object identifier assigned to this
+     * SchemaObject. All schema objects except for MatchingRuleUses have an OID
+     * assigned specifically to then. A MatchingRuleUse's OID really is the OID
+     * of it's MatchingRule and not specific to the MatchingRuleUse. This
+     * effects how MatchingRuleUse objects are maintained by the system.
+     * 
+     * @return an OID for this SchemaObject or its MatchingRule if this
+     *         SchemaObject is a MatchingRuleUse object
+     */
+    String getOid();
+
+
+    /**
+     * A special method used when renaming an SchemaObject: we may have to
+     * change it's OID
+     * @param oid The new OID
+     */
+    void setOid( String oid );
+
+
+    /**
+     * Gets short names for this SchemaObject if any exists for it, otherwise,
+     * returns an empty list.
+     * 
+     * @return the names for this SchemaObject
+     */
+    List<String> getNames();
+
+
+    /**
+     * Gets the first name in the set of short names for this SchemaObject if
+     * any exists for it.
+     * 
+     * @return the first of the names for this SchemaObject or the oid
+     * if one does not exist
+     */
+    String getName();
+
+
+    /**
+     * Add a new name to the list of names for this SchemaObject. The name
+     * is lower cased and trimmed.
+     * 
+     * @param names The names to add
+     */
+    void addName( String... names );
+
+
+    /**
+     * Sets the list of names for this SchemaObject. The names are
+     * lower cased and trimmed.
+     * 
+     * @param names The list of names. Can be empty
+     */
+    void setNames( List<String> names );
+
+
+    /**
+     * Gets a short description about this SchemaObject.
+     * 
+     * @return a short description about this SchemaObject
+     */
+    String getDescription();
+
+
+    /**
+     * Sets the SchemaObject's description
+     * 
+     * @param description The SchemaObject's description
+     */
+    void setDescription( String description );
+
+
+    /**
+     * Gets the SchemaObject specification.
+     * 
+     * @return the SchemaObject specification
+     */
+    String getSpecification();
+
+
+    /**
+     * Sets the SchemaObject's specification
+     * 
+     * @param specification The SchemaObject's specification
+     */
+    void setSpecification( String specification );
+
+
+    /**
+     * Tells if this SchemaObject is enabled.
+     * 
+     * @return true if the SchemaObject is enabled, or if it depends on
+     * an enabled schema
+     */
+    boolean isEnabled();
+
+
+    /**
+     * Tells if this SchemaObject is disabled.
+     * 
+     * @return true if the SchemaObject is disabled
+     */
+    boolean isDisabled();
+
+
+    /**
+     * Sets the SchemaObject state, either enabled or disabled.
+     * 
+     * @param enabled The current SchemaObject state
+     */
+    void setEnabled( boolean enabled );
+
+
+    /**
+     * Tells if this SchemaObject is ReadOnly.
+     * 
+     * @return true if the SchemaObject is not modifiable
+     */
+    boolean isReadOnly();
+
+
+    /**
+     * Sets the SchemaObject readOnly flag
+     * 
+     * @param isReadOnly The current SchemaObject ReadOnly status
+     */
+    void setReadOnly( boolean isReadOnly );
+
+
+    /**
+     * Gets whether or not this SchemaObject has been inactivated. All
+     * SchemaObjects except Syntaxes allow for this parameter within their
+     * definition. For Syntaxes this property should always return false in
+     * which case it is never included in the description.
+     * 
+     * @return true if inactive, false if active
+     */
+    boolean isObsolete();
+
+
+    /**
+     * Sets the Obsolete flag.
+     * 
+     * @param obsolete The Obsolete flag state
+     */
+    void setObsolete( boolean obsolete );
+
+
+    /**
+     * @return The SchemaObject extensions, as a Map of [extension, values]
+     */
+    Map<String, List<String>> getExtensions();
+
+
+    /**
+     * Check if a given extension is part of the SchemaObject. Extensions are case insensitive.
+     * 
+     * @param extension The extension we are looking for.
+     * @return <code>true</code> if the extension is present.
+     */
+    boolean hasExtension( String extension );
+
+
+    /**
+     * Get back the values associated with a given extension.
+     * 
+     * @param extension The extension we are looking for.
+     * @return The list of values associated with the extension
+     */
+    List<String> getExtension( String extension );
+
+
+    /**
+     * Add an extension with its values
+     * @param key The extension key
+     * @param values The associated values
+     */
+    void addExtension( String key, String... values );
+
+
+    /**
+     * Add an extension with its values
+     * @param key The extension key
+     * @param values The associated values
+     */
+    void addExtension( String key, List<String> values );
+
+
+    /**
+     * Add an extensions with their values. (Actually do a copy)
+     * 
+     * @param extensions The extensions map
+     */
+    void setExtensions( Map<String, List<String>> extensions );
+
+
+    /**
+     * The SchemaObject type :
+     * <li> AttributeType
+     * <li> DitCOntentRule
+     * <li> DitStructureRule
+     * <li> LdapComparator (specific to ADS)
+     * <li> LdapSyntaxe
+     * <li> MatchingRule
+     * <li> MatchingRuleUse
+     * <li> NameForm
+     * <li> Normalizer (specific to ADS)
+     * <li> ObjectClass
+     * <li> SyntaxChecker (specific to ADS)
+     * 
+     * @return the SchemaObject type
+     */
+    SchemaObjectType getObjectType();
+
+
+    /**
+     * Gets the name of the schema this SchemaObject is associated with.
+     *
+     * @return the name of the schema associated with this schemaObject
+     */
+    String getSchemaName();
+
+
+    /**
+     * Sets the name of the schema this SchemaObject is associated with.
+     * 
+     * @param schemaName the new schema name
+     */
+    void setSchemaName( String schemaName );
+
+
+    /**
+     * {@inheritDoc}
+     */
+    int hashCode();
+
+
+    /**
+     * {@inheritDoc}
+     */
+    boolean equals( Object o1 );
+
+
+    /**
+     * Copy the current SchemaObject on place
+     *
+     * @return The copied SchemaObject
+     */
+    SchemaObject copy();
+
+
+    /**
+     * Copies the given schema object into this schema object.
+     *
+     * @param original the original SchemaObject
+     * @return this
+     */
+    SchemaObject copy( SchemaObject original );
+
+
+    /**
+     * Clear the current SchemaObject : remove all the references to other objects,
+     * and all the Maps.
+     */
+    void clear();
+
+
+    /**
+     * Transform the SchemaObject to an immutable object
+     * TODO locked.
+     *
+     */
+    void lock();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectRenderer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectRenderer.java
new file mode 100644
index 0000000..841ceb7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectRenderer.java
@@ -0,0 +1,835 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.List;
+
+
+/**
+ * Renderer for schema objects.
+ * 
+ * Currently the following preconfigured renderers exist: 
+ * <ol>
+ * <li> {@link SchemaObjectRenderer#SUBSCHEMA_SUBENTRY_RENDERER}: renders the schema object 
+ *      without line break and with X-SCHEMA extension. To be used for building subschema subentry.
+ * <li> {@link SchemaObjectRenderer#OPEN_LDAP_SCHEMA_RENDERER}: renders the schema object in OpenLDAP schema  
+ *      format. That means is starts with schema type and contains line breaks for easier readability.
+ * </ol>
+ * <p>
+ * TODO: currently only {@link ObjectClass} and {@link AttributeType} are supported, implement other schema object types.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SchemaObjectRenderer
+{
+    /**
+     * Preconfigured {@link SchemaObjectRenderer} that renders the schema object without line break and with
+     * X-SCHEMA extension. To be used for building subschema subentry.
+     */
+    public static final SchemaObjectRenderer SUBSCHEMA_SUBENTRY_RENDERER = new SchemaObjectRenderer(
+        Style.SUBSCHEMA_SUBENTRY_WITH_SCHEMA_NAME );
+
+    /**
+     * Preconfigured {@link SchemaObjectRenderer} that renders the schema object in OpenLDAP schema format. 
+     * That means is starts with schema type and contains line breaks for easier readability.
+     */
+    public static final SchemaObjectRenderer OPEN_LDAP_SCHEMA_RENDERER = new SchemaObjectRenderer(
+        Style.OPENLDAP_SCHEMA_PRETTY_PRINTED );
+
+    private enum Style
+    {
+        SUBSCHEMA_SUBENTRY_WITH_SCHEMA_NAME(false, false, true),
+
+        OPENLDAP_SCHEMA_PRETTY_PRINTED(true, true, false);
+
+        final boolean startWithSchemaType;
+        final boolean prettyPrint;
+        final boolean printSchemaName;
+
+
+        private Style( boolean startWithSchemaType, boolean prettyPrint, boolean printSchemaName )
+        {
+            this.startWithSchemaType = startWithSchemaType;
+            this.prettyPrint = prettyPrint;
+            this.printSchemaName = printSchemaName;
+        }
+    }
+
+    private final Style style;
+
+
+    private SchemaObjectRenderer( Style style )
+    {
+        this.style = style;
+    }
+
+
+    /**
+     * Renders an objectClass according to the Object Class 
+     * Description Syntax 1.3.6.1.4.1.1466.115.121.1.37. The syntax is
+     * described in detail within section 4.1.1. of 
+     * <a href="https://tools.ietf.org/rfc/rfc4512.txt">RFC 4512</a>
+     * which is replicated here for convenience:
+     * 
+     * <pre>
+     *  4.1.1. Object Class Definitions
+     * 
+     *   Object Class definitions are written according to the ABNF:
+     * 
+     *     ObjectClassDescription = LPAREN WSP
+     *         numericoid                 ; object identifier
+     *         [ SP &quot;NAME&quot; SP qdescrs ]   ; short names (descriptors)
+     *         [ SP &quot;DESC&quot; SP qdstring ]  ; description
+     *         [ SP &quot;OBSOLETE&quot; ]          ; not active
+     *         [ SP &quot;SUP&quot; SP oids ]       ; superior object classes
+     *         [ SP kind ]                ; kind of class
+     *         [ SP &quot;MUST&quot; SP oids ]      ; attribute types
+     *         [ SP &quot;MAY&quot; SP oids ]       ; attribute types
+     *         extensions WSP RPAREN
+     * 
+     *     kind = &quot;ABSTRACT&quot; / &quot;STRUCTURAL&quot; / &quot;AUXILIARY&quot;
+     * 
+     *   where:
+     *     &lt;numericoid&gt; is object identifier assigned to this object class;
+     *     NAME &lt;qdescrs&gt; are short names (descriptors) identifying this object
+     *         class;
+     *     DESC &lt;qdstring&gt; is a short descriptive string;
+     *     OBSOLETE indicates this object class is not active;
+     *     SUP &lt;oids&gt; specifies the direct superclasses of this object class;
+     *     the kind of object class is indicated by one of ABSTRACT,
+     *         STRUCTURAL, or AUXILIARY, default is STRUCTURAL;
+     *     MUST and MAY specify the sets of required and allowed attribute
+     *         types, respectively; and
+     *     &lt;extensions&gt; describe extensions.
+     * </pre>
+     * @param oc the ObjectClass to render the description of
+     * @return the string form of the Object Class description
+     */
+    public String render( ObjectClass oc )
+    {
+        StringBuilder buf = renderStartOidNamesDescObsolete( oc, "objectclass" );
+
+        renderOids( buf, "SUP", oc.getSuperiorOids() );
+
+        if ( oc.getType() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( oc.getType() );
+            prettyPrintNewLine( buf );
+        }
+
+        renderOids( buf, "MUST", oc.getMustAttributeTypeOids() );
+
+        renderOids( buf, "MAY", oc.getMayAttributeTypeOids() );
+
+        renderXSchemaName( oc, buf );
+
+        // @todo extensions are not presently supported and skipped
+        // the extensions would go here before closing off the description
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Renders an attributeType according to the
+     * Attribute Type Description Syntax 1.3.6.1.4.1.1466.115.121.1.3. The
+     * syntax is described in detail within section 4.1.2. of 
+     * <a href="https://tools.ietf.org/rfc/rfc4512.txt">RFC 4512</a>
+     * which is replicated here for convenience:
+     * 
+     * <pre>
+     *  4.1.2. Attribute Types
+     * 
+     *   Attribute Type definitions are written according to the ABNF:
+     * 
+     *   AttributeTypeDescription = LPAREN WSP
+     *         numericoid                    ; object identifier
+     *         [ SP &quot;NAME&quot; SP qdescrs ]      ; short names (descriptors)
+     *         [ SP &quot;DESC&quot; SP qdstring ]     ; description
+     *         [ SP &quot;OBSOLETE&quot; ]             ; not active
+     *         [ SP &quot;SUP&quot; SP oid ]           ; supertype
+     *         [ SP &quot;EQUALITY&quot; SP oid ]      ; equality matching rule
+     *         [ SP &quot;ORDERING&quot; SP oid ]      ; ordering matching rule
+     *         [ SP &quot;SUBSTR&quot; SP oid ]        ; substrings matching rule
+     *         [ SP &quot;SYNTAX&quot; SP noidlen ]    ; value syntax
+     *         [ SP &quot;SINGLE-VALUE&quot; ]         ; single-value
+     *         [ SP &quot;COLLECTIVE&quot; ]           ; collective
+     *         [ SP &quot;NO-USER-MODIFICATION&quot; ] ; not user modifiable
+     *         [ SP &quot;USAGE&quot; SP usage ]       ; usage
+     *         extensions WSP RPAREN         ; extensions
+     * 
+     *     usage = &quot;userApplications&quot;     /  ; user
+     *             &quot;directoryOperation&quot;   /  ; directory operational
+     *             &quot;distributedOperation&quot; /  ; DSA-shared operational
+     *             &quot;dSAOperation&quot;            ; DSA-specific operational
+     * 
+     *   where:
+     *     &lt;numericoid&gt; is object identifier assigned to this attribute type;
+     *     NAME &lt;qdescrs&gt; are short names (descriptors) identifying this
+     *         attribute type;
+     *     DESC &lt;qdstring&gt; is a short descriptive string;
+     *     OBSOLETE indicates this attribute type is not active;
+     *     SUP oid specifies the direct supertype of this type;
+     *     EQUALITY, ORDERING, SUBSTR provide the oid of the equality,
+     *         ordering, and substrings matching rules, respectively;
+     *     SYNTAX identifies value syntax by object identifier and may suggest
+     *         a minimum upper bound;
+     *     SINGLE-VALUE indicates attributes of this type are restricted to a
+     *         single value;
+     *     COLLECTIVE indicates this attribute type is collective
+     *         [X.501][RFC3671];
+     *     NO-USER-MODIFICATION indicates this attribute type is not user
+     *         modifiable;
+     *     USAGE indicates the application of this attribute type; and
+     *     &lt;extensions&gt; describe extensions.
+     * </pre>
+     * @param at the AttributeType to render the description for
+     * @return the StringBuffer containing the rendered attributeType description
+     * @throws LdapException if there are problems accessing the objects
+     * associated with the attribute type.
+     */
+    public String render( AttributeType at )
+    {
+        StringBuilder buf = renderStartOidNamesDescObsolete( at, "attributetype" );
+
+        /*
+         *  TODO: Check for getSuperior(), getEquality(), getOrdering(), and getSubstring() should not be necessary. 
+         *  The getXyzOid() methods should return a name but return a numeric OID currently.
+         */
+
+        if ( at.getSuperior() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "SUP " ).append( at.getSuperior().getName() );
+            prettyPrintNewLine( buf );
+        }
+        else if ( at.getSuperiorOid() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "SUP " ).append( at.getSuperiorOid() );
+            prettyPrintNewLine( buf );
+        }
+
+        if ( at.getEquality() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "EQUALITY " ).append( at.getEquality().getName() );
+            prettyPrintNewLine( buf );
+        }
+        else if ( at.getEqualityOid() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "EQUALITY " ).append( at.getEqualityOid() );
+            prettyPrintNewLine( buf );
+        }
+
+        if ( at.getOrdering() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "ORDERING " ).append( at.getOrdering().getName() );
+            prettyPrintNewLine( buf );
+        }
+        else if ( at.getOrderingOid() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "ORDERING " ).append( at.getOrderingOid() );
+            prettyPrintNewLine( buf );
+        }
+
+        if ( at.getSubstring() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "SUBSTR " ).append( at.getSubstring().getName() );
+            prettyPrintNewLine( buf );
+        }
+        else if ( at.getSubstringOid() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "SUBSTR " ).append( at.getSubstringOid() );
+            prettyPrintNewLine( buf );
+        }
+
+        if ( at.getSyntaxOid() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "SYNTAX " ).append( at.getSyntaxOid() );
+
+            if ( at.getSyntaxLength() > 0 )
+            {
+                buf.append( "{" ).append( at.getSyntaxLength() ).append( "}" );
+            }
+            prettyPrintNewLine( buf );
+        }
+
+        if ( at.isSingleValued() )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "SINGLE-VALUE" );
+            prettyPrintNewLine( buf );
+        }
+
+        if ( at.isCollective() )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "COLLECTIVE" );
+            prettyPrintNewLine( buf );
+        }
+
+        if ( !at.isUserModifiable() )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "NO-USER-MODIFICATION" );
+            prettyPrintNewLine( buf );
+        }
+
+        if ( at.getUsage() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "USAGE " ).append( UsageEnum.render( at.getUsage() ) );
+            prettyPrintNewLine( buf );
+        }
+
+        renderXSchemaName( at, buf );
+
+        // @todo extensions are not presently supported and skipped
+        // the extensions would go here before closing off the description
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Renders an matchingRule according to the
+     * MatchingRule Description Syntax 1.3.6.1.4.1.1466.115.121.1.30. The syntax
+     * is described in detail within section 4.1.3. 
+     * <a href="https://tools.ietf.org/rfc/rfc4512.txt">RFC 4512</a>
+     * which is replicated here for convenience:
+     * 
+     * <pre>
+     *  4.1.3. Matching Rules
+     * 
+     *   Matching rules are used in performance of attribute value assertions,
+     *   such as in performance of a Compare operation.  They are also used in
+     *   evaluation of a Search filters, in determining which individual values
+     *   are be added or deleted during performance of a Modify operation, and
+     *   used in comparison of distinguished names.
+     * 
+     *   Each matching rule is identified by an object identifier (OID) and,
+     *   optionally, one or more short names (descriptors).
+     * 
+     *   Matching rule definitions are written according to the ABNF:
+     * 
+     *   MatchingRuleDescription = LPAREN WSP
+     *        numericoid                 ; object identifier
+     *         [ SP &quot;NAME&quot; SP qdescrs ]   ; short names (descriptors)
+     *         [ SP &quot;DESC&quot; SP qdstring ]  ; description
+     *         [ SP &quot;OBSOLETE&quot; ]          ; not active
+     *         SP &quot;SYNTAX&quot; SP numericoid  ; assertion syntax
+     *         extensions WSP RPAREN      ; extensions
+     * 
+     *   where:
+     *     &lt;numericoid&gt; is object identifier assigned to this matching rule;
+     *     NAME &lt;qdescrs&gt; are short names (descriptors) identifying this
+     *         matching rule;
+     *     DESC &lt;qdstring&gt; is a short descriptive string;
+     *     OBSOLETE indicates this matching rule is not active;
+     *     SYNTAX identifies the assertion syntax (the syntax of the assertion
+     *         value) by object identifier; and
+     *     &lt;extensions&gt; describe extensions.
+     * </pre>
+     * @param mr the MatchingRule to render the description for
+     * @return the StringBuffer containing the rendered matchingRule description
+     * @throws LdapException if there are problems accessing the objects
+     * associated with the MatchingRule.
+     */
+    public String render( MatchingRule mr )
+    {
+        StringBuilder buf = renderStartOidNamesDescObsolete( mr, "matchingrule" );
+
+        prettyPrintIndent( buf );
+        buf.append( "SYNTAX " ).append( mr.getSyntaxOid() );
+        prettyPrintNewLine( buf );
+
+        renderXSchemaName( mr, buf );
+
+        // @todo extensions are not presently supported and skipped
+        // the extensions would go here before closing off the description
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Renders a Syntax according to the LDAP Syntax
+     * Description Syntax 1.3.6.1.4.1.1466.115.121.1.54. The syntax is described
+     * in detail within section 4.1.5. of 
+     * <a href="https://tools.ietf.org/rfc/rfc4512.txt">RFC 4512</a>
+     * which is replicated here for convenience:
+     * 
+     * <pre>
+     *  LDAP syntax definitions are written according to the ABNF:
+     * 
+     *   SyntaxDescription = LPAREN WSP
+     *       numericoid                 ; object identifier
+     *       [ SP &quot;DESC&quot; SP qdstring ]  ; description
+     *       extensions WSP RPAREN      ; extensions
+     * 
+     *  where:
+     *   &lt;numericoid&gt; is the object identifier assigned to this LDAP syntax;
+     *   DESC &lt;qdstring&gt; is a short descriptive string; and
+     *   &lt;extensions&gt; describe extensions.
+     * </pre>
+     * @param syntax the Syntax to render the description for
+     * @return the StringBuffer containing the rendered syntax description
+     */
+    public String render( LdapSyntax syntax )
+    {
+        StringBuilder buf = new StringBuilder();
+
+        if ( style.startWithSchemaType )
+        {
+            buf.append( "ldapsyntax " );
+        }
+
+        buf.append( "( " ).append( syntax.getOid() );
+        prettyPrintNewLine( buf );
+
+        renderDescription( syntax, buf );
+
+        renderXSchemaName( syntax, buf );
+
+        prettyPrintIndent( buf );
+        if ( syntax.isHumanReadable() )
+        {
+            buf.append( "X-NOT-HUMAN-READABLE 'false'" );
+        }
+        else
+        {
+            buf.append( "X-NOT-HUMAN-READABLE 'true'" );
+        }
+        prettyPrintNewLine( buf );
+
+        // @todo extensions are not presently supported and skipped
+        // the extensions would go here before closing off the description
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * NOT FULLY IMPLEMENTED!
+     */
+    public String render( MatchingRuleUse mru )
+    {
+        StringBuilder buf = renderStartOidNamesDescObsolete( mru, "matchingruleuse" );
+
+        List<String> applies = mru.getApplicableAttributeOids();
+
+        if ( ( applies != null ) && ( applies.size() > 0 ) )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "APPLIES " );
+            renderOids( buf, applies );
+            prettyPrintNewLine( buf );
+        }
+
+        renderXSchemaName( mru, buf );
+
+        // @todo extensions are not presently supported and skipped
+        // the extensions would go here before closing off the description
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * NOT FULLY IMPLEMENTED!
+     */
+    public String render( DitContentRule dcr )
+    {
+        StringBuilder buf = renderStartOidNamesDescObsolete( dcr, "ditcontentrule" );
+
+        renderOids( buf, "AUX", dcr.getAuxObjectClassOids() );
+
+        renderOids( buf, "MUST", dcr.getMustAttributeTypeOids() );
+
+        renderOids( buf, "MAY", dcr.getMayAttributeTypeOids() );
+
+        renderOids( buf, "NOT", dcr.getNotAttributeTypeOids() );
+
+        renderXSchemaName( dcr, buf );
+
+        // @todo extensions are not presently supported and skipped
+        // the extensions would go here before closing off the description
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * NOT FULLY IMPLEMENTED!
+     */
+    public String render( DitStructureRule dsr )
+    {
+        StringBuilder buf = new StringBuilder();
+
+        if ( style.startWithSchemaType )
+        {
+            buf.append( "ditstructurerule " );
+        }
+
+        buf.append( "( " ).append( dsr.getRuleId() );
+
+        renderNames( dsr, buf );
+
+        renderDescription( dsr, buf );
+
+        renderObsolete( dsr, buf );
+
+        prettyPrintIndent( buf );
+        buf.append( "FORM " ).append( dsr.getForm() );
+        prettyPrintNewLine( buf );
+
+        renderRuleIds( buf, dsr.getSuperRules() );
+
+        renderXSchemaName( dsr, buf );
+
+        // @todo extensions are not presently supported and skipped
+        // the extensions would go here before closing off the description
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * NOT FULLY IMPLEMENTED!
+     */
+    public String render( NameForm nf )
+    {
+        StringBuilder buf = renderStartOidNamesDescObsolete( nf, "nameform" );
+
+        prettyPrintIndent( buf );
+        buf.append( "OC " ).append( nf.getStructuralObjectClassOid() );
+        prettyPrintNewLine( buf );
+
+        renderOids( buf, "MUST", nf.getMustAttributeTypeOids() );
+
+        renderOids( buf, "MAY", nf.getMayAttributeTypeOids() );
+
+        renderXSchemaName( nf, buf );
+
+        renderClose( buf );
+
+        return buf.toString();
+    }
+
+
+    private StringBuilder renderStartOidNamesDescObsolete( SchemaObject so, String schemaObjectType )
+    {
+        StringBuilder buf = new StringBuilder();
+
+        if ( style.startWithSchemaType )
+        {
+            buf.append( schemaObjectType ).append( ' ' );
+        }
+
+        buf.append( "( " ).append( so.getOid() );
+
+        renderNames( so, buf );
+
+        renderDescription( so, buf );
+
+        renderObsolete( so, buf );
+        return buf;
+    }
+
+
+    private void renderNames( SchemaObject so, StringBuilder buf )
+    {
+        List<String> names = so.getNames();
+
+        if ( ( names != null ) && ( names.size() > 0 ) )
+        {
+            buf.append( " NAME " );
+            renderQDescrs( buf, names );
+            prettyPrintNewLine( buf );
+        }
+        else
+        {
+            prettyPrintNewLine( buf );
+        }
+    }
+
+
+    private void renderDescription( SchemaObject so, StringBuilder buf )
+    {
+        if ( so.getDescription() != null )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "DESC " );
+            renderQDString( buf, so.getDescription() );
+            prettyPrintNewLine( buf );
+        }
+    }
+
+
+    private void renderObsolete( SchemaObject so, StringBuilder buf )
+    {
+        if ( so.isObsolete() )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "OBSOLETE" );
+            prettyPrintNewLine( buf );
+        }
+    }
+
+
+    private void prettyPrintNewLine( StringBuilder buf )
+    {
+        if ( style.prettyPrint )
+        {
+            buf.append( '\n' );
+        }
+        else
+        {
+            buf.append( " " );
+        }
+    }
+
+
+    private void prettyPrintIndent( StringBuilder buf )
+    {
+        if ( style.prettyPrint )
+        {
+            buf.append( "\t" );
+        }
+    }
+
+
+    /**
+     * Renders qdescrs into a new buffer.<br>
+     * <pre>
+     * descrs ::= qdescr | '(' WSP qdescrlist WSP ')'
+     * qdescrlist ::= [ qdescr ( SP qdescr )* ]
+     * qdescr     ::= SQUOTE descr SQUOTE
+     * </pre>
+     * @param qdescrs the quoted description strings to render
+     * @return the string buffer the qdescrs are rendered into
+     */
+    private StringBuilder renderQDescrs( StringBuilder buf, List<String> qdescrs )
+    {
+        if ( ( qdescrs == null ) || ( qdescrs.size() == 0 ) )
+        {
+            return buf;
+        }
+
+        if ( qdescrs.size() == 1 )
+        {
+            buf.append( '\'' ).append( qdescrs.get( 0 ) ).append( '\'' );
+        }
+        else
+        {
+            buf.append( "( " );
+
+            for ( String qdescr : qdescrs )
+            {
+                buf.append( '\'' ).append( qdescr ).append( "' " );
+            }
+
+            buf.append( ")" );
+        }
+
+        return buf;
+    }
+
+
+    private void renderOids( StringBuilder buf, String prefix, List<String> oids )
+    {
+        if ( ( oids != null ) && ( oids.size() > 0 ) )
+        {
+            prettyPrintIndent( buf );
+            buf.append( prefix ).append( ' ' );
+            renderOids( buf, oids );
+            prettyPrintNewLine( buf );
+        }
+    }
+
+
+    /**
+     * Renders oids into a new buffer.<br>
+     * <pre>
+     * oids    ::= oid | '(' WSP oidlist WSP ')'
+     * oidlist ::= oid ( WSP '$' WSP oid )*
+     * </pre>
+     * 
+     * @param qdescrs the quoted description strings to render
+     * @return the string buffer the qdescrs are rendered into
+     */
+    private StringBuilder renderOids( StringBuilder buf, List<String> oids )
+    {
+        if ( oids.size() == 1 )
+        {
+            buf.append( oids.get( 0 ) );
+        }
+        else
+        {
+            buf.append( "( " );
+
+            boolean isFirst = true;
+
+            for ( String oid : oids )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    buf.append( " $ " );
+                }
+
+                buf.append( oid );
+            }
+
+            buf.append( " )" );
+        }
+
+        return buf;
+    }
+
+
+    /**
+     * Renders QDString into a new buffer.<br>
+     * 
+     * @param qdescrs the quoted description strings to render
+     * @return the string buffer the qdescrs are rendered into
+     */
+    private StringBuilder renderQDString( StringBuilder buf, String qdString )
+    {
+        buf.append( '\'' );
+
+        for ( char c : qdString.toCharArray() )
+        {
+            switch ( c )
+            {
+                case 0x27:
+                    buf.append( "\\27" );
+                    break;
+
+                case 0x5C:
+                    buf.append( "\\5C" );
+                    break;
+
+                default:
+                    buf.append( c );
+                    break;
+            }
+        }
+
+        buf.append( '\'' );
+
+        return buf;
+    }
+
+
+    private StringBuilder renderRuleIds( StringBuilder buf, List<Integer> ruleIds )
+    {
+        if ( ( ruleIds != null ) && ( ruleIds.size() > 0 ) )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "SUP " );
+
+            if ( ruleIds.size() == 1 )
+            {
+                buf.append( ruleIds.get( 0 ) );
+            }
+            else
+            {
+                buf.append( "( " );
+
+                boolean isFirst = true;
+
+                for ( Integer ruleId : ruleIds )
+                {
+                    if ( isFirst )
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        buf.append( " " );
+                    }
+
+                    buf.append( ruleId );
+                }
+
+                buf.append( " )" );
+            }
+
+            prettyPrintNewLine( buf );
+        }
+
+        return buf;
+    }
+
+
+    private void renderXSchemaName( SchemaObject oc, StringBuilder buf )
+    {
+        if ( style.printSchemaName )
+        {
+            prettyPrintIndent( buf );
+            buf.append( "X-SCHEMA '" );
+            buf.append( oc.getSchemaName() );
+            buf.append( "'" );
+            prettyPrintNewLine( buf );
+        }
+    }
+
+
+    private void renderClose( StringBuilder buf )
+    {
+        if ( style.prettyPrint )
+        {
+            if ( buf.charAt( buf.length() - 1 ) == '\n' )
+            {
+                buf.deleteCharAt( buf.length() - 1 );
+                buf.append( " " );
+            }
+        }
+        buf.append( ")" );
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectSorter.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectSorter.java
new file mode 100644
index 0000000..5fa3efd
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectSorter.java
@@ -0,0 +1,249 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Various utility methods for sorting schema objects.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SchemaObjectSorter
+{
+    private SchemaObjectSorter()
+    {
+    }
+
+
+    /**
+     * Gets an hierarchical ordered {@link Iterable} of the given {@link AttributeType}s. 
+     * In other words parent {@link AttributeType}s are returned before child {@link AttributeType}s.
+     * @param attributeTypes list of attribute types to order
+     * @return the hierarchical ordered attribute types
+     */
+    public static Iterable<AttributeType> hierarchicalOrdered( List<AttributeType> attributeTypes )
+    {
+        return new SchemaObjectIterable<AttributeType>( attributeTypes, new ReferenceCallback<AttributeType>()
+        {
+            @Override
+            public Collection<String> getSuperiorOids( AttributeType at )
+            {
+                return Collections.singleton( at.getSuperiorOid() );
+            }
+        } );
+    }
+
+
+    /**
+     * Gets an hierarchical ordered {@link Iterable} of the given {@link ObjectClass}es. 
+     * In other words parent {@link ObjectClass}es are returned before child {@link ObjectClass}es.
+     * @param objectClasses list of object classes to order
+     * @return the hierarchical ordered object classes
+     */
+    public static Iterable<ObjectClass> sortObjectClasses( List<ObjectClass> objectClasses )
+    {
+        return new SchemaObjectIterable<ObjectClass>( objectClasses, new ReferenceCallback<ObjectClass>()
+        {
+            @Override
+            public Collection<String> getSuperiorOids( ObjectClass oc )
+            {
+                return oc.getSuperiorOids();
+            }
+        } );
+    }
+
+    private interface ReferenceCallback<T extends SchemaObject>
+    {
+
+        Collection<String> getSuperiorOids( T schemaObject );
+
+    }
+
+    private static final class SchemaObjectIterable<T extends SchemaObject> implements Iterable<T>
+    {
+
+        private final List<T> schemaObjects;
+        private final ReferenceCallback<T> callback;
+
+
+        private SchemaObjectIterable( List<T> schemaObjects, ReferenceCallback<T> callback )
+        {
+            this.schemaObjects = schemaObjects;
+            this.callback = callback;
+        }
+
+
+        @Override
+        public Iterator<T> iterator()
+        {
+            return new SchemaObjectIterator<T>( schemaObjects, callback );
+        }
+
+    }
+
+    private static final class SchemaObjectIterator<T extends SchemaObject> implements Iterator<T>
+    {
+        private final List<T> schemaObjects;
+        private final ReferenceCallback<T> callback;
+
+        private final Map<String, String> oid2numericOid;
+        private final Map<String, T> numericOid2schemaObject;
+
+        private int loopCount;
+        private Iterator<Entry<String, T>> schemaObjectIterator;
+
+
+        private SchemaObjectIterator( List<T> schemaObjects, ReferenceCallback<T> callback )
+        {
+            this.schemaObjects = schemaObjects;
+            this.callback = callback;
+
+            this.oid2numericOid = new HashMap<String, String>();
+            this.numericOid2schemaObject = new TreeMap<String, T>();
+            this.loopCount = 0;
+
+            for ( T schemaObject : schemaObjects )
+            {
+                String oid = Strings.toLowerCaseAscii( schemaObject.getOid() );
+                oid2numericOid.put( oid, oid );
+                
+                for ( String name : schemaObject.getNames() )
+                {
+                    oid2numericOid.put( Strings.toLowerCaseAscii( name ), oid );
+                }
+                
+                numericOid2schemaObject.put( oid, schemaObject );
+            }
+        }
+
+
+        @Override
+        public boolean hasNext()
+        {
+            return !numericOid2schemaObject.isEmpty();
+        }
+
+
+        @Override
+        public T next()
+        {
+            while ( !maxLoopCountReached() )
+            {
+                Iterator<Entry<String, T>> iterator = getIterator();
+
+                while ( iterator.hasNext() )
+                {
+                    Entry<String, T> entry = iterator.next();
+                    T schemaObject = entry.getValue();
+
+                    Collection<String> superiorOids = callback.getSuperiorOids( schemaObject );
+
+                    // schema object has no superior
+                    if ( superiorOids == null )
+                    {
+                        iterator.remove();
+                        return schemaObject;
+                    }
+
+                    boolean allSuperiorsProcessed = true;
+
+                    for ( String superiorOid : superiorOids )
+                    {
+                        if ( superiorOid == null )
+                        {
+                            continue;
+                        }
+
+                        String superiorNumeridOid = oid2numericOid.get( Strings.toLowerCaseAscii( superiorOid ) );
+
+                        // AT's superior is not within the processed AT list
+                        if ( superiorNumeridOid == null )
+                        {
+                            continue;
+                        }
+
+                        T superiorSchemaObject = numericOid2schemaObject.get( Strings.toLowerCaseAscii( superiorNumeridOid ) );
+
+                        // AT's superior was already removed
+                        if ( superiorSchemaObject == null )
+                        {
+                            continue;
+                        }
+
+                        allSuperiorsProcessed = false;
+                        break;
+                    }
+
+                    if ( allSuperiorsProcessed )
+                    {
+                        iterator.remove();
+                        return schemaObject;
+                    }
+                }
+            }
+            throw new IllegalStateException( "Loop detected: " + numericOid2schemaObject.values() );
+        }
+
+
+        private Iterator<Entry<String, T>> getIterator()
+        {
+            if ( schemaObjectIterator != null && schemaObjectIterator.hasNext() )
+            {
+                return schemaObjectIterator;
+            }
+
+            if ( !maxLoopCountReached() )
+            {
+                schemaObjectIterator = numericOid2schemaObject.entrySet().iterator();
+                loopCount++;
+                return schemaObjectIterator;
+            }
+
+            throw new IllegalStateException( "Loop detected: " + numericOid2schemaObject.values() );
+        }
+
+
+        private boolean maxLoopCountReached()
+        {
+            return loopCount > schemaObjects.size();
+        }
+
+
+        @Override
+        public void remove()
+        {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectType.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectType.java
new file mode 100644
index 0000000..aa1b09a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectType.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+
+
+/**
+ * The SchemaObject types
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum SchemaObjectType
+{
+    ATTRIBUTE_TYPE(0),
+    COMPARATOR(1),
+    DIT_CONTENT_RULE(2),
+    DIT_STRUCTURE_RULE(3),
+    LDAP_SYNTAX(4),
+    MATCHING_RULE(5),
+    MATCHING_RULE_USE(6),
+    NAME_FORM(7),
+    NORMALIZER(8),
+    OBJECT_CLASS(9),
+    SYNTAX_CHECKER(10);
+
+    /** The inner value*/
+    private int value;
+
+
+    /**
+     * A private constructor to associated a number to the type
+     */
+    private SchemaObjectType( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The numeric value for this type
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Get the Rdn associated with a schemaObjectType
+     *
+     * @return The associated Rdn
+     */
+    public String getRdn()
+    {
+        String schemaObjectPath = null;
+
+        switch ( this )
+        {
+            case ATTRIBUTE_TYPE:
+                schemaObjectPath = SchemaConstants.ATTRIBUTE_TYPES_PATH;
+                break;
+
+            case COMPARATOR:
+                schemaObjectPath = SchemaConstants.COMPARATORS_PATH;
+                break;
+
+            case DIT_CONTENT_RULE:
+                schemaObjectPath = SchemaConstants.DIT_CONTENT_RULES_PATH;
+                break;
+
+            case DIT_STRUCTURE_RULE:
+                schemaObjectPath = SchemaConstants.DIT_STRUCTURE_RULES_PATH;
+                break;
+
+            case LDAP_SYNTAX:
+                schemaObjectPath = SchemaConstants.SYNTAXES_PATH;
+                break;
+
+            case MATCHING_RULE:
+                schemaObjectPath = SchemaConstants.MATCHING_RULES_PATH;
+                break;
+
+            case MATCHING_RULE_USE:
+                schemaObjectPath = SchemaConstants.MATCHING_RULE_USE_PATH;
+                break;
+
+            case NAME_FORM:
+                schemaObjectPath = SchemaConstants.NAME_FORMS_PATH;
+                break;
+
+            case NORMALIZER:
+                schemaObjectPath = SchemaConstants.NORMALIZERS_PATH;
+                break;
+
+            case OBJECT_CLASS:
+                schemaObjectPath = SchemaConstants.OBJECT_CLASSES_PATH;
+                break;
+
+            case SYNTAX_CHECKER:
+                schemaObjectPath = SchemaConstants.SYNTAX_CHECKERS_PATH;
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected SchemaObjectType " + this );
+        }
+
+        return schemaObjectPath;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectWrapper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectWrapper.java
new file mode 100644
index 0000000..6b0443f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaObjectWrapper.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+/**
+ * A class containing a SchemaObject, used by the global registries. As the hash code
+ * method of the SchemaObject class is too complex, we had to define a simplest class
+ * for this purpose, where the hash code is computed using only the SchemaObject
+ * type and its OID.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaObjectWrapper
+{
+    /** The internal schemaObject */
+    private SchemaObject schemaObject;
+
+
+    /**
+     * Creates a new instance of SchemaObjectWrapper.
+     *
+     * @param schemaObject The contained SchemaObject
+     */
+    public SchemaObjectWrapper( SchemaObject schemaObject )
+    {
+        this.schemaObject = schemaObject;
+    }
+
+
+    /**
+     * Compute the hash code for this wrapper. We only use the object type
+     * and its oid.
+     */
+    public int hashCode()
+    {
+        int h = 37;
+        h += h * 17 + schemaObject.getObjectType().getValue();
+
+        if ( schemaObject.getOid() != null )
+        {
+            h += h * 17 + schemaObject.getOid().hashCode();
+        }
+
+        return h;
+    }
+
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals( Object o )
+    {
+        if ( o == this )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof SchemaObjectWrapper ) )
+        {
+            return false;
+        }
+
+        SchemaObject that = ( ( SchemaObjectWrapper ) o ).get();
+        SchemaObject current = get();
+
+        // Ultimately, that has to be true, regardless of the OID value
+        if ( that.getObjectType() != current.getObjectType() )
+        {
+            return false;
+        }
+
+        // If both OID are null, instances are equals
+        if ( that.getOid() == null )
+        {
+            return ( current.getOid() == null );
+        }
+
+        // The that'oid will never be null, we don't really care if current.oid is null here.
+        return that.getOid().equals( current.getOid() );
+    }
+
+
+    /**
+     *  @return The interned SchemaObject
+     */
+    public SchemaObject get()
+    {
+        return schemaObject;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return "<" + schemaObject.getObjectType() + "," + schemaObject.getOid() + ">";
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaUtils.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaUtils.java
new file mode 100644
index 0000000..236fce9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SchemaUtils.java
@@ -0,0 +1,665 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Various utility methods for schema functions and objects.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SchemaUtils
+{
+    /**
+     * Private constructor.
+     */
+    private SchemaUtils()
+    {
+    }
+
+
+    /**
+     * Gets the target entry as it would look after a modification operation
+     * were performed on it.
+     * 
+     * @param mods the modifications performed on the entry
+     * @param entry the source entry that is modified
+     * @return the resultant entry after the modifications have taken place
+     * @throws LdapException if there are problems accessing attributes
+     */
+    public static Entry getTargetEntry( List<? extends Modification> mods, Entry entry )
+        throws LdapException
+    {
+        Entry targetEntry = entry.clone();
+
+        for ( Modification mod : mods )
+        {
+            String id = mod.getAttribute().getId();
+
+            switch ( mod.getOperation() )
+            {
+                case REPLACE_ATTRIBUTE:
+                    targetEntry.put( mod.getAttribute() );
+                    break;
+
+                case ADD_ATTRIBUTE:
+                    Attribute combined = mod.getAttribute().clone();
+                    Attribute toBeAdded = mod.getAttribute();
+                    Attribute existing = entry.get( id );
+
+                    if ( existing != null )
+                    {
+                        for ( Value<?> value : existing )
+                        {
+                            combined.add( value );
+                        }
+                    }
+
+                    for ( Value<?> value : toBeAdded )
+                    {
+                        combined.add( value );
+                    }
+
+                    targetEntry.put( combined );
+                    break;
+
+                case REMOVE_ATTRIBUTE:
+                    Attribute toBeRemoved = mod.getAttribute();
+
+                    if ( toBeRemoved.size() == 0 )
+                    {
+                        targetEntry.removeAttributes( id );
+                    }
+                    else
+                    {
+                        existing = targetEntry.get( id );
+
+                        if ( existing != null )
+                        {
+                            for ( Value<?> value : toBeRemoved )
+                            {
+                                existing.remove( value );
+                            }
+                        }
+                    }
+
+                    break;
+
+                default:
+                    throw new IllegalStateException( I18n.err( I18n.ERR_04328, mod.getOperation() ) );
+            }
+        }
+
+        return targetEntry;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // qdescrs rendering operations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Renders qdescrs into an existing buffer.
+     * 
+     * @param buf
+     *            the string buffer to render the quoted description strs into
+     * @param qdescrs
+     *            the quoted description strings to render
+     * @return the same string buffer that was given for call chaining
+     */
+    public static StringBuffer render( StringBuffer buf, List<String> qdescrs )
+    {
+        if ( ( qdescrs == null ) || ( qdescrs.size() == 0 ) )
+        {
+            return buf;
+        }
+        else if ( qdescrs.size() == 1 )
+        {
+            buf.append( "'" ).append( qdescrs.get( 0 ) ).append( "'" );
+        }
+        else
+        {
+            buf.append( "( " );
+
+            for ( String qdescr : qdescrs )
+            {
+                buf.append( "'" ).append( qdescr ).append( "' " );
+            }
+
+            buf.append( ")" );
+        }
+
+        return buf;
+    }
+
+
+    /**
+     * Renders qdescrs into a new buffer.<br>
+     * <pre>
+     * descrs ::= qdescr | '(' WSP qdescrlist WSP ')'
+     * qdescrlist ::= [ qdescr ( SP qdescr )* ]
+     * qdescr     ::= SQUOTE descr SQUOTE
+     * </pre>
+     * @param qdescrs the quoted description strings to render
+     * @return the string buffer the qdescrs are rendered into
+     */
+    /* No qualifier */static StringBuffer renderQDescrs( StringBuffer buf, List<String> qdescrs )
+    {
+        if ( ( qdescrs == null ) || ( qdescrs.size() == 0 ) )
+        {
+            return buf;
+        }
+
+        if ( qdescrs.size() == 1 )
+        {
+            buf.append( '\'' ).append( qdescrs.get( 0 ) ).append( '\'' );
+        }
+        else
+        {
+            buf.append( "( " );
+
+            for ( String qdescr : qdescrs )
+            {
+                buf.append( '\'' ).append( qdescr ).append( "' " );
+            }
+
+            buf.append( ")" );
+        }
+
+        return buf;
+    }
+
+
+    /**
+     * Renders QDString into a new buffer.<br>
+     * 
+     * @param qdescrs the quoted description strings to render
+     * @return the string buffer the qdescrs are rendered into
+     */
+    private static StringBuffer renderQDString( StringBuffer buf, String qdString )
+    {
+        buf.append( '\'' );
+
+        for ( char c : qdString.toCharArray() )
+        {
+            switch ( c )
+            {
+                case 0x27:
+                    buf.append( "\\27" );
+                    break;
+
+                case 0x5C:
+                    buf.append( "\\5C" );
+                    break;
+
+                default:
+                    buf.append( c );
+                    break;
+            }
+        }
+
+        buf.append( '\'' );
+
+        return buf;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // objectClass list rendering operations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Renders a list of object classes for things like a list of superior
+     * objectClasses using the ( oid $ oid ) format.
+     * 
+     * @param ocs
+     *            the objectClasses to list
+     * @return a buffer which contains the rendered list
+     */
+    public static StringBuffer render( ObjectClass[] ocs )
+    {
+        StringBuffer buf = new StringBuffer();
+
+        return render( buf, ocs );
+    }
+
+
+    /**
+     * Renders a list of object classes for things like a list of superior
+     * objectClasses using the ( oid $ oid ) format into an existing buffer.
+     * 
+     * @param buf
+     *            the string buffer to render the list of objectClasses into
+     * @param ocs
+     *            the objectClasses to list
+     * @return a buffer which contains the rendered list
+     */
+    public static StringBuffer render( StringBuffer buf, ObjectClass[] ocs )
+    {
+        if ( ocs == null || ocs.length == 0 )
+        {
+            return buf;
+        }
+        else if ( ocs.length == 1 )
+        {
+            buf.append( ocs[0].getName() );
+        }
+        else
+        {
+            buf.append( "( " );
+
+            for ( int ii = 0; ii < ocs.length; ii++ )
+            {
+                if ( ii + 1 < ocs.length )
+                {
+                    buf.append( ocs[ii].getName() ).append( " $ " );
+                }
+                else
+                {
+                    buf.append( ocs[ii].getName() );
+                }
+            }
+
+            buf.append( " )" );
+        }
+
+        return buf;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // attributeType list rendering operations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Renders a list of attributeTypes for things like the must or may list of
+     * objectClasses using the ( oid $ oid ) format.
+     * 
+     * @param ats
+     *            the attributeTypes to list
+     * @return a buffer which contains the rendered list
+     */
+    public static StringBuffer render( AttributeType[] ats )
+    {
+        StringBuffer buf = new StringBuffer();
+        return render( buf, ats );
+    }
+
+
+    /**
+     * Renders a list of attributeTypes for things like the must or may list of
+     * objectClasses using the ( oid $ oid ) format into an existing buffer.
+     * 
+     * @param buf
+     *            the string buffer to render the list of attributeTypes into
+     * @param ats
+     *            the attributeTypes to list
+     * @return a buffer which contains the rendered list
+     */
+    public static StringBuffer render( StringBuffer buf, AttributeType[] ats )
+    {
+        if ( ats == null || ats.length == 0 )
+        {
+            return buf;
+        }
+        else if ( ats.length == 1 )
+        {
+            buf.append( ats[0].getName() );
+        }
+        else
+        {
+            buf.append( "( " );
+            for ( int ii = 0; ii < ats.length; ii++ )
+            {
+                if ( ii + 1 < ats.length )
+                {
+                    buf.append( ats[ii].getName() ).append( " $ " );
+                }
+                else
+                {
+                    buf.append( ats[ii].getName() );
+                }
+            }
+            buf.append( " )" );
+        }
+
+        return buf;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // schema object rendering operations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Renders the schema extensions into a new StringBuffer.
+     *
+     * @param extensions the schema extensions map with key and values
+     * @return a StringBuffer with the extensions component of a syntax description
+     */
+    public static StringBuffer render( Map<String, List<String>> extensions )
+    {
+        StringBuffer buf = new StringBuffer();
+
+        if ( extensions.isEmpty() )
+        {
+            return buf;
+        }
+
+        for ( Map.Entry<String, List<String>> entry : extensions.entrySet() )
+        {
+            buf.append( " " ).append( entry.getKey() ).append( " " );
+
+            List<String> values = entry.getValue();
+
+            // For extensions without values like X-IS-HUMAN-READIBLE
+            if ( values == null || values.isEmpty() )
+            {
+                continue;
+            }
+
+            // For extensions with a single value we can use one qdstring like 'value'
+            if ( values.size() == 1 )
+            {
+                buf.append( "'" ).append( values.get( 0 ) ).append( "' " );
+                continue;
+            }
+
+            // For extensions with several values we have to surround whitespace
+            // separated list of qdstrings like ( 'value0' 'value1' 'value2' )
+            buf.append( "( " );
+            for ( String value : values )
+            {
+                buf.append( "'" ).append( value ).append( "' " );
+            }
+            buf.append( ")" );
+        }
+
+        if ( buf.charAt( buf.length() - 1 ) != ' ' )
+        {
+            buf.append( " " );
+        }
+
+        return buf;
+    }
+
+
+    /**
+     * Returns a String description of a schema. The resulting String format is :
+     * <br>
+     * (OID [DESC '<description>'] FQCN <fcqn> [BYTECODE <bytecode>] X-SCHEMA '<schema>')
+     * <br>
+     * @param description The description to transform to a String
+     * @return
+     */
+    public static String render( LoadableSchemaObject description )
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append( "( " ).append( description.getOid() );
+
+        if ( description.getDescription() != null )
+        {
+            buf.append( " DESC " );
+            renderQDString( buf, description.getDescription() );
+        }
+
+        buf.append( " FQCN " ).append( description.getFqcn() );
+
+        if ( !Strings.isEmpty( description.getBytecode() ) )
+        {
+            buf.append( " BYTECODE " ).append( description.getBytecode() );
+        }
+
+        buf.append( " X-SCHEMA '" );
+        buf.append( getSchemaName( description ) );
+        buf.append( "' )" );
+
+        return buf.toString();
+    }
+
+
+    private static String getSchemaName( SchemaObject desc )
+    {
+        List<String> values = desc.getExtension( MetaSchemaConstants.X_SCHEMA_AT );
+
+        if ( values == null || values.size() == 0 )
+        {
+            return MetaSchemaConstants.SCHEMA_OTHER;
+        }
+
+        return values.get( 0 );
+    }
+
+
+    /**
+     * Remove the options from the attributeType, and returns the ID.
+     * 
+     * RFC 4512 :
+     * attributedescription = attributetype options
+     * attributetype = oid
+     * options = *( SEMI option )
+     * option = 1*keychar
+     */
+    public static String stripOptions( String attributeId )
+    {
+        int optionsPos = attributeId.indexOf( ';' );
+
+        if ( optionsPos != -1 )
+        {
+            return attributeId.substring( 0, optionsPos );
+        }
+        else
+        {
+            return attributeId;
+        }
+    }
+
+
+    /**
+     * Get the options from the attributeType.
+     * 
+     * For instance, given :
+     * jpegphoto;binary;lang=jp
+     * 
+     * your get back a set containing { "binary", "lang=jp" }
+     */
+    public static Set<String> getOptions( String attributeId )
+    {
+        int optionsPos = attributeId.indexOf( ';' );
+
+        if ( optionsPos != -1 )
+        {
+            Set<String> options = new HashSet<String>();
+
+            String[] res = attributeId.substring( optionsPos + 1 ).split( ";" );
+
+            for ( String option : res )
+            {
+                if ( !Strings.isEmpty( option ) )
+                {
+                    options.add( option );
+                }
+            }
+
+            return options;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Transform an UUID in a byte array
+     * @param uuid The UUID to transform
+     * @return The byte[] representing the UUID
+     */
+    public static byte[] uuidToBytes( UUID uuid )
+    {
+        Long low = uuid.getLeastSignificantBits();
+        Long high = uuid.getMostSignificantBits();
+        byte[] bytes = new byte[16];
+
+        bytes[0] = ( byte ) ( ( high & 0xff00000000000000L ) >> 56 );
+        bytes[1] = ( byte ) ( ( high & 0x00ff000000000000L ) >> 48 );
+        bytes[2] = ( byte ) ( ( high & 0x0000ff0000000000L ) >> 40 );
+        bytes[3] = ( byte ) ( ( high & 0x000000ff00000000L ) >> 32 );
+        bytes[4] = ( byte ) ( ( high & 0x00000000ff000000L ) >> 24 );
+        bytes[5] = ( byte ) ( ( high & 0x0000000000ff0000L ) >> 16 );
+        bytes[6] = ( byte ) ( ( high & 0x000000000000ff00L ) >> 8 );
+        bytes[7] = ( byte ) ( high & 0x00000000000000ffL );
+        bytes[8] = ( byte ) ( ( low & 0xff00000000000000L ) >> 56 );
+        bytes[9] = ( byte ) ( ( low & 0x00ff000000000000L ) >> 48 );
+        bytes[10] = ( byte ) ( ( low & 0x0000ff0000000000L ) >> 40 );
+        bytes[11] = ( byte ) ( ( low & 0x000000ff00000000L ) >> 32 );
+        bytes[12] = ( byte ) ( ( low & 0x00000000ff000000L ) >> 24 );
+        bytes[13] = ( byte ) ( ( low & 0x0000000000ff0000L ) >> 16 );
+        bytes[14] = ( byte ) ( ( low & 0x000000000000ff00L ) >> 8 );
+        bytes[15] = ( byte ) ( low & 0x00000000000000ffL );
+
+        return bytes;
+    }
+
+
+    /**
+     * Tells if an AttributeType name is valid or not. An Attribute name is valid if 
+     * it's a descr / numericoid, as described in rfc4512 :
+     * <pre>
+     * name = descr / numericOid
+     * descr = keystring
+     * keystring = leadkeychar *keychar
+     * leadkeychar = ALPHA
+     * keychar = ALPHA / DIGIT / HYPHEN / USCORE
+     * numericoid = number 1*( DOT number )
+     * number  = DIGIT / ( LDIGIT 1*DIGIT )
+     * ALPHA   = %x41-5A / %x61-7A   ; "A"-"Z" / "a"-"z"
+     * DIGIT   = %x30 / LDIGIT       ; "0"-"9"
+     * HYPHEN  = %x2D ; hyphen ("-")
+     * LDIGIT  = %x31-39             ; "1"-"9"
+     * DOT     = %x2E ; period (".")
+     * USCORE  = %x5F ; underscore ("_")
+     * </pre>
+     * 
+     * Note that we have extended this grammar to accept the '_' char, which is widely used in teh LDAP world.
+     *
+     * @param attributeName The AttributeType name to check
+     * @return true if it's valid
+     */
+    public static boolean isAttributeNameValid( String attributeName )
+    {
+        if ( Strings.isEmpty( attributeName ) )
+        {
+            return false;
+        }
+        
+        // Check the first char which must be ALPHA or DIGIT
+        boolean descr = false;
+        boolean zero = false;
+        boolean dot = false;
+        
+        char c = attributeName.charAt( 0 );
+        
+        if ( ( ( c >= 'a' ) && ( c <= 'z' ) ) || ( ( c >= 'A' ) && ( c <= 'Z' ) ) )
+        {
+            descr = true;
+        }
+        else if ( ( c >= '0' ) && ( c <= '9' ) )
+        {
+            descr = false;
+            
+            zero = c == '0'; 
+        }
+        else
+        {
+            return false;
+        }
+        
+        for ( int i = 1; i < attributeName.length(); i++ )
+        {
+            c = attributeName.charAt( i ); 
+            
+            if ( descr )
+            {
+                // This is a descr, iterate on KeyChars (ALPHA / DIGIT / HYPHEN / USCORE)
+                if ( ( ( c < 'a' ) || ( c > 'z' ) )
+                    && ( ( c < 'A' ) || ( c > 'Z' ) )
+                    && ( ( c < '0' ) || ( c > '9' ) )
+                    && ( c != '-' )
+                    && ( c != '_' ) )
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                // This is a numericOid, check it
+                if ( c == '.' )
+                {
+                    // Not allowed if we already have had a dot
+                    if ( dot )
+                    {
+                        return false;
+                    }
+                    
+                    dot = true;
+                    zero = false;
+                }
+                else if ( ( c >= '0' ) && ( c <= '9' ) )
+                {
+                    dot = false;
+                    
+                    if ( zero )
+                    {
+                        // We can't have a leading '0' followed by another number
+                        return false;
+                    }
+                    else if ( c == '0' )
+                    {
+                        zero = true;
+                    }
+                }
+                else
+                {
+                    // Not valid
+                    return false;
+                }
+            }
+        }
+        
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SyntaxChecker.java
new file mode 100644
index 0000000..76023ea
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/SyntaxChecker.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+/**
+ * Used to validate values of a particular syntax. This interface does not
+ * correlate to any LDAP or X.500 construct. It has been created as a means to
+ * enforce a syntax within the Eve server.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class SyntaxChecker extends LoadableSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * The SyntaxChecker base constructor
+     * @param oid The associated OID
+     */
+    protected SyntaxChecker( String oid )
+    {
+        super( SchemaObjectType.SYNTAX_CHECKER, oid );
+    }
+
+
+    /**
+     * The SyntaxChecker default constructor where the oid is set after 
+     * instantiation.
+     */
+    protected SyntaxChecker()
+    {
+        super( SchemaObjectType.SYNTAX_CHECKER );
+    }
+
+
+    /**
+     * Determines if the attribute's value conforms to the attribute syntax.
+     * 
+     * @param value the value of some attribute with the syntax
+     * @return true if the value is in the valid syntax, false otherwise
+     */
+    public abstract boolean isValidSyntax( Object value );
+
+
+    /**
+     * Store the SchemaManager in this instance. It may be necessary for some
+     * syntaxChecker which needs to have access to the oidNormalizer Map.
+     *
+     * @param schemaManager the schemaManager to store
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        // Do nothing (general case).
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( !super.equals( o ) )
+        {
+            return false;
+        }
+
+        return o instanceof SyntaxChecker;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return objectType + " " + DescriptionUtils.getDescription( this );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/UsageEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/UsageEnum.java
new file mode 100644
index 0000000..eeac1d1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/UsageEnum.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+/**
+ * Type safe enum for an AttributeType definition's usage string. This can be
+ * take one of the following four values:
+ * <ul>
+ * <li>userApplications</li>
+ * <li>directoryOperation</li>
+ * <li>distributedOperation</li>
+ * <li>dSAOperation</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum UsageEnum
+{
+    /** value for attributes with userApplications usage */
+    USER_APPLICATIONS(0),
+
+    /** value for attributes with directoryOperation usage */
+    DIRECTORY_OPERATION(1),
+
+    /** value for attributes with distributedOperation usage */
+    DISTRIBUTED_OPERATION(2),
+
+    /** value for attributes with dSAOperation usage */
+    DSA_OPERATION(3);
+
+    /** Stores the integer value of each element of the enumeration */
+    private int value;
+
+
+    /**
+     * Private construct so no other instances can be created other than the
+     * public static constants in this class.
+     * 
+     * @param value the integer value of the enumeration.
+     */
+    private UsageEnum( int value )
+    {
+        this.value = value;
+    }
+
+
+    /**
+     * @return The value associated with the current element.
+     */
+    public int getValue()
+    {
+        return value;
+    }
+
+
+    /**
+     * Gets the enumeration type for the attributeType usage string regardless
+     * of case.
+     * 
+     * @param usage the usage string
+     * @return the usage enumeration type
+     */
+    public static UsageEnum getUsage( String usage )
+    {
+        try
+        {
+            UsageEnum result = valueOf( usage );
+
+            return result;
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            if ( "directoryOperation".equals( usage ) )
+            {
+                return DIRECTORY_OPERATION;
+            }
+            else if ( "distributedOperation".equals( usage ) )
+            {
+                return DISTRIBUTED_OPERATION;
+            }
+            else if ( "dSAOperation".equals( usage ) )
+            {
+                return DSA_OPERATION;
+            }
+            else if ( "userApplications".equals( usage ) )
+            {
+                return USER_APPLICATIONS;
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+
+
+    /**
+     * Get the string representation for UsageEnum, which will be
+     * used by the AttributeType rendering 
+     * @param usage The UsageEnum of which we want the rendering string
+     * @return The rendering stringe
+     */
+    public static String render( UsageEnum usage )
+    {
+        if ( usage == null )
+        {
+            return "userApplications";
+        }
+
+        switch ( usage )
+        {
+            case DIRECTORY_OPERATION:
+                return "directoryOperation";
+            case DISTRIBUTED_OPERATION:
+                return "distributedOperation";
+            case DSA_OPERATION:
+                return "dSAOperation";
+            case USER_APPLICATIONS:
+                return "userApplications";
+            default:
+                return "";
+        }
+    }
+
+
+    /**
+     * Get the string representation for UsageEnum, which will be
+     * used by the AttributeType rendering 
+     * @return The rendering stringe
+     */
+    public String render()
+    {
+        return render( this );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/BitStringComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/BitStringComparator.java
new file mode 100644
index 0000000..c5e3bf9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/BitStringComparator.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class for the bitStringMatch matchingRule (RFC 4517, par. 4.2.1)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BitStringComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( BitStringComparator.class );
+
+
+    /**
+     * The BitStringComparator constructor. Its OID is the IntegerOrderingMatch matching
+     * rule OID.
+     */
+    public BitStringComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    public int compare( String bs1, String bs2 )
+    {
+        LOG.debug( "comparing BitString objects '{}' with '{}'", bs1, bs2 );
+
+        // First, shortcut the process by comparing
+        // references. If they are equals, then bs1 and bs2
+        // reference the same object
+        if ( bs1 == bs2 )
+        {
+            return 0;
+        }
+
+        // Then, deal with one of bs1 or bs2 being null
+        // Both can't be null, because then they would
+        // have been caught by the previous test
+        if ( ( bs1 == null ) || ( bs2 == null ) )
+        {
+            return ( bs1 == null ? -1 : 1 );
+        }
+
+        // We have to get rid of 0 from left of each BitString
+        char[] array1 = bs1.toCharArray();
+        char[] array2 = bs2.toCharArray();
+
+        int pos1 = bs1.indexOf( '1' );
+        int pos2 = bs2.indexOf( '1' );
+
+        if ( pos1 == -1 )
+        {
+            if ( pos2 == -1 )
+            {
+                return 0;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+        else if ( pos2 == -1 )
+        {
+            return 1;
+        }
+
+        int length1 = array1.length - pos1;
+        int length2 = array2.length - pos2;
+
+        if ( length1 == length2 )
+        {
+            for ( int i = 0; i < length1; i++ )
+            {
+                int i1 = i + pos1;
+                int i2 = i + pos2;
+
+                if ( array1[i1] < array2[i2] )
+                {
+                    return -1;
+                }
+                else if ( array1[i1] > array2[i2] )
+                {
+                    return 1;
+                }
+            }
+
+            return 0;
+        }
+
+        if ( length1 < length2 )
+        {
+            return -1;
+        }
+        else
+        {
+            return 1;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/BooleanComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/BooleanComparator.java
new file mode 100644
index 0000000..48d0f45
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/BooleanComparator.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class for the BooleanComparator matchingRule (RFC 4517, par. 4.2.2)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BooleanComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( BooleanComparator.class );
+
+
+    /**
+     * The BooleanComparator constructor. Its OID is the BooleanMatch matching
+     * rule OID.
+     */
+    public BooleanComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    public int compare( String b1, String b2 )
+    {
+        LOG.debug( "comparing boolean objects '{}' with '{}'", b1, b2 );
+
+        // First, shortcut the process by comparing
+        // references. If they are equals, then o1 and o2
+        // reference the same object
+        if ( b1 == b2 )
+        {
+            return 0;
+        }
+
+        // Then, deal with one of o1 or o2 being null
+        // Both can't be null, because then they would 
+        // have been catched by the previous test
+        if ( ( b1 == null ) || ( b2 == null ) )
+        {
+            return ( b1 == null ? -1 : 1 );
+        }
+
+        // The boolean should have been stored as 'TRUE' or 'FALSE'
+        // into the server, and the compare method will be called
+        // with normalized booleans, so no need to upper case them.
+        // We don't need to check the assertion value, because we
+        // are dealing with booleans.
+        boolean boolean1 = Boolean.valueOf( b1 );
+        boolean boolean2 = Boolean.valueOf( b2 );
+
+        if ( boolean1 == boolean2 )
+        {
+            return 0;
+        }
+
+        return ( boolean1 ? 1 : -1 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ByteArrayComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ByteArrayComparator.java
new file mode 100644
index 0000000..186258e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ByteArrayComparator.java
@@ -0,0 +1,120 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for byte[]s.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ByteArrayComparator extends LdapComparator<byte[]>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ByteArrayComparator.class );
+
+
+    /**
+     * The ByteArrayComparator constructor. Its OID is the OctetStringMatch matching
+     * rule OID.
+     */
+    public ByteArrayComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( byte[] b1, byte[] b2 )
+    {
+        LOG.debug( "comparing OctetString objects '{}' with '{}'",
+            Strings.dumpBytes( b1 ), Strings.dumpBytes( b2 ) );
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+
+        if ( b1 == null )
+        {
+            return ( b2 == null ) ? 0 : -1;
+        }
+
+        if ( b2 == null )
+        {
+            return 1;
+        }
+
+        if ( b1.length == b2.length )
+        {
+            for ( int i = 0; i < b1.length; i++ )
+            {
+                if ( b1[i] > b2[i] )
+                {
+                    return 1;
+                }
+                else if ( b1[i] < b2[i] )
+                {
+                    return -1;
+                }
+            }
+
+            return 0;
+        }
+
+        int minLength = Math.min( b1.length, b2.length );
+
+        for ( int i = 0; i < minLength; i++ )
+        {
+            if ( b1[i] > b2[i] )
+            {
+                return 1;
+            }
+            else if ( b1[i] < b2[i] )
+            {
+                return -1;
+            }
+        }
+
+        // b2 is longer w/ b1 as prefix 
+        if ( b1.length == minLength )
+        {
+            return -1;
+        }
+
+        // b1 is longer w/ b2 as prefix
+        if ( b2.length == minLength )
+        {
+            return 1;
+        }
+
+        return 0;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CertificateComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CertificateComparator.java
new file mode 100644
index 0000000..19d7aa3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CertificateComparator.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Comparator for Certificates
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CertificateComparator extends ByteArrayComparator
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CertificateComparator.class );
+
+
+    /**
+     * Creates a new instance of CertificateComparator.
+     */
+    public CertificateComparator( String oid )
+    {
+        super( oid );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ComparableComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ComparableComparator.java
new file mode 100644
index 0000000..eb55e8d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ComparableComparator.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Compares two objects taking into account that one might be a Comparable.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @param <T> the type, must extend {@link Comparable}
+ */
+public class ComparableComparator<T> extends LdapComparator<Comparable<T>>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ComparableComparator.class );
+
+
+    /**
+     * The ComparableComparator constructor.
+     *
+     * @param oid the comparator OID
+     */
+    public ComparableComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Compares two objects taking into account that one may be a Comparable. If
+     * the first is a comparable then its compareTo operation is called and the
+     * result returned as is. If the first is not a Comparable but the second is
+     * then its compareTo method is called and the result is returned after
+     * being negated. If none are comparable the hashCode of o1 minus the
+     * hashCode of o2 is returned.
+     *
+     * @param o1 the first comparable
+     * @param o2 the second comparable
+     * @return {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public int compare( Comparable<T> o1, Comparable<T> o2 )
+    {
+        LOG.debug( "comparing objects '{}' with '{}'", o1, o2 );
+
+        if ( o1 == null )
+        {
+            if ( o2 == null )
+            {
+                return 0;
+            }
+            else
+            {
+                return -11;
+            }
+        }
+
+        if ( o2 == null )
+        {
+            return 1;
+        }
+
+        return o1.compareTo( ( T ) o2 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CsnComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CsnComparator.java
new file mode 100644
index 0000000..9b7001e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CsnComparator.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for CSN.
+ *
+ * The CSN are ordered depending on an evaluation of its component, in this order :
+ * - time, 
+ * - changeCount,
+ * - sid
+ * - modifierNumber
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CsnComparator extends LdapComparator<Object>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CsnComparator.class );
+
+
+    /**
+     * The CsnComparator constructor. Its OID is the CsnMatch matching
+     * rule OID.
+     */
+    public CsnComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( Object csnObj1, Object csnObj2 )
+    {
+        LOG.debug( "comparing CSN objects '{}' with '{}'", csnObj1, csnObj2 );
+
+        if ( csnObj1 == csnObj2 )
+        {
+            return 0;
+        }
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( csnObj1 == null )
+        {
+            return ( csnObj2 == null ) ? 0 : -1;
+        }
+
+        if ( csnObj2 == null )
+        {
+            return 1;
+        }
+
+        String csnStr1 = null;
+        String csnStr2 = null;
+
+        if ( csnObj1 instanceof StringValue )
+        {
+            csnStr1 = ( ( StringValue ) csnObj1 ).getValue();
+        }
+        else
+        {
+            csnStr1 = csnObj1.toString();
+        }
+
+        if ( csnObj2 instanceof StringValue )
+        {
+            csnStr2 = ( ( StringValue ) csnObj2 ).getValue();
+        }
+        else
+        {
+            csnStr2 = csnObj2.toString();
+        }
+
+        return csnStr1.compareTo( csnStr2 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CsnSidComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CsnSidComparator.java
new file mode 100644
index 0000000..cc7c6fe
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/CsnSidComparator.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for CSN SID.
+ *
+ * The SID is supposed to be an hexadecimal number between 0x0 and 0xfff
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CsnSidComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CsnSidComparator.class );
+
+
+    /**
+     * The CsnSidComparator constructor. Its OID is the CsnSidMatch matching
+     * rule OID.
+     */
+    public CsnSidComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( String sidStr1, String sidStr2 )
+    {
+        LOG.debug( "comparing CSN SID objects '{}' with '{}'", sidStr1, sidStr2 );
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( sidStr1 == null )
+        {
+            return ( sidStr2 == null ) ? 0 : -1;
+        }
+
+        if ( sidStr2 == null )
+        {
+            return 1;
+        }
+
+        int sid1 = 0;
+        int sid2 = 0;
+
+        try
+        {
+            sid1 = Integer.parseInt( sidStr1, 16 );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            return -1;
+        }
+
+        try
+        {
+            sid2 = Integer.parseInt( sidStr2, 16 );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            return 1;
+        }
+
+        if ( sid1 > sid2 )
+        {
+            return 1;
+        }
+        else if ( sid2 > sid1 )
+        {
+            return -1;
+        }
+
+        return 0;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DeepTrimCachingNormalizingComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DeepTrimCachingNormalizingComparator.java
new file mode 100644
index 0000000..6553ec8
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DeepTrimCachingNormalizingComparator.java
@@ -0,0 +1,45 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.normalizers.CachingNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimNormalizer;
+
+
+/**
+ * TODO DeepTrimCachingNormalizingComparator.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DeepTrimCachingNormalizingComparator extends NormalizingComparator
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+
+    @SuppressWarnings(
+        { "rawtypes", "unchecked" })
+    public DeepTrimCachingNormalizingComparator( String oid )
+    {
+        super( oid, new CachingNormalizer( new DeepTrimNormalizer( oid ), 10 ),
+            new ComparableComparator( oid ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DeepTrimToLowerCachingNormalizingComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DeepTrimToLowerCachingNormalizingComparator.java
new file mode 100644
index 0000000..aaf06db
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DeepTrimToLowerCachingNormalizingComparator.java
@@ -0,0 +1,45 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.normalizers.CachingNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+
+
+/**
+ * TODO DeepTrimCachingNormalizingComparator.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DeepTrimToLowerCachingNormalizingComparator extends NormalizingComparator
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+
+    @SuppressWarnings(
+        { "rawtypes", "unchecked" })
+    public DeepTrimToLowerCachingNormalizingComparator( String oid )
+    {
+        super( oid, new CachingNormalizer( new DeepTrimToLowerNormalizer( oid ), 10 ),
+            new ComparableComparator( oid ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DnComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DnComparator.java
new file mode 100644
index 0000000..22bd833
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/DnComparator.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * Compare two DNs
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DnComparator extends LdapComparator<Object>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A reference to the schema manager */
+    private SchemaManager schemaManager;
+
+    public DnComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int compare( Object obj0, Object obj1 )
+    {
+        Dn dn0 = null;
+        Dn dn1 = null;
+
+        try
+        {
+            dn0 = getDn( obj0 );
+            dn1 = getDn( obj1 );
+        }
+        catch ( LdapException e )
+        {
+            // -- what do we do here ?
+            return -1;
+        }
+
+        int dn0Size = dn0.getRdns().size();
+        int dn1Size = dn1.getRdns().size();
+        
+        // check the equality first, cause
+        // when both DNs are equal checking isAncestorOf() returns true
+        if ( dn0.equals( dn1 ) )
+        {
+            return 0;
+        }
+        else if ( dn0Size > dn1Size )
+        {
+            return -1;
+        }
+        else if ( dn1Size > dn0Size )
+        {
+            return 1;
+        }
+
+        return dn0.getNormName().compareTo( dn1.getNormName() );
+    }
+
+
+    private Dn getDn( Object obj ) throws LdapInvalidDnException
+    {
+        Dn dn = null;
+
+        if ( obj instanceof Dn )
+        {
+            dn = ( Dn ) obj;
+
+            dn = ( dn.isSchemaAware() ? dn : dn.apply( schemaManager ) );
+        }
+        else if ( obj instanceof String )
+        {
+            dn = new Dn( schemaManager, ( String ) obj );
+        }
+        else
+        {
+            throw new IllegalStateException( I18n.err( I18n.ERR_04218, ( obj == null ? null : obj.getClass() ) ) );
+        }
+
+        return dn;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/GeneralizedTimeComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/GeneralizedTimeComparator.java
new file mode 100644
index 0000000..ffda500
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/GeneralizedTimeComparator.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.io.IOException;
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+import org.apache.directory.api.util.GeneralizedTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class for the generalizedTimeOrderingMatch matchingRule (RFC 4517, par. 4.2.17)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GeneralizedTimeComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( GeneralizedTimeComparator.class );
+
+
+    /**
+     * The GeneralizedTimeComparator constructor. Its OID is the
+     * generalizedTimeOrderingMatch matching rule OID.
+     */
+    public GeneralizedTimeComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    public int compare( String backendValue, String assertValue )
+    {
+        LOG.debug( "comparing generalizedTimeOrdering objects '{}' with '{}'", backendValue, assertValue );
+
+        // First, shortcut the process by comparing
+        // references. If they are equals, then o1 and o2
+        // reference the same object
+        if ( backendValue == assertValue )
+        {
+            return 0;
+        }
+
+        // Then, deal with one of o1 or o2 being null
+        // Both can't be null, because then they would
+        // have been caught by the previous test
+        if ( ( backendValue == null ) || ( assertValue == null ) )
+        {
+            return ( backendValue == null ? -1 : 1 );
+        }
+
+        // Both objects must be stored as String for generalized tim.
+        // But we need to normalize the values first.
+        GeneralizedTime backendTime;
+        try
+        {
+            String prepared = PrepareString.normalize( backendValue, PrepareString.StringType.DIRECTORY_STRING );
+            backendTime = new GeneralizedTime( prepared );
+        }
+        catch ( IOException ioe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, backendValue ), ioe );
+        }
+        catch ( ParseException pe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, backendValue ), pe );
+        }
+
+        GeneralizedTime assertTime;
+        
+        try
+        {
+            String prepared = PrepareString.normalize( assertValue, PrepareString.StringType.DIRECTORY_STRING );
+            assertTime = new GeneralizedTime( prepared );
+        }
+        catch ( IOException ioe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, assertValue ), ioe );
+        }
+        catch ( ParseException pe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, assertValue ), pe );
+        }
+
+        return backendTime.compareTo( assertTime );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/IntegerComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/IntegerComparator.java
new file mode 100644
index 0000000..08f6719
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/IntegerComparator.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.math.BigInteger;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class for the integerOrderingMatch matchingRule (RFC 4517, par. 4.2.20)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class IntegerComparator extends LdapComparator<Object> implements Serializable
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( IntegerComparator.class );
+
+
+    /**
+     * The IntegerComparator constructor. Its OID is the IntegerOrderingMatch matching
+     * rule OID.
+     */
+    public IntegerComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    public int compare( Object v1, Object v2 )
+    {
+        if ( v1 instanceof String )
+        {
+            return compare( ( String ) v1, ( String ) v2 );
+        }
+        else
+        {
+            return compare( ( Long ) v1, ( Long ) v2 );
+        }
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    private int compare( Long backendValue, Long assertValue )
+    {
+        LOG.debug( "comparing Integer objects '{}' with '{}'", backendValue, assertValue );
+
+        // First, shortcut the process by comparing
+        // references. If they are equals, then o1 and o2
+        // reference the same object
+        if ( backendValue == assertValue )
+        {
+            return 0;
+        }
+
+        // Then, deal with one of o1 or o2 being null
+        // Both can't be null, because then they would
+        // have been caught by the previous test
+        if ( ( backendValue == null ) || ( assertValue == null ) )
+        {
+            return ( backendValue == null ? -1 : 1 );
+        }
+
+        return backendValue.compareTo( assertValue );
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    private int compare( String backendValue, String assertValue )
+    {
+        LOG.debug( "comparing Integer objects '{}' with '{}'", backendValue, assertValue );
+
+        // First, shortcut the process by comparing
+        // references. If they are equals, then o1 and o2
+        // reference the same object
+        if ( backendValue == assertValue )
+        {
+            return 0;
+        }
+
+        // Then, deal with one of o1 or o2 being null
+        // Both can't be null, because then they would
+        // have been caught by the previous test
+        if ( ( backendValue == null ) || ( assertValue == null ) )
+        {
+            return ( backendValue == null ? -1 : 1 );
+        }
+
+        // Both objects must be stored as String for numeric.
+        // But we need to normalize the values first.
+        try
+        {
+            backendValue = PrepareString.normalize( backendValue, PrepareString.StringType.NUMERIC_STRING );
+        }
+        catch ( IOException ioe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, backendValue ), ioe );
+        }
+        try
+        {
+            assertValue = PrepareString.normalize( assertValue, PrepareString.StringType.NUMERIC_STRING );
+        }
+        catch ( IOException ioe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, assertValue ), ioe );
+        }
+
+        BigInteger b1 = new BigInteger( backendValue );
+        BigInteger b2 = new BigInteger( assertValue );
+
+        return b1.compareTo( b2 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/LongComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/LongComparator.java
new file mode 100644
index 0000000..1c893df
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/LongComparator.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.io.Serializable;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+
+
+/**
+ * Compares Long keys and values within a table.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LongComparator extends LdapComparator<Long> implements Serializable
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+
+    /**
+     * The LongComparator constructor. Its OID is the IntegerOrderingMatch matching
+     * rule OID.
+     */
+    public LongComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Compare two objects.
+     * 
+     * @param obj1 First object
+     * @param obj2 Second object
+     * @return 1 if obj1 > obj2, 0 if obj1 == obj2, -1 if obj1 < obj2
+     */
+    public int compare( Long obj1, Long obj2 )
+    {
+        if ( obj1 == obj2 )
+        {
+            return 0;
+        }
+
+        if ( obj1 == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04219_ARGUMENT1_NULL ) );
+        }
+
+        if ( obj2 == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04220_ARGUMENT2_NULL ) );
+        }
+
+        return obj1.compareTo( obj2 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/NormalizingComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/NormalizingComparator.java
new file mode 100644
index 0000000..ad7a483
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/NormalizingComparator.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator which normalizes a value first before using a subordinate
+ * comparator to compare them.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NormalizingComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NormalizingComparator.class );
+
+    /** the Normalizer to normalize values with before comparing */
+    private Normalizer normalizer;
+
+    /** the underlying comparator to use for comparisons */
+    private LdapComparator<String> comparator;
+
+    private boolean onServer = false;
+
+
+    /**
+     * A comparator which normalizes a value first before comparing them.
+     * 
+     * @param normalizer the Normalizer to normalize values with before comparing
+     * @param comparator the underlying comparator to use for comparisons
+     */
+    public NormalizingComparator( String oid, Normalizer normalizer, LdapComparator<String> comparator )
+    {
+        super( oid );
+        this.normalizer = normalizer;
+        this.comparator = comparator;
+    }
+
+
+    /**
+     * If any normalization attempt fails we compare using the unnormalized
+     * object.
+     */
+    public int compare( String o1, String o2 )
+    {
+        if ( onServer )
+        {
+            return comparator.compare( o1, o2 );
+        }
+
+        String n1;
+        String n2;
+
+        try
+        {
+            n1 = normalizer.normalize( o1 );
+        }
+        catch ( LdapException e )
+        {
+            LOG.warn( "Failed to normalize: " + o1, e );
+            n1 = o1;
+        }
+
+        try
+        {
+            n2 = normalizer.normalize( o2 );
+        }
+        catch ( LdapException e )
+        {
+            LOG.warn( "Failed to normalize: " + o2, e );
+            n2 = o2;
+        }
+
+        return comparator.compare( n1, n2 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * This implementation makes sure we update the oid property of the contained normalizer and 
+     * comparator.
+     */
+    @Override
+    public void setOid( String oid )
+    {
+        super.setOid( oid );
+        normalizer.setOid( oid );
+        comparator.setOid( oid );
+    }
+
+
+    /**
+     * tells that the normalizingComparator should not normalize values which are
+     * already normalized on the server 
+     */
+    public void setOnServer()
+    {
+        this.onServer = true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/NumericStringComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/NumericStringComparator.java
new file mode 100644
index 0000000..54f777a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/NumericStringComparator.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class for the numericStringOrderingMatch matchingRule (RFC 4517, par. 4.2.23)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NumericStringComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NumericStringComparator.class );
+
+
+    /**
+     * The IntegerComparator constructor. Its OID is the numericStringOrderingMatch matching
+     * rule OID.
+     */
+    public NumericStringComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    public int compare( String backendValue, String assertValue )
+    {
+        LOG.debug( "comparing numericStringOrdering objects '{}' with '{}'", backendValue, assertValue );
+
+        // First, shortcut the process by comparing
+        // references. If they are equals, then o1 and o2
+        // reference the same object
+        if ( backendValue == assertValue )
+        {
+            return 0;
+        }
+
+        // Then, deal with one of o1 or o2 being null
+        // Both can't be null, because then they would
+        // have been caught by the previous test
+        if ( ( backendValue == null ) || ( assertValue == null ) )
+        {
+            return ( backendValue == null ? -1 : 1 );
+        }
+
+        // Both objects must be stored as String for numeric.
+        // But we need to normalize the values first.
+        try
+        {
+            backendValue = PrepareString.normalize( backendValue, PrepareString.StringType.NUMERIC_STRING );
+        }
+        catch ( IOException ioe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, backendValue ), ioe );
+        }
+        try
+        {
+            assertValue = PrepareString.normalize( assertValue, PrepareString.StringType.NUMERIC_STRING );
+        }
+        catch ( IOException ioe )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04224, assertValue ), ioe );
+        }
+
+        return backendValue.compareTo( assertValue );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectClassTypeComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectClassTypeComparator.java
new file mode 100644
index 0000000..f7bc45c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectClassTypeComparator.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A comparator that compares the objectClass type with values: AUXILIARY,
+ * ABSTRACT, and STRUCTURAL.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ObjectClassTypeComparator<T> extends LdapComparator<T>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+
+    public ObjectClassTypeComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    public int compare( T o1, T o2 )
+    {
+        String s1 = getString( o1 );
+        String s2 = getString( o2 );
+
+        if ( s1 == null && s2 == null )
+        {
+            return 0;
+        }
+
+        if ( s1 == null )
+        {
+            return -1;
+        }
+
+        if ( s2 == null )
+        {
+            return 1;
+        }
+
+        return s1.compareTo( s2 );
+    }
+
+
+    String getString( T obj )
+    {
+        String strValue;
+
+        if ( obj == null )
+        {
+            return null;
+        }
+
+        if ( obj instanceof String )
+        {
+            strValue = ( String ) obj;
+        }
+        else if ( obj instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) obj );
+        }
+        else
+        {
+            strValue = obj.toString();
+        }
+
+        return strValue;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierComparator.java
new file mode 100644
index 0000000..44a532b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierComparator.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for the objectIdentifierMatch matchingRule.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ObjectIdentifierComparator extends LdapComparator<Object>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ObjectIdentifierComparator.class );
+
+
+    /**
+     * The ObjectIdentifierComparator constructor. Its OID is the ObjectIdentifierMatch matching
+     * rule OID.
+     */
+    public ObjectIdentifierComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( Object o1, Object o2 )
+    {
+        LOG.debug( "comparing ObjectIdentifier objects '{}' with '{}'", o1, o2 );
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( o1 == null )
+        {
+            return ( o2 == null ) ? 0 : -1;
+        }
+        else if ( o2 == null )
+        {
+            return 1;
+        }
+
+        if ( o1.equals( o2 ) )
+        {
+            return 0;
+        }
+
+        if ( !( o1 instanceof String && o2 instanceof String ) )
+        {
+            // Both objects must be strings...
+            if ( o1.equals( o2 ) )
+            {
+                return 0;
+            }
+
+            return -1;
+        }
+
+        // Here, we should leverage the SchemaManager to compare the String and teh OID
+        return ( ( String ) o1 ).compareToIgnoreCase( ( String ) o2 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierFirstComponentComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierFirstComponentComparator.java
new file mode 100644
index 0000000..a4243ae
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierFirstComponentComparator.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for Comparators. We compare the OIDs
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ObjectIdentifierFirstComponentComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ObjectIdentifierFirstComponentComparator.class );
+
+
+    /**
+     * The ObjectIdentifierFirstComponentComparator constructor. Its OID is the 
+     * ObjectIdentifierFirstComponentMatch matching rule OID.
+     */
+    public ObjectIdentifierFirstComponentComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Get the OID from the SchemaObject description
+     */
+    private String getNumericOid( String s )
+    {
+        // Get the OID from the strings now
+        int pos = 0;
+
+        if ( !Strings.isCharASCII( s, pos++, '(' ) )
+        {
+            return null;
+        }
+
+        while ( Strings.isCharASCII( s, pos, ' ' ) )
+        {
+            pos++;
+        }
+
+        int start = pos;
+
+        while ( Chars.isDigit( s, pos ) || Strings.isCharASCII( s, pos, '.' ) )
+        {
+            pos++;
+        }
+
+        String numericOid = s.substring( start, pos );
+
+        if ( Oid.isOid( numericOid ) )
+        {
+            return numericOid;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( String s1, String s2 )
+    {
+        LOG.debug( "comparing ObjectIdentifierFirstComponent objects '{}' with '{}'", s1, s2 );
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( s1 == null )
+        {
+            return ( s2 == null ) ? 0 : -1;
+        }
+
+        if ( s2 == null )
+        {
+            return -1;
+        }
+
+        // Let's try to avoid a parse.
+        if ( s1.equals( s2 ) )
+        {
+            return 0;
+        }
+
+        // Get the OID from the strings now
+        String oid1 = getNumericOid( s1 );
+
+        if ( oid1 == null )
+        {
+            return -1;
+        }
+
+        String oid2 = getNumericOid( s2 );
+
+        if ( oid2 == null )
+        {
+            return -1;
+        }
+
+        if ( oid1.equals( oid2 ) )
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/SerializableComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/SerializableComparator.java
new file mode 100644
index 0000000..0a889c2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/SerializableComparator.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * A serializable wrapper around a Comparator which uses delayed initialization
+ * of the underlying wrapped comparator which is JIT resolved from a static
+ * global registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SerializableComparator<E> extends LdapComparator<E> implements Serializable
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** the OID of the matchingRule for this comparator */
+    private String matchingRuleOid;
+
+    /** the transient wrapped comparator */
+    private transient Comparator<E> wrapped;
+
+    /** A reference to the schema manager */
+    private transient SchemaManager schemaManager;
+
+
+    /**
+     * Creates a new instance of SerializableComparator.
+     *
+     * @param matchingRuleOid The MatchingRule OID
+     */
+    public SerializableComparator( String matchingRuleOid )
+    {
+        super( matchingRuleOid );
+        this.matchingRuleOid = matchingRuleOid;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // C O M P A R A T O R   I M P L E M E N T A T I O N S
+    // ------------------------------------------------------------------------
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    @SuppressWarnings("unchecked")
+    public int compare( E o1, E o2 )
+    {
+        if ( wrapped == null )
+        {
+            try
+            {
+                wrapped = ( Comparator<E> ) schemaManager.lookupComparatorRegistry( matchingRuleOid );
+            }
+            catch ( LdapException le )
+            {
+                throw new RuntimeException( I18n.err( I18n.ERR_04221, matchingRuleOid ), le );
+            }
+        }
+
+        return wrapped.compare( o1, o2 );
+    }
+
+
+    /**
+     * @param schemaManager the schemaManager to set
+     */
+    @SuppressWarnings("unchecked")
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        if ( wrapped == null )
+        {
+            try
+            {
+                wrapped = ( Comparator<E> )
+                    schemaManager.lookupComparatorRegistry( matchingRuleOid );
+            }
+            catch ( LdapException ne )
+            {
+                // Not found : get the default comparator
+                wrapped = ( Comparator<E> )
+                    new ComparableComparator<Comparable<E>>( matchingRuleOid );
+            }
+        }
+
+        ( ( LdapComparator<E> ) wrapped ).setSchemaManager( schemaManager );
+        this.schemaManager = schemaManager;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/StringComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/StringComparator.java
new file mode 100644
index 0000000..9ddb3a5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/StringComparator.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.io.Serializable;
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for Strings.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StringComparator extends LdapComparator<String> implements Serializable
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( StringComparator.class );
+
+
+    /**
+     * The StringComparator constructor. Its OID is the StringMatch matching
+     * rule OID.
+     */
+    public StringComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( String s1, String s2 )
+    {
+        LOG.debug( "comparing String objects '{}' with '{}'", s1, s2 );
+
+        if ( s1 == s2 )
+        {
+            return 0;
+        }
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( s1 == null )
+        {
+            return ( s2 == null ) ? 0 : -1;
+        }
+
+        if ( s2 == null )
+        {
+            return 1;
+        }
+
+        return s1.compareTo( s2 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/TelephoneNumberComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/TelephoneNumberComparator.java
new file mode 100644
index 0000000..396e98c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/TelephoneNumberComparator.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for TelephoneNumber.
+ * 
+ * The rules for matching are identical to those for caseIgnoreMatch, except that 
+ * all space and "-" characters are skipped during the comparison. 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TelephoneNumberComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( TelephoneNumberComparator.class );
+
+
+    /**
+     * The TelephoneNumberComparator constructor. Its OID is the TelephoneNumberMatch matching
+     * rule OID.
+     */
+    public TelephoneNumberComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Remove all spaces and '-' from the telephone number
+     */
+    private String strip( String telephoneNumber )
+    {
+        char[] telephoneNumberArray = telephoneNumber.toCharArray();
+        int pos = 0;
+
+        for ( char c : telephoneNumberArray )
+        {
+            if ( ( c == ' ' ) || ( c == '-' ) )
+            {
+                continue;
+            }
+
+            telephoneNumberArray[pos++] = c;
+        }
+
+        return new String( telephoneNumberArray, 0, pos );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( String telephoneNumber1, String telephoneNumber2 )
+    {
+        LOG.debug( "comparing TelephoneNumber objects '{}' with '{}'", telephoneNumber1, telephoneNumber2 );
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( telephoneNumber1 == null )
+        {
+            return ( telephoneNumber2 == null ) ? 0 : -1;
+        }
+
+        if ( telephoneNumber2 == null )
+        {
+            return 1;
+        }
+
+        // -------------------------------------------------------------------
+        // Remove all spaces and '-'
+        // -------------------------------------------------------------------
+        String strippedTelephoneNumber1 = strip( telephoneNumber1 );
+        String strippedTelephoneNumber2 = strip( telephoneNumber2 );
+
+        return ( strippedTelephoneNumber1.compareToIgnoreCase( strippedTelephoneNumber2 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/UniqueMemberComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/UniqueMemberComparator.java
new file mode 100644
index 0000000..c9b17c1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/UniqueMemberComparator.java
@@ -0,0 +1,189 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * A comparator that sorts OIDs based on their numeric id value.  Needs a 
+ * OidRegistry to properly do it's job.  Public method to set the oid 
+ * registry will be used by the server after instantiation in deserialization.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UniqueMemberComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A reference to the schema manager */
+    private SchemaManager schemaManager;
+
+
+    /**
+     * The IntegerComparator constructor. Its OID is the IntegerOrderingMatch matching
+     * rule OID.
+     */
+    public UniqueMemberComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Implementation of the Compare method
+     */
+    public int compare( String dnstr1, String dnstr2 )
+    {
+        int dash1 = dnstr1.lastIndexOf( '#' );
+        int dash2 = dnstr2.lastIndexOf( '#' );
+
+        if ( ( dash1 == -1 ) && ( dash2 == -1 ) )
+        {
+            // no UID part
+            try
+            {
+                Dn dn1 = getDn( dnstr1 );
+                Dn dn2 = getDn( dnstr2 );
+
+                if ( dn1.equals( dn2 ) )
+                {
+                    return 0;
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+            catch ( LdapInvalidDnException ne )
+            {
+                return -1;
+            }
+        }
+        else
+        {
+            // Now, check that we don't have another '#'
+            if ( dnstr1.indexOf( '#' ) != dash1 )
+            {
+                // Yes, we have one : this is not allowed, it should have been
+                // escaped.
+                return -1;
+            }
+
+            if ( dnstr2.indexOf( '#' ) != dash1 )
+            {
+                // Yes, we have one : this is not allowed, it should have been
+                // escaped.
+                return 1;
+            }
+
+            Dn dn1 = null;
+            Dn dn2 = null;
+
+            // This is an UID if the '#' is immediatly
+            // followed by a BitString, except if the '#' is
+            // on the last position
+            String uid1 = dnstr1.substring( dash1 + 1 );
+
+            if ( dash1 > 0 )
+            {
+                try
+                {
+                    dn1 = new Dn( dnstr1.substring( 0, dash1 ) );
+                }
+                catch ( LdapException ne )
+                {
+                    return -1;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+
+            // This is an UID if the '#' is immediatly
+            // followed by a BitString, except if the '#' is
+            // on the last position
+            String uid2 = dnstr2.substring( dash2 + 1 );
+
+            if ( dash2 > 0 )
+            {
+                try
+                {
+                    dn2 = new Dn( dnstr1.substring( 0, dash2 ) );
+                }
+                catch ( LdapException ne )
+                {
+                    return 1;
+                }
+            }
+            else
+            {
+                return 1;
+            }
+
+            if ( dn1.equals( dn2 ) )
+            {
+                return uid1.compareTo( uid2 );
+            }
+
+            return -1;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+
+
+    public Dn getDn( Object obj ) throws LdapInvalidDnException
+    {
+        Dn dn = null;
+
+        if ( obj instanceof Dn )
+        {
+            dn = ( Dn ) obj;
+
+            dn = ( dn.isSchemaAware() ? dn : dn.apply( schemaManager ) );
+        }
+        else if ( obj instanceof String )
+        {
+            dn = new Dn( schemaManager, ( String ) obj );
+        }
+        else
+        {
+            throw new IllegalStateException( I18n.err( I18n.ERR_04218, ( obj == null ? null : obj.getClass() ) ) );
+        }
+
+        return dn;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/UuidComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/UuidComparator.java
new file mode 100644
index 0000000..51bb64d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/UuidComparator.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A comparator for UUID. We simply use the UUID compareTo method.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UuidComparator extends SerializableComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( UuidComparator.class );
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    public static final UuidComparator INSTANCE = new UuidComparator( "1.3.6.1.1.16.4" );
+
+
+    /**
+     * The UUIDComparator constructor. Its OID is the UUIDMatch matching
+     * rule OID.
+     */
+    public UuidComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( String uuid1, String uuid2 )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "comparing UUID objects '{}' with '{}'", uuid1, uuid2 );
+        }
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( uuid1 == null )
+        {
+            return ( uuid2 == null ) ? 0 : -1;
+        }
+
+        if ( uuid2 == null )
+        {
+            return 1;
+        }
+
+        return uuid1.compareTo( uuid2 );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( UUID uuid1, UUID uuid2 )
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "comparing UUID objects '{}' with '{}'", uuid1, uuid2 );
+        }
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( uuid1 == null )
+        {
+            return ( uuid2 == null ) ? 0 : -1;
+        }
+
+        if ( uuid2 == null )
+        {
+            return 1;
+        }
+
+        return uuid1.compareTo( uuid2 );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/WordComparator.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/WordComparator.java
new file mode 100644
index 0000000..4f53290
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/comparators/WordComparator.java
@@ -0,0 +1,146 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * <p>
+ * A comparator for Words/KeyWords. RFC 4517 par. 4.2.21 (KeywordMatch) and par.
+ * 4.2.32 is pretty vague about the definition of what is a word or a keyword
+ * ("...The precise definition of a word is implementation specific...)
+ * ("...The identification of keywords in the attribute value and the exactness
+ *  of the match are both implementation specific...).
+ * <p>
+ * We will simply check that the assertion is present in the value at some place,
+ * after having deep trimmed the word.
+ * <p>
+ * For instance, the word "  World  " will be found in the value "Hello world!".
+ * <p>
+ * A word is defined by the following regexp : "(^|[^A-Za-z0-9])([A-Za-z0-9])*([^A-Za-z0-9]|$)".
+ * Anything that is not matched by this regexp will not be considered as a word.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class WordComparator extends LdapComparator<String>
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( WordComparator.class );
+
+
+    /**
+     * The StringComparator constructor. Its OID is the StringMatch matching
+     * rule OID.
+     */
+    public WordComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+     */
+    public int compare( String value, String assertion )
+    {
+        LOG.debug( "comparing String objects '{}' with '{}'", value, assertion );
+
+        if ( value == assertion )
+        {
+            return 0;
+        }
+
+        // -------------------------------------------------------------------
+        // Handle some basis cases
+        // -------------------------------------------------------------------
+        if ( ( value == null ) || ( assertion == null ) )
+        {
+            return ( assertion == null ) ? 1 : -1;
+        }
+
+        // Now, trim the assertion and find it in the value
+        String trimmedAssertion = Strings.trim( assertion );
+        int pos = value.indexOf( trimmedAssertion );
+
+        if ( pos != -1 )
+        {
+            int assertionLength = trimmedAssertion.length();
+
+            // Check that we are not in a middle of some text
+            if ( assertionLength == value.length() )
+            {
+                return 0;
+            }
+
+            if ( pos == 0 )
+            {
+                char after = value.charAt( assertionLength );
+
+                if ( !Character.isLetterOrDigit( after ) )
+                {
+                    return 0;
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+
+            if ( pos + assertionLength == value.length() )
+            {
+                char before = value.charAt( value.length() - assertionLength - 1 );
+
+                if ( !Character.isLetterOrDigit( before ) )
+                {
+                    return 0;
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+
+            char before = value.charAt( value.length() - assertionLength );
+            char after = value.charAt( assertionLength );
+
+            if ( Character.isLetterOrDigit( after ) )
+            {
+                return -1;
+            }
+
+            if ( !Character.isLetterOrDigit( before ) )
+            {
+                return -1;
+            }
+
+            return 0;
+        }
+
+        return -1;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/BooleanNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/BooleanNormalizer.java
new file mode 100644
index 0000000..299fde4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/BooleanNormalizer.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+
+
+/**
+ * 
+ * Normalizer for boolean values.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class BooleanNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of BooleanNormalizer.
+     */
+    public BooleanNormalizer()
+    {
+        super( SchemaConstants.BOOLEAN_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapInvalidDnException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        String strValue = value.getString();
+
+        return new StringValue( strValue.trim().toUpperCase() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapInvalidDnException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        return value.trim().toUpperCase();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDeepTrimNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDeepTrimNormalizer.java
new file mode 100644
index 0000000..8aa6386
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDeepTrimNormalizer.java
@@ -0,0 +1,39 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+/**
+ * A deep trimming normalizer that caches normalizations to prevent repeat
+ * normalizations from occurring needlessly.  Try to use this sparing for only
+ * those kinds of attributeTypes using this Normalizer's matchingRule while 
+ * requiring heavy parsing activity.  This way there's some advantage to caching 
+ * normalized values.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CachingDeepTrimNormalizer extends CachingNormalizer
+{
+    public CachingDeepTrimNormalizer()
+    {
+        super( new DeepTrimNormalizer() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDeepTrimToLowerNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDeepTrimToLowerNormalizer.java
new file mode 100644
index 0000000..1fefdf7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDeepTrimToLowerNormalizer.java
@@ -0,0 +1,39 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+/**
+ * A deep trimming normalizer that caches normalizations to prevent repeat
+ * normalizations from occurring needlessly.  Try to use this sparing for only
+ * those kinds of attributeTypes using this Normalizer's matchingRule while 
+ * requiring heavy parsing activity.  This way there's some advantage to caching 
+ * normalized values.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CachingDeepTrimToLowerNormalizer extends CachingNormalizer
+{
+    public CachingDeepTrimToLowerNormalizer()
+    {
+        super( new DeepTrimToLowerNormalizer() );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDnNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDnNormalizer.java
new file mode 100644
index 0000000..96c7887
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingDnNormalizer.java
@@ -0,0 +1,51 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * A deep trimming normalizer that caches normalizations to prevent repeat
+ * normalizations from occurring needlessly.  Try to use this sparing for only
+ * those kinds of attributeTypes using this Normalizer's matchingRule while 
+ * requiring heavy parsing activity.  This way there's some advantage to caching 
+ * normalized values.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CachingDnNormalizer extends CachingNormalizer
+{
+    public CachingDnNormalizer()
+    {
+        super( new DnNormalizer() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        super.normalizer.setSchemaManager( schemaManager );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingNormalizer.java
new file mode 100644
index 0000000..a542427
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/CachingNormalizer.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * Caches previously normalized values.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CachingNormalizer extends Normalizer
+{
+    /** Cache maximum size default */
+    public static final int CACHE_MAX = 250;
+
+    /** The underlying decorated Normalizer */
+    protected final Normalizer normalizer;
+
+
+    // ------------------------------------------------------------------------
+    // C O N S T R U C T O R S
+    // ------------------------------------------------------------------------
+
+    /**
+     * Creates a CachingNormalizer that decorates another normalizer using a
+     * default cache size.  This Normalizer delegates
+     * 
+     * @param normalizer the underlying Normalizer being decorated
+     */
+    public CachingNormalizer( Normalizer normalizer )
+    {
+        this( normalizer, CACHE_MAX );
+    }
+
+
+    /**
+     * Creates a CachingNormalizer that decorates another normalizer using a
+     * specified cache size.
+     * 
+     * @param normalizer the underlying Normalizer being decorated
+     * @param cacheSz the maximum size of the name cache
+     */
+    public CachingNormalizer( Normalizer normalizer, int cacheSz )
+    {
+        super( normalizer.getOid() );
+        this.normalizer = normalizer;
+    }
+
+
+    /**
+     * Overrides default behavior by returning the OID of the wrapped
+     * Normalizer.
+     */
+    @Override
+    public String getOid()
+    {
+        return normalizer.getOid();
+    }
+
+
+    /**
+     * Overrides default behavior by setting the OID of the wrapped Normalizer.
+     * 
+     * @param oid the object identifier to set
+     */
+    @Override
+    public void setOid( String oid )
+    {
+        super.setOid( oid );
+        normalizer.setOid( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        Value<?> normalized = normalizer.normalize( value );
+
+        return normalized;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        String normalized = normalizer.normalize( value );
+
+        return normalized;
+    }
+
+
+    /**
+     * Sets the SchemaManager
+     * 
+     * @param schemaManager The SchemaManager
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        normalizer.setSchemaManager( schemaManager );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/ConcreteNameComponentNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/ConcreteNameComponentNormalizer.java
new file mode 100644
index 0000000..0ac686f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/ConcreteNameComponentNormalizer.java
@@ -0,0 +1,227 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Hex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Dn Name component Normalizer which uses the bootstrap registries to find
+ * the appropriate normalizer for the attribute of the name component with which
+ * to normalize the name component value.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ConcreteNameComponentNormalizer implements NameComponentNormalizer
+{
+    /** The LoggerFactory used by this Interceptor */
+    private static final Logger LOG = LoggerFactory.getLogger( ConcreteNameComponentNormalizer.class );
+
+    /** the schemaManager used to dynamically resolve Normalizers */
+    private final SchemaManager schemaManager;
+
+
+    /**
+     * Creates a Dn Name component Normalizer which uses the bootstrap
+     * registries to find the appropriate normalizer for the attribute of the
+     * name component with which to normalize the name component value.
+     *
+     * @param schemaManager the schemaManager used to dynamically resolve Normalizers
+     */
+    public ConcreteNameComponentNormalizer( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+
+
+    private String unescape( String value )
+    {
+        char[] newVal = new char[value.length()];
+        int escaped = 0;
+        char high = 0;
+        char low = 0;
+        int pos = 0;
+
+        for ( int index = 0; index < value.length(); index++  )
+        {
+            char c = value.charAt( index );
+            
+            switch ( escaped )
+            {
+                case 0:
+                    if ( c == '\\' )
+                    {
+                        escaped = 1;
+                    }
+                    else
+                    {
+                        newVal[pos++] = c;
+                    }
+
+                    break;
+
+                case 1:
+                    escaped++;
+                    high = c;
+                    break;
+
+                case 2:
+                    escaped = 0;
+                    low = c;
+                    newVal[pos++] = ( char ) Hex.getHexValue( high, low );
+                    break;
+
+                default:
+                    throw new IllegalStateException( "escaped can never have such a value: " + value );
+            }
+        }
+
+        return new String( newVal, 0, pos );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object normalizeByName( String name, String value ) throws LdapException
+    {
+        AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( name );
+
+        if ( attributeType.getSyntax().isHumanReadable() )
+        {
+            return lookup( name ).normalize( value );
+        }
+        else
+        {
+            try
+            {
+                String unescaped = unescape( value );
+                byte[] valBytes = unescaped.getBytes( "UTF-8" );
+
+                return lookup( name ).normalize( new BinaryValue( valBytes ) );
+            }
+            catch ( UnsupportedEncodingException uee )
+            {
+                String message = I18n.err( I18n.ERR_04222 );
+                LOG.error( message );
+                throw new LdapException( message, uee );
+            }
+        }
+
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object normalizeByName( String name, byte[] value ) throws LdapException
+    {
+        AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( name );
+
+        if ( !attributeType.getSyntax().isHumanReadable() )
+        {
+            return lookup( name ).normalize( new BinaryValue( value ) );
+        }
+        else
+        {
+            try
+            {
+                String valStr = new String( value, "UTF-8" );
+                return lookup( name ).normalize( valStr );
+            }
+            catch ( UnsupportedEncodingException uee )
+            {
+                String message = I18n.err( I18n.ERR_04223 );
+                LOG.error( message );
+                throw new LdapException( message, uee );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object normalizeByOid( String oid, String value ) throws LdapException
+    {
+        return lookup( oid ).normalize( value );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object normalizeByOid( String oid, byte[] value ) throws LdapException
+    {
+        return lookup( oid ).normalize( new BinaryValue( value ) );
+    }
+
+
+    /**
+     * Looks up the Normalizer to use for a name component using the attributeId
+     * for the name component.  First the attribute is resolved, then its
+     * equality matching rule is looked up.  The normalizer of that matching
+     * rule is returned.
+     *
+     * @param id the name or oid of the attribute in the name component to
+     * normalize the value of
+     * @return the Normalizer to use for normalizing the value of the attribute
+     * @throws LdapException if there are failures resolving the Normalizer
+     */
+    private Normalizer lookup( String id ) throws LdapException
+    {
+        AttributeType type = schemaManager.lookupAttributeTypeRegistry( id );
+        MatchingRule mrule = type.getEquality();
+
+        if ( mrule == null )
+        {
+            return new NoOpNormalizer( id );
+        }
+
+        return mrule.getNormalizer();
+    }
+
+
+    /**
+     * @see NameComponentNormalizer#isDefined(String)
+     */
+    public boolean isDefined( String id )
+    {
+        return schemaManager.getAttributeTypeRegistry().contains( id );
+    }
+
+
+    public String normalizeName( String attributeName ) throws LdapException
+    {
+        return schemaManager.getAttributeTypeRegistry().getOidByName( attributeName );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimNormalizer.java
new file mode 100644
index 0000000..6bbe265
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimNormalizer.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+
+
+/**
+ * Normalizer which trims down whitespace replacing multiple whitespace
+ * characters on the edges and within the string with a single space character
+ * thereby preserving tokenization order.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DeepTrimNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of DeepTrimNormalizer with OID known.
+     * 
+     * @param oid The MR OID to use with this Normalizer
+     */
+    public DeepTrimNormalizer( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Creates a new instance of DeepTrimNormalizer when the Normalizer must be
+     * instantiated before setting the OID.
+     */
+    public DeepTrimNormalizer()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        try
+        {
+            String normalized = PrepareString.normalize( value.getString(),
+                PrepareString.StringType.DIRECTORY_STRING );
+
+            return new StringValue( normalized );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04224, value ), ioe );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        try
+        {
+            String normalized = PrepareString.normalize( value,
+                PrepareString.StringType.DIRECTORY_STRING );
+
+            return normalized;
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04224, value ), ioe );
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimToLowerNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimToLowerNormalizer.java
new file mode 100644
index 0000000..a130fad
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimToLowerNormalizer.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+
+
+/**
+ * Normalizer which trims down whitespace replacing multiple whitespace
+ * characters on the edges and within the string with a single space character
+ * thereby preserving tokenization order - while doing all this in the same pass
+ * it lower cases all characters.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DeepTrimToLowerNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of DeepTrimToLowerNormalizer.
+     * 
+     * @param oid The MR OID to use with this Normalizer
+     */
+    public DeepTrimToLowerNormalizer( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Creates a new instance of DeepTrimToLowerNormalizer where the OID is
+     * set after instantiation.
+     */
+    public DeepTrimToLowerNormalizer()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        try
+        {
+            String normalized = PrepareString.normalize( value.getString(),
+                PrepareString.StringType.CASE_IGNORE );
+
+            return new StringValue( normalized );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04224, value ), ioe );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        try
+        {
+            String normalized = PrepareString.normalize( value,
+                PrepareString.StringType.CASE_IGNORE );
+
+            return normalized;
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04224, value ), ioe );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DefaultStringNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DefaultStringNormalizer.java
new file mode 100644
index 0000000..42df09e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DefaultStringNormalizer.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A normalizer which transforms an escape sequence into an internal 
+ * canonical form: into UTF-8 characters presuming the escape sequence
+ * fits that range.  This is used explicity for non-binary attribute
+ * types only.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DefaultStringNormalizer extends Normalizer
+{
+    /** A default String normalizer */
+    private static final DefaultStringNormalizer NORMALIZER = new DefaultStringNormalizer();
+
+
+    protected DefaultStringNormalizer()
+    {
+        // TODO : This is probably not the correct OID ... 
+        super( SchemaConstants.CASE_IGNORE_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        String str = value.getString();
+
+        if ( Strings.isEmpty( str ) )
+        {
+            return new StringValue( str );
+        }
+
+        return new StringValue( str );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        if ( Strings.isEmpty( value ) )
+        {
+            return value;
+        }
+
+        return value;
+    }
+
+
+    /**
+     * Normalize the given String
+     *
+     * @param string The string to normalize
+     * @return The normalized object
+     * @throws LdapException If the normalization throws an error
+     */
+    public static String normalizeString( String string ) throws LdapException
+    {
+        return NORMALIZER.normalize( string );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DnNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DnNormalizer.java
new file mode 100644
index 0000000..2bedf27
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/DnNormalizer.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+
+/**
+ * Normalizer a Dn
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DnNormalizer extends Normalizer
+{
+    /** A reference to the schema manager used to normalize the Dn */
+    private SchemaManager schemaManager;
+
+
+    /**
+     * Empty constructor
+     */
+    public DnNormalizer()
+    {
+        super( SchemaConstants.DISTINGUISHED_NAME_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        Dn dn = null;
+
+        String dnStr = value.getString();
+
+        dn = new Dn( schemaManager, dnStr );
+
+        return new StringValue( dn.getNormName() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        Dn dn = null;
+
+        dn = new Dn( schemaManager, value );
+
+        return dn.getNormName();
+    }
+
+
+    /**
+     * Normalize a Dn
+     * @param value The Dn to normalize
+     * @return A normalized Dn
+     * @throws LdapException
+     */
+    public String normalize( Dn value ) throws LdapException
+    {
+        Dn dn = null;
+
+        dn = value.apply( schemaManager );
+
+        return dn.getNormName();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/GeneralizedTimeNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/GeneralizedTimeNormalizer.java
new file mode 100644
index 0000000..5e274ea
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/GeneralizedTimeNormalizer.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import java.io.IOException;
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+import org.apache.directory.api.util.GeneralizedTime;
+import org.apache.directory.api.util.GeneralizedTime.Format;
+import org.apache.directory.api.util.GeneralizedTime.FractionDelimiter;
+import org.apache.directory.api.util.GeneralizedTime.TimeZoneFormat;
+
+
+/**
+ * Normalizer which normalize a time following those rules :
+ * <ul>
+ * <li>if minutes are ommited, then they are replaced by 00</li>
+ * <li>if seconds are ommited, then they are replaced by 00</li>
+ * <li>if fraction is 0 or omitted, it is replaced by 000</li>
+ * <li>the time is supposed to be expressed in Zulu (GMT), so 
+ * increment is applied to hours/days/yeah, and a Z is added at the end</li>
+ * </ul>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class GeneralizedTimeNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of GeneralizedTimeNormalizer.
+     */
+    public GeneralizedTimeNormalizer()
+    {
+        super( SchemaConstants.GENERALIZED_TIME_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        try
+        {
+            String normalized = PrepareString.normalize( value.getString(), PrepareString.StringType.DIRECTORY_STRING );
+
+            return new StringValue( normalized );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04224, value ), ioe );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        try
+        {
+            String prepared = PrepareString.normalize( value, PrepareString.StringType.DIRECTORY_STRING );
+
+            GeneralizedTime time = new GeneralizedTime( prepared );
+            String normalized = time.toGeneralizedTime( Format.YEAR_MONTH_DAY_HOUR_MIN_SEC_FRACTION,
+                FractionDelimiter.DOT, 3, TimeZoneFormat.Z );
+
+            return normalized;
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04224, value ), ioe );
+        }
+        catch ( ParseException pe )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04224, value ), pe );
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NameComponentNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NameComponentNormalizer.java
new file mode 100644
index 0000000..db9e3ba
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NameComponentNormalizer.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * Normalizers of ldap name component attributes and their values.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface NameComponentNormalizer
+{
+    /**
+     * Checks to see if an attribute name/oid is defined.
+     * 
+     * @param id
+     *            the name/oid of the attribute to see if it is defined
+     * @return true if it is, false otherwise
+     */
+    boolean isDefined( String id );
+
+
+    /**
+     * Normalizes the attribute name/alias to use the OID for it instead.
+     * 
+     * @param attributeName the name or OID of the attributeType
+     * @return the OID of the attributeType if it is recognized
+     * @throws LdapException if the attributeName is not recognized as a valid alias
+     */
+    String normalizeName( String attributeName ) throws LdapException;
+
+
+    /**
+     * Normalizes an attribute's value given the name of the attribute - short
+     * names like 'cn' as well as 'commonName' should work here.
+     * 
+     * @param attributeName
+     *            the name of the attribute
+     * @param value
+     *            the value of the attribute to normalize
+     * @return the normalized value
+     * @throws LdapException
+     *             if there is a recognition problem or a syntax issue
+     */
+    Object normalizeByName( String attributeName, String value ) throws LdapException;
+
+
+    /**
+     * Normalizes an attribute's value given the name of the attribute - short
+     * names like 'cn' as well as 'commonName' should work here.
+     * 
+     * @param attributeName
+     *            the name of the attribute
+     * @param value
+     *            the value of the attribute to normalize
+     * @return the normalized value
+     * @throws LdapException
+     *             if there is a recognition problem or a syntax issue
+     */
+    Object normalizeByName( String attributeName, byte[] value ) throws LdapException;
+
+
+    /**
+     * Normalizes an attribute's value given the OID of the attribute.
+     * 
+     * @param attributeOid
+     *            the OID of the attribute
+     * @param value
+     *            the value of the attribute to normalize
+     * @return the normalized value
+     * @throws LdapException
+     *             if there is a recognition problem or a syntax issue
+     */
+    Object normalizeByOid( String attributeOid, String value ) throws LdapException;
+
+
+    /**
+     * Normalizes an attribute's value given the OID of the attribute.
+     * 
+     * @param attributeOid
+     *            the OID of the attribute
+     * @param value
+     *            the value of the attribute to normalize
+     * @return the normalized value
+     * @throws LdapException
+     *             if there is a recognition problem or a syntax issue
+     */
+    Object normalizeByOid( String attributeOid, byte[] value ) throws LdapException;
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NameOrNumericIdNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NameOrNumericIdNormalizer.java
new file mode 100644
index 0000000..037195d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NameOrNumericIdNormalizer.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapOtherException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.NumericOidSyntaxChecker;
+
+
+/**
+ * A name or numeric id normalizer.  Needs an OID registry to operate properly.
+ * The OID registry is injected into this class after instantiation if a 
+ * setRegistries(Registries) method is exposed.
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NameOrNumericIdNormalizer extends Normalizer
+{
+    private NumericOidSyntaxChecker checker = new NumericOidSyntaxChecker();
+
+    /** A reference to the schema manager used to normalize the Name */
+    private SchemaManager schemaManager;
+
+    /** A static instance of this normalizer */
+    public static final NameOrNumericIdNormalizer INSTANCE = new NameOrNumericIdNormalizer();
+
+
+    /**
+     * Creates a new instance of GeneralizedTimeNormalizer.
+     */
+    public NameOrNumericIdNormalizer()
+    {
+        super( SchemaConstants.NAME_OR_NUMERIC_ID_MATCH_OID );
+    }
+
+
+    /**
+     * {@inheritDoc} 
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        String strValue = value.getString();
+
+        if ( strValue.length() == 0 )
+        {
+            return new StringValue( "" );
+        }
+
+        // if value is a numeric id then return it as is
+        if ( checker.isValidSyntax( strValue ) )
+        {
+            return value;
+        }
+
+        // if it is a name we need to do a lookup
+        String oid = schemaManager.getRegistries().getOid( strValue );
+
+        if ( oid != null )
+        {
+            return new StringValue( oid );
+        }
+
+        // if all else fails
+        throw new LdapOtherException( I18n.err( I18n.ERR_04225, value ) );
+    }
+
+
+    /**
+     * {@inheritDoc} 
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        if ( value.length() == 0 )
+        {
+            return value;
+        }
+
+        // if value is a numeric id then return it as is
+        if ( checker.isValidSyntax( value ) )
+        {
+            return value;
+        }
+
+        // if it is a name we need to do a lookup
+        String oid = schemaManager.getRegistries().getOid( value );
+
+        if ( oid != null )
+        {
+            return oid;
+        }
+
+        // if all else fails
+        throw new LdapOtherException( I18n.err( I18n.ERR_04226, value ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NoOpNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NoOpNormalizer.java
new file mode 100644
index 0000000..aa28520
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NoOpNormalizer.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+
+
+/**
+ * No op (pass through or do nothing) normalizer returning what its given.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NoOpNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of NoOpNormalizer.
+     * 
+     * @param oid The MR OID to use with this Normalizer
+     */
+    public NoOpNormalizer( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Default constructor for NoOpNormalizer used when we must set the OID
+     * after instantiating the Normalizer.
+     */
+    public NoOpNormalizer()
+    {
+    }
+
+
+    /**
+     * Returns the value argument as-is without alterations all the time.
+     * 
+     * @param value any value
+     * @return the value argument returned as-is
+     * @see org.apache.directory.api.ldap.model.schema.Normalizer#normalize(Value)
+     */
+    public Value<?> normalize( Value<?> value )
+    {
+        return value;
+    }
+
+
+    /**
+     * Returns the value argument as-is without alterations all the time.
+     * 
+     * @param value any value
+     * @return the value argument returned as-is
+     * @see org.apache.directory.api.ldap.model.schema.Normalizer#normalize(String)
+     */
+    public String normalize( String value )
+    {
+        return value;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NumericNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NumericNormalizer.java
new file mode 100644
index 0000000..0f6a1e2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/NumericNormalizer.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+
+
+/**
+ * Normalize Numeric Strings
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NumericNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of NumericNormalizer.
+     */
+    public NumericNormalizer()
+    {
+        super( SchemaConstants.NUMERIC_STRING_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        try
+        {
+            String normalized = PrepareString.normalize( value.getString(),
+                PrepareString.StringType.NUMERIC_STRING );
+
+            return new StringValue( normalized );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidDnException( I18n.err( I18n.ERR_04224, value ), ioe );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        try
+        {
+            return PrepareString.normalize( value,
+                PrepareString.StringType.NUMERIC_STRING );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidDnException( I18n.err( I18n.ERR_04224, value ), ioe );
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/ObjectIdentifierNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/ObjectIdentifierNormalizer.java
new file mode 100644
index 0000000..5b4dd25
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/ObjectIdentifierNormalizer.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A normalizer for the objectIdentifierMatch matching rule.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class ObjectIdentifierNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of ObjectIdentifierNormalizer.
+     */
+    public ObjectIdentifierNormalizer()
+    {
+        super( SchemaConstants.OBJECT_IDENTIFIER_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        String str = value.getString().trim();
+
+        if ( str.length() == 0 )
+        {
+            return new StringValue( "" );
+        }
+        else if ( Character.isDigit( str.charAt( 0 ) ) )
+        {
+            // We do this test to avoid a lowerCasing which cost time
+            return new StringValue( str );
+        }
+        else
+        {
+            return new StringValue( Strings.toLowerCase( str ) );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        String str = value.trim();
+
+        if ( str.length() == 0 )
+        {
+            return "";
+        }
+        else if ( Character.isDigit( str.charAt( 0 ) ) )
+        {
+            // We do this test to avoid a lowerCasing which cost time
+            return str;
+        }
+        else
+        {
+            return Strings.toLowerCase( str );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/OidNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/OidNormalizer.java
new file mode 100644
index 0000000..04ba6bf
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/OidNormalizer.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+
+
+/**
+ * The OidNomalizer class contains a tuple: an OID with its Normalizer.  It itself
+ * is not a normalizer.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OidNormalizer
+{
+    /** The oid */
+    private String attributeTypeOid;
+
+    /** The normalizer to be used with this OID */
+    private Normalizer normalizer;
+
+
+    /**
+     * A constructor which accept two parameters
+     * 
+     * @param attributeTypeOid the oid of the attributeType mapped to the normalizer
+     * @param normalizer the associated equality match based normalizer
+     */
+    public OidNormalizer( String attributeTypeOid, Normalizer normalizer )
+    {
+        this.attributeTypeOid = attributeTypeOid;
+        this.normalizer = normalizer;
+    }
+
+
+    /**
+     * A copy constructor.
+     * 
+     * @param oidNormalizer the OidNormalizer to copy from
+     */
+    public OidNormalizer( OidNormalizer oidNormalizer )
+    {
+        attributeTypeOid = oidNormalizer.attributeTypeOid;
+        normalizer = oidNormalizer.normalizer;
+    }
+
+
+    /**
+     * Get the normalizer
+     * 
+     * @return The normalizer associated to the current OID
+     */
+    public Normalizer getNormalizer()
+    {
+        return normalizer;
+    }
+
+
+    /**
+     * Get the current name
+     * 
+     * @return The current name
+     */
+    public String getAttributeTypeOid()
+    {
+        return attributeTypeOid;
+    }
+
+
+    /**
+     * Return a String representation of this class
+     */
+    public String toString()
+    {
+        return "OidNormalizer : { " + attributeTypeOid + ", " + normalizer.toString() + "}";
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/RegexNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/RegexNormalizer.java
new file mode 100644
index 0000000..999f5f1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/RegexNormalizer.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+
+
+/**
+ * A Normalizer that uses Perl5 based regular expressions to normalize values.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class RegexNormalizer extends Normalizer
+{
+    /** the perl 5 regex engine */
+    private final Pattern[] regexes;
+
+    /** the set of regular expressions used to transform values */
+    private final Matcher[] matchers;
+
+
+    /**
+     * Creates a Perl5 regular expression based normalizer.
+     * 
+     * @param oid The MR OID to use for this Normalizer
+     * @param regexes the set of regular expressions used to transform values
+     */
+    public RegexNormalizer( String oid, Pattern[] regexes )
+    {
+        super( oid );
+        if ( regexes != null )
+        {
+            this.regexes = new Pattern[regexes.length];
+            System.arraycopy( regexes, 0, this.regexes, 0, regexes.length );
+
+            matchers = new Matcher[regexes.length];
+
+            for ( int i = 0; i < regexes.length; i++ )
+            {
+                matchers[i] = regexes[i].matcher( "" );
+            }
+        }
+        else
+        {
+            this.regexes = null;
+            matchers = new Matcher[0];
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( final Value<?> value )
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        if ( value.isHumanReadable() )
+        {
+            String str = value.getString();
+
+            for ( int i = 0; i < matchers.length; i++ )
+            {
+
+                str = matchers[i].replaceAll( str );
+            }
+
+            return new StringValue( str );
+        }
+
+        return value;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value )
+    {
+        if ( value == null )
+        {
+            return null;
+        }
+
+        String str = value;
+
+        for ( int i = 0; i < matchers.length; i++ )
+        {
+
+            str = matchers[i].replaceAll( str );
+        }
+
+        return str;
+    }
+
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append( "RegexNormalizer( " );
+
+        for ( int i = 0; i < regexes.length; i++ )
+        {
+            buf.append( regexes[i] );
+
+            if ( i < regexes.length - 1 )
+            {
+                buf.append( ", " );
+            }
+        }
+
+        buf.append( " )" );
+        return buf.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/TelephoneNumberNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/TelephoneNumberNormalizer.java
new file mode 100644
index 0000000..d51b40e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/TelephoneNumberNormalizer.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.PrepareString;
+
+
+/**
+ * Normalize Telephone Number Strings
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class TelephoneNumberNormalizer extends Normalizer
+{
+    /**
+     * Creates a new instance of TelephoneNumberNormalizer.
+     */
+    public TelephoneNumberNormalizer()
+    {
+        super( SchemaConstants.TELEPHONE_NUMBER_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        try
+        {
+            String normalized = PrepareString.normalize( value.getString(),
+                PrepareString.StringType.TELEPHONE_NUMBER );
+
+            return new StringValue( normalized );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidDnException( I18n.err( I18n.ERR_04224, value ), ioe );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        try
+        {
+            return PrepareString.normalize( value,
+                PrepareString.StringType.TELEPHONE_NUMBER );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapInvalidDnException( I18n.err( I18n.ERR_04224, value ), ioe );
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/UniqueMemberNormalizer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/UniqueMemberNormalizer.java
new file mode 100644
index 0000000..26ca408
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/normalizers/UniqueMemberNormalizer.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A noirmalizer for UniqueMember
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class UniqueMemberNormalizer extends Normalizer
+{
+    /** A reference to the schema manager used to normalize the Dn */
+    private SchemaManager schemaManager;
+
+
+    public UniqueMemberNormalizer()
+    {
+        super( SchemaConstants.UNIQUE_MEMBER_MATCH_MR_OID );
+    }
+
+
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        String nameAndUid = value.getString();
+
+        if ( nameAndUid.length() == 0 )
+        {
+            return null;
+        }
+
+        // Let's see if we have an UID part
+        int sharpPos = nameAndUid.lastIndexOf( '#' );
+
+        if ( sharpPos != -1 )
+        {
+            // Now, check that we don't have another '#'
+            if ( nameAndUid.indexOf( '#' ) != sharpPos )
+            {
+                // Yes, we have one : this is not allowed, it should have been
+                // escaped.
+                return null;
+            }
+
+            // This is an UID if the '#' is immediately
+            // followed by a BitString, except if the '#' is
+            // on the last position
+            String uid = nameAndUid.substring( sharpPos + 1 );
+
+            if ( sharpPos > 0 )
+            {
+                Dn dn = new Dn( schemaManager, nameAndUid.substring( 0, sharpPos ) );
+
+                return new StringValue( dn.getNormName() + '#' + uid );
+            }
+            else
+            {
+                throw new IllegalStateException( I18n.err( I18n.ERR_04226, value.getClass() ) );
+            }
+        }
+        else
+        {
+            // No UID, the strValue is a Dn
+            // Return the normalized Dn
+            return new StringValue( new Dn( nameAndUid ).getNormName() );
+        }
+    }
+
+
+    public String normalize( String value ) throws LdapException
+    {
+        if ( Strings.isEmpty( value ) )
+        {
+            return null;
+        }
+
+        // Let's see if we have an UID part
+        int sharpPos = value.lastIndexOf( '#' );
+
+        if ( sharpPos != -1 )
+        {
+            // Now, check that we don't have another '#'
+            if ( value.indexOf( '#' ) != sharpPos )
+            {
+                // Yes, we have one : this is not allowed, it should have been
+                // escaped.
+                return null;
+            }
+
+            // This is an UID if the '#' is immediatly
+            // followed by a BitString, except if the '#' is
+            // on the last position
+            String uid = value.substring( sharpPos + 1 );
+
+            if ( sharpPos > 0 )
+            {
+                Dn dn = new Dn( schemaManager, value.substring( 0, sharpPos ) );
+
+                return dn.getNormName() + '#' + uid;
+            }
+            else
+            {
+                throw new IllegalStateException( I18n.err( I18n.ERR_04226, value.getClass() ) );
+            }
+        }
+        else
+        {
+            // No UID, the strValue is a Dn
+            // Return the normalized Dn
+            return new Dn( schemaManager, value ).getNormName();
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/overview.html b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/overview.html
new file mode 100644
index 0000000..7fb1a3c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/overview.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<HTML>
+<HEAD>
+  <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252"/>
+  <TITLE></TITLE>
+  <META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.0  (Win32)"/>
+  <META NAME="AUTHOR" CONTENT="Alex Karasulu"/>
+  <META NAME="CREATED" CONTENT="20031214;9293611"/>
+  <META NAME="CHANGEDBY" CONTENT="Alex Karasulu"/>
+  <META NAME="CHANGED" CONTENT="20031214;9310627"/>
+</HEAD>
+<BODY LANG="en-US" DIR="LTR">
+<P>
+LDAP and X.500 directories contain schema information.  The classes and
+interfaces defined within this package represent the schema information used to
+constrain the values of attributes, the attributes of entries and the structure
+of the directory information tree.
+</P>
+</BODY>
+</HTML>
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/package.html b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/package.html
new file mode 100644
index 0000000..15abed8
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/package.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<HTML>
+<BODY LANG="en-US" DIR="LTR">
+<P>
+Contains interfaces and base classes for representing the LDAP schema domain
+model.  We model the following LDAP schema objects:
+</P>
+
+<ul>
+  <li>attributeTypes</li>
+  <li>dITContentRules</li>
+  <li>dItStructureRules</li>
+  <li>matchingRules</li>
+  <li>matchingRuleUses</li>
+  <li>nameForms</li>
+  <li>objectClasses</li>
+  <li>syntaxes</li>
+</ul>
+
+<p>
+An interface is defined for each type of schema object.  All these interfaces
+extend from a common root interface: SchemaObject.  Other interfaces have been
+added to associate some useful behavoir with these objects.  These interfaces
+are listed below:
+</p>
+
+<ul>
+  <li>Normalizer</li>
+  <li>Comparator [from SDK]</li>
+  <li>SyntaxChecker</li>
+</ul>
+
+<p>
+These interfaces are primitive constructs that help define what some schema
+objects like a syntax or a matchingRule is in terms of use.  Namely these
+constructs determine how schema objects are applied.  For example a syntax exists
+not only as an OID to be implemented internally by some directory server.  It
+exists to constrain the values of attributes which are associated with the
+syntax.  This function is defined by the SyntaxChecker interface.  All syntaxes
+have a value checker that can apply the syntax to the value to determine if the
+value is accepted by the syntax.  A SyntaxChecker is nothing but a lexical
+pattern matcher like a regular expression.
+</p>
+
+<p>
+Normalizers and Comparators play an important role in controlling matching and
+hence giving meaning to matchingRules.  They respectively define how values are
+to be reduced to a canonical form and how they are to be compared to match
+filter assertions to values while conducting a search.  This is a very important
+aspect of the directory and unfortunately it is the least understood.  These
+two interfaces give tangible meaning to what a matchingRule is about making a
+matchingRule definition more than just an OID tag or place holder but something
+that can be used.
+</p>
+
+<p>
+The extra interfaces above are not SchemaObjects although they play a critical
+role in defining how schema objects are applied.  SchemaObjects are those that
+you actually get back from a directory server and are part of the protocol.
+Within a server environment the relevant schema objects will have valid
+SyntaxCheckers, Normalizers and Comparators.  However outside of the this
+environment these properties MAY be undefined.   We hope to make it defined
+on the client side as well if desired.
+</p>
+
+
+<p>
+  Here's what the OID of each element means according to [<a href=
+  "http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">MODELS
+  </a>]:
+</p>
+
+<table>
+  <tr><th>Schema Description</th><th>Numericoid Description</th></tr>
+  <tr><td>ObjectClass</td>
+    <td>numericoid is object identifier assigned to this object class;</td>
+  </tr>
+  <tr><td>AttributeType</td>
+    <td>numericoid is object identifier assigned to this attribute type;</td>
+  </tr>
+  <tr><td>MatchingRule</td>
+    <td>numericoid is object identifier assigned to this matching rule;</td>
+  </tr>
+  <tr><td>MatchingRuleUse</td>
+    <td>numericoid is the object identifier of the matching rule associated
+      with this matching rule use description; matching rule uses are [0-1]:[1]
+      cardinality with their respective matchingRule.
+    </td>
+  </tr>
+  <tr><td>Syntax</td>
+    <td>numericoid is object identifier assigned to this LDAP syntax;</td>
+  </tr>
+  <tr><td>DitContentRule</td>
+    <td>numericoid is the object identifier of the structural object class
+      associated with this DIT content rule;
+    </td>
+  </tr>
+  <tr><td>DitStructureRule</td>
+    <td>this now something very special and needs further investigation</td>
+  </tr>
+  <tr><td>NameForm</td>
+    <td>numericoid is object identifier which identifies this name form;</td>
+  </tr>
+</table>
+
+</BODY>
+</HTML>
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/AbstractSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/AbstractSchemaParser.java
new file mode 100644
index 0000000..7ee7a2e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/AbstractSchemaParser.java
@@ -0,0 +1,257 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.io.StringReader;
+import java.text.ParseException;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.TokenStreamRecognitionException;
+
+
+/**
+ * Base class of all schema parsers.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractSchemaParser<T extends SchemaObject>
+{
+    /** The LoggerFactory used by this class */
+    protected static final Logger LOG = LoggerFactory.getLogger( AbstractSchemaParser.class );
+
+    /** the monitor to use for this parser */
+    protected ParserMonitor monitor = new ParserMonitorAdapter();
+
+    /** the antlr generated parser being wrapped */
+    protected ReusableAntlrSchemaParser parser;
+
+    /** the antlr generated lexer being wrapped */
+    protected ReusableAntlrSchemaLexer lexer;
+
+    /** the schema object sub-type */
+    private Class<T> schemaObjectType;
+
+    /** error code used when schema descritpion is null */
+    private I18n errorCodeOnNull;
+
+    /** error code used on parse error when position is known */
+    private I18n errorCodeOnParseExceptionWithPosition;
+
+    /** error code used on parse error when position is unknown */
+    private I18n errorCodeOnParseException;
+
+
+    /**
+     * Instantiates a new abstract schema parser.
+     * @param errorCodeOnNull error code used when schema element is null
+     * @param errorCodeOnParseExceptionWithPosition error code used on parse error when position is known
+     * @param errorCodeOnParseException error code used on parse error when position is unknown
+     */
+    protected AbstractSchemaParser( Class<T> schemaObjectType, I18n errorCodeOnNull,
+        I18n errorCodeOnParseExceptionWithPosition,
+        I18n errorCodeOnParseException )
+    {
+        this.schemaObjectType = schemaObjectType;
+        this.errorCodeOnNull = errorCodeOnNull;
+        this.errorCodeOnParseExceptionWithPosition = errorCodeOnParseExceptionWithPosition;
+        this.errorCodeOnParseException = errorCodeOnParseException;
+        lexer = new ReusableAntlrSchemaLexer( new StringReader( "" ) );
+        parser = new ReusableAntlrSchemaParser( lexer );
+    }
+
+
+    /**
+     * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+     * pair with it. param spec the specification to be parsed
+     *
+     * @param spec the spec
+     */
+    protected void reset( String spec )
+    {
+        StringReader in = new StringReader( spec );
+        lexer.prepareNextInput( in );
+        parser.resetState();
+    }
+
+
+    /**
+     * Sets the parser monitor.
+     * 
+     * @param parserMonitor the new parser monitor
+     */
+    public void setParserMonitor( ParserMonitor parserMonitor )
+    {
+        this.monitor = parserMonitor;
+        parser.setParserMonitor( parserMonitor );
+    }
+
+
+    /**
+     * Sets the quirks mode. 
+     * 
+     * If enabled the parser accepts non-numeric OIDs and some 
+     * special characters in descriptions.
+     * 
+     * @param enabled the new quirks mode
+     */
+    public void setQuirksMode( boolean enabled )
+    {
+        parser.setQuirksMode( enabled );
+    }
+
+
+    /**
+     * Checks if quirks mode is enabled.
+     * 
+     * @return true, if is quirks mode is enabled
+     */
+    public boolean isQuirksMode()
+    {
+        return parser.isQuirksMode();
+    }
+
+
+    /**
+     * Parse a SchemaObject description and returns back an instance of SchemaObject.
+     * 
+     * @param schemaDescription The SchemaObject description
+     * @return A SchemaObject instance
+     * @throws ParseException If the parsing failed
+     */
+    public synchronized T parse( String schemaDescription ) throws ParseException
+    {
+        LOG.debug( "Parsing a {} : {}", schemaObjectType.getClass().getSimpleName(), schemaDescription );
+
+        if ( schemaDescription == null )
+        {
+            LOG.error( I18n.err( errorCodeOnNull ) );
+            throw new ParseException( "Null", 0 );
+        }
+
+        // reset and initialize the parser / lexer pair
+        reset( schemaDescription );
+
+        try
+        {
+            T schemaObject = doParse();
+            schemaObject.setSpecification( schemaDescription );
+
+            // Update the schemaName
+            updateSchemaName( schemaObject );
+
+            return schemaObject;
+        }
+        catch ( RecognitionException re )
+        {
+            ParseException parseException = wrapRecognitionException( schemaDescription, re );
+            throw parseException;
+        }
+        catch ( TokenStreamRecognitionException tsre )
+        {
+            if ( tsre.recog != null )
+            {
+                ParseException parseException = wrapRecognitionException( schemaDescription, tsre.recog );
+                throw parseException;
+            }
+            else
+            {
+                ParseException parseException = wrapTokenStreamException( schemaDescription, tsre );
+                throw parseException;
+            }
+        }
+        catch ( TokenStreamException tse )
+        {
+            ParseException parseException = wrapTokenStreamException( schemaDescription, tse );
+            throw parseException;
+        }
+    }
+
+
+    private ParseException wrapRecognitionException( String schemaDescription, RecognitionException re )
+    {
+        String msg = I18n.err( errorCodeOnParseExceptionWithPosition, schemaDescription, re.getMessage(),
+            re.getColumn() );
+        LOG.error( msg );
+        ParseException parseException = new ParseException( msg, re.getColumn() );
+        parseException.initCause( re );
+        return parseException;
+    }
+
+
+    private ParseException wrapTokenStreamException( String schemaDescription, TokenStreamException tse )
+    {
+        String msg = I18n.err( errorCodeOnParseException, schemaDescription, tse.getMessage() );
+        LOG.error( msg );
+        ParseException parseException = new ParseException( msg, 0 );
+        parseException.initCause( tse );
+        return parseException;
+    }
+
+
+    /**
+     * Parse a SchemaObject description and returns back an instance of SchemaObject.
+     * 
+     * @return A SchemaObject instance
+     * @throws RecognitionException the native antlr exception
+     * @throws TokenStreamException the native antlr exception
+     */
+    protected abstract T doParse() throws RecognitionException, TokenStreamException;
+
+
+    /**
+     * Update the schemaName for the given SchemaObject, accordingly to the X-SCHEMA parameter. If
+     * not present, default to 'other'
+     *
+     * @param schemaObject the schema object where the name should be updated
+     */
+    private void updateSchemaName( SchemaObject schemaObject )
+    {
+        // Update the Schema if we have the X-SCHEMA extension
+        List<String> schemaExtension = schemaObject.getExtension( MetaSchemaConstants.X_SCHEMA_AT );
+
+        if ( schemaExtension != null )
+        {
+            String schemaName = schemaExtension.get( 0 );
+
+            if ( Strings.isEmpty( schemaName ) )
+            {
+                schemaObject.setSchemaName( MetaSchemaConstants.SCHEMA_OTHER );
+            }
+            else
+            {
+                schemaObject.setSchemaName( schemaName );
+            }
+        }
+        else
+        {
+            schemaObject.setSchemaName( MetaSchemaConstants.SCHEMA_OTHER );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/AttributeTypeDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/AttributeTypeDescriptionSchemaParser.java
new file mode 100644
index 0000000..1250f96
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/AttributeTypeDescriptionSchemaParser.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 attribute type descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeTypeDescriptionSchemaParser extends AbstractSchemaParser<AttributeType>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public AttributeTypeDescriptionSchemaParser()
+    {
+        super( AttributeType.class, I18n.ERR_04227, I18n.ERR_04228, I18n.ERR_04229 );
+
+    }
+
+
+    /**
+     * Parses a attribute type description according to RFC 4512:
+     * 
+     * <pre>
+     * AttributeTypeDescription = LPAREN WSP
+     *     numericoid                    ; object identifier
+     *     [ SP "NAME" SP qdescrs ]      ; short names (descriptors)
+     *     [ SP "DESC" SP qdstring ]     ; description
+     *     [ SP "OBSOLETE" ]             ; not active
+     *     [ SP "SUP" SP oid ]           ; supertype
+     *     [ SP "EQUALITY" SP oid ]      ; equality matching rule
+     *     [ SP "ORDERING" SP oid ]      ; ordering matching rule
+     *     [ SP "SUBSTR" SP oid ]        ; substrings matching rule
+     *     [ SP "SYNTAX" SP noidlen ]    ; value syntax
+     *     [ SP "SINGLE-VALUE" ]         ; single-value
+     *     [ SP "COLLECTIVE" ]           ; collective
+     *     [ SP "NO-USER-MODIFICATION" ] ; not user modifiable
+     *     [ SP "USAGE" SP usage ]       ; usage
+     *     extensions WSP RPAREN         ; extensions
+     * 
+     * usage = "userApplications"     /  ; user
+     *         "directoryOperation"   /  ; directory operational
+     *         "distributedOperation" /  ; DSA-shared operational
+     *         "dSAOperation"            ; DSA-specific operational     
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+     * 
+     * @param attributeTypeDescription the attribute type description to be parsed
+     * @return the parsed AttributeTypeDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public AttributeType parseAttributeTypeDescription( String attributeTypeDescription ) throws ParseException
+    {
+        return super.parse( attributeTypeDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected AttributeType doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.attributeTypeDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ConsoleParserMonitor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ConsoleParserMonitor.java
new file mode 100644
index 0000000..2a05035
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ConsoleParserMonitor.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+/**
+ * A console reporting monitor.  Add system property 'maven.eve.schema.parser.trace'
+ * to get this monitor to trace parser production execution.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ConsoleParserMonitor implements ParserMonitor
+{
+    public static final String TRACE_KEY = "maven.eve.schema.parser.trace";
+
+
+    public void matchedProduction( String prod )
+    {
+        if ( System.getProperties().containsKey( TRACE_KEY ) )
+        {
+            System.out.println( prod );
+        }
+    }
+
+
+    public void startedParse( String s )
+    {
+        if ( System.getProperties().containsKey( TRACE_KEY ) )
+        {
+            System.out.println( s );
+        }
+    }
+
+
+    public void finishedParse( String s )
+    {
+        if ( System.getProperties().containsKey( TRACE_KEY ) )
+        {
+            System.out.println( s );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/DitContentRuleDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/DitContentRuleDescriptionSchemaParser.java
new file mode 100644
index 0000000..3635130
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/DitContentRuleDescriptionSchemaParser.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 DIT content rule descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DitContentRuleDescriptionSchemaParser extends AbstractSchemaParser<DitContentRule>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public DitContentRuleDescriptionSchemaParser()
+    {
+        super( DitContentRule.class, I18n.ERR_04230, I18n.ERR_04231, I18n.ERR_04232 );
+    }
+
+
+    /**
+     * Parses a DIT content rule description according to RFC 4512:
+     * 
+     * <pre>
+     * DITContentRuleDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    [ SP "AUX" SP oids ]       ; auxiliary object classes
+     *    [ SP "MUST" SP oids ]      ; attribute types
+     *    [ SP "MAY" SP oids ]       ; attribute types
+     *    [ SP "NOT" SP oids ]       ; attribute types
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+     * 
+     * @param ditContentRuleDescription the DIT content rule description to be parsed
+     * @return the parsed DITContentRuleDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public DitContentRule parseDITContentRuleDescription( String ditContentRuleDescription ) throws ParseException
+    {
+        return super.parse( ditContentRuleDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected DitContentRule doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.ditContentRuleDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/DitStructureRuleDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/DitStructureRuleDescriptionSchemaParser.java
new file mode 100644
index 0000000..806d663
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/DitStructureRuleDescriptionSchemaParser.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 DIT structure rule descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DitStructureRuleDescriptionSchemaParser extends AbstractSchemaParser<DitStructureRule>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public DitStructureRuleDescriptionSchemaParser()
+    {
+        super( DitStructureRule.class, I18n.ERR_04233, I18n.ERR_04234, I18n.ERR_04235 );
+    }
+
+
+    /**
+     * Parses a DIT structure rule description according to RFC 4512:
+     * 
+     * <pre>
+     * DITStructureRuleDescription = LPAREN WSP
+     *   ruleid                     ; rule identifier
+     *   [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *   [ SP "DESC" SP qdstring ]  ; description
+     *   [ SP "OBSOLETE" ]          ; not active
+     *   SP "FORM" SP oid           ; NameForm
+     *   [ SP "SUP" ruleids ]       ; superior rules
+     *   extensions WSP RPAREN      ; extensions
+     *
+     * ruleids = ruleid / ( LPAREN WSP ruleidlist WSP RPAREN )
+     * ruleidlist = ruleid *( SP ruleid )
+     * ruleid = numbers
+     * </pre>
+     * 
+     * @param ditStructureRuleDescription the DIT structure rule description to be parsed
+     * @return the parsed DITStructureRuleDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public DitStructureRule parseDITStructureRuleDescription( String ditStructureRuleDescription )
+        throws ParseException
+    {
+        return super.parse( ditStructureRuleDescription );
+
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected DitStructureRule doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.ditStructureRuleDescription();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapComparatorDescription.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapComparatorDescription.java
new file mode 100644
index 0000000..69cdd67
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapComparatorDescription.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An ApacheDS specific schema description for a Comparator.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapComparatorDescription extends LoadableSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * A constructor for a LdapComparatorDescription.
+     * @param oid The associated OID
+     */
+    public LdapComparatorDescription( String oid )
+    {
+        super( SchemaObjectType.COMPARATOR, oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return "Comparator description : " + getDescription();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapComparatorDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapComparatorDescriptionSchemaParser.java
new file mode 100644
index 0000000..0539944
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapComparatorDescriptionSchemaParser.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for ApacheDS comparator descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapComparatorDescriptionSchemaParser extends AbstractSchemaParser<LdapComparatorDescription>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public LdapComparatorDescriptionSchemaParser()
+    {
+        super( LdapComparatorDescription.class, I18n.ERR_04236, I18n.ERR_04237, I18n.ERR_04238 );
+    }
+
+
+    /**
+     * Parses an comparator description:
+     * 
+     * <pre>
+     * ComparatorDescription = LPAREN WSP
+     *     numericoid                           ; object identifier
+     *     [ SP "DESC" SP qdstring ]            ; description
+     *     SP "FQCN" SP fqcn                    ; fully qualified class name
+     *     [ SP "BYTECODE" SP base64 ]          ; optional base64 encoded bytecode
+     *     extensions WSP RPAREN                ; extensions
+     * 
+     * base64          = *(4base64-char)
+     * base64-char     = ALPHA / DIGIT / "+" / "/"
+     * fqcn = fqcnComponent 1*( DOT fqcnComponent )
+     * fqcnComponent = ???
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+     * 
+     * @param comparatorDescription the comparator description to be parsed
+     * @return the parsed ComparatorDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public LdapComparatorDescription parseComparatorDescription( String comparatorDescription ) throws ParseException
+    {
+        return super.parse( comparatorDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected LdapComparatorDescription doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.ldapComparator();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapSyntaxDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapSyntaxDescriptionSchemaParser.java
new file mode 100644
index 0000000..979c528
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/LdapSyntaxDescriptionSchemaParser.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 LDAP syntx descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapSyntaxDescriptionSchemaParser extends AbstractSchemaParser<LdapSyntax>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public LdapSyntaxDescriptionSchemaParser()
+    {
+        super( LdapSyntax.class, I18n.ERR_04239, I18n.ERR_04240, I18n.ERR_04241 );
+    }
+
+
+    /**
+     * Parses a LDAP syntax description according to RFC 4512:
+     * 
+     * <pre>
+     * SyntaxDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+     * 
+     * @param ldapSyntaxDescription the LDAP syntax description to be parsed
+     * @return the parsed LdapSyntax bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public LdapSyntax parseLdapSyntaxDescription( String ldapSyntaxDescription ) throws ParseException
+    {
+        return super.parse( ldapSyntaxDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected LdapSyntax doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.ldapSyntaxDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/MatchingRuleDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/MatchingRuleDescriptionSchemaParser.java
new file mode 100644
index 0000000..103fe2b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/MatchingRuleDescriptionSchemaParser.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 matching rule descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MatchingRuleDescriptionSchemaParser extends AbstractSchemaParser<MatchingRule>
+{
+    /**
+     * Creates a schema parser instance.
+     */
+    public MatchingRuleDescriptionSchemaParser()
+    {
+        super( MatchingRule.class, I18n.ERR_04242, I18n.ERR_04243, I18n.ERR_04244 );
+    }
+
+
+    /**
+     * Parses a matching rule description according to RFC 4512:
+     * 
+     * <pre>
+     * MatchingRuleDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    SP "SYNTAX" SP numericoid  ; assertion syntax
+     *    extensions WSP RPAREN      ; extensions
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+     * 
+     * @param matchingRuleDescription the matching rule description to be parsed
+     * @return the parsed MatchingRuleDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public MatchingRule parseMatchingRuleDescription( String matchingRuleDescription ) throws ParseException
+    {
+        return super.parse( matchingRuleDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected MatchingRule doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.matchingRuleDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/MatchingRuleUseDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/MatchingRuleUseDescriptionSchemaParser.java
new file mode 100644
index 0000000..b8b5f15
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/MatchingRuleUseDescriptionSchemaParser.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 matching rule use descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MatchingRuleUseDescriptionSchemaParser extends AbstractSchemaParser<MatchingRuleUse>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public MatchingRuleUseDescriptionSchemaParser()
+    {
+        super( MatchingRuleUse.class, I18n.ERR_04245, I18n.ERR_04246, I18n.ERR_04247 );
+    }
+
+
+    /**
+     * Parses a matching rule use description according to RFC 4512:
+     * 
+     * <pre>
+     * MatchingRuleUseDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    SP "APPLIES" SP oids       ; attribute types
+     *    extensions WSP RPAREN      ; extensions
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+     * 
+     * @param matchingRuleUseDescription the matching rule use description to be parsed
+     * @return the parsed MatchingRuleUseDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public MatchingRuleUse parseMatchingRuleUseDescription( String matchingRuleUseDescription ) throws ParseException
+    {
+        return super.parse( matchingRuleUseDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected MatchingRuleUse doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.matchingRuleUseDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NameFormDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NameFormDescriptionSchemaParser.java
new file mode 100644
index 0000000..4d81cf7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NameFormDescriptionSchemaParser.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.NameForm;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 name form descriptions
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NameFormDescriptionSchemaParser extends AbstractSchemaParser<NameForm>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public NameFormDescriptionSchemaParser()
+    {
+        super( NameForm.class, I18n.ERR_04248, I18n.ERR_04249, I18n.ERR_04250 );
+    }
+
+
+    /**
+     * Parses a name form description according to RFC 4512:
+     * 
+     * <pre>
+     * NameFormDescription = LPAREN WSP
+     *    numericoid                 ; object identifier
+     *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *    [ SP "DESC" SP qdstring ]  ; description
+     *    [ SP "OBSOLETE" ]          ; not active
+     *    SP "OC" SP oid             ; structural object class
+     *    SP "MUST" SP oids          ; attribute types
+     *    [ SP "MAY" SP oids ]       ; attribute types
+     *    extensions WSP RPAREN      ; extensions
+     * </pre>
+     * 
+     * @param nameFormDescription the name form description to be parsed
+     * @return the parsed NameForm bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public NameForm parseNameFormDescription( String nameFormDescription ) throws ParseException
+    {
+        return super.parse( nameFormDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected NameForm doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.nameFormDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NormalizerDescription.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NormalizerDescription.java
new file mode 100644
index 0000000..ecce24f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NormalizerDescription.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An ApacheDS specific schema description for a Normalizer.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NormalizerDescription extends LoadableSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * Default constructor for a NormalizerDecription
+     * @param oid The SyntaxChecker OID
+     */
+    public NormalizerDescription( String oid )
+    {
+        super( SchemaObjectType.NORMALIZER, oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return "SyntaxChecker description : " + getDescription();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NormalizerDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NormalizerDescriptionSchemaParser.java
new file mode 100644
index 0000000..83fdfef
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/NormalizerDescriptionSchemaParser.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for ApacheDS normalizer descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NormalizerDescriptionSchemaParser extends AbstractSchemaParser<NormalizerDescription>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public NormalizerDescriptionSchemaParser()
+    {
+        super( NormalizerDescription.class, I18n.ERR_04251, I18n.ERR_04252, I18n.ERR_04253 );
+    }
+
+
+    /**
+     * Parses a normalizer description:
+     * 
+     * <pre>
+     * NormalizerDescription = LPAREN WSP
+     *     numericoid                           ; object identifier
+     *     [ SP "DESC" SP qdstring ]            ; description
+     *     SP "FQCN" SP fqcn                    ; fully qualified class name
+     *     [ SP "BYTECODE" SP base64 ]          ; optional base64 encoded bytecode
+     *     extensions WSP RPAREN                ; extensions
+     * 
+     * base64          = *(4base64-char)
+     * base64-char     = ALPHA / DIGIT / "+" / "/"
+     * fqcn = fqcnComponent 1*( DOT fqcnComponent )
+     * fqcnComponent = ???
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+     * 
+     * @param normalizerDescription the normalizer description to be parsed
+     * @return the parsed NormalizerDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public NormalizerDescription parseNormalizerDescription( String normalizerDescription ) throws ParseException
+    {
+        return super.parse( normalizerDescription );
+    }
+
+
+    @Override
+    protected NormalizerDescription doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.normalizerDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ObjectClassDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ObjectClassDescriptionSchemaParser.java
new file mode 100644
index 0000000..e9ca3bd
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ObjectClassDescriptionSchemaParser.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 object class descriptons
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ObjectClassDescriptionSchemaParser extends AbstractSchemaParser<ObjectClass>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public ObjectClassDescriptionSchemaParser()
+    {
+        super( ObjectClass.class, I18n.ERR_04254, I18n.ERR_04255, I18n.ERR_04256 );
+    }
+
+
+    /**
+     * Parses a object class definition according to RFC 4512:
+     * 
+     * <pre>
+     * ObjectClassDescription = LPAREN WSP
+     *     numericoid                 ; object identifier
+     *     [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+     *     [ SP "DESC" SP qdstring ]  ; description
+     *     [ SP "OBSOLETE" ]          ; not active
+     *     [ SP "SUP" SP oids ]       ; superior object classes
+     *     [ SP kind ]                ; kind of class
+     *     [ SP "MUST" SP oids ]      ; attribute types
+     *     [ SP "MAY" SP oids ]       ; attribute types
+     *     extensions WSP RPAREN
+     *
+     * kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )
+     * </pre>
+     * 
+     * @param objectClassDescription the object class description to be parsed
+     * @return the parsed ObjectClassDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public ObjectClass parseObjectClassDescription( String objectClassDescription ) throws ParseException
+    {
+        return super.parse( objectClassDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected ObjectClass doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.objectClassDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/OpenLdapSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/OpenLdapSchemaParser.java
new file mode 100644
index 0000000..a6f023a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/OpenLdapSchemaParser.java
@@ -0,0 +1,359 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OpenLdapObjectIdentifierMacro;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper for antlr generated OpenLDAP schema parsers.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OpenLdapSchemaParser extends AbstractSchemaParser<SchemaObject>
+{
+
+    /** The list of parsed schema descriptions */
+    private List<Object> schemaDescriptions;
+
+    /** The list of attribute type, initialized by splitParsedSchemaDescriptions() */
+    private List<MutableAttributeType> attributeTypes;
+
+    /** The list of object classes, initialized by splitParsedSchemaDescriptions()*/
+    private List<ObjectClass> objectClasses;
+
+    /** The map of object identifier macros, initialized by splitParsedSchemaDescriptions()*/
+    private Map<String, OpenLdapObjectIdentifierMacro> objectIdentifierMacros;
+
+    /** Flag whether object identifier macros should be resolved. */
+    private boolean isResolveObjectIdentifierMacros;
+
+
+    /**
+     * Creates a reusable instance of an OpenLdapSchemaParser.
+     *
+     * @throws IOException if the pipe cannot be formed
+     */
+    public OpenLdapSchemaParser() throws IOException
+    {
+        super( null, null, null, null );
+        isResolveObjectIdentifierMacros = true;
+        super.setQuirksMode( true );
+    }
+
+
+    @Override
+    protected SchemaObject doParse() throws RecognitionException, TokenStreamException
+    {
+        throw new UnsupportedOperationException( "OpenLdapSchemaParser is not a normal schema parser" );
+    }
+
+
+    /**
+     * Reset the parser
+     */
+    public void clear()
+    {
+    }
+
+
+    /**
+     * Gets the attribute types.
+     * 
+     * @return the attribute types
+     */
+    public List<MutableAttributeType> getAttributeTypes()
+    {
+        return attributeTypes;
+    }
+
+
+    /**
+     * Gets the object class types.
+     * 
+     * @return the object class types
+     */
+    public List<ObjectClass> getObjectClassTypes()
+    {
+        return objectClasses;
+    }
+
+
+    /**
+     * Gets the object identifier macros.
+     * 
+     * @return the object identifier macros
+     */
+    public Map<String, OpenLdapObjectIdentifierMacro> getObjectIdentifierMacros()
+    {
+        return objectIdentifierMacros;
+    }
+
+
+    /**
+     * Splits parsed schema descriptions and resolved
+     * object identifier macros.
+     * 
+     * @throws ParseException the parse exception
+     */
+    private void afterParse() throws ParseException
+    {
+        objectClasses = new ArrayList<ObjectClass>();
+        attributeTypes = new ArrayList<MutableAttributeType>();
+        objectIdentifierMacros = new HashMap<String, OpenLdapObjectIdentifierMacro>();
+
+        // split parsed schema descriptions
+        for ( Object obj : schemaDescriptions )
+        {
+            if ( obj instanceof OpenLdapObjectIdentifierMacro )
+            {
+                OpenLdapObjectIdentifierMacro oid = ( OpenLdapObjectIdentifierMacro ) obj;
+                objectIdentifierMacros.put( oid.getName(), oid );
+            }
+            else if ( obj instanceof AttributeType )
+            {
+                MutableAttributeType attributeType = ( MutableAttributeType ) obj;
+
+                attributeTypes.add( attributeType );
+            }
+            else if ( obj instanceof ObjectClass )
+            {
+                ObjectClass objectClass = ( ObjectClass ) obj;
+
+                objectClasses.add( objectClass );
+            }
+        }
+
+        if ( isResolveObjectIdentifierMacros() )
+        {
+            // resolve object identifier macros
+            for ( OpenLdapObjectIdentifierMacro oid : objectIdentifierMacros.values() )
+            {
+                resolveObjectIdentifierMacro( oid );
+            }
+
+            // apply object identifier macros to object classes
+            for ( ObjectClass objectClass : objectClasses )
+            {
+                objectClass.setOid( getResolveOid( objectClass.getOid() ) );
+            }
+
+            // apply object identifier macros to attribute types
+            for ( MutableAttributeType attributeType : attributeTypes )
+            {
+                attributeType.setOid( getResolveOid( attributeType.getOid() ) );
+                attributeType.setSyntaxOid( getResolveOid( attributeType.getSyntaxOid() ) );
+            }
+
+        }
+    }
+
+
+    private String getResolveOid( String oid )
+    {
+        if ( oid != null && oid.indexOf( ':' ) != -1 )
+        {
+            // resolve OID
+            String[] nameAndSuffix = oid.split( ":" );
+            if ( objectIdentifierMacros.containsKey( nameAndSuffix[0] ) )
+            {
+                OpenLdapObjectIdentifierMacro macro = objectIdentifierMacros.get( nameAndSuffix[0] );
+                return macro.getResolvedOid() + "." + nameAndSuffix[1];
+            }
+        }
+        return oid;
+    }
+
+
+    private void resolveObjectIdentifierMacro( OpenLdapObjectIdentifierMacro macro ) throws ParseException
+    {
+        String rawOidOrNameSuffix = macro.getRawOidOrNameSuffix();
+
+        if ( macro.isResolved() )
+        {
+            // finished
+            return;
+        }
+        else if ( rawOidOrNameSuffix.indexOf( ':' ) != -1 )
+        {
+            // resolve OID
+            String[] nameAndSuffix = rawOidOrNameSuffix.split( ":" );
+            if ( objectIdentifierMacros.containsKey( nameAndSuffix[0] ) )
+            {
+                OpenLdapObjectIdentifierMacro parentMacro = objectIdentifierMacros.get( nameAndSuffix[0] );
+                resolveObjectIdentifierMacro( parentMacro );
+                macro.setResolvedOid( parentMacro.getResolvedOid() + "." + nameAndSuffix[1] );
+            }
+            else
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04257, nameAndSuffix[0] ), 0 );
+            }
+
+        }
+        else
+        {
+            // no :suffix,
+            if ( objectIdentifierMacros.containsKey( rawOidOrNameSuffix ) )
+            {
+                OpenLdapObjectIdentifierMacro parentMacro = objectIdentifierMacros.get( rawOidOrNameSuffix );
+                resolveObjectIdentifierMacro( parentMacro );
+                macro.setResolvedOid( parentMacro.getResolvedOid() );
+            }
+            else
+            {
+                macro.setResolvedOid( rawOidOrNameSuffix );
+            }
+        }
+    }
+
+
+    /**
+     * Parses an OpenLDAP schemaObject element/object.
+     *
+     * @param schemaObject the String image of a complete schema object
+     * @return the schema object
+     * @throws ParseException If the schemaObject can't be parsed
+     */
+    public SchemaObject parse( String schemaObject ) throws ParseException
+    {
+        if ( schemaObject == null || schemaObject.trim().equals( "" ) )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04258 ), 0 );
+        }
+
+        // reset and initialize the parser / lexer pair
+        reset( schemaObject );
+        invokeParser( schemaObject );
+
+        if ( !schemaDescriptions.isEmpty() )
+        {
+            for ( Object obj : schemaDescriptions )
+            {
+                if ( obj instanceof SchemaObject )
+                {
+                    return ( SchemaObject ) obj;
+                }
+            }
+        }
+        return null;
+    }
+
+
+    private void invokeParser( String subject ) throws ParseException
+    {
+        try
+        {
+            monitor.startedParse( "starting parse on:\n" + subject );
+            schemaDescriptions = parser.openLdapSchema();
+            afterParse();
+            monitor.finishedParse( "Done parsing!" );
+        }
+        catch ( RecognitionException re )
+        {
+            String msg = "Parser failure on:\n\t" + subject;
+            msg += "\nAntlr exception trace:\n" + ExceptionUtils.getFullStackTrace( re );
+            throw new ParseException( msg, re.getColumn() );
+        }
+        catch ( TokenStreamException tse )
+        {
+            String msg = "Parser failure on:\n\t" + subject;
+            msg += "\nAntlr exception trace:\n" + ExceptionUtils.getFullStackTrace( tse );
+            throw new ParseException( msg, 0 );
+        }
+    }
+
+
+    /**
+     * Parses a stream of OpenLDAP schemaObject elements/objects.
+     *
+     * @param schemaIn a stream of schema objects
+     * @throws IOException If the schemaObject can't be transformed to a byteArrayInputStream
+     * @throws ParseException If the schemaObject can't be parsed
+     */
+    public void parse( InputStream schemaIn ) throws IOException, ParseException
+    {
+        InputStreamReader in = new InputStreamReader( schemaIn );
+        lexer.prepareNextInput( in );
+        parser.resetState();
+
+        invokeParser( "schema input stream ==> " + schemaIn.toString() );
+    }
+
+
+    /**
+     * Parses a file of OpenLDAP schemaObject elements/objects.
+     *
+     * @param schemaFile a file of schema objects
+     * @throws IOException If the schemaObject can't be transformed to a byteArrayInputStream
+     * @throws ParseException If the schemaObject can't be parsed
+     */
+    public void parse( File schemaFile ) throws IOException, ParseException
+    {
+        FileReader in = new FileReader( schemaFile );
+        lexer.prepareNextInput( in );
+        parser.resetState();
+
+        invokeParser( "schema file ==> " + schemaFile.getAbsolutePath() );
+    }
+
+
+    /**
+     * Checks if object identifier macros should be resolved.
+     * 
+     * @return true, object identifier macros should be resolved.
+     */
+    public boolean isResolveObjectIdentifierMacros()
+    {
+        return isResolveObjectIdentifierMacros;
+    }
+
+
+    /**
+     * Sets if object identifier macros should be resolved.
+     * 
+     * @param resolveObjectIdentifierMacros true if object identifier macros should be resolved
+     */
+    public void setResolveObjectIdentifierMacros( boolean resolveObjectIdentifierMacros )
+    {
+        this.isResolveObjectIdentifierMacros = resolveObjectIdentifierMacros;
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserDescriptionUtils.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserDescriptionUtils.java
new file mode 100644
index 0000000..c9d5c78
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserDescriptionUtils.java
@@ -0,0 +1,337 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+
+
+/**
+ * Utilities for dealing with various schema descriptions.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ParserDescriptionUtils
+{
+    /**
+     * Private constructor.
+     */
+    private ParserDescriptionUtils()
+    {
+    }
+
+
+    /**
+     * Checks two schema objectClasses for an exact match.
+     *
+     * @param oc0 the first objectClass to compare
+     * @param oc1 the second objectClass to compare
+     * @return true if both objectClasses match exactly, false otherwise
+     */
+    public static boolean objectClassesMatch( ObjectClass oc0, ObjectClass oc1 )
+    {
+        // compare all common description parameters
+        if ( !descriptionsMatch( oc0, oc1 ) )
+        {
+            return false;
+        }
+
+        // compare the objectClass type (AUXILIARY, STRUCTURAL, ABSTRACT)
+        if ( oc0.getType() != oc1.getType() )
+        {
+            return false;
+        }
+
+        // compare the superior objectClasses (sizes must match)
+        if ( oc0.getSuperiorOids().size() != oc1.getSuperiorOids().size() )
+        {
+            return false;
+        }
+
+        // compare the superior objectClasses (sizes must match)
+        for ( int i = 0; i < oc0.getSuperiorOids().size(); i++ )
+        {
+            if ( !oc0.getSuperiorOids().get( i ).equals( oc1.getSuperiorOids().get( i ) ) )
+            {
+                return false;
+            }
+        }
+
+        // compare the must attributes (sizes must match)
+        for ( int i = 0; i < oc0.getMustAttributeTypeOids().size(); i++ )
+        {
+            if ( !oc0.getMustAttributeTypeOids().get( i ).equals( oc1.getMustAttributeTypeOids().get( i ) ) )
+            {
+                return false;
+            }
+        }
+
+        // compare the may attributes (sizes must match)
+        for ( int i = 0; i < oc0.getMayAttributeTypeOids().size(); i++ )
+        {
+            if ( !oc0.getMayAttributeTypeOids().get( i ).equals( oc1.getMayAttributeTypeOids().get( i ) ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Checks two schema attributeTypes for an exact match.
+     *
+     * @param at0 the first attributeType to compare
+     * @param at1 the second attributeType to compare
+     * @return true if both attributeTypes match exactly, false otherwise
+     */
+    public static boolean attributeTypesMatch( AttributeType at0, AttributeType at1 )
+    {
+        // compare all common description parameters
+        if ( !descriptionsMatch( at0, at1 ) )
+        {
+            return false;
+        }
+
+        // check that the same super type is being used for both attributes
+        if ( !at0.getSuperiorOid().equals( at1.getSuperiorOid() ) )
+        {
+            return false;
+        }
+
+        // check that the same matchingRule is used by both ATs for EQUALITY
+        if ( !at0.getEqualityOid().equals( at1.getEqualityOid() ) )
+        {
+            return false;
+        }
+
+        // check that the same matchingRule is used by both ATs for SUBSTRING
+        if ( !at0.getSubstringOid().equals( at1.getSubstringOid() ) )
+        {
+            return false;
+        }
+
+        // check that the same matchingRule is used by both ATs for ORDERING
+        if ( !at0.getOrderingOid().equals( at1.getOrderingOid() ) )
+        {
+            return false;
+        }
+
+        // check that the same syntax is used by both ATs
+        if ( !at0.getSyntaxOid().equals( at1.getSyntaxOid() ) )
+        {
+            return false;
+        }
+
+        // check that the syntax length constraint is the same for both
+        if ( at0.getSyntaxLength() != at1.getSyntaxLength() )
+        {
+            return false;
+        }
+
+        // check that the ATs have the same single valued flag value
+        if ( at0.isSingleValued() != at1.isSingleValued() )
+        {
+            return false;
+        }
+
+        // check that the ATs have the same collective flag value
+        if ( at0.isCollective() != at1.isCollective() )
+        {
+            return false;
+        }
+
+        // check that the ATs have the same user modifiable flag value
+        if ( at0.isUserModifiable() != at1.isUserModifiable() )
+        {
+            return false;
+        }
+
+        // check that the ATs have the same USAGE
+        if ( at0.getUsage() != at1.getUsage() )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Checks to see if two matchingRule match exactly.
+     *
+     * @param matchingRule0 the first matchingRule to compare
+     * @param matchingRule1 the second matchingRule to compare
+     * @return true if the matchingRules match exactly, false otherwise
+     */
+    public static boolean matchingRulesMatch( MatchingRule matchingRule0, MatchingRule matchingRule1 )
+    {
+        // compare all common description parameters
+        if ( !descriptionsMatch( matchingRule0, matchingRule1 ) )
+        {
+            return false;
+        }
+
+        // check that the syntaxes of the matchingRules match
+        if ( !matchingRule0.getSyntaxOid().equals( matchingRule1.getSyntaxOid() ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Checks to see if two syntax match exactly.
+     *
+     * @param ldapSyntax0 the first ldapSyntax to compare
+     * @param ldapSyntax1 the second ldapSyntax to compare
+     * @return true if the syntaxes match exactly, false otherwise
+     */
+    public static boolean syntaxesMatch( LdapSyntax ldapSyntax0, LdapSyntax ldapSyntax1 )
+    {
+        return descriptionsMatch( ldapSyntax0, ldapSyntax1 );
+    }
+
+
+    /**
+     * Checks if two base schema descriptions match for the common components 
+     * in every schema description.  NOTE: for syntaxes the obsolete flag is 
+     * not compared because doing so would raise an exception since syntax 
+     * descriptions do not support the OBSOLETE flag.
+     * 
+     * @param so0 the first schema description to compare 
+     * @param so1 the second schema description to compare 
+     * @return true if the descriptions match exactly, false otherwise
+     */
+    public static boolean descriptionsMatch( SchemaObject so0, SchemaObject so1 )
+    {
+        // check that the OID matches
+        if ( !so0.getOid().equals( so1.getOid() ) )
+        {
+            return false;
+        }
+
+        // check that the obsolete flag is equal but not for syntaxes
+        if ( ( ( so0 instanceof LdapSyntax ) || ( so1 instanceof LdapSyntax ) ) && so0.isObsolete() != so1.isObsolete() )
+        {
+            return false;
+        }
+
+        // check that the description matches
+        if ( !so0.getDescription().equals( so1.getDescription() ) )
+        {
+            return false;
+        }
+
+        // check alias names for exact match
+        if ( !aliasNamesMatch( so0, so1 ) )
+        {
+            return false;
+        }
+
+        // check extensions for exact match
+        if ( !extensionsMatch( so0, so1 ) )
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Checks to see if the extensions of a schema description match another
+     * description.  The order of the extension values must match for a true
+     * return.
+     *
+     * @param lsd0 the first schema description to compare the extensions of
+     * @param lsd1 the second schema description to compare the extensions of
+     * @return true if the extensions match exactly, false otherwise
+     */
+    public static boolean extensionsMatch( SchemaObject lsd0, SchemaObject lsd1 )
+    {
+        // check sizes first
+        if ( lsd0.getExtensions().size() != lsd1.getExtensions().size() )
+        {
+            return false;
+        }
+
+        // check contents and order of extension values must match
+        for ( String key : lsd0.getExtensions().keySet() )
+        {
+            List<String> values0 = lsd0.getExtension( key );
+            List<String> values1 = lsd1.getExtension( key );
+
+            // if the key is not present in asd1
+            if ( values1 == null )
+            {
+                return false;
+            }
+
+            for ( int i = 0; i < values0.size(); i++ )
+            {
+                if ( !values0.get( i ).equals( values1.get( i ) ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Checks to see if the alias names of a schema description match another 
+     * description.  The order of the alias names do matter.
+     *
+     * @param so0 the schema description to compare
+     * @param so1 the schema description to compare
+     * @return true if alias names match exactly, false otherwise
+     */
+    public static boolean aliasNamesMatch( SchemaObject so0, SchemaObject so1 )
+    {
+        // check sizes first
+        if ( so0.getNames().size() != so1.getNames().size() )
+        {
+            return false;
+        }
+
+        // check contents and order must match too
+        for ( int i = 0; i < so0.getNames().size(); i++ )
+        {
+            if ( !so0.getNames().get( i ).equals( so1.getNames().get( i ) ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserMonitor.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserMonitor.java
new file mode 100644
index 0000000..b7e3ac3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserMonitor.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+/**
+ * A monitor for the OpenLdap parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ParserMonitor
+{
+
+    /**
+     * Called when a production matched.
+     *
+     * @param prod the production
+     */
+    void matchedProduction( String prod );
+
+
+    /**
+     * Called when parsing is started.
+     *
+     * @param subject the subject
+     */
+    void startedParse( String subject );
+
+
+    /**
+     * Called when parsing is finished.
+     *
+     * @param subject the subject
+     */
+    void finishedParse( String subject );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserMonitorAdapter.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserMonitorAdapter.java
new file mode 100644
index 0000000..b1de815
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ParserMonitorAdapter.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+/**
+ * Default implementation of {@link ParserMonitor} with empty method implementations.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ParserMonitorAdapter implements ParserMonitor
+{
+    /**
+     * {@inheritDoc}
+     */
+    public void matchedProduction( String prod )
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void startedParse( String s )
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void finishedParse( String s )
+    {
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ReusableAntlrSchemaLexer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ReusableAntlrSchemaLexer.java
new file mode 100644
index 0000000..aba4a05
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ReusableAntlrSchemaLexer.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.io.Reader;
+
+import org.apache.directory.api.ldap.model.schema.syntaxes.AntlrSchemaLexer;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+
+
+/**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * schema as defined in RFC 4512. This class
+ * enables the reuse of the antlr lexer without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ */
+public class ReusableAntlrSchemaLexer extends AntlrSchemaLexer
+{
+    private boolean savedCaseSensitive;
+
+    private boolean savedCaseSensitiveLiterals;
+
+
+    /**
+     * Creates a ReusableAntlrSchemaLexer instance.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public ReusableAntlrSchemaLexer( Reader in )
+    {
+        super( in );
+        savedCaseSensitive = getCaseSensitive();
+        savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+    }
+
+
+    /**
+     * Resets the state of an antlr lexer and initializes it with new input.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public void prepareNextInput( Reader in )
+    {
+        CharBuffer buf = new CharBuffer( in );
+        LexerSharedInputState state = new LexerSharedInputState( buf );
+        this.setInputState( state );
+
+        this.setCaseSensitive( savedCaseSensitive );
+
+        // no set method for this protected field.
+        this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ReusableAntlrSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ReusableAntlrSchemaParser.java
new file mode 100644
index 0000000..5d7692c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/ReusableAntlrSchemaParser.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import org.apache.directory.api.ldap.model.schema.syntaxes.AntlrSchemaParser;
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * schema as defined in RFC 4512. This class
+ * enables the reuse of the antlr parser without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ */
+public class ReusableAntlrSchemaParser extends AntlrSchemaParser
+{
+
+    /**
+     * Creates a ReusableAntlrSchemaParser instance.
+     *
+     * @param lexer the lexer
+     */
+    public ReusableAntlrSchemaParser( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+
+        this.getInputState().reset();
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/SyntaxCheckerDescription.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/SyntaxCheckerDescription.java
new file mode 100644
index 0000000..9457b17
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/SyntaxCheckerDescription.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An ApacheDS specific schema description for a SyntaxChecker.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyntaxCheckerDescription extends LoadableSchemaObject
+{
+    /** The mandatory serialVersionUID */
+    public static final long serialVersionUID = 1L;
+
+
+    /**
+     * Default constructor for a SyntaxCheckerDecription
+     * @param oid The SyntaxChecker OID
+     */
+    public SyntaxCheckerDescription( String oid )
+    {
+        super( SchemaObjectType.SYNTAX_CHECKER, oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return "SyntaxChecker description : " + getDescription();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/SyntaxCheckerDescriptionSchemaParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/SyntaxCheckerDescriptionSchemaParser.java
new file mode 100644
index 0000000..2e666aa
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/parsers/SyntaxCheckerDescriptionSchemaParser.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for ApacheDS syntax checker descriptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SyntaxCheckerDescriptionSchemaParser extends AbstractSchemaParser<SyntaxCheckerDescription>
+{
+
+    /**
+     * Creates a schema parser instance.
+     */
+    public SyntaxCheckerDescriptionSchemaParser()
+    {
+        super( SyntaxCheckerDescription.class, I18n.ERR_04258, I18n.ERR_04259, I18n.ERR_04260 );
+    }
+
+
+    /**
+     * Parses a syntax checker description:
+     * 
+     * <pre>
+     * SyntaxCheckerDescription = LPAREN WSP
+     *     numericoid                           ; object identifier
+     *     [ SP "DESC" SP qdstring ]            ; description
+     *     SP "FQCN" SP fqcn                    ; fully qualified class name
+     *     [ SP "BYTECODE" SP base64 ]          ; optional base64 encoded bytecode
+     *     extensions WSP RPAREN                ; extensions
+     * 
+     * base64          = *(4base64-char)
+     * base64-char     = ALPHA / DIGIT / "+" / "/"
+     * fqcn = fqcnComponent 1*( DOT fqcnComponent )
+     * fqcnComponent = ???
+     * 
+     * extensions = *( SP xstring SP qdstrings )
+     * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+     * </pre>
+     * 
+     * @param syntaxCheckerDescription the syntax checker description to be parsed
+     * @return the parsed SyntaxCheckerDescription bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     */
+    public SyntaxCheckerDescription parseSyntaxCheckerDescription( String syntaxCheckerDescription )
+        throws ParseException
+    {
+        return super.parse( syntaxCheckerDescription );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected SyntaxCheckerDescription doParse() throws RecognitionException, TokenStreamException
+    {
+        return parser.syntaxCheckerDescription();
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/AbstractSchemaLoader.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/AbstractSchemaLoader.java
new file mode 100644
index 0000000..208741a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/AbstractSchemaLoader.java
@@ -0,0 +1,411 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * An abstract class with a utility method and setListener() implemented.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractSchemaLoader implements SchemaLoader
+{
+    /**
+     * A map of all available schema names to schema objects. This map is
+     * populated when this class is created with all the schemas present in
+     * the LDIF based schema repository.
+     */
+    protected final Map<String, Schema> schemaMap = new LowerCaseKeyMap();
+    
+    /** The flag that tells about the SchemaLoader mode : relaxed or strict */
+    private boolean relaxed;
+
+    /**
+     * a map implementation which converts the keys to lower case before inserting
+     */
+    private static class LowerCaseKeyMap extends HashMap<String, Schema>
+    {
+        private static final long serialVersionUID = 1L;
+
+
+        @Override
+        public Schema put( String key, Schema value )
+        {
+            return super.put( Strings.toLowerCaseAscii( key ), value );
+        }
+
+
+        @Override
+        public void putAll( Map<? extends String, ? extends Schema> map )
+        {
+            for ( Map.Entry<? extends String, ? extends Schema> e : map.entrySet() )
+            {
+                put( e.getKey(), e.getValue() );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final Collection<Schema> getAllEnabled() throws Exception
+    {
+        Collection<Schema> enabledSchemas = new ArrayList<Schema>();
+
+        for ( Schema schema : schemaMap.values() )
+        {
+            if ( schema.isEnabled() )
+            {
+                enabledSchemas.add( schema );
+            }
+        }
+
+        return enabledSchemas;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public final Collection<Schema> getAllSchemas() throws Exception
+    {
+        return schemaMap.values();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Schema getSchema( String schemaName )
+    {
+        return schemaMap.get( Strings.toLowerCaseAscii( schemaName ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addSchema( Schema schema )
+    {
+        schemaMap.put( schema.getSchemaName(), schema );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeSchema( Schema schema )
+    {
+        schemaMap.remove( Strings.toLowerCaseAscii( schema.getSchemaName() ) );
+    }
+
+
+    /**
+     * Gets the schema.
+     *
+     * @param entry the entry
+     * @return the schema
+     * @throws Exception the exception
+     */
+    protected Schema getSchema( Entry entry ) throws Exception
+    {
+        if ( entry == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04261 ) );
+        }
+
+        Attribute objectClasses = entry.get( SchemaConstants.OBJECT_CLASS_AT );
+        boolean isSchema = false;
+
+        for ( Value<?> value : objectClasses )
+        {
+            if ( MetaSchemaConstants.META_SCHEMA_OC.equalsIgnoreCase( value.getString() ) )
+            {
+                isSchema = true;
+                break;
+            }
+        }
+
+        if ( !isSchema )
+        {
+            return null;
+        }
+
+        String name;
+        String owner;
+        String[] dependencies = StringConstants.EMPTY_STRINGS;
+        boolean isDisabled = false;
+
+        if ( entry.get( SchemaConstants.CN_AT ) == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04262 ) );
+        }
+
+        name = entry.get( SchemaConstants.CN_AT ).getString();
+
+        Attribute creatorsName = entry.get( SchemaConstants.CREATORS_NAME_AT );
+
+        if ( creatorsName == null )
+        {
+            owner = null;
+        }
+        else
+        {
+            owner = creatorsName.getString();
+        }
+
+        if ( entry.get( MetaSchemaConstants.M_DISABLED_AT ) != null )
+        {
+            String value = entry.get( MetaSchemaConstants.M_DISABLED_AT ).getString();
+            value = value.toUpperCase();
+            isDisabled = value.equals( "TRUE" );
+        }
+
+        if ( entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT ) != null )
+        {
+            Set<String> depsSet = new HashSet<String>();
+            Attribute depsAttr = entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT );
+
+            for ( Value<?> value : depsAttr )
+            {
+                depsSet.add( value.getString() );
+            }
+
+            dependencies = depsSet.toArray( StringConstants.EMPTY_STRINGS );
+        }
+
+        return new DefaultSchema( name, owner, dependencies, isDisabled );
+    }
+
+
+    private Schema[] buildSchemaArray( String... schemaNames ) throws Exception
+    {
+        Schema[] schemas = new Schema[schemaNames.length];
+        int pos = 0;
+
+        for ( String schemaName : schemaNames )
+        {
+            schemas[pos++] = getSchema( schemaName );
+        }
+
+        return schemas;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadAttributeTypes( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadAttributeTypes( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadComparators( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadComparators( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitContentRules( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadDitContentRules( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitStructureRules( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadDitStructureRules( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRules( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadMatchingRules( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRuleUses( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadMatchingRuleUses( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNameForms( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadNameForms( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNormalizers( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadNormalizers( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadObjectClasses( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadObjectClasses( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxes( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadSyntaxes( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxCheckers( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames == null )
+        {
+            return new ArrayList<Entry>();
+        }
+
+        return loadSyntaxCheckers( buildSchemaArray( schemaNames ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isRelaxed()
+    {
+        return SchemaManager.RELAXED;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isStrict()
+    {
+        return relaxed == SchemaManager.STRICT;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRelaxed( boolean relaxed )
+    {
+        this.relaxed = relaxed;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/AttributeTypeRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/AttributeTypeRegistry.java
new file mode 100644
index 0000000..1170873
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/AttributeTypeRegistry.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+
+
+/**
+ * An AttributeType registry service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface AttributeTypeRegistry extends SchemaObjectRegistry<AttributeType>, Iterable<AttributeType>
+{
+    /**
+     * Gets an oid/name to normalizer mapping used to normalize distinguished 
+     * names.
+     *
+     * @return a map of OID Strings to OidNormalizer instances
+     */
+    Map<String, OidNormalizer> getNormalizerMapping();
+
+
+    /**
+     * Quick lookup to see if an attribute has descendants.
+     * 
+     * @param ancestorId the name alias or OID for an attributeType
+     * @return an Iterator over the AttributeTypes which have the ancestor
+     * within their superior chain to the top
+     * @throws LdapException if the ancestor attributeType cannot be 
+     * discerned from the ancestorId supplied
+     */
+    boolean hasDescendants( String ancestorId ) throws LdapException;
+
+
+    /**
+     * Quick lookup to see if an attribute has descendants.
+     * 
+     * @param ancestor the attributeType we are looking for
+     * @return an Iterator over the AttributeTypes which have the ancestor
+     * within their superior chain to the top
+     * @throws LdapException if the ancestor attributeType cannot be 
+     * discerned from the ancestorId supplied
+     */
+    boolean hasDescendants( AttributeType ancestor ) throws LdapException;
+
+
+    /**
+     * Get's an iterator over the set of descendant attributeTypes for
+     * some ancestor's name alias or their OID.
+     * 
+     * @param ancestorId the name alias or OID for an attributeType
+     * @return an Iterator over the AttributeTypes which have the ancestor
+     * within their superior chain to the top
+     * @throws LdapException if the ancestor attributeType cannot be 
+     * discerned from the ancestorId supplied
+     */
+    Iterator<AttributeType> descendants( String ancestorId ) throws LdapException;
+
+
+    /**
+     * Get's an iterator over the set of descendant attributeTypes for
+     * some ancestor's name alias or their OID.
+     * 
+     * @param ancestor the AttributeType we are looking for
+     * @return an Iterator over the AttributeTypes which have the ancestor
+     * within their superior chain to the top
+     * @throws LdapException if the ancestor attributeType cannot be 
+     * discerned from the ancestorId supplied
+     */
+    Iterator<AttributeType> descendants( AttributeType ancestor ) throws LdapException;
+
+
+    /**
+     * Store the AttributeType into a map associating an AttributeType to its
+     * descendants.
+     * 
+     * @param attributeType The attributeType to register
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If something went wrong
+     */
+    void registerDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException;
+
+
+    /**
+     * Remove the AttributeType from the map associating an AttributeType to its
+     * descendants.
+     * 
+     * @param attributeType The attributeType to unregister
+     * @param ancestor its ancestor 
+     * @throws LdapException If something went wrong
+     */
+    void unregisterDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException;
+
+
+    /**
+     * Add a new Oid/Normalizer couple in the OidNormalizer map
+     */
+    void addMappingFor( AttributeType attributeType ) throws LdapException;
+
+
+    /**
+     * Remove a new Oid/Normalizer couple in the OidNormalizer map
+     */
+    void removeMappingFor( AttributeType attributeType ) throws LdapException;
+
+
+    /**
+     * Copy the AttributeTypeRegistry
+     */
+    AttributeTypeRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ComparatorRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ComparatorRegistry.java
new file mode 100644
index 0000000..8148e22
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ComparatorRegistry.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+
+
+/**
+ * Comparator registry component's service class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ComparatorRegistry extends SchemaObjectRegistry<LdapComparator<?>>,
+    Iterable<LdapComparator<?>>
+{
+    /**
+     * Registers a new LdapComparator with this registry.
+     *
+     * @param comparator the LdapComparator to register
+     * @throws LdapException if the LdapComparator is already registered or
+     * the registration operation is not supported
+     */
+    void register( LdapComparator<?> comparator ) throws LdapException;
+
+
+    /**
+     * Removes the LdapComparator registered with this registry, using its
+     * numeric OID.
+     * 
+     * @param numericOid the numeric identifier
+     * @throws LdapException if the numeric identifier is invalid
+     */
+    LdapComparator<?> unregister( String numericOid ) throws LdapException;
+
+
+    /**
+     * Unregisters all LdapComparators defined for a specific schema from
+     * this registry.
+     * 
+     * @param schemaName the name of the schema whose LdapComparators will be removed from
+     */
+    void unregisterSchemaElements( String schemaName ) throws LdapException;
+
+
+    /**
+     * Copy the ComparatorRegistry
+     */
+    ComparatorRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultAttributeTypeRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultAttributeTypeRegistry.java
new file mode 100644
index 0000000..5543ace
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultAttributeTypeRegistry.java
@@ -0,0 +1,336 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An AttributeType registry service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultAttributeTypeRegistry extends DefaultSchemaObjectRegistry<AttributeType> implements
+    AttributeTypeRegistry
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultAttributeTypeRegistry.class );
+
+    /** cached Oid/normalizer mapping */
+    private Map<String, OidNormalizer> oidNormalizerMap;
+
+    /** maps OIDs to a Set of descendants for that OID */
+    private Map<String, Set<AttributeType>> oidToDescendantSet;
+
+
+    /**
+     * Creates a new default AttributeTypeRegistry instance.
+     */
+    public DefaultAttributeTypeRegistry()
+    {
+        super( SchemaObjectType.ATTRIBUTE_TYPE, new OidRegistry<AttributeType>() );
+        oidNormalizerMap = new HashMap<String, OidNormalizer>();
+        oidToDescendantSet = new HashMap<String, Set<AttributeType>>();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, OidNormalizer> getNormalizerMapping()
+    {
+        return Collections.unmodifiableMap( oidNormalizerMap );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasDescendants( String ancestorId ) throws LdapException
+    {
+        try
+        {
+            String oid = getOidByName( ancestorId );
+            Set<AttributeType> descendants = oidToDescendantSet.get( oid );
+            return ( descendants != null ) && !descendants.isEmpty();
+        }
+        catch ( LdapException ne )
+        {
+            throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasDescendants( AttributeType ancestor ) throws LdapException
+    {
+        String oid = ancestor.getOid();
+        Set<AttributeType> descendants = oidToDescendantSet.get( oid );
+        return ( descendants != null ) && !descendants.isEmpty();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public Iterator<AttributeType> descendants( String ancestorId ) throws LdapException
+    {
+        try
+        {
+            String oid = getOidByName( ancestorId );
+            Set<AttributeType> descendants = oidToDescendantSet.get( oid );
+
+            if ( descendants == null )
+            {
+                return Collections.EMPTY_SET.iterator();
+            }
+
+            return descendants.iterator();
+        }
+        catch ( LdapException ne )
+        {
+            throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public Iterator<AttributeType> descendants( AttributeType ancestor ) throws LdapException
+    {
+        String oid = ancestor.getOid();
+        Set<AttributeType> descendants = oidToDescendantSet.get( oid );
+
+        if ( descendants == null )
+        {
+            return Collections.EMPTY_SET.iterator();
+        }
+
+        return descendants.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void registerDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
+    {
+        // add this attribute to descendant list of other attributes in superior chain
+        if ( ancestor == null )
+        {
+            return;
+        }
+
+        // Get the ancestor's descendant, if any
+        Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() );
+
+        // Initialize the descendant Set to store the descendants for the attributeType
+        if ( descendants == null )
+        {
+            descendants = new HashSet<AttributeType>( 1 );
+            oidToDescendantSet.put( ancestor.getOid(), descendants );
+        }
+
+        // Add the current type as a descendant
+        descendants.add( attributeType );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
+    {
+        // add this attribute to descendant list of other attributes in superior chain
+        if ( ancestor == null )
+        {
+            return;
+        }
+
+        // Get the ancestor's descendant, if any
+        Set<AttributeType> descendants = oidToDescendantSet.get( ancestor.getOid() );
+
+        if ( descendants != null )
+        {
+            descendants.remove( attributeType );
+
+            if ( descendants.size() == 0 )
+            {
+                oidToDescendantSet.remove( ancestor.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType unregister( String numericOid ) throws LdapException
+    {
+        try
+        {
+            AttributeType removed = super.unregister( numericOid );
+
+            removeMappingFor( removed );
+
+            // Deleting an AT which might be used as a superior means we have
+            // to recursively update the descendant map. We also have to remove
+            // the at.oid -> descendant relation
+            oidToDescendantSet.remove( numericOid );
+
+            // Now recurse if needed
+            unregisterDescendants( removed, removed.getSuperior() );
+
+            return removed;
+        }
+        catch ( LdapException ne )
+        {
+            throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addMappingFor( AttributeType attributeType ) throws LdapException
+    {
+        MatchingRule equality = attributeType.getEquality();
+        OidNormalizer oidNormalizer;
+        String oid = attributeType.getOid();
+
+        if ( equality == null )
+        {
+            LOG.debug( "Attribute {} does not have an EQUALITY MatchingRule : using NoopNormalizer", attributeType
+                .getName() );
+            oidNormalizer = new OidNormalizer( oid, new NoOpNormalizer( attributeType.getOid() ) );
+        }
+        else
+        {
+            oidNormalizer = new OidNormalizer( oid, equality.getNormalizer() );
+        }
+
+        oidNormalizerMap.put( oid, oidNormalizer );
+
+        // Also inject the attributeType's short names in the map
+        for ( String name : attributeType.getNames() )
+        {
+            oidNormalizerMap.put( Strings.toLowerCase( name ), oidNormalizer );
+        }
+    }
+
+
+    /**
+     * Remove the AttributeType normalizer from the OidNormalizer map 
+     */
+    public void removeMappingFor( AttributeType attributeType ) throws LdapException
+    {
+        if ( attributeType == null )
+        {
+            return;
+        }
+
+        oidNormalizerMap.remove( attributeType.getOid() );
+
+        // We also have to remove all the short names for this attribute
+        for ( String name : attributeType.getNames() )
+        {
+            oidNormalizerMap.remove( Strings.toLowerCase( name ) );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType lookup( String oid ) throws LdapException
+    {
+        try
+        {
+            return super.lookup( oid );
+        }
+        catch ( LdapException ne )
+        {
+            throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultAttributeTypeRegistry copy()
+    {
+        DefaultAttributeTypeRegistry copy = new DefaultAttributeTypeRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // First clear the shared elements
+        super.clear();
+
+        // clear the OidNormalizer map
+        oidNormalizerMap.clear();
+
+        // and clear the descendant
+        for ( Map.Entry<String, Set<AttributeType>> entry : oidToDescendantSet.entrySet() )
+        {
+            Set<AttributeType> descendants = entry.getValue();
+
+            if ( descendants != null )
+            {
+                descendants.clear();
+            }
+        }
+
+        oidToDescendantSet.clear();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultComparatorRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultComparatorRegistry.java
new file mode 100644
index 0000000..c0da061
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultComparatorRegistry.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Comparator registry service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultComparatorRegistry extends DefaultSchemaObjectRegistry<LdapComparator<?>>
+    implements ComparatorRegistry
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultComparatorRegistry.class );
+
+    /** A speedup for debug */
+    private static final boolean DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Creates a new default ComparatorRegistry instance.
+     */
+    public DefaultComparatorRegistry()
+    {
+        super( SchemaObjectType.COMPARATOR, new OidRegistry<LdapComparator<?>>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        if ( schemaName == null )
+        {
+            return;
+        }
+
+        // Loop on all the SchemaObjects stored and remove those associated
+        // with the give schemaName
+        for ( LdapComparator<?> comparator : this )
+        {
+            if ( schemaName.equalsIgnoreCase( comparator.getSchemaName() ) )
+            {
+                String oid = comparator.getOid();
+                SchemaObject removed = unregister( oid );
+
+                if ( DEBUG )
+                {
+                    LOG.debug( "Removed {} with oid {} from the registry", removed, oid );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultComparatorRegistry copy()
+    {
+        DefaultComparatorRegistry copy = new DefaultComparatorRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( schemaObjectType ).append( ": " );
+        boolean isFirst = true;
+
+        for ( Map.Entry<String, LdapComparator<?>> entry : byName.entrySet() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            LdapComparator<?> comparator = entry.getValue();
+
+            String fqcn = comparator.getFqcn();
+            int lastDotPos = fqcn.lastIndexOf( '.' );
+
+            sb.append( '<' ).append( comparator.getOid() ).append( ", " );
+
+            if ( lastDotPos > 0 )
+            {
+                sb.append( fqcn.substring( lastDotPos + 1 ) );
+            }
+            else
+            {
+                sb.append( fqcn );
+            }
+
+            sb.append( '>' );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultDitContentRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultDitContentRuleRegistry.java
new file mode 100644
index 0000000..c70f027
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultDitContentRuleRegistry.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An DitContentRule registry's service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultDitContentRuleRegistry extends DefaultSchemaObjectRegistry<DitContentRule>
+    implements DitContentRuleRegistry
+{
+    /**
+     * Creates a new default DitContentRuleRegistry instance.
+     */
+    public DefaultDitContentRuleRegistry()
+    {
+        super( SchemaObjectType.DIT_CONTENT_RULE, new OidRegistry<DitContentRule>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultDitContentRuleRegistry copy()
+    {
+        DefaultDitContentRuleRegistry copy = new DefaultDitContentRuleRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultDitStructureRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultDitStructureRuleRegistry.java
new file mode 100644
index 0000000..965b53a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultDitStructureRuleRegistry.java
@@ -0,0 +1,231 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A DitStructureRule registry's service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultDitStructureRuleRegistry extends DefaultSchemaObjectRegistry<DitStructureRule>
+    implements DitStructureRuleRegistry
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultDitStructureRuleRegistry.class );
+
+    /** A speedup for debug */
+    private static final boolean DEBUG = LOG.isDebugEnabled();
+
+    /** a map of DitStructureRule looked up by RuleId */
+    protected Map<Integer, DitStructureRule> byRuleId;
+
+
+    /**
+     * Creates a new default NormalizerRegistry instance.
+     */
+    public DefaultDitStructureRuleRegistry()
+    {
+        super( SchemaObjectType.DIT_STRUCTURE_RULE, new OidRegistry<DitStructureRule>() );
+        byRuleId = new HashMap<Integer, DitStructureRule>();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( int ruleId )
+    {
+        return byRuleId.containsKey( ruleId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<DitStructureRule> iterator()
+    {
+        return byRuleId.values().iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<Integer> ruleIdIterator()
+    {
+        return byRuleId.keySet().iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( int ruleId ) throws LdapException
+    {
+        DitStructureRule ditStructureRule = byRuleId.get( ruleId );
+
+        if ( ditStructureRule != null )
+        {
+            return ditStructureRule.getSchemaName();
+        }
+
+        String msg = I18n.err( I18n.ERR_04263, ruleId );
+        LOG.warn( msg );
+        throw new LdapException( msg );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( DitStructureRule ditStructureRule ) throws LdapException
+    {
+        int ruleId = ditStructureRule.getRuleId();
+
+        if ( byRuleId.containsKey( ruleId ) )
+        {
+            String msg = I18n.err( I18n.ERR_04264, ruleId );
+            LOG.warn( msg );
+            throw new LdapException( msg );
+        }
+
+        byRuleId.put( ruleId, ditStructureRule );
+
+        if ( LOG.isDebugEnabled() )
+        {
+            LOG.debug( "registered {} for OID {}", ditStructureRule, ruleId );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRule lookup( int ruleId ) throws LdapException
+    {
+        DitStructureRule ditStructureRule = byRuleId.get( ruleId );
+
+        if ( ditStructureRule == null )
+        {
+            String msg = I18n.err( I18n.ERR_04265, ruleId );
+            LOG.debug( msg );
+            throw new LdapException( msg );
+        }
+
+        if ( DEBUG )
+        {
+            LOG.debug( "Found {} with ruleId: {}", ditStructureRule, ruleId );
+        }
+
+        return ditStructureRule;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregister( int ruleId ) throws LdapException
+    {
+        DitStructureRule ditStructureRule = byRuleId.remove( ruleId );
+
+        if ( DEBUG )
+        {
+            LOG.debug( "Removed {} with ruleId {} from the registry", ditStructureRule, ruleId );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName )
+    {
+        if ( schemaName == null )
+        {
+            return;
+        }
+
+        // Loop on all the SchemaObjects stored and remove those associated
+        // with the give schemaName
+        for ( DitStructureRule ditStructureRule : this )
+        {
+            if ( schemaName.equalsIgnoreCase( ditStructureRule.getSchemaName() ) )
+            {
+                int ruleId = ditStructureRule.getRuleId();
+                SchemaObject removed = byRuleId.remove( ruleId );
+
+                if ( DEBUG )
+                {
+                    LOG.debug( "Removed {} with ruleId {} from the registry", removed, ruleId );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName )
+    {
+        // Loop on all the SchemaObjects stored and remove those associated
+        // with the give schemaName
+        for ( DitStructureRule ditStructureRule : this )
+        {
+            if ( originalSchemaName.equalsIgnoreCase( ditStructureRule.getSchemaName() ) )
+            {
+                ditStructureRule.setSchemaName( newSchemaName );
+
+                if ( DEBUG )
+                {
+                    LOG.debug( "Renamed {} schemaName to {}", ditStructureRule, newSchemaName );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultDitStructureRuleRegistry copy()
+    {
+        DefaultDitStructureRuleRegistry copy = new DefaultDitStructureRuleRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultLdapSyntaxRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultLdapSyntaxRegistry.java
new file mode 100644
index 0000000..d90e62c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultLdapSyntaxRegistry.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * A LdapSyntax registry's service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultLdapSyntaxRegistry extends DefaultSchemaObjectRegistry<LdapSyntax>
+    implements LdapSyntaxRegistry
+{
+    /**
+     * Creates a new default LdapSyntaxRegistry instance.
+     */
+    public DefaultLdapSyntaxRegistry()
+    {
+        super( SchemaObjectType.LDAP_SYNTAX, new OidRegistry<LdapSyntax>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultLdapSyntaxRegistry copy()
+    {
+        DefaultLdapSyntaxRegistry copy = new DefaultLdapSyntaxRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultMatchingRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultMatchingRuleRegistry.java
new file mode 100644
index 0000000..2a5b67d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultMatchingRuleRegistry.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * A MatchingRule registry's service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultMatchingRuleRegistry extends DefaultSchemaObjectRegistry<MatchingRule>
+    implements MatchingRuleRegistry
+{
+    /**
+     * Creates a new default MatchingRuleRegistry instance.
+     */
+    public DefaultMatchingRuleRegistry()
+    {
+        super( SchemaObjectType.MATCHING_RULE, new OidRegistry<MatchingRule>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultMatchingRuleRegistry copy()
+    {
+        DefaultMatchingRuleRegistry copy = new DefaultMatchingRuleRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultMatchingRuleUseRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultMatchingRuleUseRegistry.java
new file mode 100644
index 0000000..dfbdd17
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultMatchingRuleUseRegistry.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * A MatchingRuleUse registry service default implementation. 
+ * MatchingRuleUse objects are special in that they do not have unique OID's 
+ * specifically assigned to them. Their OID is really the OID of the MatchingRule 
+ * they refer to.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultMatchingRuleUseRegistry extends DefaultSchemaObjectRegistry<MatchingRuleUse>
+    implements MatchingRuleUseRegistry
+{
+    /**
+     * Creates a new default MatchingRuleUseRegistry instance.
+     */
+    public DefaultMatchingRuleUseRegistry()
+    {
+        super( SchemaObjectType.MATCHING_RULE_USE, new OidRegistry<MatchingRuleUse>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultMatchingRuleUseRegistry copy()
+    {
+        DefaultMatchingRuleUseRegistry copy = new DefaultMatchingRuleUseRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultNameFormRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultNameFormRegistry.java
new file mode 100644
index 0000000..289fbb3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultNameFormRegistry.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.NameForm;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An NameForm registry's service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultNameFormRegistry extends DefaultSchemaObjectRegistry<NameForm>
+    implements NameFormRegistry
+{
+    /**
+     * Creates a new default NameFormRegistry instance.
+     */
+    public DefaultNameFormRegistry()
+    {
+        super( SchemaObjectType.NAME_FORM, new OidRegistry<NameForm>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultNameFormRegistry copy()
+    {
+        DefaultNameFormRegistry copy = new DefaultNameFormRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultNormalizerRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultNormalizerRegistry.java
new file mode 100644
index 0000000..c78f983
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultNormalizerRegistry.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A Normalizer registry's service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultNormalizerRegistry extends DefaultSchemaObjectRegistry<Normalizer>
+    implements NormalizerRegistry
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultNormalizerRegistry.class );
+
+    /** A speedup for debug */
+    private static final boolean DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Creates a new default NormalizerRegistry instance.
+     */
+    public DefaultNormalizerRegistry()
+    {
+        super( SchemaObjectType.NORMALIZER, new OidRegistry<Normalizer>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        if ( schemaName == null )
+        {
+            return;
+        }
+
+        // Loop on all the SchemaObjects stored and remove those associated
+        // with the give schemaName
+        for ( Normalizer normalizer : this )
+        {
+            if ( schemaName.equalsIgnoreCase( normalizer.getSchemaName() ) )
+            {
+                String oid = normalizer.getOid();
+                SchemaObject removed = unregister( oid );
+
+                if ( DEBUG )
+                {
+                    LOG.debug( "Removed {} with oid {} from the registry", removed, oid );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultNormalizerRegistry copy()
+    {
+        DefaultNormalizerRegistry copy = new DefaultNormalizerRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( schemaObjectType ).append( ": " );
+        boolean isFirst = true;
+
+        for ( Map.Entry<String, Normalizer> entry : byName.entrySet() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            Normalizer normalizer = entry.getValue();
+
+            String fqcn = normalizer.getFqcn();
+            int lastDotPos = fqcn.lastIndexOf( '.' );
+
+            sb.append( '<' ).append( normalizer.getOid() ).append( ", " );
+
+            if ( lastDotPos > 0 )
+            {
+                sb.append( fqcn.substring( lastDotPos + 1 ) );
+            }
+            else
+            {
+                sb.append( fqcn );
+            }
+
+            sb.append( '>' );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultObjectClassRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultObjectClassRegistry.java
new file mode 100644
index 0000000..cd2da82
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultObjectClassRegistry.java
@@ -0,0 +1,250 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An ObjectClass registry's service default implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultObjectClassRegistry extends DefaultSchemaObjectRegistry<ObjectClass>
+    implements ObjectClassRegistry
+{
+    /** maps OIDs to a Set of descendants for that OID */
+    private Map<String, Set<ObjectClass>> oidToDescendants;
+
+
+    /**
+     * Creates a new default ObjectClassRegistry instance.
+     */
+    public DefaultObjectClassRegistry()
+    {
+        super( SchemaObjectType.OBJECT_CLASS, new OidRegistry<ObjectClass>() );
+        oidToDescendants = new HashMap<String, Set<ObjectClass>>();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasDescendants( String ancestorId ) throws LdapException
+    {
+        try
+        {
+            String oid = getOidByName( ancestorId );
+            Set<ObjectClass> descendants = oidToDescendants.get( oid );
+            return ( descendants != null ) && !descendants.isEmpty();
+        }
+        catch ( LdapException ne )
+        {
+            throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public Iterator<ObjectClass> descendants( String ancestorId ) throws LdapException
+    {
+        try
+        {
+            String oid = getOidByName( ancestorId );
+            Set<ObjectClass> descendants = oidToDescendants.get( oid );
+
+            if ( descendants == null )
+            {
+                return Collections.EMPTY_SET.iterator();
+            }
+
+            return descendants.iterator();
+        }
+        catch ( LdapException ne )
+        {
+            throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors )
+        throws LdapException
+    {
+        // add this attribute to descendant list of other attributes in superior chain
+        if ( ( ancestors == null ) || ( ancestors.size() == 0 ) )
+        {
+            return;
+        }
+
+        for ( ObjectClass ancestor : ancestors )
+        {
+            // Get the ancestor's descendant, if any
+            Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
+
+            // Initialize the descendant Set to store the descendants for the attributeType
+            if ( descendants == null )
+            {
+                descendants = new HashSet<ObjectClass>( 1 );
+                oidToDescendants.put( ancestor.getOid(), descendants );
+            }
+
+            // Add the current ObjectClass as a descendant
+            descendants.add( objectClass );
+
+            try
+            {
+                // And recurse until we reach the top of the hierarchy
+                registerDescendants( objectClass, ancestor.getSuperiors() );
+            }
+            catch ( LdapException ne )
+            {
+                throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors )
+        throws LdapException
+    {
+        // add this attribute to descendant list of other attributes in superior chain
+        if ( ( ancestors == null ) || ( ancestors.size() == 0 ) )
+        {
+            return;
+        }
+
+        for ( ObjectClass ancestor : ancestors )
+        {
+            // Get the ancestor's descendant, if any
+            Set<ObjectClass> descendants = oidToDescendants.get( ancestor.getOid() );
+
+            if ( descendants != null )
+            {
+                descendants.remove( attributeType );
+
+                if ( descendants.size() == 0 )
+                {
+                    oidToDescendants.remove( ancestor.getOid() );
+                }
+            }
+
+            try
+            {
+                // And recurse until we reach the top of the hierarchy
+                unregisterDescendants( attributeType, ancestor.getSuperiors() );
+            }
+            catch ( LdapException ne )
+            {
+                throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClass unregister( String numericOid ) throws LdapException
+    {
+        try
+        {
+            ObjectClass removed = super.unregister( numericOid );
+
+            // Deleting an ObjectClass which might be used as a superior means we have
+            // to recursively update the descendant map. We also have to remove
+            // the at.oid -> descendant relation
+            oidToDescendants.remove( numericOid );
+
+            // Now recurse if needed
+            unregisterDescendants( removed, removed.getSuperiors() );
+
+            return removed;
+        }
+        catch ( LdapException ne )
+        {
+            throw new LdapNoSuchAttributeException( ne.getMessage(), ne );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultObjectClassRegistry copy()
+    {
+        DefaultObjectClassRegistry copy = new DefaultObjectClassRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear the contained SchemaObjects
+        for ( SchemaObject objectClass : oidRegistry )
+        {
+            objectClass.clear();
+        }
+
+        // First clear the shared elements
+        super.clear();
+
+        // and clear the descendant
+        for ( Map.Entry<String, Set<ObjectClass>> entry : oidToDescendants.entrySet() )
+        {
+            Set<ObjectClass> descendants = entry.getValue();
+
+            if ( descendants != null )
+            {
+                descendants.clear();
+            }
+        }
+
+        oidToDescendants.clear();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSchema.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSchema.java
new file mode 100644
index 0000000..c8db105
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSchema.java
@@ -0,0 +1,254 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
+import org.apache.directory.api.util.StringConstants;
+
+
+/**
+ * The default Schema interface implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultSchema implements Schema
+{
+    /** The default schema's owner */
+    protected static final String DEFAULT_OWNER = "uid=admin,ou=system";
+
+    /** Tells if this schema is disabled */
+    protected boolean disabled;
+
+    /** Contains the list of schema it depends on */
+    protected String[] dependencies;
+
+    /** The schema owner */
+    protected String owner;
+
+    /** The schema name */
+    protected String name;
+
+    /** The set of SchemaObjects declared in this schema */
+    protected Set<SchemaObjectWrapper> content;
+
+
+    /**
+     * Creates a new instance of DefaultSchema.
+     *
+     * @param name The schema's name
+     */
+    public DefaultSchema( String name )
+    {
+        this( name, null, null, false );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultSchema.
+     *
+     * @param name The schema's name
+     * @param owner the schema's owner
+     */
+    public DefaultSchema( String name, String owner )
+    {
+        this( name, owner, null, false );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultSchema.
+     *
+     * @param name The schema's name
+     * @param owner the schema's owner
+     * @param dependencies The list of schemas it depends on 
+     */
+    public DefaultSchema( String name, String owner, String[] dependencies )
+    {
+        this( name, owner, dependencies, false );
+    }
+
+
+    /**
+     * Creates a new instance of DefaultSchema.
+     *
+     * @param name The schema's name
+     * @param owner the schema's owner
+     * @param dependencies The list of schemas it depends on
+     * @param disabled Set the status for this schema 
+     */
+    public DefaultSchema( String name, String owner, String[] dependencies, boolean disabled )
+    {
+        if ( name == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04266 ) );
+        }
+
+        this.name = name;
+
+        if ( owner != null )
+        {
+            this.owner = owner;
+        }
+        else
+        {
+            this.owner = DEFAULT_OWNER;
+        }
+
+        if ( dependencies != null )
+        {
+            this.dependencies = new String[dependencies.length];
+            System.arraycopy( dependencies, 0, this.dependencies, 0, dependencies.length );
+        }
+        else
+        {
+            this.dependencies = StringConstants.EMPTY_STRINGS;
+        }
+
+        this.disabled = disabled;
+
+        content = new HashSet<SchemaObjectWrapper>();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String[] getDependencies()
+    {
+        String[] copy = new String[dependencies.length];
+        System.arraycopy( dependencies, 0, copy, 0, dependencies.length );
+        return copy;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addDependencies( String... dependenciesToAdd )
+    {
+        if ( dependenciesToAdd != null )
+        {
+            int start = 0;
+
+            if ( dependencies == null )
+            {
+                dependencies = new String[dependenciesToAdd.length];
+            }
+            else
+            {
+                String[] tempDependencies = new String[dependencies.length + dependenciesToAdd.length];
+                System.arraycopy( dependencies, 0, tempDependencies, 0, dependencies.length );
+                start = dependencies.length;
+                dependencies = tempDependencies;
+            }
+
+            System.arraycopy( dependenciesToAdd, 0, dependencies, start, dependenciesToAdd.length );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOwner()
+    {
+        return owner;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDisabled()
+    {
+        return disabled;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEnabled()
+    {
+        return !disabled;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void disable()
+    {
+        this.disabled = true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void enable()
+    {
+        this.disabled = false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<SchemaObjectWrapper> getContent()
+    {
+        return content;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder( "\tSchema Name: " );
+        sb.append( name );
+        sb.append( "\n\t\tDisabled: " );
+        sb.append( disabled );
+        sb.append( "\n\t\tOwner: " );
+        sb.append( owner );
+        sb.append( "\n\t\tDependencies: " );
+        sb.append( Arrays.toString( dependencies ) );
+
+        // TODO : print the associated ShcemaObjects
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSchemaObjectRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSchemaObjectRegistry.java
new file mode 100644
index 0000000..1af49fa
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSchemaObjectRegistry.java
@@ -0,0 +1,549 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
+import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Common schema object registry interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class DefaultSchemaObjectRegistry<T extends SchemaObject> implements SchemaObjectRegistry<T>,
+    Iterable<T>
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaObjectRegistry.class );
+
+    /** A speedup for debug */
+    private static final boolean DEBUG = LOG.isDebugEnabled();
+
+    /** a map of SchemaObject looked up by name */
+    protected Map<String, T> byName;
+
+    /** The SchemaObject type, used by the toString() method  */
+    protected SchemaObjectType schemaObjectType;
+
+    /** the global OID Registry */
+    protected OidRegistry<T> oidRegistry;
+    
+    /** A flag indicating that the Registry is relaxed or not */
+    private boolean isRelaxed;
+
+
+    /**
+     * Creates a new DefaultSchemaObjectRegistry instance.
+     */
+    protected DefaultSchemaObjectRegistry( SchemaObjectType schemaObjectType, OidRegistry<T> oidRegistry )
+    {
+        byName = new HashMap<String, T>();
+        this.schemaObjectType = schemaObjectType;
+        this.oidRegistry = oidRegistry;
+        this.isRelaxed = Registries.STRICT;
+    }
+    
+    /**
+     * Tells if the Registry is permissive or if it must be checked
+     * against inconsistencies.
+     *
+     * @return True if SchemaObjects can be added even if they break the consistency
+     */
+    public boolean isRelaxed()
+    {
+        return isRelaxed;
+    }
+
+
+    /**
+     * Tells if the Registry is strict.
+     *
+     * @return True if SchemaObjects cannot be added if they break the consistency
+     */
+    public boolean isStrict()
+    {
+        return !isRelaxed;
+    }
+
+
+    /**
+     * Change the Registry to a relaxed mode, where invalid SchemaObjects
+     * can be registered.
+     */
+    public void setRelaxed()
+    {
+        isRelaxed = Registries.RELAXED;
+        oidRegistry.setRelaxed();
+    }
+
+
+    /**
+     * Change the Registry to a strict mode, where invalid SchemaObjects
+     * cannot be registered.
+     */
+    public void setStrict()
+    {
+        isRelaxed = Registries.STRICT;
+        oidRegistry.setStrict();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        if ( !byName.containsKey( oid ) )
+        {
+            return byName.containsKey( Strings.toLowerCase( oid ) );
+        }
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        if ( !Oid.isOid( oid ) )
+        {
+            String msg = I18n.err( I18n.ERR_04267 );
+            LOG.warn( msg );
+            throw new LdapException( msg );
+        }
+
+        SchemaObject schemaObject = byName.get( oid );
+
+        if ( schemaObject != null )
+        {
+            return schemaObject.getSchemaName();
+        }
+
+        String msg = I18n.err( I18n.ERR_04268_OID_NOT_FOUND, oid );
+        LOG.warn( msg );
+        throw new LdapException( msg );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName )
+    {
+        // Loop on all the SchemaObjects stored and remove those associated
+        // with the give schemaName
+        for ( T schemaObject : this )
+        {
+            if ( originalSchemaName.equalsIgnoreCase( schemaObject.getSchemaName() ) )
+            {
+                schemaObject.setSchemaName( newSchemaName );
+
+                if ( DEBUG )
+                {
+                    LOG.debug( "Renamed {} schemaName to {}", schemaObject, newSchemaName );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<T> iterator()
+    {
+        return oidRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return byName.keySet().iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public T lookup( String oid ) throws LdapException
+    {
+        if ( oid == null )
+        {
+            return null;
+        }
+
+        T schemaObject = byName.get( oid );
+
+        if ( schemaObject == null )
+        {
+            // let's try with trimming and lowercasing now
+            schemaObject = byName.get( Strings.trim( Strings.toLowerCase( oid ) ) );
+        }
+
+        if ( schemaObject == null )
+        {
+            String msg = I18n.err( I18n.ERR_04269, schemaObjectType.name(), oid );
+            LOG.debug( msg );
+            throw new LdapException( msg );
+        }
+
+        if ( DEBUG )
+        {
+            LOG.debug( "Found {} with oid: {}", schemaObject, oid );
+        }
+
+        return schemaObject;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( T schemaObject ) throws LdapException
+    {
+        String oid = schemaObject.getOid();
+
+        if ( byName.containsKey( oid ) )
+        {
+            String msg = I18n.err( I18n.ERR_04270, schemaObjectType.name(), oid );
+            LOG.warn( msg );
+            LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, msg );
+            ldapSchemaException.setSourceObject( schemaObject );
+            throw ldapSchemaException;
+        }
+
+        byName.put( oid, schemaObject );
+
+        /*
+         * add the aliases/names to the name map along with their toLowerCase
+         * versions of the name: this is used to make sure name lookups work
+         */
+        for ( String name : schemaObject.getNames() )
+        {
+            String lowerName = Strings.trim( Strings.toLowerCase( name ) );
+
+            if ( byName.containsKey( lowerName ) )
+            {
+                String msg = I18n.err( I18n.ERR_04271, schemaObjectType.name(), name );
+                LOG.warn( msg );
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.NAME_ALREADY_REGISTERED, msg );
+                ldapSchemaException.setSourceObject( schemaObject );
+                throw ldapSchemaException;
+            }
+            else
+            {
+                byName.put( lowerName, schemaObject );
+            }
+        }
+
+        // And register the oid -> schemaObject relation
+        oidRegistry.register( schemaObject );
+
+        if ( LOG.isDebugEnabled() )
+        {
+            LOG.debug( "registered " + schemaObject.getName() + " for OID {}", oid );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public T unregister( String numericOid ) throws LdapException
+    {
+        if ( !Oid.isOid( numericOid ) )
+        {
+            String msg = I18n.err( I18n.ERR_04272, numericOid );
+            LOG.error( msg );
+            throw new LdapException( msg );
+        }
+
+        T schemaObject = byName.remove( numericOid );
+
+        for ( String name : schemaObject.getNames() )
+        {
+            byName.remove( name );
+        }
+
+        // And remove the SchemaObject from the oidRegistry
+        oidRegistry.unregister( numericOid );
+
+        if ( DEBUG )
+        {
+            LOG.debug( "Removed {} with oid {} from the registry", schemaObject, numericOid );
+        }
+
+        return schemaObject;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public T unregister( T schemaObject ) throws LdapException
+    {
+        String oid = schemaObject.getOid();
+
+        if ( !byName.containsKey( oid ) )
+        {
+            String msg = I18n.err( I18n.ERR_04273, schemaObjectType.name(), oid );
+            LOG.warn( msg );
+            throw new LdapException( msg );
+        }
+
+        // Remove the oid
+        T removed = byName.remove( oid );
+
+        /*
+         * Remove the aliases/names from the name map along with their toLowerCase
+         * versions of the name.
+         */
+        for ( String name : schemaObject.getNames() )
+        {
+            byName.remove( Strings.trim( Strings.toLowerCase( name ) ) );
+        }
+
+        // And unregister the oid -> schemaObject relation
+        oidRegistry.unregister( oid );
+
+        return removed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        if ( schemaName == null )
+        {
+            return;
+        }
+
+        // Loop on all the SchemaObjects stored and remove those associated
+        // with the give schemaName
+        for ( T schemaObject : this )
+        {
+            if ( schemaName.equalsIgnoreCase( schemaObject.getSchemaName() ) )
+            {
+                String oid = schemaObject.getOid();
+                SchemaObject removed = unregister( oid );
+
+                if ( DEBUG )
+                {
+                    LOG.debug( "Removed {} with oid {} from the registry", removed, oid );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        T schemaObject = byName.get( name );
+
+        if ( schemaObject == null )
+        {
+            // last resort before giving up check with lower cased version
+            String lowerCased = Strings.toLowerCase( name );
+
+            schemaObject = byName.get( lowerCased );
+
+            // ok this name is not for a schema object in the registry
+            if ( schemaObject == null )
+            {
+                throw new LdapException( I18n.err( I18n.ERR_04274, name ) );
+            }
+        }
+
+        // we found the schema object by key on the first lookup attempt
+        return schemaObject.getOid();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    // This will suppress PMD.EmptyCatchBlock warnings in this method
+    @SuppressWarnings("unchecked")
+    public SchemaObjectRegistry<T> copy( SchemaObjectRegistry<T> original )
+    {
+        // Fill the byName and OidRegistry maps, the type has already be copied
+        for ( Map.Entry<String, T> entry : ( ( DefaultSchemaObjectRegistry<T> ) original ).byName.entrySet() )
+        {
+            String key = entry.getKey();
+            // Clone each SchemaObject
+            T value = entry.getValue();
+
+            if ( value instanceof LoadableSchemaObject )
+            {
+                // Update the data structure. 
+                // Comparators, Normalizers and SyntaxCheckers aren't copied, 
+                // they are immutable
+                byName.put( key, value );
+
+                // Update the OidRegistry
+                oidRegistry.put( value );
+            }
+            else
+            {
+                T copiedValue = null;
+
+                // Copy the value if it's not already in the oidRegistry
+                if ( oidRegistry.contains( value.getOid() ) )
+                {
+                    try
+                    {
+                        copiedValue = oidRegistry.getSchemaObject( value.getOid() );
+                    }
+                    catch ( LdapException ne )
+                    {
+                        // Can't happen
+                    }
+                }
+                else
+                {
+                    copiedValue = ( T ) value.copy();
+                }
+
+                // Update the data structure. 
+                byName.put( key, copiedValue );
+
+                // Update the OidRegistry
+                oidRegistry.put( copiedValue );
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public T get( String oid )
+    {
+        try
+        {
+            return oidRegistry.getSchemaObject( oid );
+        }
+        catch ( LdapException ne )
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return schemaObjectType;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return oidRegistry.size();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( schemaObjectType ).append( ": " );
+        boolean isFirst = true;
+
+        for ( Map.Entry<String, T> entry : byName.entrySet() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            String name = entry.getKey();
+            T schemaObject = entry.getValue();
+
+            sb.append( '<' ).append( name ).append( ", " ).append( schemaObject.getOid() ).append( '>' );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear()
+    {
+        // Clear all the schemaObjects
+        for ( SchemaObject schemaObject : oidRegistry )
+        {
+            // Don't clear LoadableSchemaObject
+            if ( !( schemaObject instanceof LoadableSchemaObject ) )
+            {
+                schemaObject.clear();
+            }
+        }
+
+        // Remove the byName elements
+        byName.clear();
+
+        // Clear the OidRegistry
+        oidRegistry.clear();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSyntaxCheckerRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSyntaxCheckerRegistry.java
new file mode 100644
index 0000000..3743ad9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DefaultSyntaxCheckerRegistry.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * SyntaxChecker registry component's service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultSyntaxCheckerRegistry extends DefaultSchemaObjectRegistry<SyntaxChecker>
+    implements SyntaxCheckerRegistry
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultSyntaxCheckerRegistry.class );
+
+    /** A speedup for debug */
+    private static final boolean DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Creates a new default SyntaxCheckerRegistry instance.
+     */
+    public DefaultSyntaxCheckerRegistry()
+    {
+        super( SchemaObjectType.SYNTAX_CHECKER, new OidRegistry<SyntaxChecker>() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        if ( schemaName == null )
+        {
+            return;
+        }
+
+        // Loop on all the SchemaObjects stored and remove those associated
+        // with the give schemaName
+        for ( SyntaxChecker syntaxChecker : this )
+        {
+            if ( schemaName.equalsIgnoreCase( syntaxChecker.getSchemaName() ) )
+            {
+                String oid = syntaxChecker.getOid();
+                SchemaObject removed = unregister( oid );
+
+                if ( DEBUG )
+                {
+                    LOG.debug( "Removed {} with oid {} from the registry", removed, oid );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DefaultSyntaxCheckerRegistry copy()
+    {
+        DefaultSyntaxCheckerRegistry copy = new DefaultSyntaxCheckerRegistry();
+
+        // Copy the base data
+        copy.copy( this );
+
+        return copy;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( schemaObjectType ).append( ": " );
+        boolean isFirst = true;
+
+        for ( Map.Entry<String, SyntaxChecker> entry : byName.entrySet() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            SyntaxChecker syntaxChecker = entry.getValue();
+
+            String fqcn = syntaxChecker.getFqcn();
+            int lastDotPos = fqcn.lastIndexOf( '.' );
+
+            sb.append( '<' ).append( syntaxChecker.getOid() ).append( ", " );
+
+            if ( lastDotPos > 0 )
+            {
+                sb.append( fqcn.substring( lastDotPos + 1 ) );
+            }
+            else
+            {
+                sb.append( fqcn );
+            }
+
+            sb.append( '>' );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DitContentRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DitContentRuleRegistry.java
new file mode 100644
index 0000000..6317a5b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DitContentRuleRegistry.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+
+
+/**
+ * An DitContentRule registry's service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface DitContentRuleRegistry extends SchemaObjectRegistry<DitContentRule>,
+    Iterable<DitContentRule>
+{
+    /**
+     * Copy the DitContentRuleRegistry
+     */
+    DitContentRuleRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DitStructureRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DitStructureRuleRegistry.java
new file mode 100644
index 0000000..a189b40
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/DitStructureRuleRegistry.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+
+
+/**
+ * An DitStructureRule registry service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface DitStructureRuleRegistry extends SchemaObjectRegistry<DitStructureRule>,
+    Iterable<DitStructureRule>
+{
+    /**
+     * Checks to see if an DitStructureRule exists in the registry, by its
+     * ruleId. 
+     * 
+     * @param ruleId the rule identifier of the DitStructureRule
+     * @return true if a DitStructureRule definition exists for the ruleId, false
+     * otherwise
+     */
+    boolean contains( int ruleId );
+
+
+    /**
+     * Gets an iterator over the registered descriptions in the registry.
+     *
+     * @return an Iterator of descriptions
+     */
+    Iterator<DitStructureRule> iterator();
+
+
+    /**
+     * Gets an iterator over the registered ruleId in the registry.
+     *
+     * @return an Iterator of ruleId
+     */
+    Iterator<Integer> ruleIdIterator();
+
+
+    /**
+     * Gets the name of the schema this schema object is associated with.
+     *
+     * @param ruleId the object identifier
+     * @return the schema name
+     * @throws LdapException if the schema object does not exist
+     */
+    String getSchemaName( int ruleId ) throws LdapException;
+
+
+    /**
+     * Registers a new DitStructureRule with this registry.
+     *
+     * @param ditStructureRule the DitStructureRule to register
+     * @throws LdapException if the DitStructureRule is already registered or
+     * the registration operation is not supported
+     */
+    void register( DitStructureRule ditStructureRule ) throws LdapException;
+
+
+    /**
+     * Looks up an dITStructureRule by its unique Object IDentifier or by its
+     * name.
+     * 
+     * @param ruleId the rule identifier for the DitStructureRule
+     * @return the DitStructureRule instance for rule identifier
+     * @throws LdapException if the DitStructureRule does not exist
+     */
+    DitStructureRule lookup( int ruleId ) throws LdapException;
+
+
+    /**
+     * Unregisters a DitStructureRule using it's rule identifier. 
+     * 
+     * @param ruleId the rule identifier for the DitStructureRule to unregister
+     * @throws LdapException if no such DitStructureRule exists
+     */
+    void unregister( int ruleId ) throws LdapException;
+
+
+    /**
+     * Unregisters all DITStructureRules defined for a specific schema from
+     * this registry.
+     * 
+     * @param schemaName the name of the schema whose syntaxCheckers will be removed from
+     * @throws LdapException if no such SchemaElement exists
+     */
+    void unregisterSchemaElements( String schemaName ) throws LdapException;
+
+
+    /**
+     * Modify all the DitStructureRule using a schemaName when this name changes.
+     *
+     * @param originalSchemaName The original Schema name
+     * @param newSchemaName The new Schema name
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if the schema can't be renamed
+     */
+    void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException;
+
+
+    /**
+     * Copy the DitStructureRuleRegistry
+     */
+    DitStructureRuleRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableAttributeTypeRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableAttributeTypeRegistry.java
new file mode 100644
index 0000000..193a67f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableAttributeTypeRegistry.java
@@ -0,0 +1,298 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+
+
+/**
+ * An immutable wrapper of the AttributeType registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableAttributeTypeRegistry implements AttributeTypeRegistry
+{
+    /** The wrapped AttributeType registry */
+    AttributeTypeRegistry immutableAttributeTypeRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableAttributeTypeRegistry.
+     *
+     * @param attributeTypeRegistry The wrapped AttributeType registry
+     */
+    public ImmutableAttributeTypeRegistry( AttributeTypeRegistry attributeTypeRegistry )
+    {
+        immutableAttributeTypeRegistry = attributeTypeRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, OidNormalizer> getNormalizerMapping()
+    {
+        return immutableAttributeTypeRegistry.getNormalizerMapping();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasDescendants( String ancestorId ) throws LdapException
+    {
+        return immutableAttributeTypeRegistry.hasDescendants( ancestorId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasDescendants( AttributeType ancestor ) throws LdapException
+    {
+        return immutableAttributeTypeRegistry.hasDescendants( ancestor );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<AttributeType> descendants( String ancestorId ) throws LdapException
+    {
+        return immutableAttributeTypeRegistry.descendants( ancestorId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<AttributeType> descendants( AttributeType ancestor ) throws LdapException
+    {
+        return immutableAttributeTypeRegistry.descendants( ancestor );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( AttributeType attributeType ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void registerDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterDescendants( AttributeType attributeType, AttributeType ancestor ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION,
+            "Cannot modify the AttributeTypeRegistry copy" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addMappingFor( AttributeType attributeType ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeMappingFor( AttributeType attributeType ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType lookup( String oid ) throws LdapException
+    {
+        return immutableAttributeTypeRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString()
+    {
+        return immutableAttributeTypeRegistry.toString();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeTypeRegistry copy()
+    {
+        return ( AttributeTypeRegistry ) immutableAttributeTypeRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableAttributeTypeRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<AttributeType> iterator()
+    {
+        return immutableAttributeTypeRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableAttributeTypeRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableAttributeTypeRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        try
+        {
+            return immutableAttributeTypeRegistry.getOidByName( name );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapNoSuchAttributeException( le.getMessage(), le );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableAttributeTypeRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableAttributeTypeRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName )
+    {
+        // Do nothing
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType get( String oid )
+    {
+        return immutableAttributeTypeRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType unregister( AttributeType schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04275 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableComparatorRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableComparatorRegistry.java
new file mode 100644
index 0000000..033f944
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableComparatorRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the Comparator registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableComparatorRegistry implements ComparatorRegistry
+{
+    /** The wrapped LdapComparator registry */
+    ComparatorRegistry immutableComparatorRegistry;
+
+
+    /**
+     * Creates a new immutable ComparatorRegistry instance.
+     * 
+     * @param comparatorRegistry The wrapped LdapComparator registry 
+     */
+    public ImmutableComparatorRegistry( ComparatorRegistry comparatorRegistry )
+    {
+        immutableComparatorRegistry = comparatorRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( LdapComparator<?> comparator ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04276 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapComparator<?> unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04276 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04276 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableComparatorRegistry copy()
+    {
+        return ( ImmutableComparatorRegistry ) immutableComparatorRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableComparatorRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableComparatorRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableComparatorRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableComparatorRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableComparatorRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<LdapComparator<?>> iterator()
+    {
+        return immutableComparatorRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapComparator<?> lookup( String oid ) throws LdapException
+    {
+        return immutableComparatorRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableComparatorRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04276 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapComparator<?> get( String oid )
+    {
+        return immutableComparatorRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04276 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapComparator<?> unregister( LdapComparator<?> schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04276 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableDitContentRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableDitContentRuleRegistry.java
new file mode 100644
index 0000000..1328110
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableDitContentRuleRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the DitContentRule registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableDitContentRuleRegistry implements DitContentRuleRegistry
+{
+    /** The wrapped DitContentRule registry */
+    DitContentRuleRegistry immutableDITContentRuleRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableDitContentRuleRegistry.
+     *
+     * @param ditContentRuleRegistry The wrapped DitContentRule registry
+     */
+    public ImmutableDitContentRuleRegistry( DitContentRuleRegistry ditContentRuleRegistry )
+    {
+        immutableDITContentRuleRegistry = ditContentRuleRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableDitContentRuleRegistry copy()
+    {
+        return ( ImmutableDitContentRuleRegistry ) immutableDITContentRuleRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableDITContentRuleRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableDITContentRuleRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableDITContentRuleRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableDITContentRuleRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableDITContentRuleRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<DitContentRule> iterator()
+    {
+        return immutableDITContentRuleRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitContentRule lookup( String oid ) throws LdapException
+    {
+        return immutableDITContentRuleRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableDITContentRuleRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( DitContentRule schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04277 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04277 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitContentRule unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04277 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04277 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitContentRule get( String oid )
+    {
+        return immutableDITContentRuleRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04277 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitContentRule unregister( DitContentRule schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04277 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableDitStructureRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableDitStructureRuleRegistry.java
new file mode 100644
index 0000000..12b5f7a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableDitStructureRuleRegistry.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the DitStructureRule registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableDitStructureRuleRegistry implements DitStructureRuleRegistry
+{
+    /** The wrapped DitStructureRule registry */
+    DitStructureRuleRegistry immutableDITStructureRuleRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableDitStructureRuleRegistry.
+     *
+     * @param ditStructureRuleRegistry The wrapped DitStructureRule registry
+     */
+    public ImmutableDitStructureRuleRegistry( DitStructureRuleRegistry ditStructureRuleRegistry )
+    {
+        immutableDITStructureRuleRegistry = ditStructureRuleRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( int ruleId )
+    {
+        return immutableDITStructureRuleRegistry.contains( ruleId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<DitStructureRule> iterator()
+    {
+        return immutableDITStructureRuleRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<Integer> ruleIdIterator()
+    {
+        return immutableDITStructureRuleRegistry.ruleIdIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( int ruleId ) throws LdapException
+    {
+        return immutableDITStructureRuleRegistry.getSchemaName( ruleId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( DitStructureRule ditStructureRule ) throws LdapException
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRule lookup( int ruleId ) throws LdapException
+    {
+        return immutableDITStructureRuleRegistry.lookup( ruleId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregister( int ruleId ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04278 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04278 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04278 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableDitStructureRuleRegistry copy()
+    {
+        return ( ImmutableDitStructureRuleRegistry ) immutableDITStructureRuleRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableDITStructureRuleRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableDITStructureRuleRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableDITStructureRuleRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableDITStructureRuleRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableDITStructureRuleRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRule lookup( String oid ) throws LdapException
+    {
+        return immutableDITStructureRuleRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableDITStructureRuleRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRule unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04278 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRule get( String oid )
+    {
+        return immutableDITStructureRuleRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04278 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRule unregister( DitStructureRule schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04278 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableLdapSyntaxRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableLdapSyntaxRegistry.java
new file mode 100644
index 0000000..69a0500
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableLdapSyntaxRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the Syntax registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableLdapSyntaxRegistry implements LdapSyntaxRegistry
+{
+    /** The wrapped LdapSyntax registry */
+    LdapSyntaxRegistry immutableLdapSyntaxRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableLdapSyntaxRegistry.
+     *
+     * @param ldapSyntaxRegistry The wrapped LdapSyntax registry
+     */
+    public ImmutableLdapSyntaxRegistry( LdapSyntaxRegistry ldapSyntaxRegistry )
+    {
+        immutableLdapSyntaxRegistry = ldapSyntaxRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableLdapSyntaxRegistry copy()
+    {
+        return ( ImmutableLdapSyntaxRegistry ) immutableLdapSyntaxRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableLdapSyntaxRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableLdapSyntaxRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableLdapSyntaxRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableLdapSyntaxRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableLdapSyntaxRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<LdapSyntax> iterator()
+    {
+        return immutableLdapSyntaxRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapSyntax lookup( String oid ) throws LdapException
+    {
+        return immutableLdapSyntaxRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableLdapSyntaxRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( LdapSyntax schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04279 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04279 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapSyntax unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04279 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04279 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapSyntax get( String oid )
+    {
+        return immutableLdapSyntaxRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04279 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapSyntax unregister( LdapSyntax schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04279 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableMatchingRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableMatchingRuleRegistry.java
new file mode 100644
index 0000000..9e4fa4a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableMatchingRuleRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the MatchingRule registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableMatchingRuleRegistry implements MatchingRuleRegistry
+{
+    /** The wrapped MatchingRule registry */
+    MatchingRuleRegistry immutableMatchingRuleRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableMatchingRuleRegistry.
+     *
+     * @param matchingRuleRegistry The wrapped MatchingRule registry
+     */
+    public ImmutableMatchingRuleRegistry( MatchingRuleRegistry matchingRuleRegistry )
+    {
+        immutableMatchingRuleRegistry = matchingRuleRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableMatchingRuleRegistry copy()
+    {
+        return ( ImmutableMatchingRuleRegistry ) immutableMatchingRuleRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableMatchingRuleRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableMatchingRuleRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableMatchingRuleRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableMatchingRuleRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableMatchingRuleRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<MatchingRule> iterator()
+    {
+        return immutableMatchingRuleRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRule lookup( String oid ) throws LdapException
+    {
+        return immutableMatchingRuleRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableMatchingRuleRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( MatchingRule schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04280 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04280 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRule unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04280 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04280 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRule get( String oid )
+    {
+        return immutableMatchingRuleRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04280 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRule unregister( MatchingRule schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04280 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableMatchingRuleUseRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableMatchingRuleUseRegistry.java
new file mode 100644
index 0000000..3e8d235
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableMatchingRuleUseRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the MatchingRuleUse registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableMatchingRuleUseRegistry implements MatchingRuleUseRegistry
+{
+    /** The wrapped MatchingRuleUse registry */
+    MatchingRuleUseRegistry immutableMatchingRuleUseRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableMatchingRuleUseRegistry.
+     *
+     * @param matchingRuleUseRegistry The wrapped MatchingRuleUse registry
+     */
+    public ImmutableMatchingRuleUseRegistry( MatchingRuleUseRegistry matchingRuleUseRegistry )
+    {
+        immutableMatchingRuleUseRegistry = matchingRuleUseRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableMatchingRuleUseRegistry copy()
+    {
+        return ( ImmutableMatchingRuleUseRegistry ) immutableMatchingRuleUseRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableMatchingRuleUseRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableMatchingRuleUseRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableMatchingRuleUseRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableMatchingRuleUseRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableMatchingRuleUseRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<MatchingRuleUse> iterator()
+    {
+        return immutableMatchingRuleUseRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRuleUse lookup( String oid ) throws LdapException
+    {
+        return immutableMatchingRuleUseRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableMatchingRuleUseRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( MatchingRuleUse schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04281 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04281 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRuleUse unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04281 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04281 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRuleUse get( String oid )
+    {
+        return immutableMatchingRuleUseRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04281 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRuleUse unregister( MatchingRuleUse schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04281 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableNameFormRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableNameFormRegistry.java
new file mode 100644
index 0000000..656b41e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableNameFormRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.NameForm;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the NameForm registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableNameFormRegistry implements NameFormRegistry
+{
+    /** The wrapped NameForm registry */
+    NameFormRegistry immutableNameFormRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableNameFormRegistry.
+     *
+     * @param nameFormRegistry The wrapped NameForm registry
+     */
+    public ImmutableNameFormRegistry( NameFormRegistry nameFormRegistry )
+    {
+        immutableNameFormRegistry = nameFormRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableNameFormRegistry copy()
+    {
+        return ( ImmutableNameFormRegistry ) immutableNameFormRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableNameFormRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableNameFormRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableNameFormRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableNameFormRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableNameFormRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<NameForm> iterator()
+    {
+        return immutableNameFormRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public NameForm lookup( String oid ) throws LdapException
+    {
+        return immutableNameFormRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableNameFormRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( NameForm schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04282 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04282 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public NameForm unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04282 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04282 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public NameForm get( String oid )
+    {
+        return immutableNameFormRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04282 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public NameForm unregister( NameForm schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04282 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableNormalizerRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableNormalizerRegistry.java
new file mode 100644
index 0000000..b15b855
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableNormalizerRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the Normalizer registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableNormalizerRegistry implements NormalizerRegistry
+{
+    /** The wrapped Normalizer registry */
+    NormalizerRegistry immutableNormalizerRegistry;
+
+
+    /**
+     * Creates a new immutable NormalizerRegistry instance.
+     * 
+     * @param normalizerRegistry The wrapped Normalizer registry 
+     */
+    public ImmutableNormalizerRegistry( NormalizerRegistry normalizerRegistry )
+    {
+        immutableNormalizerRegistry = normalizerRegistry;
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public void register( Normalizer normalizer ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04283 ) );
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public Normalizer unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04283 ) );
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04283 ) );
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public ImmutableNormalizerRegistry copy()
+    {
+        return ( ImmutableNormalizerRegistry ) immutableNormalizerRegistry.copy();
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableNormalizerRegistry.size();
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableNormalizerRegistry.contains( oid );
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableNormalizerRegistry.getOidByName( name );
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableNormalizerRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableNormalizerRegistry.getType();
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public Iterator<Normalizer> iterator()
+    {
+        return immutableNormalizerRegistry.iterator();
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public Normalizer lookup( String oid ) throws LdapException
+    {
+        return immutableNormalizerRegistry.lookup( oid );
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableNormalizerRegistry.oidsIterator();
+    }
+
+
+    /**
+     *  {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04283 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Normalizer get( String oid )
+    {
+        return immutableNormalizerRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04283 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Normalizer unregister( Normalizer schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04283 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableObjectClassRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableObjectClassRegistry.java
new file mode 100644
index 0000000..1324c46
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableObjectClassRegistry.java
@@ -0,0 +1,234 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * An immutable wrapper of the ObjectClass registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableObjectClassRegistry implements ObjectClassRegistry, Cloneable
+{
+    /** The wrapped ObjectClass registry */
+    private ObjectClassRegistry immutableObjectClassRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableAttributeTypeRegistry.
+     *
+     * @param ocRegistry The wrapped Attrib uteType registry
+     */
+    public ImmutableObjectClassRegistry( ObjectClassRegistry ocRegistry )
+    {
+        immutableObjectClassRegistry = ocRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasDescendants( String ancestorId ) throws LdapException
+    {
+        return immutableObjectClassRegistry.hasDescendants( ancestorId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<ObjectClass> descendants( String ancestorId ) throws LdapException
+    {
+        return immutableObjectClassRegistry.descendants( ancestorId );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( ObjectClass objectClass ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClass unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+
+
+    /**
+     * Clone the ObjectClassRegistry
+     */
+    public ImmutableObjectClassRegistry copy()
+    {
+        return ( ImmutableObjectClassRegistry ) immutableObjectClassRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableObjectClassRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableObjectClassRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableObjectClassRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableObjectClassRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableObjectClassRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<ObjectClass> iterator()
+    {
+        return immutableObjectClassRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClass lookup( String oid ) throws LdapException
+    {
+        return immutableObjectClassRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableObjectClassRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClass get( String oid )
+    {
+        return immutableObjectClassRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClass unregister( ObjectClass schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04284 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableSyntaxCheckerRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableSyntaxCheckerRegistry.java
new file mode 100644
index 0000000..7c7c854
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ImmutableSyntaxCheckerRegistry.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+
+
+/**
+ * An immutable wrapper of the SyntaxChecker registry.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ImmutableSyntaxCheckerRegistry implements SyntaxCheckerRegistry
+{
+    /** The wrapped SyntaxChecker registry */
+    SyntaxCheckerRegistry immutableSyntaxCheckerRegistry;
+
+
+    /**
+     * Creates a new instance of ImmutableSyntaxCheckerRegistry.
+     *
+     * @param syntaxCheckerRegistry The wrapped SyntaxChecker registry
+     */
+    public ImmutableSyntaxCheckerRegistry( SyntaxCheckerRegistry syntaxCheckerRegistry )
+    {
+        immutableSyntaxCheckerRegistry = syntaxCheckerRegistry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void register( SyntaxChecker syntaxChecker ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04285 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxChecker unregister( String numericOid ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04285 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unregisterSchemaElements( String schemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04285 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ImmutableSyntaxCheckerRegistry copy()
+    {
+        return ( ImmutableSyntaxCheckerRegistry ) immutableSyntaxCheckerRegistry.copy();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size()
+    {
+        return immutableSyntaxCheckerRegistry.size();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains( String oid )
+    {
+        return immutableSyntaxCheckerRegistry.contains( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOidByName( String name ) throws LdapException
+    {
+        return immutableSyntaxCheckerRegistry.getOidByName( name );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSchemaName( String oid ) throws LdapException
+    {
+        return immutableSyntaxCheckerRegistry.getSchemaName( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObjectType getType()
+    {
+        return immutableSyntaxCheckerRegistry.getType();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<SyntaxChecker> iterator()
+    {
+        return immutableSyntaxCheckerRegistry.iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxChecker lookup( String oid ) throws LdapException
+    {
+        return immutableSyntaxCheckerRegistry.lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> oidsIterator()
+    {
+        return immutableSyntaxCheckerRegistry.oidsIterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04285 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxChecker get( String oid )
+    {
+        return immutableSyntaxCheckerRegistry.get( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04285 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxChecker unregister( SyntaxChecker schemaObject ) throws LdapException
+    {
+        throw new LdapUnwillingToPerformException( ResultCodeEnum.NO_SUCH_OPERATION, I18n.err( I18n.ERR_04285 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/LdapSyntaxRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/LdapSyntaxRegistry.java
new file mode 100644
index 0000000..05326a5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/LdapSyntaxRegistry.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+
+
+/**
+ * An LdapSyntax registry service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface LdapSyntaxRegistry extends SchemaObjectRegistry<LdapSyntax>,
+    Iterable<LdapSyntax>
+{
+    /**
+     * Copy the LdapSyntaxRegistry
+     */
+    LdapSyntaxRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/MatchingRuleRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/MatchingRuleRegistry.java
new file mode 100644
index 0000000..9d1ddc8
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/MatchingRuleRegistry.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+
+
+/**
+ * An AttributeType registry service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface MatchingRuleRegistry extends SchemaObjectRegistry<MatchingRule>,
+    Iterable<MatchingRule>
+{
+    /**
+     * Copy the MatchingRuleRegistry
+     */
+    MatchingRuleRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/MatchingRuleUseRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/MatchingRuleUseRegistry.java
new file mode 100644
index 0000000..e529f79
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/MatchingRuleUseRegistry.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+
+
+/**
+ * A MatchingRuleUse registry service interface.  MatchingRuleUse objects are
+ * special in that they do not have unique OID's specifically assigned to them.
+ * Their OID is really the OID of the MatchingRule they refer to.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface MatchingRuleUseRegistry extends SchemaObjectRegistry<MatchingRuleUse>,
+    Iterable<MatchingRuleUse>
+{
+    /**
+     * Copy the MatchingRuleUseRegistry
+     */
+    MatchingRuleUseRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/NameFormRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/NameFormRegistry.java
new file mode 100644
index 0000000..fc3a4af
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/NameFormRegistry.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.schema.NameForm;
+
+
+/**
+ * An NameForm registry service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface NameFormRegistry extends SchemaObjectRegistry<NameForm>,
+    Iterable<NameForm>
+{
+    /**
+     * Copy the NameFormRegistry
+     */
+    NameFormRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/NormalizerRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/NormalizerRegistry.java
new file mode 100644
index 0000000..c459ce8
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/NormalizerRegistry.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+
+
+/**
+ * Normalizer registry service class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface NormalizerRegistry extends SchemaObjectRegistry<Normalizer>,
+    Iterable<Normalizer>
+{
+    /**
+     * Registers a new Normalizer with this registry.
+     *
+     * @param normalizer the Normalizer to register
+     * @throws LdapException if the Normalizer is already registered or
+     * the registration operation is not supported
+     */
+    void register( Normalizer normalizer ) throws LdapException;
+
+
+    /**
+     * Removes the Normalizer registered with this registry, using its
+     * numeric OID.
+     * 
+     * @param numericOid the numeric identifier
+     * @throws LdapException if the numeric identifier is invalid
+     */
+    Normalizer unregister( String numericOid ) throws LdapException;
+
+
+    /**
+     * Unregisters all Normalizers defined for a specific schema from
+     * this registry.
+     * 
+     * @param schemaName the name of the schema whose Normalizers will be removed from
+     */
+    void unregisterSchemaElements( String schemaName ) throws LdapException;
+
+
+    /**
+     * Copy the NormalizerRegistry
+     */
+    NormalizerRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ObjectClassRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ObjectClassRegistry.java
new file mode 100644
index 0000000..d561c8e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/ObjectClassRegistry.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+
+
+/**
+ * ObjectClass registry service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ObjectClassRegistry extends SchemaObjectRegistry<ObjectClass>,
+    Iterable<ObjectClass>
+{
+    /**
+     * Quick lookup to see if an objectClass has descendants.
+     * 
+     * @param ancestorId the name alias or OID for an ObjectClass
+     * @return an Iterator over the ObjectClasses which have the ancestor
+     * within their superior chain to the top
+     * @throws LdapException if the ancestor ObjectClass cannot be 
+     * discerned from the ancestorId supplied
+     */
+    boolean hasDescendants( String ancestorId ) throws LdapException;
+
+
+    /**
+     * Get's an iterator over the set of descendant ObjectClasses for
+     * some ancestor's name alias or their OID.
+     * 
+     * @param ancestorId the name alias or OID for an ObjectClass
+     * @return an Iterator over the ObjectClasses which have the ancestor
+     * within their superior chain to the top
+     * @throws LdapException if the ancestor ObjectClass cannot be 
+     * discerned from the ancestorId supplied
+     */
+    Iterator<ObjectClass> descendants( String ancestorId ) throws LdapException;
+
+
+    /**
+     * Store the ObjectClass into a map associating an ObjectClass to its
+     * descendants.
+     * 
+     * @param objectClass The ObjectClass to register
+     * @param ancestors Its ancestors
+     * @throws LdapException If something went wrong
+     */
+    void registerDescendants( ObjectClass objectClass, List<ObjectClass> ancestors )
+        throws LdapException;
+
+
+    /**
+     * Remove the ObjectClass from the map associating an ObjectClass to its
+     * descendants.
+     * 
+     * @param attributeType The ObjectClass to unregister
+     * @param ancestors its ancestors 
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If something went wrong
+     */
+    void unregisterDescendants( ObjectClass attributeType, List<ObjectClass> ancestors )
+        throws LdapException;
+
+
+    /**
+     * Registers a new ObjectClass with this registry.
+     *
+     * @param objectClass the ObjectClass to register
+     * @throws LdapException if the ObjectClass is already registered or
+     * the registration operation is not supported
+     */
+    void register( ObjectClass objectClass ) throws LdapException;
+
+
+    /**
+     * Removes the ObjectClass registered with this registry.
+     * 
+     * @param numericOid the numeric identifier
+     * @throws LdapException if the numeric identifier is invalid
+     */
+    ObjectClass unregister( String numericOid ) throws LdapException;
+
+
+    /**
+     * Copy the ObjectClassRegistry
+     */
+    ObjectClassRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/OidRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/OidRegistry.java
new file mode 100644
index 0000000..b923139
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/OidRegistry.java
@@ -0,0 +1,378 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Object identifier registry. It stores the OIDs for AT, OC, MR, LS, MRU, DSR, DCR and NF.
+ * An OID is unique, and associated with a SO.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OidRegistry<T extends SchemaObject> implements Iterable<T>
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( OidRegistry.class );
+
+    /** Speedup for DEBUG mode */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** Maps OID to a type of SchemaObject */
+    private Map<String, T> byOid = new HashMap<String, T>();
+    
+    /** A flag indicating that the Registry is relaxed or not */
+    private boolean isRelaxed = Registries.STRICT;;
+
+
+    /**
+     * Tells if the given OID is present on this registry
+     * 
+     * @param oid The OID to lookup
+     * @return true if the OID already exists
+     */
+    public boolean contains( String oid )
+    {
+        return byOid.containsKey( oid );
+    }
+
+
+    /**
+     * Gets the primary name associated with an OID.  The primary name is the
+     * first name specified for the OID.
+     * 
+     * @param oid the object identifier
+     * @return the primary name
+     * @throws LdapException if oid does not exist
+     */
+    public String getPrimaryName( String oid ) throws LdapException
+    {
+        SchemaObject schemaObject = byOid.get( oid );
+
+        if ( schemaObject != null )
+        {
+            return schemaObject.getName();
+        }
+        else
+        {
+            String msg = I18n.err( I18n.ERR_04286, oid );
+            LOG.error( msg );
+            throw new LdapException( msg );
+        }
+    }
+
+
+    /**
+     * Gets the SchemaObject associated with an OID. 
+     * 
+     * @param oid the object identifier
+     * @return the associated SchemaObject
+     * @throws LdapException if oid does not exist
+     */
+    public T getSchemaObject( String oid ) throws LdapException
+    {
+        T schemaObject = byOid.get( oid );
+
+        if ( schemaObject != null )
+        {
+            return schemaObject;
+        }
+        else
+        {
+            String msg = I18n.err( I18n.ERR_04287, oid );
+            LOG.error( msg );
+            throw new LdapException( msg );
+        }
+    }
+
+
+    /**
+     * Gets the names associated with an OID.  An OID is unique however it may 
+     * have many names used to refer to it.  A good example is the cn and
+     * commonName attribute names for OID 2.5.4.3.  Within a server one name 
+     * within the set must be chosen as the primary name.  This is used to
+     * name certain things within the server internally.  If there is more than
+     * one name then the first name is taken to be the primary.
+     * 
+     * @param oid the OID for which we return the set of common names
+     * @return a sorted set of names
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException if oid does not exist
+     */
+    public List<String> getNameSet( String oid ) throws LdapException
+    {
+        SchemaObject schemaObject = byOid.get( oid );
+
+        if ( null == schemaObject )
+        {
+            String msg = I18n.err( I18n.ERR_04288, oid );
+            LOG.error( msg );
+            throw new LdapException( msg );
+        }
+
+        List<String> names = schemaObject.getNames();
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "looked up names '{}' for OID '{}'", ArrayUtils.toString( names ), oid );
+        }
+
+        return names;
+    }
+
+
+    /**
+     * Lists all the OIDs within the registry.  This may be a really big list.
+     * 
+     * @return all the OIDs registered
+     */
+    public Iterator<String> iteratorOids()
+    {
+        return Collections.unmodifiableSet( byOid.keySet() ).iterator();
+    }
+
+
+    /**
+     * Lists all the SchemaObjects within the registry.  This may be a really big list.
+     * 
+     * @return all the SchemaObject registered
+     */
+    public Iterator<T> iterator()
+    {
+        return byOid.values().iterator();
+    }
+
+    
+    /**
+     * Tells if the Registry is permissive or if it must be checked
+     * against inconsistencies.
+     *
+     * @return True if SchemaObjects can be added even if they break the consistency
+     */
+    public boolean isRelaxed()
+    {
+        return isRelaxed;
+    }
+
+
+    /**
+     * Tells if the Registry is strict.
+     *
+     * @return True if SchemaObjects cannot be added if they break the consistency
+     */
+    public boolean isStrict()
+    {
+        return !isRelaxed;
+    }
+
+
+    /**
+     * Change the Registry to a relaxed mode, where invalid SchemaObjects
+     * can be registered.
+     */
+    public void setRelaxed()
+    {
+        isRelaxed = Registries.RELAXED;
+    }
+
+
+    /**
+     * Change the Registry to a strict mode, where invalid SchemaObjects
+     * cannot be registered.
+     */
+    public void setStrict()
+    {
+        isRelaxed = Registries.STRICT;
+    }
+
+    /**
+     * Adds an OID name pair to the registry.
+     * 
+     * @param schemaObject The SchemaObject the oid belongs to
+     */
+    public void register( T schemaObject ) throws LdapException
+    {
+        if ( schemaObject == null )
+        {
+            String message = I18n.err( I18n.ERR_04289 );
+
+            LOG.debug( message );
+            throw new LdapException( message );
+        }
+
+        String oid = schemaObject.getOid();
+
+        if ( isStrict() )
+        {
+            if ( !Oid.isOid( oid ) )
+            {
+                String message = I18n.err( I18n.ERR_04290 );
+
+                LOG.debug( message );
+                throw new LdapException( message );
+            }
+        }
+        else
+        {
+            if ( ( oid == null ) || oid.isEmpty() )
+            {
+                throw new LdapException( I18n.err( I18n.ERR_00033_INVALID_OID, "" ) );
+            }
+        }
+
+        /*
+         * Update OID Map if it does not already exist
+         */
+        if ( byOid.containsKey( oid ) )
+        {
+            String message = I18n.err( I18n.ERR_04291, oid );
+            LOG.info( message );
+            return;
+        }
+        else
+        {
+            byOid.put( oid, schemaObject );
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( "registed SchemaObject '" + schemaObject + "' with OID: " + oid );
+            }
+        }
+    }
+
+
+    /**
+     * Store the given SchemaObject into the OidRegistry. Available only to 
+     * the current package. A weak form (no check is done) of the register 
+     * method, define for clone methods.
+     *
+     * @param schemaObject The SchemaObject to inject into the OidRegistry
+     */
+    /* No qualifier */void put( T schemaObject )
+    {
+        byOid.put( schemaObject.getOid(), schemaObject );
+    }
+
+
+    /**
+     * Removes an oid from this registry.
+     *
+     * @param oid the numeric identifier for the object
+     * @throws LdapException if the identifier is not numeric
+     */
+    public void unregister( String oid ) throws LdapException
+    {
+        // Removes the <OID, names> from the byOID map
+        SchemaObject removed = byOid.remove( oid );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Unregisted SchemaObject '{}' with OID: {}", removed, oid );
+        }
+    }
+
+
+    /**
+     * Copy the OidRegistry, without the contained values
+     * 
+     * @return A new OidRegistry instance
+     */
+    public OidRegistry<T> copy()
+    {
+        OidRegistry<T> copy = new OidRegistry<T>();
+
+        // Clone the map
+        copy.byOid = new HashMap<String, T>();
+
+        return copy;
+    }
+
+
+    /**
+     * @return The number of stored OIDs
+     */
+    public int size()
+    {
+        return byOid.size();
+    }
+
+
+    public void clear()
+    {
+        // remove all the OID
+        byOid.clear();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        if ( byOid != null )
+        {
+            boolean isFirst = true;
+
+            for ( Map.Entry<String, T> entry : byOid.entrySet() )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( ", " );
+                }
+
+                sb.append( "<" );
+
+                SchemaObject schemaObject = entry.getValue();
+
+                if ( schemaObject != null )
+                {
+                    sb.append( schemaObject.getObjectType() );
+                    sb.append( ", " );
+                    sb.append( schemaObject.getOid() );
+                    sb.append( ", " );
+                    sb.append( schemaObject.getName() );
+                }
+
+                sb.append( ">" );
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/Registries.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/Registries.java
new file mode 100644
index 0000000..87db8aa
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/Registries.java
@@ -0,0 +1,2909 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.NameForm;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.registries.helper.AttributeTypeHelper;
+import org.apache.directory.api.ldap.model.schema.registries.helper.DitContentRuleHelper;
+import org.apache.directory.api.ldap.model.schema.registries.helper.DitStructureRuleHelper;
+import org.apache.directory.api.ldap.model.schema.registries.helper.LdapSyntaxHelper;
+import org.apache.directory.api.ldap.model.schema.registries.helper.MatchingRuleHelper;
+import org.apache.directory.api.ldap.model.schema.registries.helper.MatchingRuleUseHelper;
+import org.apache.directory.api.ldap.model.schema.registries.helper.NameFormHelper;
+import org.apache.directory.api.ldap.model.schema.registries.helper.ObjectClassHelper;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Document this class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Registries implements SchemaLoaderListener, Cloneable
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( Registries.class );
+
+    /**
+     * A String name to Schema object map for the schemas loaded into this
+     * registry. The loaded schemas may be disabled.
+     */
+    protected Map<String, Schema> loadedSchemas = new HashMap<String, Schema>();
+
+    /** The AttributeType registry */
+    protected DefaultAttributeTypeRegistry attributeTypeRegistry;
+
+    /** The ObjectClass registry */
+    protected DefaultObjectClassRegistry objectClassRegistry;
+
+    /** The LdapSyntax registry */
+    protected DefaultComparatorRegistry comparatorRegistry;
+
+    /** The DitContentRule registry */
+    protected DefaultDitContentRuleRegistry ditContentRuleRegistry;
+
+    /** The DitStructureRule registry */
+    protected DefaultDitStructureRuleRegistry ditStructureRuleRegistry;
+
+    /** The MatchingRule registry */
+    protected DefaultMatchingRuleRegistry matchingRuleRegistry;
+
+    /** The MatchingRuleUse registry */
+    protected DefaultMatchingRuleUseRegistry matchingRuleUseRegistry;
+
+    /** The NameForm registry */
+    protected DefaultNameFormRegistry nameFormRegistry;
+
+    /** The Normalizer registry */
+    protected DefaultNormalizerRegistry normalizerRegistry;
+
+    /** The global OID registry */
+    protected OidRegistry<SchemaObject> globalOidRegistry;
+
+    /** The SyntaxChecker registry */
+    protected DefaultSyntaxCheckerRegistry syntaxCheckerRegistry;
+
+    /** The LdapSyntax registry */
+    protected DefaultLdapSyntaxRegistry ldapSyntaxRegistry;
+
+    /** A map storing all the schema objects associated with a schema */
+    private Map<String, Set<SchemaObjectWrapper>> schemaObjects;
+
+    /** A flag indicating that the Registries is relaxed or not */
+    private boolean isRelaxed;
+
+    /** A flag indicating that disabled SchemaObject are accepted */
+    private boolean disabledAccepted;
+
+    /** Two flags for RELAXED and STRUCT */
+    public static final boolean STRICT = false;
+    public static final boolean RELAXED = true;
+
+    /**
+     *  A map storing a relation between a SchemaObject and all the
+     *  referencing SchemaObjects.
+     */
+    protected Map<SchemaObjectWrapper, Set<SchemaObjectWrapper>> usedBy;
+
+    /**
+     *  A map storing a relation between a SchemaObject and all the
+     *  SchemaObjects it uses.
+     */
+    protected Map<SchemaObjectWrapper, Set<SchemaObjectWrapper>> using;
+
+
+    /**
+     * Creates a new instance of Registries.
+     */
+    public Registries()
+    {
+        globalOidRegistry = new OidRegistry<SchemaObject>();
+        attributeTypeRegistry = new DefaultAttributeTypeRegistry();
+        comparatorRegistry = new DefaultComparatorRegistry();
+        ditContentRuleRegistry = new DefaultDitContentRuleRegistry();
+        ditStructureRuleRegistry = new DefaultDitStructureRuleRegistry();
+        ldapSyntaxRegistry = new DefaultLdapSyntaxRegistry();
+        matchingRuleRegistry = new DefaultMatchingRuleRegistry();
+        matchingRuleUseRegistry = new DefaultMatchingRuleUseRegistry();
+        nameFormRegistry = new DefaultNameFormRegistry();
+        normalizerRegistry = new DefaultNormalizerRegistry();
+        objectClassRegistry = new DefaultObjectClassRegistry();
+        syntaxCheckerRegistry = new DefaultSyntaxCheckerRegistry();
+        schemaObjects = new HashMap<String, Set<SchemaObjectWrapper>>();
+        usedBy = new HashMap<SchemaObjectWrapper, Set<SchemaObjectWrapper>>();
+        using = new HashMap<SchemaObjectWrapper, Set<SchemaObjectWrapper>>();
+
+        isRelaxed = STRICT;
+        disabledAccepted = false;
+    }
+
+
+    /**
+     * @return The AttributeType registry
+     */
+    public AttributeTypeRegistry getAttributeTypeRegistry()
+    {
+        return attributeTypeRegistry;
+    }
+
+
+    /**
+     * @return The Comparator registry
+     */
+    public ComparatorRegistry getComparatorRegistry()
+    {
+        return comparatorRegistry;
+    }
+
+
+    /**
+     * @return The DitContentRule registry
+     */
+    public DitContentRuleRegistry getDitContentRuleRegistry()
+    {
+        return ditContentRuleRegistry;
+    }
+
+
+    /**
+     * @return The DitStructureRule registry
+     */
+    public DitStructureRuleRegistry getDitStructureRuleRegistry()
+    {
+        return ditStructureRuleRegistry;
+    }
+
+
+    /**
+     * @return The MatchingRule registry
+     */
+    public MatchingRuleRegistry getMatchingRuleRegistry()
+    {
+        return matchingRuleRegistry;
+    }
+
+
+    /**
+     * @return The MatchingRuleUse registry
+     */
+    public MatchingRuleUseRegistry getMatchingRuleUseRegistry()
+    {
+        return matchingRuleUseRegistry;
+    }
+
+
+    /**
+     * @return The NameForm registry
+     */
+    public NameFormRegistry getNameFormRegistry()
+    {
+        return nameFormRegistry;
+    }
+
+
+    /**
+     * @return The Normalizer registry
+     */
+    public NormalizerRegistry getNormalizerRegistry()
+    {
+        return normalizerRegistry;
+    }
+
+
+    /**
+     * @return The ObjectClass registry
+     */
+    public ObjectClassRegistry getObjectClassRegistry()
+    {
+        return objectClassRegistry;
+    }
+
+
+    /**
+     * @return The global Oid registry
+     */
+    public OidRegistry<SchemaObject> getGlobalOidRegistry()
+    {
+        return globalOidRegistry;
+    }
+
+
+    /**
+     * @return The SyntaxChecker registry
+     */
+    public SyntaxCheckerRegistry getSyntaxCheckerRegistry()
+    {
+        return syntaxCheckerRegistry;
+    }
+
+
+    /**
+     * @return The LdapSyntax registry
+     */
+    public LdapSyntaxRegistry getLdapSyntaxRegistry()
+    {
+        return ldapSyntaxRegistry;
+    }
+
+
+    /**
+     * Get an OID from a name. As we have many possible registries, we
+     * have to look in all of them to get the one containing the OID.
+     *
+     * @param name The name we are looking at
+     * @return The associated OID
+     */
+    public String getOid( String name )
+    {
+        // we have many possible Registries to look at.
+        // AttributeType
+        try
+        {
+            AttributeType attributeType = attributeTypeRegistry.lookup( name );
+
+            if ( attributeType != null )
+            {
+                return attributeType.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Fall down to the next registry
+        }
+
+        // ObjectClass
+        try
+        {
+            ObjectClass objectClass = objectClassRegistry.lookup( name );
+
+            if ( objectClass != null )
+            {
+                return objectClass.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Fall down to the next registry
+        }
+
+        // LdapSyntax
+        try
+        {
+            LdapSyntax ldapSyntax = ldapSyntaxRegistry.lookup( name );
+
+            if ( ldapSyntax != null )
+            {
+                return ldapSyntax.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Fall down to the next registry
+        }
+
+        // MatchingRule
+        try
+        {
+            MatchingRule matchingRule = matchingRuleRegistry.lookup( name );
+
+            if ( matchingRule != null )
+            {
+                return matchingRule.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Fall down to the next registry
+        }
+
+        // MatchingRuleUse
+        try
+        {
+            MatchingRuleUse matchingRuleUse = matchingRuleUseRegistry.lookup( name );
+
+            if ( matchingRuleUse != null )
+            {
+                return matchingRuleUse.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Fall down to the next registry
+        }
+
+        // NameForm
+        try
+        {
+            NameForm nameForm = nameFormRegistry.lookup( name );
+
+            if ( nameForm != null )
+            {
+                return nameForm.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Fall down to the next registry
+        }
+
+        // DitContentRule
+        try
+        {
+            DitContentRule ditContentRule = ditContentRuleRegistry.lookup( name );
+
+            if ( ditContentRule != null )
+            {
+                return ditContentRule.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Fall down to the next registry
+        }
+
+        // DitStructureRule
+        try
+        {
+            DitStructureRule ditStructureRule = ditStructureRuleRegistry.lookup( name );
+
+            if ( ditStructureRule != null )
+            {
+                return ditStructureRule.getOid();
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // No more registries to look at...
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Gets a schema that has been loaded into these Registries.
+     * 
+     * @param schemaName the name of the schema to lookup
+     * @return the loaded Schema if one corresponding to the name exists
+     */
+    public Schema getLoadedSchema( String schemaName )
+    {
+        return loadedSchemas.get( Strings.toLowerCase( schemaName ) );
+    }
+
+
+    /**
+     * Checks to see if a particular Schema is loaded.
+     *
+     * @param schemaName the name of the Schema to check
+     * @return true if the Schema is loaded, false otherwise
+     */
+    public boolean isSchemaLoaded( String schemaName )
+    {
+        return loadedSchemas.containsKey( Strings.toLowerCase( schemaName ) );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Code used to sanity check the resolution of entities in registries
+    // ------------------------------------------------------------------------
+    /**
+     * Attempts to resolve the dependent schema objects of all entities that
+     * refer to other objects within the registries.  Null references will be
+     * handed appropriately.
+     * The order in which the SchemaObjects must be :
+     * <li/>1) Normalizers, Comparators and SyntaxCheckers (as they depend on nothing)
+     * <li/>2) Syntaxes (depend on SyntaxCheckers)
+     * <li/>3) MatchingRules (depend on Syntaxes, Normalizers and Comparators
+     * <li/>4) AttributeTypes (depend on MatchingRules, Syntaxes and AttributeTypes : in this case, we first handle the superior)
+     * <li/>5) ObjectClasses (depend on AttributeTypes and ObjectClasses)
+     * <br/><br/>
+     * Later, when we will support them :
+     * <li/>6) MatchingRuleUses (depend on matchingRules and AttributeTypes)
+     * <li/>7) DitContentRules (depend on ObjectClasses and AttributeTypes)
+     * <li/>8) NameForms (depends on ObjectClasses and AttributeTypes)
+     * <li/>9) DitStructureRules (depends onNameForms and DitStructureRules)      *
+     *
+     * @return a list of exceptions encountered while resolving entities
+     */
+    public List<Throwable> checkRefInteg()
+    {
+        ArrayList<Throwable> errors = new ArrayList<Throwable>();
+
+        // Step 1 :
+        // We start with Normalizers, Comparators and SyntaxCheckers
+        // as they depend on nothing
+        // Check the Normalizers
+        for ( Normalizer normalizer : normalizerRegistry )
+        {
+            resolve( normalizer, errors );
+        }
+
+        // Check the Comparators
+        for ( LdapComparator<?> comparator : comparatorRegistry )
+        {
+            resolve( comparator, errors );
+        }
+
+        // Check the SyntaxCheckers
+        for ( SyntaxChecker syntaxChecker : syntaxCheckerRegistry )
+        {
+            resolve( syntaxChecker, errors );
+        }
+
+        // Step 2 :
+        // Check the LdapSyntaxes
+        for ( LdapSyntax ldapSyntax : ldapSyntaxRegistry )
+        {
+            resolve( ldapSyntax, errors );
+        }
+
+        // Step 3 :
+        // Check the matchingRules
+        for ( MatchingRule matchingRule : matchingRuleRegistry )
+        {
+            resolve( matchingRule, errors );
+        }
+
+        // Step 4 :
+        // Check the AttributeTypes
+        for ( AttributeType attributeType : attributeTypeRegistry )
+        {
+            resolve( attributeType, errors );
+        }
+
+        //  Step 5 :
+        // Check the ObjectClasses
+        for ( ObjectClass objectClass : objectClassRegistry )
+        {
+            resolve( objectClass, errors );
+        }
+
+        // Step 6-9 aren't yet defined
+        return errors;
+    }
+
+
+    /**
+     * Add the SchemaObjectReferences. This method does nothing, it's just
+     * a catch all. The other methods will be called for each specific
+     * schemaObject
+     *
+    public void addCrossReferences( SchemaObject schemaObject )
+    {
+        // Do nothing : it's a catch all method.
+    }
+    
+    
+    /**
+     * Delete the AT references (using and usedBy) :
+     * AT -> MR (for EQUALITY, ORDERING and SUBSTR)
+     * AT -> S
+     * AT -> AT
+     */
+    public void delCrossReferences( AttributeType attributeType )
+    {
+        if ( attributeType.getEquality() != null )
+        {
+            delReference( attributeType, attributeType.getEquality() );
+        }
+
+        if ( attributeType.getOrdering() != null )
+        {
+            delReference( attributeType, attributeType.getOrdering() );
+        }
+
+        if ( attributeType.getSubstring() != null )
+        {
+            delReference( attributeType, attributeType.getSubstring() );
+        }
+
+        if ( attributeType.getSyntax() != null )
+        {
+            delReference( attributeType, attributeType.getSyntax() );
+        }
+
+        if ( attributeType.getSuperior() != null )
+        {
+            delReference( attributeType, attributeType.getSuperior() );
+        }
+    }
+
+
+    /**
+     * Build the AttributeType references. This has to be done recursively, as
+     * an AttributeType may inherit its parent's MatchingRules. The references
+     * to update are :
+     * - EQUALITY MR
+     * - ORDERING MR
+     * - SUBSTRING MR
+     * - SUP AT
+     * - SYNTAX
+     */
+    private void buildAttributeTypeReferences( List<Throwable> errors )
+    {
+        for ( AttributeType attributeType : attributeTypeRegistry )
+        {
+            if ( ( getUsing( attributeType ) == null ) || getUsing( attributeType ).isEmpty() )
+            {
+                buildReference( errors, attributeType );
+            }
+        }
+    }
+
+
+    /**
+     * Build the Comparator references
+     */
+    private void buildComparatorReferences( List<Throwable> errors )
+    {
+        for ( LdapComparator<?> comparator : comparatorRegistry )
+        {
+            buildReference( errors, comparator );
+        }
+    }
+
+
+    /**
+     * Build the DitContentRule references
+     */
+    private void buildDitContentRuleReferences( List<Throwable> errors )
+    {
+        // TODO: implement
+    }
+
+
+    /**
+     * Build the DitStructureRule references
+     */
+    private void buildDitStructureRuleReferences( List<Throwable> errors )
+    {
+        // TODO: implement
+    }
+
+
+    /**
+     * Delete the MR references (using and usedBy) :
+     * MR -> C
+     * MR -> N
+     * MR -> S
+     */
+    public void delCrossReferences( MatchingRule matchingRule )
+    {
+        if ( matchingRule.getLdapComparator() != null )
+        {
+            delReference( matchingRule, matchingRule.getLdapComparator() );
+        }
+
+        if ( matchingRule.getNormalizer() != null )
+        {
+            delReference( matchingRule, matchingRule.getNormalizer() );
+        }
+
+        if ( matchingRule.getSyntax() != null )
+        {
+            delReference( matchingRule, matchingRule.getSyntax() );
+        }
+    }
+
+
+    /**
+     * Build the SchemaObject references
+     */
+    public void buildReference( List<Throwable> errors, SchemaObject schemaObject )
+    {
+        try
+        {
+            switch ( schemaObject.getObjectType() )
+            {
+                case ATTRIBUTE_TYPE:
+                    AttributeTypeHelper.addToRegistries( ( MutableAttributeType ) schemaObject, errors, this );
+                    break;
+
+                case DIT_CONTENT_RULE:
+                    DitContentRuleHelper.addToRegistries( ( DitContentRule ) schemaObject, errors, this );
+                    break;
+
+                case DIT_STRUCTURE_RULE:
+                    DitStructureRuleHelper.addToRegistries( ( DitStructureRule ) schemaObject, errors, this );
+                    break;
+
+                case LDAP_SYNTAX:
+                    LdapSyntaxHelper.addToRegistries( ( LdapSyntax ) schemaObject, errors, this );
+                    break;
+
+                case MATCHING_RULE:
+                    MatchingRuleHelper.addToRegistries( ( MutableMatchingRule ) schemaObject, errors, this );
+                    break;
+
+                case MATCHING_RULE_USE:
+                    MatchingRuleUseHelper.addToRegistries( ( MatchingRuleUse ) schemaObject, errors, this );
+                    break;
+
+                case NAME_FORM:
+                    NameFormHelper.addToRegistries( ( NameForm ) schemaObject, errors, this );
+                    break;
+
+                case OBJECT_CLASS:
+                    ObjectClassHelper.addToRegistries( ( ObjectClass ) schemaObject, errors, this );
+                    break;
+
+                case SYNTAX_CHECKER:
+                case NORMALIZER:
+                case COMPARATOR:
+                    // Those are not registered
+                    break;
+
+                default:
+                    throw new IllegalArgumentException( "Unexpected SchemaObjectType: " + schemaObject.getObjectType() );
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Not allowed.
+            String msg = I18n.err( I18n.ERR_04292, schemaObject.getName(), ne.getLocalizedMessage() );
+
+            Throwable error = new LdapProtocolErrorException( msg, ne );
+            errors.add( error );
+            LOG.info( msg );
+        }
+    }
+
+
+    /**
+     * Unlink the SchemaObject references
+     */
+    public void removeReference( List<Throwable> errors, SchemaObject schemaObject )
+    {
+        try
+        {
+            switch ( schemaObject.getObjectType() )
+            {
+                case ATTRIBUTE_TYPE:
+                    AttributeTypeHelper.removeFromRegistries( ( AttributeType ) schemaObject, errors, this );
+                    break;
+
+                case LDAP_SYNTAX:
+                    LdapSyntaxHelper.removeFromRegistries( ( LdapSyntax ) schemaObject, errors, this );
+                    break;
+
+                case MATCHING_RULE:
+                    MatchingRuleHelper.removeFromRegistries( ( MatchingRule ) schemaObject, errors, this );
+                    break;
+
+                case OBJECT_CLASS:
+                    ObjectClassHelper.removeFromRegistries( ( ObjectClass ) schemaObject, errors, this );
+                    break;
+                    
+                case DIT_CONTENT_RULE :
+                    // TODO
+                    break;
+                    
+                case DIT_STRUCTURE_RULE :
+                    // TODO
+                    break;
+                    
+                case NAME_FORM :
+                    // TODO
+                    break;
+                    
+                case MATCHING_RULE_USE :
+                    // TODO
+                    break;
+
+                case SYNTAX_CHECKER:
+                case NORMALIZER:
+                case COMPARATOR:
+                    // Those were not registered
+                    break;
+
+                default:
+                    throw new IllegalArgumentException( "Unexpected SchemaObjectType: " + schemaObject.getObjectType() );
+            }
+        }
+        catch ( LdapException ne )
+        {
+            // Not allowed.
+            String msg = I18n.err( I18n.ERR_04293, schemaObject.getName(), ne.getLocalizedMessage() );
+
+            Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg, ne );
+            errors.add( error );
+            LOG.info( msg );
+        }
+    }
+
+
+    /**
+     * Build the MatchingRule references
+     */
+    private void buildMatchingRuleReferences( List<Throwable> errors )
+    {
+        for ( MatchingRule matchingRule : matchingRuleRegistry )
+        {
+            buildReference( errors, matchingRule );
+        }
+    }
+
+
+    /**
+     * Build the MatchingRuleUse references
+     */
+    private void buildMatchingRuleUseReferences( List<Throwable> errors )
+    {
+        for ( MatchingRuleUse matchingRuleUse : matchingRuleUseRegistry )
+        {
+            buildReference( errors, matchingRuleUse );
+        }
+    }
+
+
+    /**
+     * Build the NameForm references
+     */
+    private void buildNameFormReferences( List<Throwable> errors )
+    {
+        // TODO: implement
+    }
+
+
+    /**
+     * Build the Normalizer references
+     */
+    private void buildNormalizerReferences( List<Throwable> errors )
+    {
+        for ( Normalizer normalizer : normalizerRegistry )
+        {
+            buildReference( errors, normalizer );
+        }
+    }
+
+
+    /**
+     * Build the ObjectClasses references
+     */
+    private void buildObjectClassReferences( List<Throwable> errors )
+    {
+        // Remember the OC we have already processed
+        Set<String> done = new HashSet<String>();
+
+        // The ObjectClass
+        for ( ObjectClass objectClass : objectClassRegistry )
+        {
+            if ( done.contains( objectClass.getOid() ) )
+            {
+                continue;
+            }
+            else
+            {
+                done.add( objectClass.getOid() );
+            }
+
+            buildReference( errors, objectClass );
+        }
+    }
+
+
+    /**
+     * Build the Syntax references
+     */
+    private void buildLdapSyntaxReferences( List<Throwable> errors )
+    {
+        for ( LdapSyntax syntax : ldapSyntaxRegistry )
+        {
+            buildReference( errors, syntax );
+        }
+    }
+
+
+    /**
+     * Build the SyntaxChecker references
+     */
+    private void buildSyntaxCheckerReferences( List<Throwable> errors )
+    {
+        for ( SyntaxChecker syntaxChecker : syntaxCheckerRegistry )
+        {
+            buildReference( errors, syntaxChecker );
+        }
+    }
+
+
+    /**
+     * Build the usedBy and using references from the stored elements.
+     * 
+     * @return A list of all the errors we met during the cross reference update
+     */
+    public List<Throwable> buildReferences()
+    {
+        List<Throwable> errors = new ArrayList<Throwable>();
+
+        // The Comparator references
+        buildComparatorReferences( errors );
+
+        // The Normalizer references
+        buildNormalizerReferences( errors );
+
+        // The SyntaxChecker references
+        buildSyntaxCheckerReferences( errors );
+
+        // The Syntax references
+        buildLdapSyntaxReferences( errors );
+
+        // The MatchingRules references
+        buildMatchingRuleReferences( errors );
+
+        // The AttributeType references
+        buildAttributeTypeReferences( errors );
+
+        // The MatchingRuleUse references
+        buildMatchingRuleUseReferences( errors );
+
+        // The ObjectClasses references
+        buildObjectClassReferences( errors );
+
+        // The DitContentRules references
+        buildDitContentRuleReferences( errors );
+
+        // The NameForms references
+        buildNameFormReferences( errors );
+
+        // The DitStructureRules references
+        buildDitStructureRuleReferences( errors );
+
+        return errors;
+    }
+
+
+    /**
+     * Attempts to resolve the SyntaxChecker associated with a Syntax.
+     *
+     * @param syntax the LdapSyntax to resolve the SyntaxChecker of
+     * @param errors the list of errors to add exceptions to
+     */
+    private void resolve( LdapSyntax syntax, List<Throwable> errors )
+    {
+        // A LdapSyntax must point to a valid SyntaxChecker
+        // or to the OctetString SyntaxChecker
+        try
+        {
+            LdapSyntaxHelper.addToRegistries( syntax, errors, this );
+        }
+        catch ( LdapException e )
+        {
+            errors.add( e );
+        }
+    }
+
+
+    /**
+     * Attempts to resolve the Normalizer
+     *
+     * @param normalizer the Normalizer
+     * @param errors the list of errors to add exceptions to
+     */
+    private void resolve( Normalizer normalizer, List<Throwable> errors )
+    {
+        // This is currently doing nothing.
+    }
+
+
+    /**
+     * Attempts to resolve the LdapComparator
+     *
+     * @param comparator the LdapComparator
+     * @param errors the list of errors to add exceptions to
+     */
+    private void resolve( LdapComparator<?> comparator, List<Throwable> errors )
+    {
+        // This is currently doing nothing.
+    }
+
+
+    /**
+     * Attempts to resolve the SyntaxChecker
+     *
+     * @param normalizer the SyntaxChecker
+     * @param errors the list of errors to add exceptions to
+     */
+    private void resolve( SyntaxChecker syntaxChecker, List<Throwable> errors )
+    {
+        // This is currently doing nothing.
+    }
+
+
+    /**
+     * Check if the Comparator, Normalizer and the syntax are
+     * existing for a matchingRule.
+     */
+    private void resolve( MatchingRule matchingRule, List<Throwable> errors )
+    {
+        // Process the Syntax. It can't be null
+        String syntaxOid = matchingRule.getSyntaxOid();
+
+        if ( syntaxOid != null )
+        {
+            // Check if the Syntax is present in the registries
+            try
+            {
+                ldapSyntaxRegistry.lookup( syntaxOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This MR's syntax has not been loaded into the Registries.
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_04294, matchingRule.getOid() ),
+                    ne );
+                ldapSchemaException.setSourceObject( matchingRule );
+                errors.add( ldapSchemaException );
+            }
+        }
+        else
+        {
+            // This is an error.
+            LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_04294, matchingRule.getOid() ) );
+            ldapSchemaException.setSourceObject( matchingRule );
+            errors.add( ldapSchemaException );
+        }
+
+        // Process the Normalizer
+        Normalizer normalizer = matchingRule.getNormalizer();
+
+        if ( normalizer == null )
+        {
+            // Ok, no normalizer, this is an error
+            Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04295, matchingRule.getOid() ) );
+            errors.add( error );
+        }
+
+        // Process the Comparator
+        LdapComparator<?> comparator = matchingRule.getLdapComparator();
+
+        if ( comparator == null )
+        {
+            // Ok, no comparator, this is an error
+            Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                I18n.ERR_04296, matchingRule.getOid() ) );
+            errors.add( error );
+        }
+    }
+
+
+    /**
+     * Check AttributeType referential integrity
+     */
+    private void resolveRecursive( AttributeType attributeType, Set<String> processed, List<Throwable> errors )
+    {
+        // Process the Superior, if any
+        String superiorOid = attributeType.getSuperiorOid();
+
+        AttributeType superior = null;
+
+        if ( superiorOid != null )
+        {
+            // Check if the Superior is present in the registries
+            try
+            {
+                superior = attributeTypeRegistry.lookup( superiorOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This AT's superior has not been loaded into the Registries.
+                if ( !processed.contains( superiorOid ) )
+                {
+                    errors.add( ne );
+                }
+            }
+
+            // We now have to process the superior, if it hasn't been
+            // processed yet.
+            if ( superior != null )
+            {
+                if ( !processed.contains( superiorOid ) )
+                {
+                    resolveRecursive( superior, processed, errors );
+                    processed.add( attributeType.getOid() );
+                }
+                else
+                {
+                    // Not allowed : we have a cyle
+                    Throwable error = new LdapSchemaViolationException( ResultCodeEnum.OTHER, I18n.err( I18n.ERR_04297,
+                        attributeType.getOid() ) );
+                    errors.add( error );
+                    return;
+                }
+            }
+        }
+
+        // Process the Syntax. If it's null, the attributeType must have
+        // a Superior.
+        String syntaxOid = attributeType.getSyntaxOid();
+
+        if ( syntaxOid != null )
+        {
+            // Check if the Syntax is present in the registries
+            try
+            {
+                ldapSyntaxRegistry.lookup( syntaxOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This AT's syntax has not been loaded into the Registries.
+                errors.add( ne );
+            }
+        }
+        else
+        {
+            // No Syntax : get it from the AttributeType's superior
+            if ( superior == null )
+            {
+                // This is an error. if the AT does not have a Syntax,
+                // then it must have a superior, which syntax is get from.
+                Throwable error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
+                    I18n.ERR_04298, attributeType.getOid() ) );
+                errors.add( error );
+            }
+        }
+
+        // Process the EQUALITY MatchingRule. It may be null, but if it's not
+        // it must have been processed before
+        String equalityOid = attributeType.getEqualityOid();
+
+        if ( equalityOid != null )
+        {
+            // Check if the MatchingRule is present in the registries
+            try
+            {
+                matchingRuleRegistry.lookup( equalityOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This AT's EQUALITY matchingRule has not been loaded into the Registries.
+                errors.add( ne );
+            }
+        }
+
+        // Process the ORDERING MatchingRule. It may be null, but if it's not
+        // it must have been processed before
+        String orderingOid = attributeType.getOrderingOid();
+
+        if ( orderingOid != null )
+        {
+            // Check if the MatchingRule is present in the registries
+            try
+            {
+                matchingRuleRegistry.lookup( orderingOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This AT's ORDERING matchingRule has not been loaded into the Registries.
+                errors.add( ne );
+            }
+        }
+
+        // Process the SUBSTR MatchingRule. It may be null, but if it's not
+        // it must have been processed before
+        String substringOid = attributeType.getSubstringOid();
+
+        if ( substringOid != null )
+        {
+            // Check if the MatchingRule is present in the registries
+            try
+            {
+                matchingRuleRegistry.lookup( substringOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This AT's SUBSTR matchingRule has not been loaded into the Registries.
+                errors.add( ne );
+            }
+        }
+    }
+
+
+    /**
+     * Check the inheritance, and the existence of MatchingRules and LdapSyntax
+     * for an attribute
+     */
+    private void resolve( AttributeType attributeType, List<Throwable> errors )
+    {
+        // This set is used to avoid having more than one error
+        // for an AttributeType. It's mandatory when processing
+        // a Superior, as it may be broken and referenced more than once.
+        Set<String> processed = new HashSet<String>();
+
+        // Store the AttributeType itself in the processed, to avoid cycle
+        processed.add( attributeType.getOid() );
+
+        // Call the recursive method, as we may have superiors to deal with
+        resolveRecursive( attributeType, processed, errors );
+    }
+
+
+    private List<AttributeType> getMustRecursive( List<AttributeType> musts, Set<ObjectClass> processed,
+        ObjectClass objectClass )
+    {
+        if ( objectClass != null )
+        {
+            if ( processed.contains( objectClass ) )
+            {
+                // We have found a cycle. It has already been reported,
+                // don't add a new error, just exit.
+                return null;
+            }
+
+            processed.add( objectClass );
+
+            for ( AttributeType must : objectClass.getMustAttributeTypes() )
+            {
+                musts.add( must );
+            }
+
+            for ( ObjectClass superior : objectClass.getSuperiors() )
+            {
+                getMustRecursive( musts, processed, superior );
+            }
+        }
+
+        return musts;
+    }
+
+
+    private void resolve( ObjectClass objectClass, List<Throwable> errors )
+    {
+        // This set is used to avoid having more than one error
+        // for an ObjectClass. It's mandatory when processing
+        // the Superiors, as they may be broken and referenced more than once.
+        Set<String> processed = new HashSet<String>();
+
+        // Store the ObjectClass itself in the processed, to avoid cycle
+        processed.add( objectClass.getOid() );
+
+        // Call the recursive method, as we may have superiors to deal with
+        resolveRecursive( objectClass, processed, errors );
+
+        // Check that the MAY and MUST AT are consistent (no AT in MAY and in MUST
+        // in one of its superior
+        List<AttributeType> musts = getMustRecursive( new ArrayList<AttributeType>(), new HashSet<ObjectClass>(),
+            objectClass );
+
+        if ( musts != null )
+        {
+            for ( AttributeType may : objectClass.getMayAttributeTypes() )
+            {
+                if ( musts.contains( may ) )
+                {
+                    // This is not allowed.
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY_AND_MUST );
+                    ldapSchemaException.setSourceObject( objectClass );
+                    ldapSchemaException.setOtherObject( may );
+                    errors.add( ldapSchemaException );
+                }
+            }
+        }
+    }
+
+
+    private void resolveRecursive( ObjectClass objectClass, Set<String> processed, List<Throwable> errors )
+    {
+        // Process the Superiors, if any
+        List<String> superiorOids = objectClass.getSuperiorOids();
+        ObjectClass superior = null;
+
+        for ( String superiorOid : superiorOids )
+        {
+            // Check if the Superior is present in the registries
+            try
+            {
+                superior = objectClassRegistry.lookup( superiorOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This OC's superior has not been loaded into the Registries.
+                if ( !processed.contains( superiorOid ) )
+                {
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.OC_NONEXISTENT_SUPERIOR, ne );
+                    ldapSchemaException.setSourceObject( objectClass );
+                    ldapSchemaException.setRelatedId( superiorOid );
+                    errors.add( ldapSchemaException );
+                }
+            }
+
+            // We now have to process the superior, if it hasn't been
+            // processed yet.
+            if ( superior != null )
+            {
+                if ( !processed.contains( superior.getOid() ) )
+                {
+                    resolveRecursive( superior, processed, errors );
+                    processed.add( objectClass.getOid() );
+                }
+                else
+                {
+                    // Not allowed : we have a cyle
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.OC_CYCLE_CLASS_HIERARCHY );
+                    ldapSchemaException.setSourceObject( objectClass );
+                    ldapSchemaException.setOtherObject( superior );
+                    errors.add( ldapSchemaException );
+                    return;
+                }
+            }
+        }
+
+        // Process the MAY attributeTypes.
+        for ( String mayOid : objectClass.getMayAttributeTypeOids() )
+        {
+            // Check if the MAY AttributeType is present in the registries
+            try
+            {
+                attributeTypeRegistry.lookup( mayOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This AT has not been loaded into the Registries.
+                errors.add( ne );
+            }
+        }
+
+        // Process the MUST attributeTypes.
+        for ( String mustOid : objectClass.getMustAttributeTypeOids() )
+        {
+            // Check if the MUST AttributeType is present in the registries
+            try
+            {
+                attributeTypeRegistry.lookup( mustOid );
+            }
+            catch ( LdapException ne )
+            {
+                // This AT has not been loaded into the Registries.
+                errors.add( ne );
+            }
+        }
+
+        // All is done for this ObjectClass, let's apply the registries
+        try
+        {
+            ObjectClassHelper.addToRegistries( objectClass, errors, this );
+        }
+        catch ( LdapException ne )
+        {
+            // Do nothing. We may have a broken OC,
+            // but at this point, it doesn't matter.
+        }
+    }
+
+
+    /**
+     * Applies the added SchemaObject to the given register
+     */
+    public List<Throwable> add( List<Throwable> errors, SchemaObject schemaObject, boolean check ) throws LdapException
+    {
+        // Relax the registries
+        boolean wasRelaxed = isRelaxed;
+        setRelaxed();
+
+        // Register the SchemaObject in the registries
+        register( errors, schemaObject );
+
+        // Associate the SchemaObject with its schema
+        associateWithSchema( errors, schemaObject );
+
+        // Build the SchemaObject references
+        if ( check )
+        {
+            buildReference( errors, schemaObject );
+        }
+
+        // Lock the SchemaObject
+        schemaObject.lock();
+
+        if ( check && ( errors.isEmpty() ) )
+        {
+            // Check the registries now
+            List<Throwable> checkErrors = checkRefInteg();
+
+            errors.addAll( checkErrors );
+        }
+
+        // Get back to Strict mode
+        if ( !wasRelaxed )
+        {
+            setStrict();
+        }
+
+        // return the errors
+        return errors;
+    }
+
+
+    /**
+     * Remove the given SchemaObject from the registries
+     */
+    public List<Throwable> delete( List<Throwable> errors, SchemaObject schemaObject ) throws LdapException
+    {
+        // Relax the registries
+        boolean wasRelaxed = isRelaxed;
+        setRelaxed();
+
+        // Remove the SchemaObject from the registries
+        SchemaObject removed = unregister( errors, schemaObject );
+
+        // Remove the SchemaObject from its schema
+        dissociateFromSchema( errors, removed );
+
+        // Unlink the SchemaObject references
+        removeReference( errors, removed );
+
+        if ( errors.isEmpty() )
+        {
+            // Check the registries now
+            List<Throwable> checkErrors = checkRefInteg();
+
+            errors.addAll( checkErrors );
+        }
+
+        // Restore the previous registries state
+        if ( !wasRelaxed )
+        {
+            setStrict();
+        }
+
+        // return the errors
+        return errors;
+    }
+
+
+    /**
+     * Merely adds the schema to the set of loaded schemas.  Does not
+     * actually do any work to add schema objects to registries.
+     * 
+     * {@inheritDoc}
+     */
+    public void schemaLoaded( Schema schema )
+    {
+        this.loadedSchemas.put( Strings.toLowerCase( schema.getSchemaName() ), schema );
+    }
+
+
+    /**
+     * Merely removes the schema from the set of loaded schemas.  Does not
+     * actually do any work to remove schema objects from registries.
+     * 
+     * {@inheritDoc}
+     */
+    public void schemaUnloaded( Schema schema )
+    {
+        this.loadedSchemas.remove( Strings.toLowerCase( schema.getSchemaName() ) );
+    }
+
+
+    /**
+     * Gets an unmodifiable Map of schema names to loaded Schema objects.
+     * 
+     * @return the map of loaded Schema objects
+     */
+    public Map<String, Schema> getLoadedSchemas()
+    {
+        return Collections.unmodifiableMap( loadedSchemas );
+    }
+
+
+    /**
+     * @return Gets a reference to the Map associating a schemaName to
+     * its contained SchemaObjects
+     */
+    public Map<String, Set<SchemaObjectWrapper>> getObjectBySchemaName()
+    {
+        return schemaObjects;
+    }
+
+
+    /**
+     * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found.
+     */
+    private String getSchemaName( SchemaObject schemaObject )
+    {
+        String schemaName = Strings.toLowerCase( schemaObject.getSchemaName() );
+
+        if ( loadedSchemas.containsKey( schemaName ) )
+        {
+            return schemaName;
+        }
+        else
+        {
+            return MetaSchemaConstants.SCHEMA_OTHER;
+        }
+    }
+
+
+    /**
+     * Tells if the given SchemaObject is present in one schema. The schema
+     * may be disabled.
+     *
+     * @param schemaObject The schemaObject we are looking for
+     * @return true if the schemaObject is present in a schema
+     */
+    public boolean contains( SchemaObject schemaObject )
+    {
+        String schemaName = schemaObject.getSchemaName();
+
+        Set<SchemaObjectWrapper> setSchemaObjects = schemaObjects.get( schemaName );
+
+        if ( ( setSchemaObjects == null ) || setSchemaObjects.isEmpty() )
+        {
+            return false;
+        }
+
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
+
+        return setSchemaObjects.contains( wrapper );
+    }
+
+
+    /**
+     * Create a new schema association with its content
+     *
+     * @param schemaName The schema name
+     */
+    public Set<SchemaObjectWrapper> addSchema( String schemaName )
+    {
+        Set<SchemaObjectWrapper> content = new HashSet<SchemaObjectWrapper>();
+        schemaObjects.put( schemaName, content );
+
+        return content;
+    }
+
+
+    /**
+     * Register the given SchemaObject into the associated Registry
+     */
+    private void register( List<Throwable> errors, SchemaObject schemaObject ) throws LdapException
+    {
+        LOG.debug( "Registering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
+
+        // Check that the SchemaObject is not already registered
+        // TODO : Check for existing Loadable SchemaObject
+        if ( !( schemaObject instanceof LoadableSchemaObject ) )
+        {
+            if ( globalOidRegistry.contains( schemaObject.getOid() ) )
+            {
+                // TODO : throw an exception here
+                String msg = I18n.err( I18n.ERR_04301, schemaObject.getObjectType(), schemaObject.getOid() );
+                LOG.error( msg );
+                Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+                errors.add( error );
+                return;
+            }
+        }
+
+        try
+        {
+            // First call the specific registry's register method
+            switch ( schemaObject.getObjectType() )
+            {
+                case ATTRIBUTE_TYPE:
+                    attributeTypeRegistry.register( ( AttributeType ) schemaObject );
+                    break;
+
+                case COMPARATOR:
+                    comparatorRegistry.register( ( LdapComparator<?> ) schemaObject );
+                    break;
+
+                case DIT_CONTENT_RULE:
+                    ditContentRuleRegistry.register( ( DitContentRule ) schemaObject );
+                    break;
+
+                case DIT_STRUCTURE_RULE:
+                    ditStructureRuleRegistry.register( ( DitStructureRule ) schemaObject );
+                    break;
+
+                case LDAP_SYNTAX:
+                    ldapSyntaxRegistry.register( ( LdapSyntax ) schemaObject );
+                    break;
+
+                case MATCHING_RULE:
+                    matchingRuleRegistry.register( ( MatchingRule ) schemaObject );
+                    break;
+
+                case MATCHING_RULE_USE:
+                    matchingRuleUseRegistry.register( ( MatchingRuleUse ) schemaObject );
+                    break;
+
+                case NAME_FORM:
+                    nameFormRegistry.register( ( NameForm ) schemaObject );
+                    break;
+
+                case NORMALIZER:
+                    normalizerRegistry.register( ( Normalizer ) schemaObject );
+                    break;
+
+                case OBJECT_CLASS:
+                    objectClassRegistry.register( ( ObjectClass ) schemaObject );
+                    break;
+
+                case SYNTAX_CHECKER:
+                    syntaxCheckerRegistry.register( ( SyntaxChecker ) schemaObject );
+                    break;
+
+                default:
+                    throw new IllegalArgumentException( "Unexpected SchemaObjectType: " + schemaObject.getObjectType() );
+            }
+        }
+        catch ( Exception e )
+        {
+            errors.add( e );
+        }
+    }
+
+
+    /**
+     * Store the given SchemaObject in the Map associating SchemaObjetcs to their
+     * related Schema.
+     *
+     * @param schemaObject The schemaObject to register
+     * @throws LdapException If there is a problem
+     */
+    public void associateWithSchema( List<Throwable> errors, SchemaObject schemaObject )
+    {
+        LOG.debug( "Registering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
+
+        // Check that the SchemaObject is not already registered
+        if ( !( schemaObject instanceof LoadableSchemaObject ) && globalOidRegistry.contains( schemaObject.getOid() ) )
+        {
+            // TODO : throw an exception here
+            String msg = I18n.err( I18n.ERR_04301, schemaObject.getObjectType(), schemaObject.getOid() );
+            LOG.error( msg );
+            Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+            errors.add( error );
+            return;
+        }
+
+        // Get a normalized form of schema name
+        String schemaName = getSchemaName( schemaObject );
+
+        // And register the schemaObject within its schema
+        Set<SchemaObjectWrapper> content = schemaObjects.get( schemaName );
+
+        if ( content == null )
+        {
+            content = new HashSet<SchemaObjectWrapper>();
+            schemaObjects.put( Strings.toLowerCase( schemaName ), content );
+        }
+
+        SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
+
+        if ( content.contains( schemaObjectWrapper ) )
+        {
+            // Already present !
+            // What should we do ?
+            LOG.info( "Registering of {}:{} failed, is already present in the Registries",
+                schemaObject.getObjectType(), schemaObject.getOid() );
+        }
+        else
+        {
+            // Create the association
+            content.add( schemaObjectWrapper );
+
+            // Update the global OidRegistry if the SchemaObject is not
+            // an instance of LoadableSchemaObject
+            if ( !( schemaObject instanceof LoadableSchemaObject ) )
+            {
+                try
+                {
+                    globalOidRegistry.register( schemaObject );
+                }
+                catch ( LdapException ne )
+                {
+                    errors.add( ne );
+                    return;
+                }
+            }
+
+            LOG.debug( "registered {} for OID {}", schemaObject.getName(), schemaObject.getOid() );
+        }
+    }
+
+
+    /**
+     * Store the given SchemaObject in the Map associating SchemaObjetcs to their
+     * related Schema.
+     *
+     * @param schemaObject The schemaObject to register
+     * @throws LdapException If there is a problem
+     */
+
+    public void dissociateFromSchema( List<Throwable> errors, SchemaObject schemaObject ) throws LdapException
+    {
+        LOG.debug( "Unregistering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
+
+        // Check that the SchemaObject is already registered
+        if ( !( schemaObject instanceof LoadableSchemaObject ) && !globalOidRegistry.contains( schemaObject.getOid() ) )
+        {
+            // TODO : throw an exception here
+            String msg = I18n.err( I18n.ERR_04302, schemaObject.getObjectType(), schemaObject.getOid() );
+            LOG.error( msg );
+            Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+            errors.add( error );
+            return;
+        }
+
+        // Get a normalized form of schema name
+        String schemaName = getSchemaName( schemaObject );
+        String oid = schemaObject.getOid();
+
+        // And unregister the schemaObject from its schema
+        Set<SchemaObjectWrapper> content = schemaObjects.get( schemaName );
+
+        SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
+
+        if ( !content.contains( schemaObjectWrapper ) )
+        {
+            // Not present !
+            // What should we do ?
+            LOG.info( "Unregistering of {}:{} failed, is not present in the Registries", schemaObject.getObjectType(),
+                schemaObject.getOid() );
+        }
+        else
+        {
+            // Remove the association
+            content.remove( schemaObjectWrapper );
+
+            // Update the global OidRegistry if the SchemaObject is not
+            // an instance of LoadableSchemaObject
+            if ( !( schemaObject instanceof LoadableSchemaObject ) )
+            {
+                try
+                {
+                    globalOidRegistry.unregister( oid );
+                }
+                catch ( LdapException ne )
+                {
+                    errors.add( ne );
+                    return;
+                }
+            }
+
+            LOG.debug( "Unregistered {} for OID {}", schemaObject.getName(), schemaObject.getOid() );
+        }
+    }
+
+
+    /**
+     * Unregister a SchemaObject from the registries
+     *
+     * @param schemaObject The SchemaObject we want to deregister
+     * @throws LdapException If the removal failed
+     */
+    private SchemaObject unregister( List<Throwable> errors, SchemaObject schemaObject ) throws LdapException
+    {
+        LOG.debug( "Unregistering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
+
+        // Check that the SchemaObject is present in the registries
+        // TODO : check for an existing Loadable SchemaObject
+        if ( !( schemaObject instanceof LoadableSchemaObject ) )
+        {
+            if ( !globalOidRegistry.contains( schemaObject.getOid() ) )
+            {
+                // TODO : throw an exception here
+                String msg = I18n.err( I18n.ERR_04302, schemaObject.getObjectType(), schemaObject.getOid() );
+                LOG.error( msg );
+                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+            }
+        }
+
+        SchemaObject unregistered = null;
+
+        // First call the specific registry's register method
+        switch ( schemaObject.getObjectType() )
+        {
+            case ATTRIBUTE_TYPE:
+                unregistered = attributeTypeRegistry.unregister( ( AttributeType ) schemaObject );
+                break;
+
+            case COMPARATOR:
+                unregistered = comparatorRegistry.unregister( ( LdapComparator<?> ) schemaObject );
+                break;
+
+            case DIT_CONTENT_RULE:
+                unregistered = ditContentRuleRegistry.unregister( ( DitContentRule ) schemaObject );
+                break;
+
+            case DIT_STRUCTURE_RULE:
+                unregistered = ditStructureRuleRegistry.unregister( ( DitStructureRule ) schemaObject );
+                break;
+
+            case LDAP_SYNTAX:
+                unregistered = ldapSyntaxRegistry.unregister( ( LdapSyntax ) schemaObject );
+                break;
+
+            case MATCHING_RULE:
+                unregistered = matchingRuleRegistry.unregister( ( MatchingRule ) schemaObject );
+                break;
+
+            case MATCHING_RULE_USE:
+                unregistered = matchingRuleUseRegistry.unregister( ( MatchingRuleUse ) schemaObject );
+                break;
+
+            case NAME_FORM:
+                unregistered = nameFormRegistry.unregister( ( NameForm ) schemaObject );
+                break;
+
+            case NORMALIZER:
+                unregistered = normalizerRegistry.unregister( ( Normalizer ) schemaObject );
+                break;
+
+            case OBJECT_CLASS:
+                unregistered = objectClassRegistry.unregister( ( ObjectClass ) schemaObject );
+                break;
+
+            case SYNTAX_CHECKER:
+                unregistered = syntaxCheckerRegistry.unregister( ( SyntaxChecker ) schemaObject );
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected SchemaObjectType: " + schemaObject.getObjectType() );
+        }
+
+        return unregistered;
+    }
+
+
+    /**
+     * Remove the given SchemaObject from the Map associating SchemaObjetcs to their
+     * related Schema.
+     *
+     * @param schemaObject The schemaObject to remove
+     * @throws LdapException If there is a problem
+     */
+    public void dissociateFromSchema( SchemaObject schemaObject ) throws LdapException
+    {
+        // And unregister the schemaObject within its schema
+        Set<SchemaObjectWrapper> content = schemaObjects.get( Strings.toLowerCase( schemaObject.getSchemaName() ) );
+
+        if ( content != null )
+        {
+            SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
+
+            if ( content.contains( schemaObjectWrapper ) )
+            {
+                // remove the schemaObject
+                content.remove( schemaObjectWrapper );
+
+                // Update the global OidRegistry if the SchemaObject is not
+                // an instance of LoadableSchemaObject
+                if ( !( schemaObject instanceof LoadableSchemaObject ) )
+                {
+                    globalOidRegistry.unregister( schemaObject.getOid() );
+                }
+
+                LOG.debug( "Unregistered {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
+            }
+            else
+            {
+                // Not present !!
+                // What should we do ?
+                LOG.debug( "Unregistering of {}:{} failed, not found in Registries", schemaObject.getObjectType(),
+                    schemaObject.getOid() );
+            }
+        }
+    }
+
+
+    /**
+     * Checks if a specific SchemaObject is referenced by any other SchemaObject.
+     *
+     * @param schemaObject The SchemaObject we are looking for
+     * @return true if there is at least one SchemaObjetc referencing the given one
+     */
+    public boolean isReferenced( SchemaObject schemaObject )
+    {
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
+
+        Set<SchemaObjectWrapper> set = usedBy.get( wrapper );
+
+        boolean referenced = ( set != null ) && ( set.size() != 0 );
+
+        if ( LOG.isDebugEnabled() )
+        {
+            if ( referenced )
+            {
+                LOG.debug( "The {}:{} is referenced", schemaObject.getObjectType(), schemaObject.getOid() );
+            }
+            else
+            {
+                LOG.debug( "The {}:{} is not referenced", schemaObject.getObjectType(), schemaObject.getOid() );
+            }
+        }
+
+        return referenced;
+    }
+
+
+    /**
+     * Gets the Set of SchemaObjects referencing the given SchemaObject
+     *
+     * @param schemaObject The SchemaObject we are looking for
+     * @return The Set of referencing SchemaObject, or null
+     */
+    public Set<SchemaObjectWrapper> getUsedBy( SchemaObject schemaObject )
+    {
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
+
+        return usedBy.get( wrapper );
+    }
+
+
+    /**
+     * Dump the UsedBy data structure as a String
+     */
+    public String dumpUsedBy()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "USED BY :\n" );
+
+        try
+        {
+            for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : usedBy.entrySet() )
+            {
+                SchemaObjectWrapper wrapper = entry.getKey();
+
+                sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() )
+                    .append( "] : {" );
+
+                boolean isFirst = true;
+
+                for ( SchemaObjectWrapper uses : entry.getValue() )
+                {
+                    if ( isFirst )
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        sb.append( ", " );
+                    }
+
+                    sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" );
+                }
+
+                sb.append( "}\n" );
+            }
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Dump the Using data structure as a String
+     */
+    public String dumpUsing()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "USING :\n" );
+
+        try
+        {
+            for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : using.entrySet() )
+            {
+                SchemaObjectWrapper wrapper = entry.getKey();
+
+                sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() )
+                    .append( "] : {" );
+
+                boolean isFirst = true;
+
+                for ( SchemaObjectWrapper uses : entry.getValue() )
+                {
+                    if ( isFirst )
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        sb.append( ", " );
+                    }
+
+                    sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" );
+                }
+
+                sb.append( "}\n" );
+            }
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Gets the Set of SchemaObjects referenced by the given SchemaObject
+     *
+     * @param schemaObject The SchemaObject we are looking for
+     * @return The Set of referenced SchemaObject, or null
+     */
+    public Set<SchemaObjectWrapper> getUsing( SchemaObject schemaObject )
+    {
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
+
+        return using.get( wrapper );
+    }
+
+
+    /**
+     * Add an association between a SchemaObject an the SchemaObject it refers
+     *
+     * @param reference The base SchemaObject
+     * @param referee The SchemaObject pointing on the reference
+     */
+    private void addUsing( SchemaObject reference, SchemaObject referee )
+    {
+        if ( ( reference == null ) || ( referee == null ) )
+        {
+            return;
+        }
+
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference );
+
+        Set<SchemaObjectWrapper> uses = getUsing( reference );
+
+        if ( uses == null )
+        {
+            uses = new HashSet<SchemaObjectWrapper>();
+        }
+
+        uses.add( new SchemaObjectWrapper( referee ) );
+
+        // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly
+        using.put( wrapper, uses );
+    }
+
+
+    /**
+     * Add an association between a SchemaObject an the SchemaObject it refers
+     *
+     * @param base The base SchemaObject
+     * @param referenced The referenced SchemaObject
+     */
+    public void addReference( SchemaObject base, SchemaObject referenced )
+    {
+        if ( LOG.isDebugEnabled() )
+        {
+            LOG.debug( dump( "add", base, referenced ) );
+        }
+
+        addUsing( base, referenced );
+        addUsedBy( referenced, base );
+
+        // do not change to debug mode, this makes the server logs hard to read and useless
+        // and even prevents the server from starting up
+        if ( LOG.isTraceEnabled() )
+        {
+            LOG.trace( dumpUsedBy() );
+            LOG.trace( dumpUsing() );
+        }
+    }
+
+
+    /**
+     * Add an association between a SchemaObject an the SchemaObject that refers it
+     *
+     * @param reference The base SchemaObject
+     * @param referee The SchemaObject pointing on the reference
+     */
+    private void addUsedBy( SchemaObject referee, SchemaObject reference )
+    {
+        if ( ( reference == null ) || ( referee == null ) )
+        {
+            return;
+        }
+
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee );
+
+        Set<SchemaObjectWrapper> uses = getUsedBy( referee );
+
+        if ( uses == null )
+        {
+            uses = new HashSet<SchemaObjectWrapper>();
+        }
+
+        uses.add( new SchemaObjectWrapper( reference ) );
+
+        // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly
+        usedBy.put( wrapper, uses );
+    }
+
+
+    /**
+     * Del an association between a SchemaObject an the SchemaObject it refers
+     *
+     * @param reference The base SchemaObject
+     * @param referee The SchemaObject pointing on the reference
+     */
+    private void delUsing( SchemaObject reference, SchemaObject referee )
+    {
+        if ( ( reference == null ) || ( referee == null ) )
+        {
+            return;
+        }
+
+        Set<SchemaObjectWrapper> uses = getUsing( reference );
+
+        if ( uses == null )
+        {
+            return;
+        }
+
+        uses.remove( new SchemaObjectWrapper( referee ) );
+
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference );
+
+        if ( uses.size() == 0 )
+        {
+            using.remove( wrapper );
+        }
+        else
+        {
+            using.put( wrapper, uses );
+        }
+    }
+
+
+    /**
+     * Del an association between a SchemaObject an the SchemaObject that refers it
+     *
+     * @param reference The base SchemaObject
+     * @param referee The SchemaObject pointing on the reference
+     */
+    private void delUsedBy( SchemaObject referee, SchemaObject reference )
+    {
+        if ( ( reference == null ) || ( referee == null ) )
+        {
+            return;
+        }
+
+        Set<SchemaObjectWrapper> uses = getUsedBy( referee );
+
+        if ( uses == null )
+        {
+            return;
+        }
+
+        uses.remove( new SchemaObjectWrapper( reference ) );
+
+        SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee );
+
+        if ( uses.size() == 0 )
+        {
+            usedBy.remove( wrapper );
+        }
+        else
+        {
+            usedBy.put( wrapper, uses );
+        }
+    }
+
+
+    /**
+     * Delete an association between a SchemaObject an the SchemaObject it refers
+     *
+     * @param base The base SchemaObject
+     * @param referenced The referenced SchemaObject
+     */
+    public void delReference( SchemaObject base, SchemaObject referenced )
+    {
+        if ( LOG.isDebugEnabled() )
+        {
+            LOG.debug( dump( "del", base, referenced ) );
+        }
+
+        delUsing( base, referenced );
+        delUsedBy( referenced, base );
+
+        if ( LOG.isDebugEnabled() )
+        {
+            LOG.debug( dumpUsedBy() );
+            LOG.debug( dumpUsing() );
+        }
+    }
+
+
+    /**
+     * Dump the reference operation as a String
+     */
+    private String dump( String op, SchemaObject reference, SchemaObject referee )
+    {
+        return op + " : " + reference.getObjectType() + "[" + reference.getOid() + "]/[" + referee.getObjectType()
+            + "[" + referee.getOid() + "]";
+    }
+
+
+    private boolean checkReferences( SchemaObject reference, SchemaObject referee, String message )
+    {
+        SchemaObjectWrapper referenceWrapper = new SchemaObjectWrapper( reference );
+        SchemaObjectWrapper refereeWrapper = new SchemaObjectWrapper( referee );
+
+        // Check the references : Syntax -> SyntaxChecker
+        if ( !using.containsKey( referenceWrapper ) )
+        {
+            LOG.debug( "The Syntax {}:{} does not reference any " + message, reference.getObjectType(), reference
+                .getOid() );
+
+            return false;
+        }
+
+        Set<SchemaObjectWrapper> usings = using.get( referenceWrapper );
+
+        if ( !usings.contains( refereeWrapper ) )
+        {
+            LOG.debug( "The {}:{} does not reference any " + message, reference.getObjectType(), reference.getOid() );
+
+            return false;
+        }
+
+        // Check the referees : SyntaxChecker -> Syntax
+        if ( !usedBy.containsKey( refereeWrapper ) )
+        {
+            LOG.debug( "The {}:{} is not referenced by any " + message, referee.getObjectType(), referee.getOid() );
+
+            return false;
+        }
+
+        Set<SchemaObjectWrapper> used = usedBy.get( refereeWrapper );
+
+        if ( !used.contains( referenceWrapper ) )
+        {
+            LOG.debug( "The {}:{} is not referenced by any " + message, referee.getObjectType(), referee.getOid() );
+
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Check the registries for invalid relations. This check stops at the first error.
+     *
+     * @return true if the Registries is consistent, false otherwise
+     */
+    public boolean check()
+    {
+        // Check the Syntaxes : check for a SyntaxChecker
+        LOG.debug( "Checking Syntaxes" );
+
+        for ( LdapSyntax syntax : ldapSyntaxRegistry )
+        {
+            // Check that each Syntax has a SyntaxChecker
+            if ( syntax.getSyntaxChecker() == null )
+            {
+                LOG.debug( "The Syntax {} has no SyntaxChecker", syntax );
+
+                return false;
+            }
+
+            if ( !syntaxCheckerRegistry.contains( syntax.getSyntaxChecker().getOid() ) )
+            {
+                LOG.debug( "Cannot find the SyntaxChecker {} for the Syntax {}", syntax.getSyntaxChecker().getOid(),
+                    syntax );
+
+                return false;
+            }
+
+            // Check the references : Syntax -> SyntaxChecker and SyntaxChecker -> Syntax
+            if ( !checkReferences( syntax, syntax.getSyntaxChecker(), "SyntaxChecker" ) )
+            {
+                return false;
+            }
+        }
+
+        // Check the MatchingRules : check for a Normalizer, a Comparator and a Syntax
+        LOG.debug( "Checking MatchingRules..." );
+
+        for ( MatchingRule matchingRule : matchingRuleRegistry )
+        {
+            // Check that each MatchingRule has a Normalizer
+            if ( matchingRule.getNormalizer() == null )
+            {
+                LOG.debug( "The MatchingRule {} has no Normalizer", matchingRule );
+
+                return false;
+            }
+
+            // Check that each MatchingRule has a Normalizer
+            if ( !normalizerRegistry.contains( matchingRule.getNormalizer().getOid() ) )
+            {
+                LOG.debug( "Cannot find the Normalizer {} for the MatchingRule {}", matchingRule.getNormalizer()
+                    .getOid(), matchingRule );
+
+                return false;
+            }
+
+            // Check that each MatchingRule has a Comparator
+            if ( matchingRule.getLdapComparator() == null )
+            {
+                LOG.debug( "The MatchingRule {} has no Comparator", matchingRule );
+
+                return false;
+            }
+
+            if ( !comparatorRegistry.contains( matchingRule.getLdapComparator().getOid() ) )
+            {
+                LOG.debug( "Cannot find the Comparator {} for the MatchingRule {}", matchingRule.getLdapComparator()
+                    .getOid(), matchingRule );
+
+                return false;
+            }
+
+            // Check that each MatchingRule has a Syntax
+            if ( matchingRule.getSyntax() == null )
+            {
+                LOG.debug( "The MatchingRule {} has no Syntax", matchingRule );
+
+                return false;
+            }
+
+            if ( !ldapSyntaxRegistry.contains( matchingRule.getSyntax().getOid() ) )
+            {
+                LOG.debug( "Cannot find the Syntax {} for the MatchingRule {}", matchingRule.getSyntax().getOid(),
+                    matchingRule );
+
+                return false;
+            }
+
+            // Check the references : MR -> S and S -> MR
+            if ( !checkReferences( matchingRule, matchingRule.getSyntax(), "Syntax" ) )
+            {
+                return false;
+            }
+
+            // Check the references : MR -> N
+            if ( !checkReferences( matchingRule, matchingRule.getNormalizer(), "Normalizer" ) )
+            {
+                return false;
+            }
+
+            // Check the references : MR -> C and C -> MR
+            if ( !checkReferences( matchingRule, matchingRule.getLdapComparator(), "Comparator" ) )
+            {
+                return false;
+            }
+        }
+
+        // Check the ObjectClasses : check for MAY, MUST, SUPERIORS
+        LOG.debug( "Checking ObjectClasses..." );
+
+        for ( ObjectClass objectClass : objectClassRegistry )
+        {
+            // Check that each ObjectClass has all the MAY AttributeTypes
+            if ( objectClass.getMayAttributeTypes() != null )
+            {
+                for ( AttributeType may : objectClass.getMayAttributeTypes() )
+                {
+                    if ( !attributeTypeRegistry.contains( may.getOid() ) )
+                    {
+                        LOG.debug( "Cannot find the AttributeType {} for the ObjectClass {} MAY", may, objectClass );
+
+                        return false;
+                    }
+
+                    // Check the references : OC -> AT  and AT -> OC (MAY)
+                    if ( !checkReferences( objectClass, may, "AttributeType" ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            // Check that each ObjectClass has all the MUST AttributeTypes
+            if ( objectClass.getMustAttributeTypes() != null )
+            {
+                for ( AttributeType must : objectClass.getMustAttributeTypes() )
+                {
+                    if ( !attributeTypeRegistry.contains( must.getOid() ) )
+                    {
+                        LOG.debug( "Cannot find the AttributeType {} for the ObjectClass {} MUST", must, objectClass );
+
+                        return false;
+                    }
+
+                    // Check the references : OC -> AT  and AT -> OC (MUST)
+                    if ( !checkReferences( objectClass, must, "AttributeType" ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            // Check that each ObjectClass has all the SUPERIORS ObjectClasses
+            if ( objectClass.getSuperiors() != null )
+            {
+                for ( ObjectClass superior : objectClass.getSuperiors() )
+                {
+                    if ( !objectClassRegistry.contains( objectClass.getOid() ) )
+                    {
+                        LOG.debug( "Cannot find the ObjectClass {} for the ObjectClass {} SUPERIORS", superior,
+                            objectClass );
+
+                        return false;
+                    }
+
+                    // Check the references : OC -> OC  and OC -> OC (SUPERIORS)
+                    if ( !checkReferences( objectClass, superior, "ObjectClass" ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        // Check the AttributeTypes : check for MatchingRules, Syntaxes
+        LOG.debug( "Checking AttributeTypes..." );
+
+        for ( AttributeType attributeType : attributeTypeRegistry )
+        {
+            // Check that each AttributeType has a SYNTAX
+            if ( attributeType.getSyntax() == null )
+            {
+                LOG.debug( "The AttributeType {} has no Syntax", attributeType );
+
+                return false;
+            }
+
+            if ( !ldapSyntaxRegistry.contains( attributeType.getSyntax().getOid() ) )
+            {
+                LOG.debug( "Cannot find the Syntax {} for the AttributeType {}", attributeType.getSyntax().getOid(),
+                    attributeType );
+
+                return false;
+            }
+
+            // Check the references for AT -> S and S -> AT
+            if ( !checkReferences( attributeType, attributeType.getSyntax(), "AttributeType" ) )
+            {
+                return false;
+            }
+
+            // Check the EQUALITY MatchingRule
+            if ( attributeType.getEquality() != null )
+            {
+                if ( !matchingRuleRegistry.contains( attributeType.getEquality().getOid() ) )
+                {
+                    LOG.debug( "Cannot find the MatchingRule {} for the AttributeType {}", attributeType.getEquality()
+                        .getOid(), attributeType );
+
+                    return false;
+                }
+
+                // Check the references for AT -> MR and MR -> AT
+                if ( !checkReferences( attributeType, attributeType.getEquality(), "AttributeType" ) )
+                {
+                    return false;
+                }
+            }
+
+            // Check the ORDERING MatchingRule
+            if ( attributeType.getOrdering() != null )
+            {
+                if ( !matchingRuleRegistry.contains( attributeType.getOrdering().getOid() ) )
+                {
+                    LOG.debug( "Cannot find the MatchingRule {} for the AttributeType {}", attributeType.getOrdering()
+                        .getOid(), attributeType );
+
+                    return false;
+                }
+
+                // Check the references for AT -> MR and MR -> AT
+                if ( !checkReferences( attributeType, attributeType.getOrdering(), "AttributeType" ) )
+                {
+                    return false;
+                }
+            }
+
+            // Check the SUBSTR MatchingRule
+            if ( attributeType.getSubstring() != null )
+            {
+                if ( !matchingRuleRegistry.contains( attributeType.getSubstring().getOid() ) )
+                {
+                    LOG.debug( "Cannot find the MatchingRule {} for the AttributeType {}", attributeType.getSubstring()
+                        .getOid(), attributeType );
+
+                    return false;
+                }
+
+                // Check the references for AT -> MR and MR -> AT
+                if ( !checkReferences( attributeType, attributeType.getSubstring(), "AttributeType" ) )
+                {
+                    return false;
+                }
+            }
+
+            // Check the SUP
+            if ( attributeType.getSuperior() != null )
+            {
+                AttributeType superior = attributeType.getSuperior();
+
+                if ( !attributeTypeRegistry.contains( superior.getOid() ) )
+                {
+                    LOG.debug( "Cannot find the AttributeType {} for the AttributeType {} SUPERIOR", superior,
+                        attributeType );
+
+                    return false;
+                }
+
+                // Check the references : AT -> AT  and AT -> AT (SUPERIOR)
+                if ( !checkReferences( attributeType, superior, "AttributeType" ) )
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Clone the Registries. This is done in two steps :
+     * - first clone the SchemaObjetc registries
+     * - second restore the relation between them
+     */
+    // False positive
+    public Registries clone() throws CloneNotSupportedException
+    {
+        // First clone the structure
+        Registries clone = ( Registries ) super.clone();
+
+        // Now, clone the oidRegistry
+        clone.globalOidRegistry = globalOidRegistry.copy();
+
+        // We have to clone every SchemaObject registries now
+        clone.attributeTypeRegistry = attributeTypeRegistry.copy();
+        clone.comparatorRegistry = comparatorRegistry.copy();
+        clone.ditContentRuleRegistry = ditContentRuleRegistry.copy();
+        clone.ditStructureRuleRegistry = ditStructureRuleRegistry.copy();
+        clone.ldapSyntaxRegistry = ldapSyntaxRegistry.copy();
+        clone.matchingRuleRegistry = matchingRuleRegistry.copy();
+        clone.matchingRuleUseRegistry = matchingRuleUseRegistry.copy();
+        clone.nameFormRegistry = nameFormRegistry.copy();
+        clone.normalizerRegistry = normalizerRegistry.copy();
+        clone.objectClassRegistry = objectClassRegistry.copy();
+        clone.syntaxCheckerRegistry = syntaxCheckerRegistry.copy();
+
+        // Store all the SchemaObjects into the globalOid registry
+        for ( AttributeType attributeType : clone.attributeTypeRegistry )
+        {
+            clone.globalOidRegistry.put( attributeType );
+        }
+
+        for ( DitContentRule ditContentRule : clone.ditContentRuleRegistry )
+        {
+            clone.globalOidRegistry.put( ditContentRule );
+        }
+
+        for ( DitStructureRule ditStructureRule : clone.ditStructureRuleRegistry )
+        {
+            clone.globalOidRegistry.put( ditStructureRule );
+        }
+
+        for ( MatchingRule matchingRule : clone.matchingRuleRegistry )
+        {
+            clone.globalOidRegistry.put( matchingRule );
+        }
+
+        for ( MatchingRuleUse matchingRuleUse : clone.matchingRuleUseRegistry )
+        {
+            clone.globalOidRegistry.put( matchingRuleUse );
+        }
+
+        for ( NameForm nameForm : clone.nameFormRegistry )
+        {
+            clone.globalOidRegistry.put( nameForm );
+        }
+
+        for ( ObjectClass objectClass : clone.objectClassRegistry )
+        {
+            clone.globalOidRegistry.put( objectClass );
+        }
+
+        for ( LdapSyntax syntax : clone.ldapSyntaxRegistry )
+        {
+            clone.globalOidRegistry.put( syntax );
+        }
+
+        // Clone the schema list
+        clone.loadedSchemas = new HashMap<String, Schema>();
+
+        for ( Map.Entry<String, Set<SchemaObjectWrapper>> entry : schemaObjects.entrySet() )
+        {
+            // We don't clone the schemas
+            clone.loadedSchemas.put( entry.getKey(), loadedSchemas.get( entry.getKey() ) );
+        }
+
+        // Clone the Using and usedBy structures
+        // They will be empty
+        clone.using = new HashMap<SchemaObjectWrapper, Set<SchemaObjectWrapper>>();
+        clone.usedBy = new HashMap<SchemaObjectWrapper, Set<SchemaObjectWrapper>>();
+
+        // Last, rebuild the using and usedBy references
+        clone.buildReferences();
+
+        // Now, check the registries. We don't care about errors
+        clone.checkRefInteg();
+
+        clone.schemaObjects = new HashMap<String, Set<SchemaObjectWrapper>>();
+
+        // Last, not least, clone the SchemaObjects Map, and reference all the copied
+        // SchemaObjects
+        for ( Map.Entry<String, Set<SchemaObjectWrapper>> entry : schemaObjects.entrySet() )
+        {
+            Set<SchemaObjectWrapper> objects = new HashSet<SchemaObjectWrapper>();
+
+            for ( SchemaObjectWrapper schemaObjectWrapper : entry.getValue() )
+            {
+                SchemaObject original = schemaObjectWrapper.get();
+
+                try
+                {
+                    if ( !( original instanceof LoadableSchemaObject ) )
+                    {
+                        SchemaObject copy = clone.globalOidRegistry.getSchemaObject( original.getOid() );
+                        SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( copy );
+                        objects.add( newWrapper );
+                    }
+                    else
+                    {
+                        SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( original );
+                        objects.add( newWrapper );
+                    }
+                }
+                catch ( LdapException ne )
+                {
+                    // Nothing to do
+                }
+            }
+
+            clone.schemaObjects.put( entry.getKey(), objects );
+        }
+
+        return clone;
+    }
+
+
+    /**
+     * Tells if the Registries is permissive or if it must be checked
+     * against inconsistencies.
+     *
+     * @return True if SchemaObjects can be added even if they break the consistency
+     */
+    public boolean isRelaxed()
+    {
+        return isRelaxed;
+    }
+
+
+    /**
+     * Tells if the Registries is strict.
+     *
+     * @return True if SchemaObjects cannot be added if they break the consistency
+     */
+    public boolean isStrict()
+    {
+        return !isRelaxed;
+    }
+
+
+    /**
+     * Change the Registries to a relaxed mode, where invalid SchemaObjects
+     * can be registered.
+     */
+    public void setRelaxed()
+    {
+        isRelaxed = RELAXED;
+        globalOidRegistry.setRelaxed();
+        attributeTypeRegistry.setRelaxed();
+        comparatorRegistry.setRelaxed();
+        ditContentRuleRegistry.setRelaxed();
+        ditStructureRuleRegistry.setRelaxed();
+        ldapSyntaxRegistry.setRelaxed();
+        matchingRuleRegistry.setRelaxed();
+        matchingRuleUseRegistry.setRelaxed();
+        nameFormRegistry.setRelaxed();
+        normalizerRegistry.setRelaxed();
+        objectClassRegistry.setRelaxed();
+        syntaxCheckerRegistry.setRelaxed();
+    }
+
+
+    /**
+     * Change the Registries to a strict mode, where invalid SchemaObjects
+     * cannot be registered.
+     */
+    public void setStrict()
+    {
+        isRelaxed = STRICT;
+        globalOidRegistry.setStrict();
+        attributeTypeRegistry.setStrict();
+        comparatorRegistry.setStrict();
+        ditContentRuleRegistry.setStrict();
+        ditStructureRuleRegistry.setStrict();
+        ldapSyntaxRegistry.setStrict();
+        matchingRuleRegistry.setStrict();
+        matchingRuleUseRegistry.setStrict();
+        nameFormRegistry.setStrict();
+        normalizerRegistry.setStrict();
+        objectClassRegistry.setStrict();
+        syntaxCheckerRegistry.setStrict();
+    }
+
+
+    /**
+     * Tells if the Registries accept disabled elements.
+     *
+     * @return True if disabled SchemaObjects can be added
+     */
+    public boolean isDisabledAccepted()
+    {
+        return disabledAccepted;
+    }
+
+
+    /**
+     * Check that we can remove a given SchemaObject without breaking some of its references.
+     * We will return the list of refereing objects.
+     *
+     * @param schemaObject The SchemaObject to remove
+     * @return The list of SchemaObjects referencing the SchemaObjetc we want to remove
+     */
+    public Set<SchemaObjectWrapper> getReferencing( SchemaObject schemaObject )
+    {
+        SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
+
+        return usedBy.get( schemaObjectWrapper );
+    }
+
+
+    /**
+     * Change the Registries behavior regarding disabled SchemaObject element.
+     *
+     * @param disabledAccepted If <code>false</code>, then the Registries won't accept
+     * disabled SchemaObject or enabled SchemaObject from disabled schema
+     */
+    public void setDisabledAccepted( boolean disabledAccepted )
+    {
+        this.disabledAccepted = disabledAccepted;
+    }
+
+
+    /**
+     * Clear the registries from all its elements
+     *
+     * @throws LdapException If something goes wrong
+     */
+    public void clear() throws LdapException
+    {
+        // The AttributeTypeRegistry
+        if ( attributeTypeRegistry != null )
+        {
+            attributeTypeRegistry.clear();
+        }
+
+        // The ComparatorRegistry
+        if ( comparatorRegistry != null )
+        {
+            comparatorRegistry.clear();
+        }
+
+        // The DitContentRuleRegistry
+        if ( ditContentRuleRegistry != null )
+        {
+            ditContentRuleRegistry.clear();
+        }
+
+        // The DitStructureRuleRegistry
+        if ( ditStructureRuleRegistry != null )
+        {
+            ditStructureRuleRegistry.clear();
+        }
+
+        // The MatchingRuleRegistry
+        if ( matchingRuleRegistry != null )
+        {
+            matchingRuleRegistry.clear();
+        }
+
+        // The MatchingRuleUseRegistry
+        if ( matchingRuleUseRegistry != null )
+        {
+            matchingRuleUseRegistry.clear();
+        }
+
+        // The NameFormRegistry
+        if ( nameFormRegistry != null )
+        {
+            nameFormRegistry.clear();
+        }
+
+        // The NormalizerRegistry
+        if ( normalizerRegistry != null )
+        {
+            normalizerRegistry.clear();
+        }
+
+        // The ObjectClassRegistry
+        if ( objectClassRegistry != null )
+        {
+            objectClassRegistry.clear();
+        }
+
+        // The SyntaxRegistry
+        if ( ldapSyntaxRegistry != null )
+        {
+            ldapSyntaxRegistry.clear();
+        }
+
+        // The SyntaxCheckerRegistry
+        if ( syntaxCheckerRegistry != null )
+        {
+            syntaxCheckerRegistry.clear();
+        }
+
+        // Clear the schemaObjects map
+        for ( Map.Entry<String, Set<SchemaObjectWrapper>> entry : schemaObjects.entrySet() )
+        {
+            entry.getValue().clear();
+        }
+
+        schemaObjects.clear();
+
+        // Clear the usedBy map
+        for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : usedBy.entrySet() )
+        {
+            entry.getValue().clear();
+        }
+
+        usedBy.clear();
+
+        // Clear the using map
+        for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : using.entrySet() )
+        {
+            entry.getValue().clear();
+        }
+
+        using.clear();
+
+        // Clear the global OID registry
+        globalOidRegistry.clear();
+
+        // Clear the loadedSchema Map
+        loadedSchemas.clear();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "Registries [" );
+
+        if ( isRelaxed )
+        {
+            sb.append( "RELAXED," );
+        }
+        else
+        {
+            sb.append( "STRICT," );
+        }
+
+        if ( disabledAccepted )
+        {
+            sb.append( " Disabled accepted] :\n" );
+        }
+        else
+        {
+            sb.append( " Disabled forbidden] :\n" );
+        }
+
+        sb.append( "loaded schemas [" );
+        boolean isFirst = true;
+
+        for ( String schema : loadedSchemas.keySet() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            sb.append( schema );
+        }
+
+        sb.append( "]\n" );
+
+        sb.append( "AttributeTypes : " ).append( attributeTypeRegistry.size() ).append( "\n" );
+        sb.append( "Comparators : " ).append( comparatorRegistry.size() ).append( "\n" );
+        sb.append( "DitContentRules : " ).append( ditContentRuleRegistry.size() ).append( "\n" );
+        sb.append( "DitStructureRules : " ).append( ditStructureRuleRegistry.size() ).append( "\n" );
+        sb.append( "MatchingRules : " ).append( matchingRuleRegistry.size() ).append( "\n" );
+        sb.append( "MatchingRuleUses : " ).append( matchingRuleUseRegistry.size() ).append( "\n" );
+        sb.append( "NameForms : " ).append( nameFormRegistry.size() ).append( "\n" );
+        sb.append( "Normalizers : " ).append( normalizerRegistry.size() ).append( "\n" );
+        sb.append( "ObjectClasses : " ).append( objectClassRegistry.size() ).append( "\n" );
+        sb.append( "Syntaxes : " ).append( ldapSyntaxRegistry.size() ).append( "\n" );
+        sb.append( "SyntaxCheckers : " ).append( syntaxCheckerRegistry.size() ).append( "\n" );
+
+        sb.append( "GlobalOidRegistry : " ).append( globalOidRegistry.size() ).append( '\n' );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/Schema.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/Schema.java
new file mode 100644
index 0000000..19a7f77
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/Schema.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
+
+
+/**
+ * Base schema interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface Schema
+{
+    /**
+     * Checks whether or not this schema is enabled or disabled.
+     * 
+     * @return true if this schema is disabled, false otherwise
+     */
+    boolean isDisabled();
+
+
+    /**
+     * Disable the schema
+     */
+    void disable();
+
+
+    /**
+     * Checks whether or not this schema is enabled or disabled.
+     * 
+     * @return true if this schema is enabled, false otherwise
+     */
+    boolean isEnabled();
+
+
+    /**
+     * Enable the schema
+     */
+    void enable();
+
+
+    /**
+     * Gets the name of the owner of the schema objects within this
+     * Schema.
+     *
+     * @return the identifier for the owner of this set's objects
+     */
+    String getOwner();
+
+
+    /**
+     * Gets the name of the logical schema the objects of this Schema
+     * belong to: e.g. krb5-kdc may be the logical LDAP schema name.
+     *
+     * @return the name of the logical schema
+     */
+    String getSchemaName();
+
+
+    /**
+     * Gets the names of other schemas that the objects within this
+     * Schema depends upon.
+     *
+     * @return the String names of schema dependencies
+     */
+    String[] getDependencies();
+
+
+    /**
+     * Add a set of dependencies this schema uses.
+     *
+     * @param dependencies The dependencies to add
+     */
+    void addDependencies( String... dependencies );
+
+
+    /**
+     * Gets the set of SchemaObject elements declared in this schema
+     *
+     * @return The Set of associated SchemaObjects
+     */
+    Set<SchemaObjectWrapper> getContent();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaLoader.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaLoader.java
new file mode 100644
index 0000000..693053f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaLoader.java
@@ -0,0 +1,314 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * Loads schemas into registries.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SchemaLoader
+{
+    /**
+     * Gets a schema object based on it's name.
+     * 
+     * @param schemaName the name of the schema to load
+     * @return the Schema object associated with the name
+     */
+    Schema getSchema( String schemaName );
+
+
+    /**
+     * Build a list of AttributeTypes read from the underlying storage for
+     * a list of specified schema
+     *
+     * @param schemas the schemas from which AttributeTypes are loaded
+     * @throws Exception if there are failures accessing AttributeType information
+     */
+    List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of AttributeTypes read from the underlying storage for
+     * a list of specific schema, using their name
+     *
+     * @param schemaNames the schema names from which AttributeTypes are loaded
+     * @throws Exception if there are failures accessing AttributeType information
+     */
+    List<Entry> loadAttributeTypes( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of Comparators read from the underlying storage for
+     * a list of specific schema.
+     *
+     * @param schemas the schemas from which Comparators are loaded
+     * @throws Exception if there are failures accessing Comparator information
+     */
+    List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of Comparators read from the underlying storage for
+     * a list of specific schema, using their name
+     *
+     * @param schemaNames the schema names from which Comparators are loaded
+     * @throws Exception if there are failures accessing Comparator information
+     */
+    List<Entry> loadComparators( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of DitContentRules read from the underlying storage for
+     * a list of specific schema.
+     *
+     * @param schemas the schemas from which DitContentRules are loaded
+     * @throws Exception if there are failures accessing DitContentRule information
+     */
+    List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of DitContentRules read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which DitContentRules are loaded
+     * @throws Exception if there are failures accessing DitContentRule information
+     */
+    List<Entry> loadDitContentRules( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of DitStructureRules read from the underlying storage for
+     * a list of specific schema.
+     *
+     * @param schemas the schemas from which DitStructureRules are loaded
+     * @throws Exception if there are failures accessing DitStructureRule information
+     */
+    List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of DitStructureRules read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which DitStructureRules are loaded
+     * @throws Exception if there are failures accessing DitStructureRule information
+     */
+    List<Entry> loadDitStructureRules( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of MatchingRules read from the underlying storage for
+     * a list of specific schema
+     *
+     * @param schemas the schemas from which MatchingRules are loaded
+     * @throws Exception if there are failures accessing MatchingRule information
+     */
+    List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of MatchingRules read from the underlying storage for
+     * a list of specific schema, using their name
+     *
+     * @param schemaNames the schema names from which MatchingRules are loaded
+     * @throws Exception if there are failures accessing MatchingRule information
+     */
+    List<Entry> loadMatchingRules( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of MatchingRuleUses read from the underlying storage for
+     * a list of specific schema.
+     *
+     * @param schemas the schemas from which MatchingRuleUses are loaded
+     * @throws Exception if there are failures accessing MatchingRuleUse information
+     */
+    List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of MatchingRuleUses read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which MatchingRuleUses are loaded
+     * @throws Exception if there are failures accessing MatchingRuleUses information
+     */
+    List<Entry> loadMatchingRuleUses( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of NameForms read from the underlying storage for
+     * a list of specific schema.
+     *
+     * @param schemas the schemas from which NameForms are loaded
+     * @throws Exception if there are failures accessing NameForm information
+     */
+    List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of NameForms read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which NameForms are loaded
+     * @throws Exception if there are failures accessing NameForms information
+     */
+    List<Entry> loadNameForms( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of Normalizers read from the underlying storage for
+     * a list of specified schema
+     *
+     * @param schemas the schemas from which Normalizers are loaded
+     * @throws Exception if there are failures accessing Normalizer information
+     */
+    List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of Normalizers read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which Normalizers are loaded
+     * @throws Exception if there are failures accessing Normalizer information
+     */
+    List<Entry> loadNormalizers( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of ObjectClasses read from the underlying storage for
+     * a list of specific schema.
+     *
+     * @param schemas the schemas from which ObjectClasses are loaded
+     * @throws Exception if there are failures accessing ObjectClass information
+     */
+    List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of ObjectClasses read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which ObjectClasses are loaded
+     * @throws Exception if there are failures accessing ObjectClasses information
+     */
+    List<Entry> loadObjectClasses( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of Syntaxes read from the underlying storage for
+     * a list of specified schema
+     *
+     * @param schemas the schemas from which Syntaxes are loaded
+     * @throws Exception if there are failures accessing Syntax information
+     */
+    List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of Syntaxes read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which Syntaxes are loaded
+     * @throws Exception if there are failures accessing Syntax information
+     */
+    List<Entry> loadSyntaxes( String... schemaNames ) throws Exception;
+
+
+    /**
+     * Build a list of SyntaxCheckers read from the underlying storage for
+     * a list of specified schema
+     *
+     * @param schemas the schemas from which SyntaxCheckers are loaded
+     * @throws Exception if there are failures accessing SyntaxChecker information
+     */
+    List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException;
+
+
+    /**
+     * Build a list of SyntaxCheckers read from the underlying storage for
+     * a list of specified schema names
+     *
+     * @param schemaNames the schema names from which SyntaxCheckers are loaded
+     * @throws Exception if there are failures accessing SyntaxChecker information
+     */
+    List<Entry> loadSyntaxCheckers( String... schemaNames ) throws Exception;
+
+
+    /**
+     * @return the list of enabled schemas
+     * @throws Exception TODO
+     */
+    Collection<Schema> getAllEnabled() throws Exception;
+
+
+    /**
+     * @return the list of all schemas
+     * @throws Exception TODO
+     */
+    Collection<Schema> getAllSchemas() throws Exception;
+
+
+    /**
+     * Add a new schema to the schema's list
+     */
+    void addSchema( Schema schema );
+
+
+    /**
+     * Remove a schema from the schema's list
+     * 
+     * @param schema The schema to remove
+     */
+    void removeSchema( Schema schema );
+    
+    
+    /**
+     * @return Tells if the SchemaLoader is in RELAXED mode
+     */
+    boolean isRelaxed();
+    
+    
+    /**
+     * @return Tells if the SchemaLoader is in STRICT mode
+     */
+    boolean isStrict();
+    
+    
+    /**
+     * Set the SchemzLoader in STRICT or RELAXED mode.
+     * 
+     * @param relaxed if <code>true</code>, the SchemaLoader will be in relaxed mode, otherwise
+     * it will be in strict mode (the default)
+     */
+    void setRelaxed( boolean relaxed );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaLoaderListener.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaLoaderListener.java
new file mode 100644
index 0000000..1015a1b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaLoaderListener.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+/**
+ * A listener interface used by schema loaders and the schema subsystem of 
+ * Apache Directory Server to notify the registry of events like a new schema 
+ * being loaded or unloaded.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SchemaLoaderListener
+{
+    /**
+     * Listener method called to indicate a loader or other agent finished 
+     * loading the schema objects for a schema into the Registries.
+     * 
+     * @param schema the Schema that was loaded
+     */
+    void schemaLoaded( Schema schema );
+
+
+    /**
+     * Listener method called to indicate an agent finished loading the schema
+     * objects for a schema into the Registries.
+     * 
+     * @param schema the Schema that was unloaded
+     */
+    void schemaUnloaded( Schema schema );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaObjectRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaObjectRegistry.java
new file mode 100644
index 0000000..e351aac
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SchemaObjectRegistry.java
@@ -0,0 +1,181 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import java.util.Iterator;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectType;
+
+
+/**
+ * Common schema object registry interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SchemaObjectRegistry<T extends SchemaObject>
+{
+    /**
+     * Checks to see if an SchemaObject exists in the registry, by its
+     * OID or name. 
+     * 
+     * @param oid the object identifier or name of the SchemaObject
+     * @return true if a SchemaObject definition exists for the oid, false
+     * otherwise
+     */
+    boolean contains( String oid );
+
+
+    /**
+     * Gets the name of the schema this schema object is associated with.
+     *
+     * @param oid the object identifier or the name
+     * @return the schema name
+     * @throws LdapException if the schema object does not exist
+     */
+    String getSchemaName( String oid ) throws LdapException;
+
+
+    /**
+     * Gets the SchemaObject associated with a given OID.
+     *
+     * @param oid The SchemaObject's OID we are looking for
+     * @return The SchemaObject, if any. Null otherwise
+     */
+    T get( String oid );
+
+
+    /**
+     * Modify all the SchemaObject using a schemaName when this name changes.
+     *
+     * @param originalSchemaName The original Schema name
+     * @param newSchemaName The new Schema name
+     * @throws LdapException if the schema object does not exist
+     */
+    void renameSchema( String originalSchemaName, String newSchemaName ) throws LdapException;
+
+
+    /**
+     * Gets an iterator over the registered schema objects in the registry.
+     *
+     * @return an Iterator of homogeneous schema objects
+     */
+    Iterator<T> iterator();
+
+
+    /**
+     * Gets an iterator over the registered schema objects'OID in the registry.
+     *
+     * @return an Iterator of OIDs
+     */
+    Iterator<String> oidsIterator();
+
+
+    /**
+     * Looks up a SchemaObject by its unique Object Identifier or by name.
+     *
+     * @param oid the object identifier or name
+     * @return the SchemaObject instance for the id
+     * @throws LdapException if the SchemaObject does not exist
+     */
+    T lookup( String oid ) throws LdapException;
+
+
+    /**
+     * Registers a new SchemaObject with this registry.
+     *
+     * @param schemaObject the SchemaObject to register
+     * @throws LdapException if the SchemaObject is already registered or
+     * the registration operation is not supported
+     */
+    void register( T schemaObject ) throws LdapException;
+
+
+    /**
+     * Removes the SchemaObject registered with this registry, using its
+     * numeric OID.
+     * 
+     * @param numericOid the numeric identifier
+     * @throws LdapException if the numeric identifier is invalid
+     */
+    T unregister( String numericOid ) throws LdapException;
+
+
+    /**
+     * Removes the SchemaObject registered with this registry.
+     * 
+     * @param schemaObject the schemaObject to unregister
+     * @throws LdapException if the schemaObject can't be unregistered is invalid
+     */
+    T unregister( T schemaObject ) throws LdapException;
+
+
+    /**
+     * Unregisters all SchemaObjects defined for a specific schema from
+     * this registry.
+     * 
+     * @param schemaName the name of the schema whose SchemaObjects will be removed from
+     */
+    void unregisterSchemaElements( String schemaName ) throws LdapException;
+
+
+    /**
+     * Gets the numericOid for a name/alias if one is associated.  To prevent
+     * lookup failures due to case variance in the name, a failure to lookup the
+     * OID, will trigger a lookup using a lower cased version of the name and 
+     * the name that failed to match will automatically be associated with the
+     * OID.
+     * 
+     * @param name The name we are looking the oid for
+     * @return The numericOID associated with this name
+     * @throws LdapException If the OID can't be found
+     */
+    String getOidByName( String name ) throws LdapException;
+
+
+    /**
+     * Copy a DefaultSchemaObjectRegistry. All the stored SchemaObject will also
+     * be copied, by the cross references will be lost.
+     * 
+     * @return SchemaObjectRegistry<T> The copied registry
+     */
+    SchemaObjectRegistry<T> copy();
+
+
+    /**
+     * @return the type
+     */
+    SchemaObjectType getType();
+
+
+    /**
+     *  @return The number of AttributeType stored
+     */
+    int size();
+
+
+    /**
+     * Clear the registry from all its content
+     */
+    void clear() throws LdapException;
+    
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SyntaxCheckerRegistry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SyntaxCheckerRegistry.java
new file mode 100644
index 0000000..13ca103
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/SyntaxCheckerRegistry.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+
+
+/**
+ * SyntaxChecker registry component's service interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SyntaxCheckerRegistry extends SchemaObjectRegistry<SyntaxChecker>,
+    Iterable<SyntaxChecker>
+{
+    /**
+     * Registers a new SyntaxChecker with this registry.
+     *
+     * @param syntaxChecker the SyntaxChecker to register
+     * @throws LdapException if the SyntaxChecker is already registered or
+     * the registration operation is not supported
+     */
+    void register( SyntaxChecker syntaxChecker ) throws LdapException;
+
+
+    /**
+     * Removes the SyntaxChecker registered with this registry, using its
+     * numeric OID.
+     * 
+     * @param numericOid the numeric identifier
+     * @throws LdapException if the numeric identifier is invalid
+     */
+    SyntaxChecker unregister( String numericOid ) throws LdapException;
+
+
+    /**
+     * Unregisters all SyntaxCheckers defined for a specific schema from
+     * this registry.
+     * 
+     * @param schemaName the name of the schema whose SyntaxCheckers will be removed from
+     */
+    void unregisterSchemaElements( String schemaName ) throws LdapException;
+
+
+    /**
+     * Copy the SyntaxCheckerRegistry
+     */
+    SyntaxCheckerRegistry copy();
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/AttributeTypeHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/AttributeTypeHelper.java
new file mode 100644
index 0000000..e6c1767
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/AttributeTypeHelper.java
@@ -0,0 +1,674 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An helper class used to store all the methods associated with an AttributeType
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class AttributeTypeHelper
+{
+    private AttributeTypeHelper()
+    {
+    }
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( AttributeTypeHelper.class );
+
+    /**
+     * Inject the AttributeType into the Registries, updating the references to
+     * other SchemaObject
+     *
+     * If one of the referenced SchemaObject does not exist (SUP, EQUALITY, ORDERING, SUBSTR, SYNTAX),
+     * an exception is thrown.
+     * 
+     * @param attributeType The AttributeType to add to the Registries
+     * @param errors The errors we got while adding the AttributeType to the Registries
+     * @param registries The Registries
+     * @exception If the AttributeType is not valid
+     */
+    public static void addToRegistries( MutableAttributeType attributeType, List<Throwable> errors, Registries registries ) throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                attributeType.unlock();
+                AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
+    
+                // The superior
+                if ( !buildSuperior( attributeType, errors, registries ) )
+                {
+                    // We have had errors, let's stop here as we need a correct superior to continue
+                    return;
+                }
+    
+                // The Syntax
+                buildSyntax( attributeType, errors, registries );
+    
+                // The EQUALITY matching rule
+                buildEquality( attributeType, errors, registries );
+    
+                // The ORDERING matching rule
+                buildOrdering( attributeType, errors, registries );
+    
+                // The SUBSTR matching rule
+                buildSubstring( attributeType, errors, registries );
+    
+                // Check the USAGE
+                checkUsage( attributeType, errors );
+    
+                // Check the COLLECTIVE element
+                checkCollective( attributeType, errors );
+    
+                // Inject the attributeType into the oid/normalizer map
+                attributeTypeRegistry.addMappingFor( attributeType );
+    
+                // Register this AttributeType into the Descendant map
+                attributeTypeRegistry.registerDescendants( attributeType, attributeType.getSuperior() );
+    
+                /**
+                 * Add the AT references (using and usedBy) :
+                 * AT -> MR (for EQUALITY, ORDERING and SUBSTR)
+                 * AT -> S
+                 * AT -> AT
+                 */
+                if ( attributeType.getEquality() != null )
+                {
+                    registries.addReference( attributeType, attributeType.getEquality() );
+                }
+    
+                if ( attributeType.getOrdering() != null )
+                {
+                    registries.addReference( attributeType, attributeType.getOrdering() );
+                }
+    
+                if ( attributeType.getSubstring() != null )
+                {
+                    registries.addReference( attributeType, attributeType.getSubstring() );
+                }
+    
+                if ( attributeType.getSyntax() != null )
+                {
+                    registries.addReference( attributeType, attributeType.getSyntax() );
+                }
+    
+                if ( attributeType.getSuperior() != null )
+                {
+                    registries.addReference( attributeType, attributeType.getSuperior() );
+                }
+            }
+            finally
+            {
+                attributeType.lock();
+            }
+        }
+    }
+
+
+    /**
+     * Build the Superior AttributeType reference for an AttributeType
+     */
+    private static boolean buildSuperior( MutableAttributeType attributeType, List<Throwable> errors, Registries registries )
+    {
+        MutableAttributeType currentSuperior = null;
+        AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
+        
+        String superiorOid = attributeType.getSuperiorOid();
+
+        if ( superiorOid != null )
+        {
+            // This AT has a superior
+            try
+            {
+                currentSuperior = ( MutableAttributeType ) attributeTypeRegistry.lookup( superiorOid );
+            }
+            catch ( Exception e )
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04303, superiorOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_SUPERIOR, msg, e );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( superiorOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+
+                // Get out now
+                return false;
+            }
+
+            if ( currentSuperior != null )
+            {
+                // a special case : if the superior is collective, this is an error
+                if ( currentSuperior.isCollective() )
+                {
+                    String msg = I18n.err( I18n.ERR_04482_CANNOT_SUBTYPE_COLLECTIVE,
+                        currentSuperior, attributeType.getName() );
+
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.AT_CANNOT_SUBTYPE_COLLECTIVE_AT, msg );
+                    ldapSchemaException.setSourceObject( attributeType );
+                    errors.add( ldapSchemaException );
+                    LOG.info( msg );
+                    
+                    return false;
+                }
+
+                attributeType.setSuperior( currentSuperior );
+
+                // Recursively update the superior if not already done. We don't recurse
+                // if the superior's superior is not null, as it means it has already been
+                // handled.
+                if ( currentSuperior.getSuperior() == null )
+                {
+                    registries.buildReference( errors, currentSuperior );
+                }
+
+                // Update the descendant MAP
+                try
+                {
+                    attributeTypeRegistry.registerDescendants( attributeType, currentSuperior );
+                }
+                catch ( LdapException ne )
+                {
+                    errors.add( ne );
+                    LOG.info( ne.getMessage() );
+                    
+                    return false;
+                }
+
+                // Check for cycles now
+                Set<String> superiors = new HashSet<String>();
+                superiors.add( attributeType.getOid() );
+                AttributeType tmp = currentSuperior;
+                boolean isOk = true;
+
+                while ( tmp != null )
+                {
+                    if ( superiors.contains( tmp.getOid() ) )
+                    {
+                        // There is a cycle : bad bad bad !
+                        // Not allowed.
+                        String msg = I18n.err( I18n.ERR_04304, attributeType.getName() );
+
+                        LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                            LdapSchemaExceptionCodes.AT_CYCLE_TYPE_HIERARCHY, msg );
+                        ldapSchemaException.setSourceObject( attributeType );
+                        errors.add( ldapSchemaException );
+                        LOG.info( msg );
+                        isOk = false;
+
+                        break;
+                    }
+                    else
+                    {
+                        superiors.add( tmp.getOid() );
+                        tmp = tmp.getSuperior();
+                    }
+                }
+
+                superiors.clear();
+
+                return isOk;
+            }
+            else
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04305, superiorOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_SUPERIOR, msg );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( superiorOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+
+                // Get out now
+                return false;
+            }
+        }
+        else
+        {
+            // No superior, just return
+            return true;
+        }
+    }
+
+
+    /**
+     * Build the SYNTAX reference for an AttributeType
+     */
+    private static void buildSyntax( MutableAttributeType attributeType, List<Throwable> errors, Registries registries )
+    {
+        String syntaxOid = attributeType.getSyntaxOid();
+        
+        if ( syntaxOid != null )
+        {
+            LdapSyntax currentSyntax = null;
+
+            try
+            {
+                currentSyntax = registries.getLdapSyntaxRegistry().lookup( syntaxOid );
+            }
+            catch ( LdapException ne )
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04306, syntaxOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_SYNTAX, msg, ne );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( syntaxOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+                
+                return;
+            }
+
+            if ( currentSyntax != null )
+            {
+                // Update the Syntax reference
+                attributeType.setSyntax( currentSyntax );
+            }
+            else
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04306, syntaxOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_SYNTAX, msg );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( syntaxOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+                
+                return;
+            }
+        }
+        else
+        {
+            // We inherit from the superior's syntax, if any
+            if ( attributeType.getSuperior() != null )
+            {
+                attributeType.setSyntax( attributeType.getSuperior().getSyntax() );
+            }
+            else
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04307, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_SYNTAX_OR_SUPERIOR_REQUIRED, msg );
+                ldapSchemaException.setSourceObject( attributeType );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+                
+                return;
+            }
+        }
+    }
+    
+    
+    /**
+     * Build the EQUALITY MR reference for an AttributeType
+     */
+    private static void buildEquality( MutableAttributeType attributeType, List<Throwable> errors, Registries registries )
+    {
+        String equalityOid = attributeType.getEqualityOid();
+        
+        // The equality MR. It can be null
+        if ( equalityOid != null )
+        {
+            MatchingRule currentEquality = null;
+
+            try
+            {
+                currentEquality = registries.getMatchingRuleRegistry().lookup( equalityOid );
+            }
+            catch ( LdapException ne )
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04308, equalityOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_EQUALITY_MATCHING_RULE, msg, ne );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( equalityOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+                
+                return;
+            }
+
+            if ( currentEquality != null )
+            {
+                attributeType.setEquality( currentEquality );
+                
+                // Restore the old equality OID to preserve the user's provided value
+                attributeType.setEqualityOid( equalityOid );
+            }
+            else
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04309, equalityOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_EQUALITY_MATCHING_RULE, msg );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( equalityOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+            }
+        }
+        else
+        {
+            AttributeType superior = attributeType.getSuperior();
+            
+            // If the AT has a superior, take its Equality MR if any
+            if ( ( superior != null ) && ( superior.getEquality() != null ) )
+            {
+                attributeType.setEquality( superior.getEquality() );
+            }
+        }
+    }
+
+
+    /**
+     * Build the SUBSTR MR reference for an AttributeType
+     */
+    private static void buildSubstring( MutableAttributeType attributeType, List<Throwable> errors, Registries registries )
+    {
+        String substringOid = attributeType.getSubstringOid();
+        
+        // The Substring MR. It can be null
+        if ( substringOid != null )
+        {
+            MatchingRule currentSubstring = null;
+
+            try
+            {
+                currentSubstring = registries.getMatchingRuleRegistry().lookup( substringOid );
+            }
+            catch ( LdapException ne )
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04312, substringOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_SUBSTRING_MATCHING_RULE, msg, ne );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( substringOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+                
+                return;
+            }
+
+            if ( currentSubstring != null )
+            {
+                attributeType.setSubstring( currentSubstring );
+            }
+            else
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04313, substringOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_SUBSTRING_MATCHING_RULE, msg );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( substringOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+                
+                return;
+            }
+        }
+        else
+        {
+            AttributeType superior = attributeType.getSuperior();
+            
+            // If the AT has a superior, take its Substring MR if any
+            if ( ( superior != null ) && ( superior.getSubstring() != null ) )
+            {
+                attributeType.setSubstring( superior.getSubstring() );
+            }
+        }
+    }
+    
+    
+
+
+
+
+    /**
+     * Build the ORDERING MR reference for an AttributeType
+     */
+    private static void buildOrdering( MutableAttributeType attributeType, List<Throwable> errors, Registries registries )
+    {
+        String orderingOid = attributeType.getOrderingOid();
+        
+        if ( orderingOid != null )
+        {
+            MatchingRule currentOrdering = null;
+
+            try
+            {
+                currentOrdering = registries.getMatchingRuleRegistry().lookup( orderingOid );
+            }
+            catch ( LdapException ne )
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04310, orderingOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_ORDERING_MATCHING_RULE, msg, ne );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( orderingOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+                
+                return;
+            }
+
+            if ( currentOrdering != null )
+            {
+                attributeType.setOrdering( currentOrdering );
+            }
+            else
+            {
+                // Not allowed.
+                String msg = I18n.err( I18n.ERR_04311, orderingOid, attributeType.getName() );
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.AT_NONEXISTENT_ORDERING_MATCHING_RULE, msg );
+                ldapSchemaException.setSourceObject( attributeType );
+                ldapSchemaException.setRelatedId( orderingOid );
+                errors.add( ldapSchemaException );
+                LOG.info( msg );
+            }
+        }
+        else
+        {
+            AttributeType superior = attributeType.getSuperior();
+            
+            // If the AT has a superior, take its Ordering MR if any
+            if ( ( superior != null ) && ( superior.getOrdering() != null ) )
+            {
+                attributeType.setOrdering( superior.getOrdering() );
+            }
+        }
+    }
+
+    
+    /**
+     * Check the constraints for the Usage field.
+     */
+    private static void checkUsage( AttributeType attributeType, List<Throwable> errors )
+    {
+        AttributeType superior = attributeType.getSuperior();
+        
+        // Check that the AT usage is the same that its superior
+        if ( ( superior != null ) && ( attributeType.getUsage() != superior.getUsage() ) )
+        {
+            // This is an error
+            String msg = I18n.err( I18n.ERR_04314, attributeType.getName() );
+
+            LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                LdapSchemaExceptionCodes.AT_MUST_HAVE_SAME_USAGE_THAN_SUPERIOR, msg );
+            ldapSchemaException.setSourceObject( attributeType );
+            errors.add( ldapSchemaException );
+            LOG.info( msg );
+            
+            return;
+        }
+
+        // Now, check that the AttributeType's USAGE does not conflict
+        if ( !attributeType.isUserModifiable() && ( attributeType.getUsage() == UsageEnum.USER_APPLICATIONS ) )
+        {
+            // Cannot have a not user modifiable AT which is not an operational AT
+            String msg = I18n.err( I18n.ERR_04315, attributeType.getName() );
+
+            LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                LdapSchemaExceptionCodes.AT_USER_APPLICATIONS_USAGE_MUST_BE_USER_MODIFIABLE, msg );
+            ldapSchemaException.setSourceObject( attributeType );
+            errors.add( ldapSchemaException );
+            LOG.info( msg );
+        }
+    }
+
+
+    /**
+     * Check the constraints for the Collective field.
+     */
+    private static void checkCollective( MutableAttributeType attributeType, List<Throwable> errors )
+    {
+        AttributeType superior = attributeType.getSuperior();
+
+        if ( ( superior != null ) && superior.isCollective() )
+        {
+            // An AttributeType will be collective if its superior is collective
+            attributeType.setCollective( true );
+        }
+
+        if ( attributeType.isCollective() && ( attributeType.getUsage() != UsageEnum.USER_APPLICATIONS ) )
+        {
+            // An AttributeType which is collective must be a USER attributeType
+            String msg = I18n.err( I18n.ERR_04316, attributeType.getName() );
+
+            LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                LdapSchemaExceptionCodes.AT_COLLECTIVE_MUST_HAVE_USER_APPLICATIONS_USAGE, msg );
+            ldapSchemaException.setSourceObject( attributeType );
+            errors.add( ldapSchemaException );
+            LOG.info( msg );
+        }
+
+        if ( attributeType.isCollective() && attributeType.isSingleValued() )
+        {
+            // A collective attribute must be multi-valued
+            String msg = I18n.err( I18n.ERR_04483_COLLECTIVE_NOT_MULTI_VALUED, attributeType.getName() );
+
+            LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                LdapSchemaExceptionCodes.AT_COLLECTIVE_CANNOT_BE_SINGLE_VALUED, msg );
+            ldapSchemaException.setSourceObject( attributeType );
+            errors.add( ldapSchemaException );
+            LOG.info( msg );
+        }
+    }
+    
+    
+    /**
+     * Remove the AttributeType from the registries, updating the references to
+     * other SchemaObject.
+     *
+     * If one of the referenced SchemaObject does not exist (SUP, EQUALITY, ORDERING, SUBSTR, SYNTAX),
+     * an exception is thrown.
+     * 
+     * @param attributeType The AttributeType to remove from the Registries
+     * @param errors The errors we got while removing the AttributeType from the Registries
+     * @param registries The Registries
+     * @exception If the AttributeType is not valid
+     */
+    public static void removeFromRegistries( AttributeType attributeType, List<Throwable> errors, Registries registries ) throws LdapException
+    {
+        if ( registries != null )
+        {
+            AttributeTypeRegistry attributeTypeRegistry = registries.getAttributeTypeRegistry();
+
+            // Remove the attributeType from the oid/normalizer map
+            attributeTypeRegistry.removeMappingFor( attributeType );
+
+            // Unregister this AttributeType into the Descendant map
+            attributeTypeRegistry.unregisterDescendants( attributeType, attributeType.getSuperior() );
+
+            /**
+             * Remove the AT references (using and usedBy) :
+             * AT -> MR (for EQUALITY, ORDERING and SUBSTR)
+             * AT -> S
+             * AT -> AT
+             */
+            if ( attributeType.getEquality() != null )
+            {
+                registries.delReference( attributeType, attributeType.getEquality() );
+            }
+
+            if ( attributeType.getOrdering() != null )
+            {
+                registries.delReference( attributeType, attributeType.getOrdering() );
+            }
+
+            if ( attributeType.getSubstring() != null )
+            {
+                registries.delReference( attributeType, attributeType.getSubstring() );
+            }
+
+            if ( attributeType.getSyntax() != null )
+            {
+                registries.delReference( attributeType, attributeType.getSyntax() );
+            }
+
+            if ( attributeType.getSuperior() != null )
+            {
+                registries.delReference( attributeType, attributeType.getSuperior() );
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/DitContentRuleHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/DitContentRuleHelper.java
new file mode 100644
index 0000000..3daad98
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/DitContentRuleHelper.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+
+
+/**
+ * An helper class used to store all the methods associated with an DitContentRule
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DitContentRuleHelper
+{
+    private DitContentRuleHelper()
+    {
+    }
+
+
+    /**
+     * Inject the DitContentRule into the registries, updating the references to
+     * other SchemaObject
+     *
+     * @param ditContentRule The DitContentRule to add to the Registries
+     * @param errors The errors we got while adding the DitContentRule to the Registries
+     * @param registries The Registries
+     * @exception If the addition failed
+     */
+    public static void addToRegistries( DitContentRule ditContentRule, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                ditContentRule.unlock();
+                AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
+                ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
+
+                if ( ditContentRule.getMayAttributeTypeOids() != null )
+                {
+                    ditContentRule.getMayAttributeTypes().clear();
+
+                    for ( String oid : ditContentRule.getMayAttributeTypeOids() )
+                    {
+                        ditContentRule.getMayAttributeTypes().add( atRegistry.lookup( oid ) );
+                    }
+                }
+
+                if ( ditContentRule.getMustAttributeTypeOids() != null )
+                {
+                    ditContentRule.getMustAttributeTypes().clear();
+
+                    for ( String oid : ditContentRule.getMustAttributeTypeOids() )
+                    {
+                        ditContentRule.getMustAttributeTypes().add( atRegistry.lookup( oid ) );
+                    }
+                }
+
+                if ( ditContentRule.getNotAttributeTypeOids() != null )
+                {
+                    ditContentRule.getNotAttributeTypes().clear();
+
+                    for ( String oid : ditContentRule.getNotAttributeTypeOids() )
+                    {
+                        ditContentRule.getNotAttributeTypes().add( atRegistry.lookup( oid ) );
+                    }
+                }
+
+                if ( ditContentRule.getAuxObjectClassOids() != null )
+                {
+                    ditContentRule.getAuxObjectClasses().clear();
+
+                    for ( String oid : ditContentRule.getAuxObjectClassOids() )
+                    {
+                        ditContentRule.getAuxObjectClasses().add( ocRegistry.lookup( oid ) );
+                    }
+                }
+            }
+            finally
+            {
+                ditContentRule.lock();
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/DitStructureRuleHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/DitStructureRuleHelper.java
new file mode 100644
index 0000000..fa2f27c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/DitStructureRuleHelper.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+
+
+/**
+ * An helper class used to store all the methods associated with an DitStructureRule
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DitStructureRuleHelper
+{
+    private DitStructureRuleHelper()
+    {
+    }
+
+
+    /**
+     * Inject the DitContentRule into the registries, updating the references to
+     * other SchemaObject
+     *
+     * @param ditStructureRule The DitStructureRule to add to the Registries
+     * @param errors The errors we got while adding the DitContentRule to the Registries
+     * @param registries The Registries
+     * @exception If the addition failed
+     */
+    public static void addToRegistries( DitStructureRule ditStructureRule, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                ditStructureRule.unlock();
+
+                // NOT YET IMPLEMENTED
+            }
+            finally
+            {
+                ditStructureRule.lock();
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/LdapSyntaxHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/LdapSyntaxHelper.java
new file mode 100644
index 0000000..1a39539
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/LdapSyntaxHelper.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+
+
+/**
+ * An helper class used to store all the methods associated with an LdapSyntax
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class LdapSyntaxHelper
+{
+    private LdapSyntaxHelper()
+    {
+    }
+
+
+    /**
+     * Inject the LdapSyntax into the registries, updating the references to
+     * other SchemaObject
+     *
+     * @param ldapSyntax The LdapSyntax to add to the Registries
+     * @param errors The errors we got while adding the LdapSyntax to the Registries
+     * @param registries The Registries
+     * @exception If the addition failed
+     */
+    public static void addToRegistries( LdapSyntax ldapSyntax, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                ldapSyntax.unlock();
+
+                SyntaxChecker syntaxChecker = null;
+
+                try
+                {
+                    // Gets the associated SyntaxChecker
+                    syntaxChecker = registries.getSyntaxCheckerRegistry().lookup( ldapSyntax.getOid() );
+                }
+                catch ( LdapException ne )
+                {
+                    // No SyntaxChecker ? Associate the Syntax to a catch all SyntaxChecker
+                    syntaxChecker = new OctetStringSyntaxChecker( ldapSyntax.getOid() );
+                }
+
+                // Add the references for S :
+                // S -> SC
+                if ( syntaxChecker != null )
+                {
+                    registries.addReference( ldapSyntax, syntaxChecker );
+                    ldapSyntax.setSyntaxChecker( syntaxChecker );
+                }
+            }
+            finally
+            {
+                ldapSyntax.lock();
+            }
+        }
+    }
+
+
+    /**
+     * Remove the LdapSyntax from the Registries, updating the references to
+     * other SchemaObject.
+     * 
+     * If one of the referenced SchemaObject does not exist,
+     * an exception is thrown.
+     *
+     * @param ldapSyntax The LdapSyntax to remove from the Registries
+     * @param errors The errors we got while removing the LdapSyntax from the Registries
+     * @param registries The Registries
+     * @exception If the LdapSyntax is not valid
+     */
+    public static void removeFromRegistries( LdapSyntax ldapSyntax, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( ( registries != null ) && ( ldapSyntax.getSyntaxChecker() != null ) )
+        {
+            /**
+             * Remove the Syntax references (using and usedBy) :
+             * S -> SC
+             */
+            registries.delReference( ldapSyntax, ldapSyntax.getSyntaxChecker() );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/MatchingRuleHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/MatchingRuleHelper.java
new file mode 100644
index 0000000..c3a2f99
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/MatchingRuleHelper.java
@@ -0,0 +1,192 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An helper class used to store all the methods associated with an MatchingRule
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class MatchingRuleHelper
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MatchingRuleHelper.class );
+
+
+    private MatchingRuleHelper()
+    {
+    }
+
+
+    /**
+     * Inject the MatchingRule into the Registries, updating the references to
+     * other SchemaObject
+     *
+     * @param matchingRule The MatchingRule to add to the Registries
+     * @param errors The errors we got while adding the MatchingRule to the registries
+     * @param registries The Registries
+     * @exception If the addition failed
+     */
+    @SuppressWarnings("rawtypes")
+    public static void addToRegistries( MutableMatchingRule matchingRule, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                matchingRule.unlock();
+
+                LdapComparator<?> ldapComparator = null;
+                Normalizer normalizer = null;
+                LdapSyntax ldapSyntax = null;
+
+                try
+                {
+                    // Gets the associated Comparator
+                    ldapComparator = registries.getComparatorRegistry().lookup( matchingRule.getOid() );
+                }
+                catch ( LdapException ne )
+                {
+                    // Default to a catch all comparator
+                    ldapComparator = new ComparableComparator( matchingRule.getOid() );
+                }
+
+                try
+                {
+                    // Gets the associated Normalizer
+                    normalizer = registries.getNormalizerRegistry().lookup( matchingRule.getOid() );
+                }
+                catch ( LdapException ne )
+                {
+                    // Default to the NoOp normalizer
+                    normalizer = new NoOpNormalizer( matchingRule.getOid() );
+                }
+
+                try
+                {
+                    // Get the associated LdapSyntax
+                    ldapSyntax = registries.getLdapSyntaxRegistry().lookup( matchingRule.getSyntaxOid() );
+                }
+                catch ( LdapException ne )
+                {
+                    // The Syntax is a mandatory element, it must exist.
+                    String msg = I18n.err( I18n.ERR_04317 );
+
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.MR_NONEXISTENT_SYNTAX, msg, ne );
+                    ldapSchemaException.setSourceObject( matchingRule );
+                    ldapSchemaException.setRelatedId( matchingRule.getSyntaxOid() );
+                    errors.add( ldapSchemaException );
+                    LOG.info( msg );
+                }
+
+                /**
+                 * Add the MR references (using and usedBy) :
+                 * MR -> C
+                 * MR -> N
+                 * MR -> S
+                 */
+                if ( ldapComparator != null )
+                {
+                    registries.addReference( matchingRule, ldapComparator );
+                    matchingRule.setLdapComparator( ldapComparator );
+                }
+
+                if ( normalizer != null )
+                {
+                    registries.addReference( matchingRule, normalizer );
+                    matchingRule.setNormalizer( normalizer );
+                }
+
+                if ( ldapSyntax != null )
+                {
+                    registries.addReference( matchingRule, ldapSyntax );
+                    matchingRule.setSyntax( ldapSyntax );
+                }
+            }
+            finally
+            {
+                matchingRule.lock();
+            }
+        }
+    }
+
+
+    /**
+     * Remove the MatchingRule from the Registries, updating the references to
+     * other SchemaObject.
+     * 
+     * If one of the referenced SchemaObject does not exist,
+     * an exception is thrown.
+     *
+     * @param matchingRule The MatchingRule to remove from the Registries
+     * @param errors The errors we got while removing the MatchingRule from the registries
+     * @param registries The Registries
+     * @exception If the MatchingRule is not valid
+     */
+    public static void removeFromRegistries( MatchingRule matchingRule, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( registries != null )
+        {
+            /**
+             * Remove the MR references (using and usedBy) :
+             * MR -> C
+             * MR -> N
+             * MR -> S
+             */
+            if ( matchingRule.getLdapComparator() != null )
+            {
+                registries.delReference( matchingRule, matchingRule.getLdapComparator() );
+            }
+
+            if ( matchingRule.getSyntax() != null )
+            {
+                registries.delReference( matchingRule, matchingRule.getSyntax() );
+            }
+
+            if ( matchingRule.getNormalizer() != null )
+            {
+                registries.delReference( matchingRule, matchingRule.getNormalizer() );
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/MatchingRuleUseHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/MatchingRuleUseHelper.java
new file mode 100644
index 0000000..6d9e7be
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/MatchingRuleUseHelper.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+
+
+/**
+ * An helper class used to store all the methods associated with a MatchingRuleUse
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class MatchingRuleUseHelper
+{
+    private MatchingRuleUseHelper()
+    {
+    }
+
+
+    /**
+     * Inject the MatchingRuleUse into the registries, updating the references to
+     * other SchemaObject
+     *
+     * @param matchingRuleUse The MatchingRuleUse to add to the Registries
+     * @param errors The errors we got while adding the MatchingRuleUse to the Registries
+     * @param registries The Registries
+     * @exception If the addition failed
+     */
+    public static void addToRegistries( MatchingRuleUse matchingRuleUse, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                matchingRuleUse.unlock();
+
+                AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
+
+                matchingRuleUse.getApplicableAttributes().clear();
+
+                for ( String oid : matchingRuleUse.getApplicableAttributeOids() )
+                {
+                    matchingRuleUse.getApplicableAttributes().add( atRegistry.lookup( oid ) );
+                }
+            }
+            finally
+            {
+                matchingRuleUse.lock();
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/NameFormHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/NameFormHelper.java
new file mode 100644
index 0000000..1a41e42
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/NameFormHelper.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.NameForm;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+
+
+/**
+ * An helper class used to store all the methods associated with an NameForm
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class NameFormHelper
+{
+    private NameFormHelper()
+    {
+    }
+
+
+    /**
+     * Inject the NameForm into the registries, updating the references to
+     * other SchemaObject
+     *
+     * @param nameForm The NameForm to add to the Registries
+     * @param errors The errors we got while adding the NameForm to the Registries
+     * @param registries The Registries
+     * @exception If the addition failed
+     */
+    public static void addToRegistries( NameForm nameForm, List<Throwable> errors, Registries registries )
+        throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                nameForm.unlock();
+
+                AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
+
+                ObjectClass structuralObjectClass = registries.getObjectClassRegistry().lookup(
+                    nameForm.getStructuralObjectClassOid() );
+                nameForm.setStructuralObjectClass( structuralObjectClass );
+
+                nameForm.getMayAttributeTypes().clear();
+
+                for ( String oid : nameForm.getMayAttributeTypeOids() )
+                {
+                    nameForm.getMayAttributeTypes().add( atRegistry.lookup( oid ) );
+                }
+
+                nameForm.getMustAttributeTypes().clear();
+
+                for ( String oid : nameForm.getMustAttributeTypeOids() )
+                {
+                    nameForm.getMustAttributeTypes().add( atRegistry.lookup( oid ) );
+                }
+            }
+            finally
+            {
+                nameForm.lock();
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/ObjectClassHelper.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/ObjectClassHelper.java
new file mode 100644
index 0000000..0ad1e69
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/registries/helper/ObjectClassHelper.java
@@ -0,0 +1,412 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.registries.helper;
+
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An helper class used to store all the methods associated with an ObjectClass
+ * in relation with the Registries and SchemaManager.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ObjectClassHelper
+{
+    private ObjectClassHelper()
+    {
+    }
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ObjectClassHelper.class );
+
+    /**
+     * Inject the ObjectClass into the registries, updating the references to
+     * other SchemaObject
+     *
+     * @param objectClass The ObjectClass to add to the Registries
+     * @param errors The errors we got while adding the ObjectClass to the Registries
+     * @param registries The Registries
+     * @throws Exception on failure
+     */
+    public static void addToRegistries( ObjectClass objectClass, List<Throwable> errors, Registries registries ) throws LdapException
+    {
+        if ( registries != null )
+        {
+            try
+            {
+                objectClass.unlock();
+                
+                // The superiors
+                buildSuperiors( objectClass, errors, registries );
+    
+                // The MAY AttributeTypes
+                buildMay( objectClass, errors, registries );
+    
+                // The MUST AttributeTypes
+                buildMust( objectClass, errors, registries );
+    
+                /**
+                 * Add the OC references (using and usedBy) :
+                 * OC -> AT (MAY and MUST)
+                 * OC -> OC (SUPERIORS)
+                 */
+                for ( AttributeType mayAttributeType : objectClass.getMayAttributeTypes() )
+                {
+                    registries.addReference( objectClass, mayAttributeType );
+                }
+    
+                for ( AttributeType mustAttributeType : objectClass.getMustAttributeTypes() )
+                {
+                    registries.addReference( objectClass, mustAttributeType );
+                }
+    
+                for ( ObjectClass superiorObjectClass : objectClass.getSuperiors() )
+                {
+                    registries.addReference( objectClass, superiorObjectClass );
+                }
+            }
+            finally
+            {
+                objectClass.lock();
+            }
+        }
+    }
+
+
+    /**
+     * Build the references to this ObjectClass SUPERIORS, checking that the type
+     * hierarchy is correct.
+     */
+    private static void buildSuperiors( ObjectClass objectClass, List<Throwable> errors, Registries registries )
+    {
+        ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
+        List<String> superiorOids = objectClass.getSuperiorOids();
+
+        if ( superiorOids != null )
+        {
+            objectClass.getSuperiors().clear();
+
+            for ( String superiorName : superiorOids )
+            {
+                try
+                {
+                    ObjectClass superior = ocRegistry.lookup( ocRegistry.getOidByName( superiorName ) );
+
+                    // Before adding the superior, check that the ObjectClass type is consistent
+                    switch ( objectClass.getType() )
+                    {
+                        case ABSTRACT:
+                            if ( superior.getType() != ObjectClassTypeEnum.ABSTRACT )
+                            {
+                                // An ABSTRACT OC can only inherit from ABSTRACT OCs
+                                String msg = I18n.err( I18n.ERR_04318, objectClass.getOid(), superior.getObjectType(), superior );
+
+                                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                                    LdapSchemaExceptionCodes.OC_ABSTRACT_MUST_INHERIT_FROM_ABSTRACT_OC, msg );
+                                ldapSchemaException.setSourceObject( objectClass );
+                                errors.add( ldapSchemaException );
+                                LOG.info( msg );
+
+                                continue;
+                            }
+
+                            break;
+
+                        case AUXILIARY:
+                            if ( superior.getType() == ObjectClassTypeEnum.STRUCTURAL )
+                            {
+                                // An AUXILIARY OC cannot inherit from STRUCTURAL OCs
+                                String msg = I18n.err( I18n.ERR_04319, objectClass.getOid(), superior );
+
+                                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                                    LdapSchemaExceptionCodes.OC_AUXILIARY_CANNOT_INHERIT_FROM_STRUCTURAL_OC, msg );
+                                ldapSchemaException.setSourceObject( objectClass );
+                                errors.add( ldapSchemaException );
+                                LOG.info( msg );
+
+                                continue;
+                            }
+
+                            break;
+
+                        case STRUCTURAL:
+                            if ( superior.getType() == ObjectClassTypeEnum.AUXILIARY )
+                            {
+                                // A STRUCTURAL OC cannot inherit from AUXILIARY OCs
+                                String msg = I18n.err( I18n.ERR_04320, objectClass.getOid(), superior );
+
+                                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                                    LdapSchemaExceptionCodes.OC_STRUCTURAL_CANNOT_INHERIT_FROM_AUXILIARY_OC, msg );
+                                ldapSchemaException.setSourceObject( objectClass );
+                                errors.add( ldapSchemaException );
+                                LOG.info( msg );
+
+                                continue;
+                            }
+
+                            break;
+
+                        default:
+                            throw new IllegalArgumentException( "Unexpected ObjectClassTypeEnum: "
+                                + objectClass.getType() );
+                    }
+
+                    objectClass.getSuperiors().add( superior );
+                }
+                catch ( LdapException ne )
+                {
+                    // Cannot find the OC
+                    String msg = I18n.err( I18n.ERR_04321, objectClass.getOid(), superiorName );
+
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.OC_NONEXISTENT_SUPERIOR, msg, ne );
+                    ldapSchemaException.setSourceObject( objectClass );
+                    ldapSchemaException.setRelatedId( superiorName );
+                    errors.add( ldapSchemaException );
+                    LOG.info( msg );
+
+                    return;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Build and check the MUST AT for this ObjectClass.
+     */
+    private static void buildMust( ObjectClass objectClass, List<Throwable> errors, Registries registries )
+    {
+        AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
+        List<String> mustAttributeTypeOids = objectClass.getMustAttributeTypeOids();
+
+        if ( mustAttributeTypeOids != null )
+        {
+            objectClass.getMustAttributeTypes().clear();
+
+            for ( String mustAttributeTypeName : mustAttributeTypeOids )
+            {
+                try
+                {
+                    AttributeType attributeType = atRegistry.lookup( mustAttributeTypeName );
+
+                    if ( attributeType.isCollective() )
+                    {
+                        // Collective Attributes are not allowed in MAY or MUST
+                        String msg = I18n.err( I18n.ERR_04484_COLLECTIVE_NOT_ALLOWED_IN_MUST, mustAttributeTypeName,
+                            objectClass.getOid() );
+
+                        LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                            LdapSchemaExceptionCodes.OC_COLLECTIVE_NOT_ALLOWED_IN_MUST, msg );
+                        ldapSchemaException.setSourceObject( objectClass );
+                        ldapSchemaException.setRelatedId( mustAttributeTypeName );
+                        errors.add( ldapSchemaException );
+                        LOG.info( msg );
+
+                        continue;
+                    }
+
+                    if ( objectClass.getMustAttributeTypes().contains( attributeType ) )
+                    {
+                        // Already registered : this is an error
+                        String msg = I18n.err( I18n.ERR_04324, objectClass.getOid(), mustAttributeTypeName );
+
+                        LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                            LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MUST, msg );
+                        ldapSchemaException.setSourceObject( objectClass );
+                        ldapSchemaException.setRelatedId( mustAttributeTypeName );
+                        errors.add( ldapSchemaException );
+                        LOG.info( msg );
+
+                        continue;
+                    }
+
+                    // Check that the MUST AT is not also present in the MAY AT
+                    if ( objectClass.getMayAttributeTypes().contains( attributeType ) )
+                    {
+                        // Already registered : this is an error
+                        String msg = I18n.err( I18n.ERR_04325, objectClass.getOid(), mustAttributeTypeName );
+
+                        LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                            LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY_AND_MUST,
+                            msg );
+                        ldapSchemaException.setSourceObject( objectClass );
+                        ldapSchemaException.setRelatedId( mustAttributeTypeName );
+                        errors.add( ldapSchemaException );
+                        LOG.info( msg );
+
+                        continue;
+                    }
+
+                    objectClass.getMustAttributeTypes().add( attributeType );
+                }
+                catch ( LdapException ne )
+                {
+                    // Cannot find the AT
+                    String msg = I18n.err( I18n.ERR_04326, objectClass.getOid(), mustAttributeTypeName );
+
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.OC_NONEXISTENT_MUST_AT, msg, ne );
+                    ldapSchemaException.setSourceObject( objectClass );
+                    ldapSchemaException.setRelatedId( mustAttributeTypeName );
+                    errors.add( ldapSchemaException );
+                    LOG.info( msg );
+
+                    continue;
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * Build and check the MAY AT for this ObjectClass
+     */
+    private static void buildMay( ObjectClass objectClass, List<Throwable> errors, Registries registries )
+    {
+        AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
+        List<String> mayAttributeTypeOids = objectClass.getMayAttributeTypeOids();
+
+        if ( mayAttributeTypeOids != null )
+        {
+            objectClass.getMayAttributeTypes().clear();
+
+            for ( String mayAttributeTypeName : mayAttributeTypeOids )
+            {
+                try
+                {
+                    AttributeType attributeType = atRegistry.lookup( mayAttributeTypeName );
+
+                    if ( attributeType.isCollective() )
+                    {
+                        // Collective Attributes are not allowed in MAY or MUST
+                        String msg = I18n.err( I18n.ERR_04485_COLLECTIVE_NOT_ALLOWED_IN_MAY, mayAttributeTypeName, objectClass.getOid() );
+
+                        LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                            LdapSchemaExceptionCodes.OC_COLLECTIVE_NOT_ALLOWED_IN_MAY, msg );
+                        ldapSchemaException.setSourceObject( objectClass );
+                        ldapSchemaException.setRelatedId( mayAttributeTypeName );
+                        errors.add( ldapSchemaException );
+                        LOG.info( msg );
+
+                        continue;
+                    }
+
+                    if ( objectClass.getMayAttributeTypes().contains( attributeType ) )
+                    {
+                        // Already registered : this is an error
+                        String msg = I18n.err( I18n.ERR_04322, objectClass.getOid(), mayAttributeTypeName );
+
+                        LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                            LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY, msg );
+                        ldapSchemaException.setSourceObject( objectClass );
+                        ldapSchemaException.setRelatedId( mayAttributeTypeName );
+                        errors.add( ldapSchemaException );
+                        LOG.info( msg );
+
+                        continue;
+                    }
+
+                    objectClass.getMayAttributeTypes().add( attributeType );
+                }
+                catch ( LdapException ne )
+                {
+                    // Cannot find the AT
+                    String msg = I18n.err( I18n.ERR_04323, objectClass.getOid(), mayAttributeTypeName );
+
+                    LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                        LdapSchemaExceptionCodes.OC_NONEXISTENT_MAY_AT, msg, ne );
+                    ldapSchemaException.setSourceObject( objectClass );
+                    ldapSchemaException.setRelatedId( mayAttributeTypeName );
+                    errors.add( ldapSchemaException );
+                    LOG.info( msg );
+
+                    continue;
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * Remove the ObjectClass from the registries, updating the references to
+     * other SchemaObject.
+     *
+     * If one of the referenced SchemaObject does not exist (SUPERIORS, MAY, MUST),
+     * an exception is thrown.
+     *
+     * @param objectClass The ObjectClass to remove fro the registries
+     * @param errors The errors we got while removing the ObjectClass from the registries
+     * @param registries The Registries
+     * @exception If the ObjectClass is not valid
+     */
+    public static void removeFromRegistries( ObjectClass objectClass, List<Throwable> errors, Registries registries ) throws LdapException
+    {
+        if ( registries != null )
+        {
+            ObjectClassRegistry objectClassRegistry = registries.getObjectClassRegistry();
+
+            // Unregister this ObjectClass into the Descendant map
+            objectClassRegistry.unregisterDescendants( objectClass, objectClass.getSuperiors() );
+
+            /**
+             * Remove the OC references (using and usedBy) :
+             * OC -> AT (for MAY and MUST)
+             * OC -> OC
+             */
+            if ( objectClass.getMayAttributeTypes() != null )
+            {
+                for ( AttributeType may : objectClass.getMayAttributeTypes() )
+                {
+                    registries.delReference( objectClass, may );
+                }
+            }
+
+            if ( objectClass.getMustAttributeTypes() != null )
+            {
+                for ( AttributeType must : objectClass.getMustAttributeTypes() )
+                {
+                    registries.delReference( objectClass, must );
+                }
+            }
+
+            if ( objectClass.getSuperiors() != null )
+            {
+                for ( ObjectClass superior : objectClass.getSuperiors() )
+                {
+                    registries.delReference( objectClass, superior );
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AccessPointSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AccessPointSyntaxChecker.java
new file mode 100644
index 0000000..6c3abbf
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AccessPointSyntaxChecker.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is an AccessPoint.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class AccessPointSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( AccessPointSyntaxChecker.class );
+
+
+    /**
+     * The AccessPoint SyntaxChecker constructor
+     */
+    public AccessPointSyntaxChecker()
+    {
+        super( SchemaConstants.ACCESS_POINT_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AttributeTypeDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AttributeTypeDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..d842c28
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AttributeTypeDescriptionSyntaxChecker.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.AttributeTypeDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * attribute type descripton syntax according to RFC 4512, par 4.2.2:
+ * 
+*  <pre>
+ * AttributeTypeDescription = LPAREN WSP
+ *     numericoid                    ; object identifier
+ *     [ SP "NAME" SP qdescrs ]      ; short names (descriptors)
+ *     [ SP "DESC" SP qdstring ]     ; description
+ *     [ SP "OBSOLETE" ]             ; not active
+ *     [ SP "SUP" SP oid ]           ; supertype
+ *     [ SP "EQUALITY" SP oid ]      ; equality matching rule
+ *     [ SP "ORDERING" SP oid ]      ; ordering matching rule
+ *     [ SP "SUBSTR" SP oid ]        ; substrings matching rule
+ *     [ SP "SYNTAX" SP noidlen ]    ; value syntax
+ *     [ SP "SINGLE-VALUE" ]         ; single-value
+ *     [ SP "COLLECTIVE" ]           ; collective
+ *     [ SP "NO-USER-MODIFICATION" ] ; not user modifiable
+ *     [ SP "USAGE" SP usage ]       ; usage
+ *     extensions WSP RPAREN         ; extensions
+ * 
+ * usage = "userApplications"     /  ; user
+ *         "directoryOperation"   /  ; directory operational
+ *         "distributedOperation" /  ; DSA-shared operational
+ *         "dSAOperation"            ; DSA-specific operational     
+ * 
+ * extensions = *( SP xstring SP qdstrings )
+ * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+ * 
+ * Each attribute type description must contain at least one of the SUP
+ * or SYNTAX fields. 
+ * 
+ * COLLECTIVE requires usage userApplications.
+ * 
+ * NO-USER-MODIFICATION requires an operational usage.
+ * 
+ * 
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class AttributeTypeDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( AttributeTypeDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the AttributeTypeDescription Syntax */
+    private AttributeTypeDescriptionSchemaParser schemaParser = new AttributeTypeDescriptionSchemaParser();
+
+
+    /**
+     * 
+     * Creates a new instance of AttributeTypeDescriptionSchemaParser.
+     *
+     */
+    public AttributeTypeDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.ATTRIBUTE_TYPE_DESCRIPTION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseAttributeTypeDescription( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AttributeTypeUsageSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AttributeTypeUsageSyntaxChecker.java
new file mode 100644
index 0000000..f00c93a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AttributeTypeUsageSyntaxChecker.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A syntax checker which checks to see if an attributeType's type is either: 
+ * userApplications
+ * directoryOperation
+ * distributedOperation
+ * dSAOperation
+.*  The case is NOT ignored.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class AttributeTypeUsageSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( AttributeTypeUsageSyntaxChecker.class );
+
+
+    /**
+     * 
+     * Creates a new instance of AttributeTypeUsageSyntaxChecker.
+     *
+     */
+    public AttributeTypeUsageSyntaxChecker()
+    {
+        super( SchemaConstants.ATTRIBUTE_TYPE_USAGE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( ( strValue.length() < "userApplications".length() )
+            || ( strValue.length() > "userApplications".length() ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        char ch = strValue.charAt( 0 );
+
+        switch ( ch )
+        {
+            case ( 'd' ):
+                if ( "dSAOperation".equals( strValue )
+                    || "directoryOperation".equals( strValue )
+                    || "distributedOperation".equals( strValue ) )
+                {
+                    LOG.debug( "Syntax valid for '{}'", value );
+                    return true;
+                }
+
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+
+            case ( 'u' ):
+                boolean comp = "userApplications".equals( strValue );
+
+                if ( comp )
+                {
+                    LOG.debug( "Syntax valid for '{}'", value );
+                }
+                else
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+
+                }
+
+                return comp;
+
+            default:
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AudioSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AudioSyntaxChecker.java
new file mode 100644
index 0000000..218341d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/AudioSyntaxChecker.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is an Audio according to RFC 2252.
+ * 
+ * The encoding of a value with Audio syntax is the octets of the value
+ * itself, an 8KHz uncompressed encoding compatible with the SunOS 
+ * 4.1.3 'play' utility. We implement it as a binary element.
+ * 
+ * It has been removed in RFC 4517
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class AudioSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( AudioSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of AudioSyntaxChecker
+     */
+    public AudioSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.AUDIO_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BinarySyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BinarySyntaxChecker.java
new file mode 100644
index 0000000..9df5238
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BinarySyntaxChecker.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A binary value (universal value acceptor) syntax checker.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class BinarySyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( BinarySyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of BinarySyntaxChecker
+     */
+    public BinarySyntaxChecker()
+    {
+        super( SchemaConstants.BINARY_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BitStringSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BitStringSyntaxChecker.java
new file mode 100644
index 0000000..acd0f58
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BitStringSyntaxChecker.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Boolean according to RFC 4517.
+ * 
+ * From RFC 4512 & RFC 4517 :
+ * 
+ * BitString    = SQUOTE *binary-digit SQUOTE "B"
+ * binary-digit = "0" / "1"
+ * SQUOTE  = %x27                           ; hyphen ("'")
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class BitStringSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( BitStringSyntaxChecker.class );
+
+
+    /**
+     * 
+     * Creates a new instance of BitStringSyntaxChecker.
+     *
+     */
+    public BitStringSyntaxChecker()
+    {
+        super( SchemaConstants.BIT_STRING_SYNTAX );
+    }
+
+
+    /**
+     * A shared and static method used to check that the string is a BitString.
+     * A BitString is a string of bits, between quotes and followed by a 'B' :
+     * 
+     * '01010110'B for instance
+     * 
+     * @param strValue The string to check
+     * @return <code>true</code> if the string is a BitString
+     */
+    public static boolean isValid( String strValue )
+    {
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", strValue );
+            return false;
+        }
+
+        int pos = 0;
+
+        // Check that the String respect the syntax : ' ([01]+) ' B
+        if ( !Strings.isCharASCII( strValue, pos++, '\'' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", strValue );
+            return false;
+        }
+
+        // We must have at least one bit
+        if ( !Chars.isBit( strValue, pos++ ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", strValue );
+            return false;
+        }
+
+        while ( Chars.isBit( strValue, pos ) )
+        {
+            // Loop until we get a char which is not a 0 or a 1
+            pos++;
+        }
+
+        // Now, we must have a simple quote 
+        if ( !Strings.isCharASCII( strValue, pos++, '\'' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", strValue );
+            return false;
+        }
+
+        // followed by a 'B'
+        if ( !Strings.isCharASCII( strValue, pos, 'B' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", strValue );
+            return false;
+        }
+
+        LOG.debug( "Syntax valid for '{}'", strValue );
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        return isValid( strValue );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BooleanSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BooleanSyntaxChecker.java
new file mode 100644
index 0000000..511c2f2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/BooleanSyntaxChecker.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Boolean according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * 
+ * Boolean = "TRUE" / "FALSE"
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class BooleanSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( BooleanSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of BooleanSyntaxChecker.
+     */
+    public BooleanSyntaxChecker()
+    {
+        super( SchemaConstants.BOOLEAN_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", strValue );
+            return false;
+        }
+
+        boolean valid = ( ( "TRUE".equalsIgnoreCase( strValue ) ) || ( "FALSE".equalsIgnoreCase( strValue ) ) );
+
+        if ( valid )
+        {
+            LOG.debug( "Syntax valid for '{}'", strValue );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", strValue );
+        }
+
+        return valid;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificateListSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificateListSyntaxChecker.java
new file mode 100644
index 0000000..af5aa43
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificateListSyntaxChecker.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a certificateList according to RFC 4523 :
+ * 
+ * "Due to changes made to the definition of a CertificateList through time,
+ *  no LDAP-specific encoding is defined for this syntax.  Values of this
+ *  syntax SHOULD be encoded using Distinguished Encoding Rules (DER)
+ *  [X.690] and MUST only be transferred using the ;binary transfer
+ *  option"
+ * 
+ * It has been removed in RFC 4517
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CertificateListSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CertificateListSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of CertificateListSyntaxChecker.
+     */
+    public CertificateListSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.CERTIFICATE_LIST_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificatePairSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificatePairSyntaxChecker.java
new file mode 100644
index 0000000..70982f4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificatePairSyntaxChecker.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a certificate pair according to RFC 4523 :
+ * 
+ * "Due to changes made to the definition of a CertificatePair through time,
+ *  no LDAP-specific encoding is defined for this syntax.  Values of this
+ *  syntax SHOULD be encoded using Distinguished Encoding Rules (DER)
+ *  [X.690] and MUST only be transferred using the ;binary transfer
+ *  option"
+ * 
+ * It has been removed in RFC 4517
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CertificatePairSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CertificatePairSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of CertificatePairSyntaxChecker.
+     */
+    public CertificatePairSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.CERTIFICATE_PAIR_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificateSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificateSyntaxChecker.java
new file mode 100644
index 0000000..516b892
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CertificateSyntaxChecker.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a certificate according to RFC 4523 :
+ * 
+ * "Due to changes made to the definition of a Certificate through time,
+ *  no LDAP-specific encoding is defined for this syntax.  Values of this
+ *  syntax SHOULD be encoded using Distinguished Encoding Rules (DER)
+ *  [X.690] and MUST only be transferred using the ;binary transfer
+ *  option"
+ * 
+ * It has been removed in RFC 4517
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CertificateSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CertificateSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of CertificateSyntaxChecker.
+     */
+    public CertificateSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.CERTIFICATE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ComparatorSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ComparatorSyntaxChecker.java
new file mode 100644
index 0000000..895ad64
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ComparatorSyntaxChecker.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+
+
+/**
+ * A SyntaxChecker for the Comparator schema element
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class ComparatorSyntaxChecker extends Ia5StringSyntaxChecker
+{
+    /**
+     * 
+     * Creates a new instance of ComparatorSyntaxChecker.
+     *
+     */
+    public ComparatorSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.COMPARATOR_SYNTAX );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CountrySyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CountrySyntaxChecker.java
new file mode 100644
index 0000000..b6e63f2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CountrySyntaxChecker.java
@@ -0,0 +1,368 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a country according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * 
+ * A value of the Country String syntax is one of the two-character
+ * codes from ISO 3166 [ISO3166] for representing a country.
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CountrySyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CountrySyntaxChecker.class );
+
+    /** The ISO 3166 list of countries, as of 2006 */
+    private static final String[] COUNTRY_ISO_3166 =
+        {
+            "AD",
+            "AE",
+            "AF",
+            "AG",
+            "AI",
+            "AL",
+            "AM",
+            "AN",
+            "AO",
+            "AQ",
+            "AR",
+            "AS",
+            "AT",
+            "AU",
+            "AW",
+            "AX",
+            "AZ",
+            "BA",
+            "BB",
+            "BD",
+            "BE",
+            "BF",
+            "BG",
+            "BH",
+            "BI",
+            "BJ",
+            "BM",
+            "BN",
+            "BO",
+            "BR",
+            "BS",
+            "BT",
+            "BV",
+            "BW",
+            "BY",
+            "BZ",
+            "CA",
+            "CC",
+            "CD",
+            "CF",
+            "CG",
+            "CH",
+            "CI",
+            "CK",
+            "CL",
+            "CM",
+            "CN",
+            "CO",
+            "CR",
+            "CU",
+            "CV",
+            "CX",
+            "CY",
+            "CZ",
+            "DE",
+            "DJ",
+            "DK",
+            "DM",
+            "DO",
+            "DZ",
+            "EC",
+            "EE",
+            "EG",
+            "EH",
+            "ER",
+            "ES",
+            "ET",
+            "FI",
+            "FJ",
+            "FK",
+            "FM",
+            "FO",
+            "FR",
+            "GA",
+            "GB",
+            "GD",
+            "GE",
+            "GG",
+            "GF",
+            "GH",
+            "GI",
+            "GL",
+            "GM",
+            "GN",
+            "GP",
+            "GQ",
+            "GR",
+            "GS",
+            "GT",
+            "GU",
+            "GW",
+            "GY",
+            "HK",
+            "HM",
+            "HN",
+            "HR",
+            "HT",
+            "HU",
+            "ID",
+            "IE",
+            "IL",
+            "IM",
+            "IN",
+            "IO",
+            "IQ",
+            "IR",
+            "IS",
+            "IT",
+            "JE",
+            "JM",
+            "JO",
+            "JP",
+            "KE",
+            "KG",
+            "KH",
+            "KI",
+            "KM",
+            "KN",
+            "KP",
+            "KR",
+            "KW",
+            "KY",
+            "KZ",
+            "LA",
+            "LB",
+            "LC",
+            "LI",
+            "LK",
+            "LR",
+            "LS",
+            "LT",
+            "LU",
+            "LV",
+            "LY",
+            "MA",
+            "MC",
+            "MD",
+            "ME",
+            "MG",
+            "MH",
+            "MK",
+            "ML",
+            "MM",
+            "MN",
+            "MO",
+            "MP",
+            "MQ",
+            "MR",
+            "MS",
+            "MT",
+            "MU",
+            "MV",
+            "MW",
+            "MX",
+            "MY",
+            "MZ",
+            "NA",
+            "NC",
+            "NE",
+            "NF",
+            "NG",
+            "NI",
+            "NL",
+            "NO",
+            "NP",
+            "NR",
+            "NU",
+            "NZ",
+            "OM",
+            "PA",
+            "PE",
+            "PF",
+            "PG",
+            "PH",
+            "PK",
+            "PL",
+            "PM",
+            "PN",
+            "PR",
+            "PS",
+            "PT",
+            "PW",
+            "PY",
+            "QA",
+            "RE",
+            "RO",
+            "RS",
+            "RU",
+            "RW",
+            "SA",
+            "SB",
+            "SC",
+            "SD",
+            "SE",
+            "SG",
+            "SH",
+            "SI",
+            "SJ",
+            "SK",
+            "SL",
+            "SM",
+            "SN",
+            "SO",
+            "SR",
+            "ST",
+            "SV",
+            "SY",
+            "SZ",
+            "TC",
+            "TD",
+            "TF",
+            "TG",
+            "TH",
+            "TJ",
+            "TK",
+            "TL",
+            "TM",
+            "TN",
+            "TO",
+            "TR",
+            "TT",
+            "TV",
+            "TW",
+            "TZ",
+            "UA",
+            "UG",
+            "UM",
+            "US",
+            "UY",
+            "UZ",
+            "VA",
+            "VC",
+            "VE",
+            "VG",
+            "VI",
+            "VN",
+            "VU",
+            "WF",
+            "WS",
+            "YE",
+            "YT",
+            "ZA",
+            "ZM",
+            "ZW"
+    };
+
+    /** The Set which contains the countries */
+    private static final Set<String> COUNTRIES = new HashSet<String>();
+
+    /** Initialization of the country set */
+    static
+    {
+        for ( String country : COUNTRY_ISO_3166 )
+        {
+            COUNTRIES.add( country );
+        }
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of CountrySyntaxChecker.
+     *
+     */
+    public CountrySyntaxChecker()
+    {
+        super( SchemaConstants.COUNTRY_STRING_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        boolean result = COUNTRIES.contains( Strings.toUpperCaseAscii( strValue ) );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CsnSidSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CsnSidSyntaxChecker.java
new file mode 100644
index 0000000..8409870
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CsnSidSyntaxChecker.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, eCopyOfUuidSyntaxCheckerither express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An CSN SID syntax checker.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CsnSidSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CsnSidSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of CsnSyntaxChecker.
+     */
+    public CsnSidSyntaxChecker()
+    {
+        super( SchemaConstants.CSN_SID_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( !( value instanceof String ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        String sidStr = ( String ) value;
+
+        if ( sidStr.length() > 3 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The SID must be an hexadecimal number between 0x00 and 0xFFF
+
+        try
+        {
+            int sid = Integer.parseInt( sidStr, 16 );
+
+            if ( ( sid < 0 ) || ( sid > 0x0fff ) )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+        }
+        catch ( NumberFormatException nfe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CsnSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CsnSyntaxChecker.java
new file mode 100644
index 0000000..780e410
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/CsnSyntaxChecker.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, eCopyOfUuidSyntaxCheckerither express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.csn.Csn;
+import org.apache.directory.api.ldap.model.csn.InvalidCSNException;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An CSN syntax checker.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class CsnSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( CsnSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of CsnSyntaxChecker.
+     */
+    public CsnSyntaxChecker()
+    {
+        super( SchemaConstants.CSN_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( !( value instanceof String ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        String csnStr = ( String ) value;
+
+        // It must be a valid CSN : try to create a new one.
+        try
+        {
+            boolean result = Csn.isValid( csnStr );
+
+            if ( result )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+            }
+            else
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+            }
+
+            return result;
+        }
+        catch ( InvalidCSNException icsne )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DataQualitySyntaxSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DataQualitySyntaxSyntaxChecker.java
new file mode 100644
index 0000000..3819b11
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DataQualitySyntaxSyntaxChecker.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a DataQualitySyntax.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DataQualitySyntaxSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DataQualitySyntaxSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of DataQualitySyntaxSyntaxChecker.
+     */
+    public DataQualitySyntaxSyntaxChecker()
+    {
+        super( SchemaConstants.DATA_QUALITY_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DeliveryMethodSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DeliveryMethodSyntaxChecker.java
new file mode 100644
index 0000000..264a37a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DeliveryMethodSyntaxChecker.java
@@ -0,0 +1,220 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a delivery method 
+ * according to RFC 4517.
+ * 
+ * From RFC 4517 & RFC 4512:
+ * 
+ * DeliveryMethod = pdm *( WSP DOLLAR WSP pdm )
+ *
+ * pdm = "any" | "mhs" | "physical" | "telex" | "teletex" |
+ *       "g3fax" | "g4fax" | "ia5" | "videotex" | "telephone"
+ *           
+ * WSP     = 0*SPACE  ; zero or more " "
+ * DOLLAR  = %x24 ; dollar sign ("$")
+ * SPACE   = %x20 ; space (" ")
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DeliveryMethodSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DeliveryMethodSyntaxChecker.class );
+
+    private static final String[] PDMS =
+        {
+            "any", "mhs", "physical", "telex", "teletex",
+            "g3fax", "g4fax", "ia5", "videotex", "telephone"
+    };
+
+    /** The Set which contains the delivery methods */
+    private static final Set<String> DELIVERY_METHODS = new HashSet<String>();
+
+    /** Initialization of the delivery methods set */
+    static
+    {
+        for ( String country : PDMS )
+        {
+            DELIVERY_METHODS.add( country );
+        }
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of DeliveryMethodSyntaxChecker.
+     *
+     */
+    public DeliveryMethodSyntaxChecker()
+    {
+        super( SchemaConstants.DELIVERY_METHOD_SYNTAX );
+    }
+
+
+    /**
+     * 
+     * Check if the string contains a delivery method which has 
+     * not already been found.
+     * 
+     * @param strValue The string we want to look into for a PDM 
+     * @param pos The current position in the string
+     * @param pdms The set containing all the PDM
+     * @return if a Prefered Delivery Method is found in the given string, returns 
+     * its position, otherwise, returns -1
+     */
+    private int isPdm( String strValue, int start, Set<String> pdms )
+    {
+        int pos = start;
+
+        while ( Chars.isAlphaDigit( strValue, pos ) )
+        {
+            pos++;
+        }
+
+        // No ascii string, this is not a delivery method
+        if ( pos == start )
+        {
+            return -1;
+        }
+
+        String pdm = strValue.substring( start, pos );
+
+        if ( !DELIVERY_METHODS.contains( pdm ) )
+        {
+            // The delivery method is unknown
+            return -1;
+        }
+        else
+        {
+            if ( pdms.contains( pdm ) )
+            {
+                // The delivery method has already been found
+                return -1;
+            }
+            else
+            {
+                pdms.add( pdm );
+                return pos;
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // We will get the first delivery method
+        int length = strValue.length();
+        int pos = 0;
+        Set<String> pmds = new HashSet<String>();
+
+        pos = isPdm( strValue, pos, pmds );
+        if ( pos == -1 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // We have found at least the first pmd,
+        // now iterate through the other ones. We may have
+        // SP* '$' SP* before each pmd.
+        while ( pos < length )
+        {
+            // Skip spaces
+            while ( Strings.isCharASCII( strValue, pos, ' ' ) )
+            {
+                pos++;
+            }
+
+            if ( !Strings.isCharASCII( strValue, pos, '$' ) )
+            {
+                // A '$' was expected
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+            else
+            {
+                pos++;
+            }
+
+            // Skip spaces
+            while ( Strings.isCharASCII( strValue, pos, ' ' ) )
+            {
+                pos++;
+            }
+
+            pos = isPdm( strValue, pos, pmds );
+            if ( pos == -1 )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+        }
+
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DerefAliasSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DerefAliasSyntaxChecker.java
new file mode 100644
index 0000000..27e0039
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DerefAliasSyntaxChecker.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid DerefAlias. We
+ * have four possible values :
+ * <ul>
+ * <li>NEVER</li>
+ * <li>SEARCHING</li>
+ * <li>FINDING</li>
+ * <li>ALWAYS</li>
+ * </ul>
+ * The value is case insensitive
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DerefAliasSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DerefAliasSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of DerefAliasSyntaxChecker.
+     */
+    public DerefAliasSyntaxChecker()
+    {
+        super( SchemaConstants.DEREF_ALIAS_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        strValue = Strings.trim( Strings.toLowerCase( strValue ) );
+
+        return ( "never".equals( strValue ) || "finding".equals( strValue ) || "searching".equals( strValue ) || "always"
+            .equals( strValue ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DirectoryStringSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DirectoryStringSyntaxChecker.java
new file mode 100644
index 0000000..e8719843c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DirectoryStringSyntaxChecker.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Directory String according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * DirectoryString = 1*UTF8
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DirectoryStringSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DirectoryStringSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of DirectoryStringSyntaxChecker.
+     */
+    public DirectoryStringSyntaxChecker()
+    {
+        super( SchemaConstants.DIRECTORY_STRING_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        // If the value was an invalid UTF8 string, then it's length
+        // will be 0 as the StringTools.utf8ToString() call will
+        // return an empty string
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // In any other case, we have to check that the
+        // string does not contains the '0xFFFD' character
+        for ( char c : strValue.toCharArray() )
+        {
+            if ( c == 0xFFFD )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+        }
+
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DitContentRuleDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DitContentRuleDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..f2b7fb2
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DitContentRuleDescriptionSyntaxChecker.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.DitContentRuleDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * DIT content rule descripton syntax according to RFC 4512, par 4.2.6:
+ * 
+ * <pre>
+ * DITContentRuleDescription = LPAREN WSP
+ *    numericoid                 ; object identifier
+ *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+ *    [ SP "DESC" SP qdstring ]  ; description
+ *    [ SP "OBSOLETE" ]          ; not active
+ *    [ SP "AUX" SP oids ]       ; auxiliary object classes
+ *    [ SP "MUST" SP oids ]      ; attribute types
+ *    [ SP "MAY" SP oids ]       ; attribute types
+ *    [ SP "NOT" SP oids ]       ; attribute types
+ *    extensions WSP RPAREN      ; extensions
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DitContentRuleDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DitContentRuleDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the DITContentRuleDescription Syntax */
+    private DitContentRuleDescriptionSchemaParser schemaParser = new DitContentRuleDescriptionSchemaParser();
+
+
+    /**
+     * Creates a new instance of DITContentRuleDescriptionSyntaxChecker.
+     */
+    public DitContentRuleDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.DIT_CONTENT_RULE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseDITContentRuleDescription( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DitStructureRuleDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DitStructureRuleDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..4839d74
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DitStructureRuleDescriptionSyntaxChecker.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.DitStructureRuleDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * DIT structure rule descripton syntax according to RFC 4512, par 4.2.7.1:
+ * 
+ * <pre>
+ * DITStructureRuleDescription = LPAREN WSP
+ *   ruleid                     ; rule identifier
+ *   [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+ *   [ SP "DESC" SP qdstring ]  ; description
+ *   [ SP "OBSOLETE" ]          ; not active
+ *   SP "FORM" SP oid           ; NameForm
+ *   [ SP "SUP" ruleids ]       ; superior rules
+ *   extensions WSP RPAREN      ; extensions
+ *
+ * ruleids = ruleid / ( LPAREN WSP ruleidlist WSP RPAREN )
+ * ruleidlist = ruleid *( SP ruleid )
+ * ruleid = numbers
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DitStructureRuleDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DitStructureRuleDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the DITContentRuleDescription Syntax */
+    private DitStructureRuleDescriptionSchemaParser schemaParser = new DitStructureRuleDescriptionSchemaParser();
+
+
+    /**
+     * Creates a new instance of DITContentRuleDescriptionSyntaxChecker.
+     */
+    public DitStructureRuleDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.DIT_STRUCTURE_RULE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseDITStructureRuleDescription( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DlSubmitPermissionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DlSubmitPermissionSyntaxChecker.java
new file mode 100644
index 0000000..7d9058d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DlSubmitPermissionSyntaxChecker.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a DLSubmitPermission.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DlSubmitPermissionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DlSubmitPermissionSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of DLSubmitPermissionSyntaxChecker.
+     */
+    public DlSubmitPermissionSyntaxChecker()
+    {
+        super( SchemaConstants.DL_SUBMIT_PERMISSION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DnSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DnSyntaxChecker.java
new file mode 100644
index 0000000..aa72a3c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DnSyntaxChecker.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid Dn. We just check
+ * that the Dn is valid, we don't need to verify each of the Rdn syntax.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DnSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DnSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of DNSyntaxChecker.
+     */
+    public DnSyntaxChecker()
+    {
+        super( SchemaConstants.DN_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            // TODO: this should be a false, but for 
+            // some reason, the principal is empty in 
+            // some cases.
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+
+        // Check that the value is a valid Dn
+        boolean result = Dn.isValid( strValue );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DsaQualitySyntaxSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DsaQualitySyntaxSyntaxChecker.java
new file mode 100644
index 0000000..5625fdf
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DsaQualitySyntaxSyntaxChecker.java
@@ -0,0 +1,180 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a DSAQualitySyntax according to 
+ * http://tools.ietf.org/id/draft-ietf-asid-ldapv3-attributes-03.txt, par 5.2.2.2 :
+ * 
+ * <DsaQualitySyntax> ::= <DSAKeyword> [ '#' <description> ]
+ *
+ * <DSAKeyword> ::= 'DEFUNCT' | 'EXPERIMENTAL' | 'BEST-EFFORT' |
+ *                  'PILOT-SERVICE' | 'FULL-SERVICE'
+ *
+ * <description> ::= encoded as a PrintableString
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DsaQualitySyntaxSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DsaQualitySyntaxSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of DSAQualitySyntaxSyntaxChecker.
+     */
+    public DsaQualitySyntaxSyntaxChecker()
+    {
+        super( SchemaConstants.DSA_QUALITY_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() < 7 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        String remaining = null;
+
+        switch ( strValue.charAt( 0 ) )
+        {
+            case 'B':
+                if ( !strValue.startsWith( "BEST-EFFORT" ) )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                remaining = strValue.substring( "BEST-EFFORT".length() );
+                break;
+
+            case 'D':
+                if ( !strValue.startsWith( "DEFUNCT" ) )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                remaining = strValue.substring( "DEFUNCT".length() );
+                break;
+
+            case 'E':
+                if ( !strValue.startsWith( "EXPERIMENTAL" ) )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                remaining = strValue.substring( "EXPERIMENTAL".length() );
+                break;
+
+            case 'F':
+                if ( !strValue.startsWith( "FULL-SERVICE" ) )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                remaining = strValue.substring( "FULL-SERVICE".length() );
+                break;
+
+            case 'P':
+                if ( !strValue.startsWith( "PILOT-SERVICE" ) )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                remaining = strValue.substring( "PILOT-SERVICE".length() );
+                break;
+
+            default:
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+        }
+
+        // Now, we might have a description separated from the keyword by a '#'
+        // but this is optional
+        if ( remaining.length() == 0 )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+
+        if ( remaining.charAt( 0 ) != '#' )
+        {
+            // We were expecting a '#'
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Check that the description is a PrintableString
+        boolean result = Strings.isPrintableString( remaining.substring( 1 ) );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DseTypeSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DseTypeSyntaxChecker.java
new file mode 100644
index 0000000..de7fd50
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DseTypeSyntaxChecker.java
@@ -0,0 +1,202 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a DSEType according to 
+ * http://tools.ietf.org/id/draft-ietf-asid-ldapv3-attributes-03.txt, par 6.2.1.5 :
+ * 
+ * <DSEType>    ::= '(' <sp>* <DSEBit> <sp>* <DSEBitList> ')'
+ * <DSEBitList> ::= '$' <sp>* <DSEBit> <sp>* <DSEBitList> | e      
+ * <DSEBit>     ::= 'root' | 'glue' | 'cp' | 'entry' | 'alias' | 'subr' |
+ *                  'nssr' | 'supr' | 'xr' | 'admPoint' | 'subentry' |
+ *                  'shadow' | 'zombie' | 'immSupr' | 'rhob' | 'sa'
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DseTypeSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DseTypeSyntaxChecker.class );
+
+    /** The DSE BITS keywords */
+    private static final String[] DSE_BITS_STRINGS =
+        {
+            "root", "glue", "cp", "entry", "alias", "subr",
+            "nssr", "supr", "xr", "admPoint", "subentry",
+            "shadow", "zombie", "immSupr", "rhob", "sa"
+    };
+
+    /** The Set which contains the DESBits */
+    private static final Set<String> DSE_BITS = new HashSet<String>();
+
+    /** Initialization of the country set */
+    static
+    {
+        for ( String country : DSE_BITS_STRINGS )
+        {
+            DSE_BITS.add( country );
+        }
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of DSETypeSyntaxChecker.
+     *
+     */
+    public DseTypeSyntaxChecker()
+    {
+        super( SchemaConstants.DSE_TYPE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        // We must have at least '(cp)', '(xr)' or '(ca)'
+        if ( strValue.length() < 4 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Check the opening and closing parenthesis
+        if ( ( strValue.charAt( 0 ) != '(' )
+            || ( strValue.charAt( strValue.length() - 1 ) != ')' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        Set<String> keywords = new HashSet<String>();
+        int len = strValue.length() - 1;
+        boolean needKeyword = true;
+
+        // 
+        for ( int i = 1; i < len; /* */)
+        {
+            // Skip spaces
+            while ( ( i < len ) && ( strValue.charAt( i ) == ' ' ) )
+            {
+                i++;
+            }
+
+            int pos = i;
+
+            // Search for a keyword
+            while ( ( i < len ) && Chars.isAlphaASCII( strValue, pos ) )
+            {
+                pos++;
+            }
+
+            if ( pos == i )
+            {
+                // No keyword : error
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            String keyword = strValue.substring( i, pos );
+            i = pos;
+
+            if ( !DSE_BITS.contains( keyword ) )
+            {
+                // Unknown keyword
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            // Check that the keyword has not been met
+            if ( keywords.contains( keyword ) )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            keywords.add( keyword );
+            needKeyword = false;
+
+            // Skip spaces
+            while ( ( i < len ) && ( strValue.charAt( i ) == ' ' ) )
+            {
+                i++;
+            }
+
+            // Do we have another keyword ?
+            if ( ( i < len ) && ( strValue.charAt( i ) == '$' ) )
+            {
+                // yes
+                i++;
+                needKeyword = true;
+                continue;
+            }
+        }
+
+        // We are done
+        if ( needKeyword )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+
+        return !needKeyword;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/EnhancedGuideSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/EnhancedGuideSyntaxChecker.java
new file mode 100644
index 0000000..21d6a1e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/EnhancedGuideSyntaxChecker.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is an EnhancedGuide according to 
+ * RFC 4517.
+ *
+ * Implemented as binary right now...
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class EnhancedGuideSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( EnhancedGuideSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of EnhancedGuideSyntaxChecker.
+     */
+    public EnhancedGuideSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.ENHANCED_GUIDE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/FacsimileTelephoneNumberSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/FacsimileTelephoneNumberSyntaxChecker.java
new file mode 100644
index 0000000..8aa7e16
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/FacsimileTelephoneNumberSyntaxChecker.java
@@ -0,0 +1,215 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a facsimile TelephoneNumber according 
+ * to ITU recommendation E.123 for the Telephone number part, and from RFC 4517, par. 
+ * 3.3.11 :
+ * 
+ * fax-number       = telephone-number *( DOLLAR fax-parameter )
+ * telephone-number = PrintableString
+ * fax-parameter    = "twoDimensional" |
+ *                    "fineResolution" |
+ *                    "unlimitedLength" |
+ *                    "b4Length" |
+ *                    "a3Width" |
+ *                    "b4Width" |
+ *                    "uncompressed"
+ *
+ * 
+ * If needed, and to allow more syntaxes, a list of regexps has been added
+ * which can be initialized to other values
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class FacsimileTelephoneNumberSyntaxChecker extends TelephoneNumberSyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( FacsimileTelephoneNumberSyntaxChecker.class );
+
+    /** Fax parameters possible values */
+    private static final String TWO_DIMENSIONAL = "twoDimensional";
+    private static final String FINE_RESOLUTION = "fineResolution";
+    private static final String UNLIMITED_LENGTH = "unlimitedLength";
+    private static final String B4_LENGTH = "b4Length";
+    private static final String A3_LENGTH = "a3Width";
+    private static final String B4_WIDTH = "b4Width";
+    private static final String UNCOMPRESSED = "uncompressed";
+
+    /** A set which contaons all the possible fax parameters values */
+    private static Set<String> faxParameters = new HashSet<String>();
+
+    /** Initialization of the fax parameters set of values */
+    static
+    {
+        faxParameters.add( Strings.toLowerCase( TWO_DIMENSIONAL ) );
+        faxParameters.add( Strings.toLowerCase( FINE_RESOLUTION ) );
+        faxParameters.add( Strings.toLowerCase( UNLIMITED_LENGTH ) );
+        faxParameters.add( Strings.toLowerCase( B4_LENGTH ) );
+        faxParameters.add( Strings.toLowerCase( A3_LENGTH ) );
+        faxParameters.add( Strings.toLowerCase( B4_WIDTH ) );
+        faxParameters.add( Strings.toLowerCase( UNCOMPRESSED ) );
+    }
+
+
+    /**
+     * Creates a new instance of TelephoneNumberSyntaxChecker.
+     */
+    public FacsimileTelephoneNumberSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.FACSIMILE_TELEPHONE_NUMBER_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The facsimile telephone number might be composed
+        // of two parts separated by a '$'.
+        int dollarPos = strValue.indexOf( '$' );
+
+        if ( dollarPos == -1 )
+        {
+            // We have no fax-parameter : check the Telephone number
+            boolean result = super.isValidSyntax( strValue );
+
+            if ( result )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+            }
+            else
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+            }
+
+            return result;
+        }
+
+        // First check the telephone number if the '$' is not at the first position
+        if ( dollarPos > 0 )
+        {
+            if ( !super.isValidSyntax( strValue.substring( 0, dollarPos - 1 ) ) )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            // Now, try to validate the fax-parameters : we may
+            // have more than one, so we will store the seen params
+            // in a set to check that we don't have the same param twice
+            Set<String> paramsSeen = new HashSet<String>();
+
+            while ( dollarPos > 0 )
+            {
+                String faxParam = null;
+                int newDollar = strValue.indexOf( '$', dollarPos + 1 );
+
+                if ( newDollar == -1 )
+                {
+                    faxParam = strValue.substring( dollarPos + 1 );
+                }
+                else
+                {
+                    faxParam = strValue.substring( dollarPos + 1, newDollar );
+                }
+
+                if ( faxParam.length() == 0 )
+                {
+                    // Not allowed
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                // Relax a little bit the syntax by lowercasing the param
+                faxParam = Strings.toLowerCase( faxParam );
+
+                if ( !faxParameters.contains( faxParam ) )
+                {
+                    // This parameter is not in the possible set
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+                else if ( paramsSeen.contains( faxParam ) )
+                {
+                    // We have the same parameters twice...
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+                else
+                {
+                    // It's a correct param, let's add it to the seen 
+                    // params.
+                    paramsSeen.add( faxParam );
+                }
+
+                dollarPos = newDollar;
+            }
+
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+
+        // We must have a valid telephone number !
+        LOG.debug( "Syntax invalid for '{}'", value );
+        return false;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/FaxSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/FaxSyntaxChecker.java
new file mode 100644
index 0000000..bfff009
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/FaxSyntaxChecker.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Fax according to RFC 4517.
+ * 
+ * We didn't implemented the check against RFC 804, so the value is considered
+ * to contain an OctetString.
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class FaxSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( FaxSyntaxChecker.class );
+
+
+    /**
+     * Private default constructor to prevent unnecessary instantiation.
+     */
+    public FaxSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.FAX_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/GeneralizedTimeSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/GeneralizedTimeSyntaxChecker.java
new file mode 100644
index 0000000..6efecbd
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/GeneralizedTimeSyntaxChecker.java
@@ -0,0 +1,157 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a generalized time
+ * according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * GeneralizedTime = century year month day hour
+ *                          [ minute [ second / leap-second ] ]
+ *                          [ fraction ]
+ *                          g-time-zone
+ *
+ * century = 2(%x30-39)            ; "00" to "99"
+ * year    = 2(%x30-39)            ; "00" to "99"
+ * month   = ( %x30 %x31-39 )      ; "01" (January) to "09"
+ *           | ( %x31 %x30-32 )    ; "10" to "12"
+ * day     = ( %x30 %x31-39 )      ; "01" to "09"
+ *           | ( %x31-32 %x30-39 ) ; "10" to "29"
+ *           | ( %x33 %x30-31 )    ; "30" to "31"
+ * hour    = ( %x30-31 %x30-39 ) 
+ *           | ( %x32 %x30-33 )    ; "00" to "23"
+ * minute  = %x30-35 %x30-39       ; "00" to "59"
+ *
+ * second  = ( %x30-35 %x30-39 )   ; "00" to "59"
+ * leap-second = ( %x36 %x30 )     ; "60"
+ *
+ * fraction = ( DOT / COMMA ) 1*(%x30-39)
+ * g-time-zone = %x5A              ; "Z"
+ *               | g-differential
+ * g-differential = ( MINUS / PLUS ) hour [ minute ]
+ * MINUS   = %x2D  ; minus sign ("-")
+ * 
+ * From RFC 4512 :
+ * PLUS    = %x2B ; plus sign ("+")
+ * DOT     = %x2E ; period (".")
+ * COMMA   = %x2C ; comma (",")
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class GeneralizedTimeSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( GeneralizedTimeSyntaxChecker.class );
+
+    /** The GeneralizedDate pattern matching */
+    private static final String GENERALIZED_TIME_PATTERN =
+        // century + year : 0000 to 9999
+        "^\\d{4}"
+            // month : 01 to 12
+            + "(0[1-9]|1[0-2])"
+            // day : 01 to 31
+            + "(0[1-9]|[12]\\d|3[01])"
+            // hour : 00 to 23
+            + "([01]\\d|2[0-3])"
+            + "("
+            // optional minute : 00 to 59
+            + "([0-5]\\d)"
+            // optional second | leap second
+            + "([0-5]\\d|60)?"
+            + ")?"
+            // fraction
+            + "([.,]\\d+)?"
+            // time-zone
+            + "(Z|[+-]([01]\\d|2[0-3])([0-5]\\d)?)$";
+
+    /** The date pattern. The regexp pattern is immutable, only one instance needed. */
+    private static final Pattern DATE_PATTERN = Pattern.compile( GENERALIZED_TIME_PATTERN );
+
+
+    /**
+     * Creates a new instance of GeneralizedTimeSyntaxChecker.
+     */
+    public GeneralizedTimeSyntaxChecker()
+    {
+        super( SchemaConstants.GENERALIZED_TIME_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        // A generalized time must have a minimal length of 11 
+        if ( strValue.length() < 11 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Start the date parsing
+        boolean result = DATE_PATTERN.matcher( strValue ).find();
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/GuideSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/GuideSyntaxChecker.java
new file mode 100644
index 0000000..2a49346
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/GuideSyntaxChecker.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Guide according to RFC 4517.
+ * 
+ * Implemented as binary right now ...
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class GuideSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( GuideSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of GuideSyntaxChecker
+     */
+    public GuideSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.GUIDE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/Ia5StringSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/Ia5StringSyntaxChecker.java
new file mode 100644
index 0000000..d17d285
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/Ia5StringSyntaxChecker.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a IA5 String according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * IA5String          = *(%x00-7F)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class Ia5StringSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( Ia5StringSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of Ia5StringSyntaxChecker.
+     */
+    public Ia5StringSyntaxChecker()
+    {
+        super( SchemaConstants.IA5_STRING_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return true;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        boolean result = Strings.isIA5String( strValue );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/IntegerSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/IntegerSyntaxChecker.java
new file mode 100644
index 0000000..9f7dc90
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/IntegerSyntaxChecker.java
@@ -0,0 +1,157 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is an Integer according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * 
+ * Integer = ( HYPHEN LDIGIT *DIGIT ) | number
+ * 
+ * From RFC 4512 :
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * HYPHEN  = %x2D                ; hyphen ("-")
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class IntegerSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( IntegerSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of IntegerSyntaxChecker.
+     */
+    public IntegerSyntaxChecker()
+    {
+        super( SchemaConstants.INTEGER_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The first char must be either a '-' or in [0..9].
+        // If it's a '0', then there should be any other char after
+        int pos = 0;
+        char c = strValue.charAt( pos );
+
+        if ( c == '-' )
+        {
+            pos = 1;
+        }
+        else if ( !Chars.isDigit( c ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( c == '0' )
+        {
+            if ( strValue.length() > 1 )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+            else
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+        }
+
+        // We must have at least a digit which is not '0'
+        if ( !Chars.isDigit( strValue, pos ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( Strings.isCharASCII( strValue, pos, '0' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else
+        {
+            pos++;
+        }
+
+        while ( Chars.isDigit( strValue, pos ) )
+        {
+            pos++;
+        }
+
+        boolean result = ( pos == strValue.length() );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaByteSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaByteSyntaxChecker.java
new file mode 100644
index 0000000..b5d9dc9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaByteSyntaxChecker.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid Java primitive short or
+ * the Short wrapper.  Essentially this constrains the min and max values of
+ * the Integer.
+ *
+ * From RFC 4517 :
+ *
+ * Integer = ( HYPHEN LDIGIT *DIGIT ) | number
+ *
+ * From RFC 4512 :
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * HYPHEN  = %x2D                ; hyphen ("-")
+ *
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class JavaByteSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( JavaByteSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of JavaByteSyntaxChecker.
+     */
+    public JavaByteSyntaxChecker()
+    {
+        super( SchemaConstants.JAVA_BYTE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The first char must be either a '-' or in [0..9].
+        // If it's a '0', then there should be any other char after
+        int pos = 0;
+        char c = strValue.charAt( pos );
+
+        if ( c == '-' )
+        {
+            pos = 1;
+        }
+        else if ( !Chars.isDigit( c ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( c == '0' )
+        {
+            if ( strValue.length() > 1 )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+            else
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+        }
+
+        // We must have at least a digit which is not '0'
+        if ( !Chars.isDigit( strValue, pos ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( Strings.isCharASCII( strValue, pos, '0' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else
+        {
+            pos++;
+        }
+
+        while ( Chars.isDigit( strValue, pos ) )
+        {
+            pos++;
+        }
+
+        if ( pos != strValue.length() )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Should get a NumberFormatException for Byte values out of range
+        try
+        {
+            Byte.valueOf( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( NumberFormatException e )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaIntegerSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaIntegerSyntaxChecker.java
new file mode 100644
index 0000000..72b8bdd
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaIntegerSyntaxChecker.java
@@ -0,0 +1,166 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid Java primitive int or
+ * the Integer wrapper.  Essentially this constrains the min and max values of
+ * the Integer.
+ *
+ * From RFC 4517 :
+ *
+ * Integer = ( HYPHEN LDIGIT *DIGIT ) | number
+ *
+ * From RFC 4512 :
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * HYPHEN  = %x2D                ; hyphen ("-")
+ *
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class JavaIntegerSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( JavaIntegerSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of JavaIntegerSyntaxChecker.
+     */
+    public JavaIntegerSyntaxChecker()
+    {
+        super( SchemaConstants.JAVA_INT_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The first char must be either a '-' or in [0..9].
+        // If it's a '0', then there should be any other char after
+        int pos = 0;
+        char c = strValue.charAt( pos );
+
+        if ( c == '-' )
+        {
+            pos = 1;
+        }
+        else if ( !Chars.isDigit( c ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( c == '0' )
+        {
+            boolean result = strValue.length() <= 1;
+
+            if ( result )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+            }
+            else
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+            }
+
+            return result;
+        }
+
+        // We must have at least a digit which is not '0'
+        if ( !Chars.isDigit( strValue, pos ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( Strings.isCharASCII( strValue, pos, '0' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else
+        {
+            pos++;
+        }
+
+        while ( Chars.isDigit( strValue, pos ) )
+        {
+            pos++;
+        }
+
+        if ( pos != strValue.length() )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        try
+        {
+            Integer.valueOf( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( NumberFormatException e )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaLongSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaLongSyntaxChecker.java
new file mode 100644
index 0000000..06e4075
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaLongSyntaxChecker.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid Java primitive long or
+ * the Long wrapper.  Essentially this constrains the min and max values of
+ * the Integer.
+ *
+ * From RFC 4517 :
+ *
+ * Integer = ( HYPHEN LDIGIT *DIGIT ) | number
+ *
+ * From RFC 4512 :
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * HYPHEN  = %x2D                ; hyphen ("-")
+ *
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class JavaLongSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( JavaLongSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of JavaLongSyntaxChecker.
+     */
+    public JavaLongSyntaxChecker()
+    {
+        super( SchemaConstants.JAVA_LONG_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The first char must be either a '-' or in [0..9].
+        // If it's a '0', then there should be any other char after
+        int pos = 0;
+        char c = strValue.charAt( pos );
+
+        if ( c == '-' )
+        {
+            pos = 1;
+        }
+        else if ( !Chars.isDigit( c ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( c == '0' )
+        {
+            if ( strValue.length() > 1 )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+            else
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+        }
+
+        // We must have at least a digit which is not '0'
+        if ( !Chars.isDigit( strValue, pos ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( Strings.isCharASCII( strValue, pos, '0' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else
+        {
+            pos++;
+        }
+
+        while ( Chars.isDigit( strValue, pos ) )
+        {
+            pos++;
+        }
+
+        if ( pos != strValue.length() )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Should get a NumberFormatException for Byte values out of range
+        try
+        {
+            Long.valueOf( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( NumberFormatException e )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaShortSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaShortSyntaxChecker.java
new file mode 100644
index 0000000..700d668
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JavaShortSyntaxChecker.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid Java primitive Short or
+ * the Short wrapper.  Essentially this constrains the min and max values of
+ * the Short.
+ *
+ * From RFC 4517 :
+ *
+ * Integer = ( HYPHEN LDIGIT *DIGIT ) | number
+ *
+ * From RFC 4512 :
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * HYPHEN  = %x2D                ; hyphen ("-")
+ *
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class JavaShortSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( JavaShortSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of JavaShortSyntaxChecker.
+     */
+    public JavaShortSyntaxChecker()
+    {
+        super( SchemaConstants.JAVA_SHORT_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The first char must be either a '-' or in [0..9].
+        // If it's a '0', then there should be any other char after
+        int pos = 0;
+        char c = strValue.charAt( pos );
+
+        if ( c == '-' )
+        {
+            pos = 1;
+        }
+        else if ( !Chars.isDigit( c ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( c == '0' )
+        {
+            if ( strValue.length() > 1 )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+            else
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+        }
+
+        // We must have at least a digit which is not '0'
+        if ( !Chars.isDigit( strValue, pos ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else if ( Strings.isCharASCII( strValue, pos, '0' ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+        else
+        {
+            pos++;
+        }
+
+        while ( Chars.isDigit( strValue, pos ) )
+        {
+            pos++;
+        }
+
+        if ( pos != strValue.length() )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Should get a NumberFormatException for Byte values out of range
+        try
+        {
+            Short.valueOf( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( NumberFormatException e )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JpegSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JpegSyntaxChecker.java
new file mode 100644
index 0000000..dfe6e88
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/JpegSyntaxChecker.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Jpeg according to RFC 4517.
+ * 
+ * The JFIF (Jpeg File Interchange Format) specify that a jpeg image starts with
+ * the following bytes :
+ * 0xFF 0xD8 (SOI, Start Of Image)
+ * 0xFF 0xE0 (App0 for JFIF) or 0xDD 0xE1 (App1 for Exif)
+ * 0xNN 0xNN (Header length)
+ * "JFIF\0" (JFIF string with an ending \0)
+ * some other bytes which are related to the image.
+ * 
+ * We will check for those 11 bytes, except the length.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class JpegSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( JpegSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of JpegSyntaxChecker.
+     */
+    public JpegSyntaxChecker()
+    {
+        super( SchemaConstants.JPEG_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        // The value must be a byte array
+        if ( !( value instanceof byte[] ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        byte[] bytes = ( byte[] ) value;
+
+        // The header must be at least 11 bytes long
+        if ( bytes.length < 11 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // SOI or APP0 or APP1 format
+        if ( ( bytes[0] == ( byte ) 0x00FF )
+            && ( bytes[1] == ( byte ) 0x00D8 )
+            && ( bytes[2] == ( byte ) 0x00FF ) )
+        {
+            // JFIF format
+            if ( ( bytes[3] == ( byte ) 0x00E0 )
+                && ( bytes[6] == 'J' )
+                && ( bytes[7] == 'F' )
+                && ( bytes[8] == 'I' )
+                && ( bytes[9] == 'F' )
+                && ( bytes[10] == 0x00 ) )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+        // EXIF Format
+            else if ( ( bytes[3] == ( byte ) 0x00E1 ) 
+                    && ( bytes[6] == 'E' )
+                    && ( bytes[7] == 'x' )
+                    && ( bytes[8] == 'i' )
+                    && ( bytes[9] == 'f' )
+                    && ( bytes[10] == 0x00 ) )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+        }
+
+        LOG.debug( "Syntax invalid for '{}'", value );
+        return false;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/LdapSyntaxDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/LdapSyntaxDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..35da9c3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/LdapSyntaxDescriptionSyntaxChecker.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapSyntaxDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * LDAP syntax descripton syntax according to RFC 4512, par 4.2.2:
+ * 
+ * <pre>
+ * SyntaxDescription = LPAREN WSP
+ *    numericoid                 ; object identifier
+ *    [ SP "DESC" SP qdstring ]  ; description
+ *    extensions WSP RPAREN      ; extensions
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class LdapSyntaxDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( LdapSyntaxDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the LdapSyntax description Syntax */
+    private LdapSyntaxDescriptionSchemaParser schemaParser = new LdapSyntaxDescriptionSchemaParser();
+
+
+    /**
+     * 
+     * Creates a new instance of LdapSyntaxDescriptionSyntaxChecker.
+     *
+     */
+    public LdapSyntaxDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.LDAP_SYNTAX_DESCRIPTION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseLdapSyntaxDescription( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MailPreferenceSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MailPreferenceSyntaxChecker.java
new file mode 100644
index 0000000..213ab63
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MailPreferenceSyntaxChecker.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Boolean according to RFC 1778.
+ * 
+ * From RFC 1778 :
+ * 
+ * <mail-preference> ::= "NO-LISTS" | "ANY-LIST" | "PROFESSIONAL-LISTS"
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class MailPreferenceSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MailPreferenceSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of MailPreferenceSyntaxChecker.
+     */
+    public MailPreferenceSyntaxChecker()
+    {
+        super( SchemaConstants.MAIL_PREFERENCE_SYNTAX );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of MailPreferenceSyntaxChecker.
+     * 
+     * @param oid the oid to associate with this new SyntaxChecker
+     *
+     */
+    protected MailPreferenceSyntaxChecker( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( ( strValue.length() < 8 ) || ( strValue.length() > 18 ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        boolean result = ( ( "NO-LISTS".equals( strValue ) ) || ( "ANY-LIST".equals( strValue ) )
+            || ( "PROFESSIONAL-LISTS".equals( strValue ) ) );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MasterAndShadowAccessPointSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MasterAndShadowAccessPointSyntaxChecker.java
new file mode 100644
index 0000000..d4e2ba9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MasterAndShadowAccessPointSyntaxChecker.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a 
+ * MasterAndShadowAccessPoint.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class MasterAndShadowAccessPointSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MasterAndShadowAccessPointSyntaxChecker.class );
+
+
+    /**
+     * Create a new instance of MasterAndShadowAccessPointSyntaxChecker
+     */
+    public MasterAndShadowAccessPointSyntaxChecker()
+    {
+        super( SchemaConstants.MASTER_AND_SHADOW_ACCESS_POINTS_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MatchingRuleDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MatchingRuleDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..80ff668
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MatchingRuleDescriptionSyntaxChecker.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * matching rule descripton syntax according to RFC 4512, par 4.2.3:
+ * 
+ *  <pre>
+ * MatchingRuleDescription = LPAREN WSP
+ *    numericoid                 ; object identifier
+ *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+ *    [ SP "DESC" SP qdstring ]  ; description
+ *    [ SP "OBSOLETE" ]          ; not active
+ *    SP "SYNTAX" SP numericoid  ; assertion syntax
+ *    extensions WSP RPAREN      ; extensions
+ * 
+ * extensions = *( SP xstring SP qdstrings )
+ * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE ) 
+ * 
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class MatchingRuleDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MatchingRuleDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the MatchingRuleDescription Syntax */
+    private MatchingRuleDescriptionSchemaParser schemaParser = new MatchingRuleDescriptionSchemaParser();
+
+
+    /**
+     * 
+     * Creates a new instance of MatchingRuleDescriptionSchemaParser.
+     *
+     */
+    public MatchingRuleDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.MATCHING_RULE_DESCRIPTION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseMatchingRuleDescription( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MatchingRuleUseDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MatchingRuleUseDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..a1020ec
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MatchingRuleUseDescriptionSyntaxChecker.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleUseDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * matching rule use descripton syntax according to RFC 4512, par 4.2.4:
+ * 
+ *  <pre>
+ * MatchingRuleUseDescription = LPAREN WSP
+ *    numericoid                 ; object identifier
+ *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+ *    [ SP "DESC" SP qdstring ]  ; description
+ *    [ SP "OBSOLETE" ]          ; not active
+ *    SP "APPLIES" SP oids       ; attribute types
+ *    extensions WSP RPAREN      ; extensions
+ * 
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class MatchingRuleUseDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MatchingRuleUseDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the MatchingRuleUseDescription Syntax */
+    private MatchingRuleUseDescriptionSchemaParser schemaParser = new MatchingRuleUseDescriptionSchemaParser();
+
+
+    /**
+     * 
+     * Creates a new instance of MatchingRuleUseDescriptionSchemaParser.
+     *
+     */
+    public MatchingRuleUseDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.MATCHING_RULE_USE_DESCRIPTION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseMatchingRuleUseDescription( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MhsOrAddressSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MhsOrAddressSyntaxChecker.java
new file mode 100644
index 0000000..8bf769b
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/MhsOrAddressSyntaxChecker.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a 
+ * MHSORAddress.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class MhsOrAddressSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MhsOrAddressSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of MHSORAddressSyntaxChecker.
+     */
+    public MhsOrAddressSyntaxChecker()
+    {
+        super( SchemaConstants.MHS_OR_ADDRESS_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NameAndOptionalUIDSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NameAndOptionalUIDSyntaxChecker.java
new file mode 100644
index 0000000..ced20a5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NameAndOptionalUIDSyntaxChecker.java
@@ -0,0 +1,164 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid Name and Optional UID.
+ * 
+ * This element is a composition of two parts : a Dn and an optional UID :
+ * NameAndOptionalUID = distinguishedName [ SHARP BitString ]
+ * 
+ * Both part already have their syntax checkers, so we will just call them
+ * after having splitted the element in two ( if necessary)
+ * 
+ * We just check that the Dn is valid, we don't need to verify each of the Rdn
+ * syntax.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NameAndOptionalUIDSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NameAndOptionalUIDSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of NameAndOptionalUIDSyntaxChecker.
+     */
+    public NameAndOptionalUIDSyntaxChecker()
+    {
+        super( SchemaConstants.NAME_AND_OPTIONAL_UID_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Let's see if we have an UID part
+        int sharpPos = strValue.lastIndexOf( '#' );
+
+        if ( sharpPos != -1 )
+        {
+            // Now, check that we don't have another '#'
+            if ( strValue.indexOf( '#' ) != sharpPos )
+            {
+                // Yes, we have one : this is not allowed, it should have been
+                // escaped.
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            // This is an UID if the '#' is immediatly
+            // followed by a BitString, except if the '#' is
+            // on the last position
+            // We shoould not find a
+            if ( BitStringSyntaxChecker.isValid( strValue.substring( sharpPos + 1 ) )
+                && ( sharpPos < strValue.length() ) )
+            {
+                // Ok, we have a BitString, now check the Dn,
+                // except if the '#' is in first position
+                if ( sharpPos > 0 )
+                {
+                    boolean result = Dn.isValid( strValue.substring( 0, sharpPos ) );
+
+                    if ( result )
+                    {
+                        LOG.debug( "Syntax valid for '{}'", value );
+                    }
+                    else
+                    {
+                        LOG.debug( "Syntax invalid for '{}'", value );
+                    }
+
+                    return result;
+
+                }
+                else
+                {
+                    // The Dn must not be null ?
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+            }
+            else
+            {
+                // We have found a '#' but no UID part.
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+        }
+        else
+        {
+            // No UID, the strValue is a Dn
+            // Check that the value is a valid Dn
+            boolean result = Dn.isValid( strValue );
+
+            if ( result )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+            }
+            else
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NameFormDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NameFormDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..b8773ec
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NameFormDescriptionSyntaxChecker.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.NameFormDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * name descripton syntax according to RFC 4512, par 4.2.7.2:
+ * 
+ * <pre>
+ * NameFormDescription = LPAREN WSP
+ *    numericoid                 ; object identifier
+ *    [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+ *    [ SP "DESC" SP qdstring ]  ; description
+ *    [ SP "OBSOLETE" ]          ; not active
+ *    SP "OC" SP oid             ; structural object class
+ *    SP "MUST" SP oids          ; attribute types
+ *    [ SP "MAY" SP oids ]       ; attribute types
+ *    extensions WSP RPAREN      ; extensions
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NameFormDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NameFormDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the DITContentRuleDescription Syntax */
+    private NameFormDescriptionSchemaParser schemaParser = new NameFormDescriptionSchemaParser();
+
+
+    /**
+     * 
+     * Creates a new instance of DITContentRuleDescriptionSyntaxChecker.
+     *
+     */
+    public NameFormDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.NAME_FORM_DESCRIPTION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseNameFormDescription( strValue );
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NormalizerSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NormalizerSyntaxChecker.java
new file mode 100644
index 0000000..294d782
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NormalizerSyntaxChecker.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+
+
+/**
+ * A SyntaxChecker for the Normalizer schema element
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NormalizerSyntaxChecker extends Ia5StringSyntaxChecker
+{
+    /**
+     * Creates a new instance of NormalizerSyntaxChecker.
+     */
+    public NormalizerSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.NORMALIZER_SYNTAX );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumberSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumberSyntaxChecker.java
new file mode 100644
index 0000000..65806ab
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumberSyntaxChecker.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Number according to RFC 4512.
+ * 
+ * From RFC 4512 :
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NumberSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NumberSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of NumberSyntaxChecker.
+     */
+    public NumberSyntaxChecker()
+    {
+        super( SchemaConstants.NUMBER_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        // We should have at least one char
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Check that each char is either a digit or a space
+        for ( int i = 0; i < strValue.length(); i++ )
+        {
+            switch ( strValue.charAt( i ) )
+            {
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    continue;
+
+                default:
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+            }
+        }
+
+        if ( ( strValue.charAt( 0 ) == '0' ) && strValue.length() > 1 )
+        {
+            // A number can't start with a '0' unless it's the only
+            // number
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumericOidSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumericOidSyntaxChecker.java
new file mode 100644
index 0000000..50b9633
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumericOidSyntaxChecker.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a numeric oid 
+ * according to RFC 4512.
+ * 
+ * From RFC 4512 :
+ * 
+ * numericoid = number 1*( DOT number )
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT   = %x30 | LDIGIT                  ; "0"-"9"
+ * LDIGIT  = %x31-39                        ; "1"-"9"
+ * DOT     = %x2E                           ; period (".")
+
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NumericOidSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NumericOidSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of NumericOidSyntaxChecker.
+     */
+    public NumericOidSyntaxChecker()
+    {
+        super( SchemaConstants.NUMERIC_OID_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Just check that the value is a valid OID
+        boolean result = ( Oid.isOid( strValue ) );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumericStringSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumericStringSyntaxChecker.java
new file mode 100644
index 0000000..2f6f447
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/NumericStringSyntaxChecker.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Numeric String according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * 
+ * NumericString = 1*(DIGIT / SPACE)
+ * 
+ * From RFC 4512 :
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * SPACE   = %x20                ; space (" ")
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class NumericStringSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NumericStringSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of NumericStringSyntaxChecker.
+     */
+    public NumericStringSyntaxChecker()
+    {
+        super( SchemaConstants.NUMERIC_STRING_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        // We should have at least one char
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Check that each char is either a digit or a space
+        for ( int i = 0; i < strValue.length(); i++ )
+        {
+            switch ( strValue.charAt( i ) )
+            {
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                case ' ':
+                    continue;
+
+                default:
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+            }
+        }
+
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectClassDescriptionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectClassDescriptionSyntaxChecker.java
new file mode 100644
index 0000000..88ec6fe
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectClassDescriptionSyntaxChecker.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.ObjectClassDescriptionSchemaParser;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * object class descripton syntax according to RFC 4512, par 4.2.1:
+ * 
+ * <pre>
+ * ObjectClassDescription = LPAREN WSP
+ *     numericoid                 ; object identifier
+ *     [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
+ *     [ SP "DESC" SP qdstring ]  ; description
+ *     [ SP "OBSOLETE" ]          ; not active
+ *     [ SP "SUP" SP oids ]       ; superior object classes
+ *     [ SP kind ]                ; kind of class
+ *     [ SP "MUST" SP oids ]      ; attribute types
+ *     [ SP "MAY" SP oids ]       ; attribute types
+ *     extensions WSP RPAREN
+ *
+ * kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"
+ * 
+ * extensions = *( SP xstring SP qdstrings )
+ * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class ObjectClassDescriptionSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ObjectClassDescriptionSyntaxChecker.class );
+
+    /** The schema parser used to parse the ObjectClassDescription Syntax */
+    private ObjectClassDescriptionSchemaParser schemaParser = new ObjectClassDescriptionSchemaParser();
+
+
+    /**
+     * Creates a new instance of ObjectClassDescriptionSyntaxChecker.
+     */
+    public ObjectClassDescriptionSyntaxChecker()
+    {
+        super( SchemaConstants.OBJECT_CLASS_DESCRIPTION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        try
+        {
+            schemaParser.parseObjectClassDescription( strValue );
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectClassTypeSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectClassTypeSyntaxChecker.java
new file mode 100644
index 0000000..0bfe7e3
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectClassTypeSyntaxChecker.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A syntax checker which checks to see if an objectClass' type is either: 
+ * AUXILIARY, STRUCTURAL, or ABSTRACT.  The case is NOT ignored.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class ObjectClassTypeSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ObjectClassTypeSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of ObjectClassTypeSyntaxChecker.
+     */
+    public ObjectClassTypeSyntaxChecker()
+    {
+        super( SchemaConstants.OBJECT_CLASS_TYPE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() < 8 || strValue.length() > 10 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        char ch = strValue.charAt( 0 );
+
+        switch ( ch )
+        {
+            case ( 'A' ):
+                if ( "AUXILIARY".equals( strValue ) || "ABSTRACT".equals( strValue ) )
+                {
+                    LOG.debug( "Syntax valid for '{}'", value );
+                    return true;
+                }
+
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+
+            case ( 'S' ):
+                boolean result = "STRUCTURAL".equals( strValue );
+
+                if ( result )
+                {
+                    LOG.debug( "Syntax valid for '{}'", value );
+                }
+                else
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                }
+
+                return result;
+
+            default:
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectNameSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectNameSyntaxChecker.java
new file mode 100644
index 0000000..135ced6
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ObjectNameSyntaxChecker.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a name is valid for an ObjectClass
+ * or an AttributeType<br/><br/>
+ * 
+ * &lt;m-name&gt; = &lt;keystring&gt; <br/>
+ * &lt;keystring&gt; = &lt;leadkeychar&gt; *&lt;keychar&gt;<br/>
+ * &lt;leadkeychar&gt; = &lt;ALPHA&gt;<br/>
+ * &lt;keychar&gt; = &lt;ALPHA&gt; / &lt;DIGIT&gt; / &lt;HYPHEN&gt; / &lt;SEMI&gt;<br/>
+ * &lt;ALPHA&gt;   = %x41-5A / %x61-7A   ; "A"-"Z" / "a"-"z"<br/>
+ * &lt;DIGIT&gt;   = %x30 / &lt;LDIGIT       ; "0"-"9"<br/>
+ * &lt;LDIGIT&gt;  = %x31-39             ; "1"-"9"<br/>
+ * &lt;HYPHEN&gt;  = %x2D ; hyphen ("-")<br/>
+ * &lt;SEMI&gt;    = %x3B ; semicolon (";")<br/>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class ObjectNameSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ObjectNameSyntaxChecker.class );
+
+    private static final String REGEXP = "^([a-zA-Z][a-zA-Z0-9-;]*)$";
+
+    private static final Pattern PATTERN = Pattern.compile( REGEXP );
+
+
+    /**
+     * Creates a new instance of ObjectNameSyntaxChecker.
+     */
+    public ObjectNameSyntaxChecker()
+    {
+        super( SchemaConstants.OBJECT_NAME_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Search for the '$' separator
+        Matcher match = PATTERN.matcher( strValue );
+
+        boolean result = match.matches();
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OctetStringSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OctetStringSyntaxChecker.java
new file mode 100644
index 0000000..c48bb60
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OctetStringSyntaxChecker.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Octet String according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * OctetString = *OCTET
+ * 
+ * From RFC 4512 :
+ * OCTET   = %x00-FF ; Any octet (8-bit data unit)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class OctetStringSyntaxChecker extends SyntaxChecker
+{
+    /**
+     * Creates a new instance of OctetStringSyntaxChecker.
+     */
+    public OctetStringSyntaxChecker()
+    {
+        super( SchemaConstants.OCTET_STRING_SYNTAX );
+    }
+
+
+    /**
+     * Creates a new instance of OctetStringSyntaxChecker, with a specific OID
+     * 
+     * @param oid The Syntax's OID 
+     */
+    public OctetStringSyntaxChecker( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        // Always true.
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OidLenSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OidLenSyntaxChecker.java
new file mode 100644
index 0000000..92f786d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OidLenSyntaxChecker.java
@@ -0,0 +1,174 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a numeric oid and a length
+ * constraint according to RFC 4512.
+ * 
+ * From RFC 4512 :
+ * 
+ * noidlen    = numericoid [ LCURLY len RCURLY ]
+ * numericoid = number 1*( DOT number )
+ * len        = number
+ * number     = DIGIT | ( LDIGIT 1*DIGIT )
+ * DIGIT      = %x30 | LDIGIT                  ; "0"-"9"
+ * LDIGIT     = %x31-39                        ; "1"-"9"
+ * DOT        = %x2E                           ; period (".")
+ * LCURLY  = %x7B                              ; left curly brace "{"
+ * RCURLY  = %x7D                              ; right curly brace "}"
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class OidLenSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( OidLenSyntaxChecker.class );
+
+
+    /**
+     * 
+     * Creates a new instance of OidLenSyntaxChecker.
+     *
+     */
+    public OidLenSyntaxChecker()
+    {
+        super( SchemaConstants.OID_LEN_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // We are looking at the first position of the len part
+        int pos = strValue.indexOf( '{' );
+
+        if ( pos < 0 )
+        {
+            // Not found ... but it may still be a valid OID
+            boolean result = Oid.isOid( strValue );
+
+            if ( result )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+            }
+            else
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+            }
+
+            return result;
+        }
+        else
+        {
+            // we should have a len value. First check that the OID is valid
+            String oid = strValue.substring( 0, pos );
+
+            if ( !Oid.isOid( oid ) )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            String len = strValue.substring( pos );
+
+            // We must have a lnumber and a '}' at the end
+            if ( len.charAt( len.length() - 1 ) != '}' )
+            {
+                // No final '}'
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            for ( int i = 1; i < len.length() - 1; i++ )
+            {
+                switch ( len.charAt( i ) )
+                {
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                    case '8':
+                    case '9':
+                        break;
+
+                    default:
+                        LOG.debug( "Syntax invalid for '{}'", value );
+                        return false;
+                }
+            }
+
+            if ( ( len.charAt( 1 ) == '0' ) && len.length() > 3 )
+            {
+                // A number can't start with a '0' unless it's the only
+                // number
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OidSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OidSyntaxChecker.java
new file mode 100644
index 0000000..590374d
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OidSyntaxChecker.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is an oid according to RFC 4512.
+ * 
+ * From RFC 4512 :
+ * 
+ * oid = descr | numericoid
+ * descr = keystring
+ * keystring = leadkeychar *keychar
+ * leadkeychar = ALPHA
+ * keychar = ALPHA | DIGIT | HYPHEN
+ * number  = DIGIT | ( LDIGIT 1*DIGIT )
+ * ALPHA   = %x41-5A | %x61-7A              ; "A"-"Z" | "a"-"z"
+ * DIGIT   = %x30 | LDIGIT                  ; "0"-"9"
+ * LDIGIT  = %x31-39                        ; "1"-"9"
+ * HYPHEN  = %x2D                           ; hyphen ("-")
+ * numericoid = number 1*( DOT number )
+ * DOT     = %x2E                           ; period (".")
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class OidSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( OidSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of OidSyntaxChecker.
+     */
+    public OidSyntaxChecker()
+    {
+        super( SchemaConstants.OID_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // if the first character is a digit it's an attempt at an OID and must be
+        // checked to make sure there are no other chars except '.' and digits.
+        if ( Chars.isDigit( strValue.charAt( 0 ) ) )
+        {
+            if ( !Oid.isOid( strValue ) )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+            else
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+        }
+
+        // here we just need to make sure that we have the right characters in the 
+        // string and that it starts with a letter.
+        if ( Chars.isAlphaASCII( strValue, 0 ) )
+        {
+            for ( int index = 0; index < strValue.length(); index++ )
+            {
+                char c = strValue.charAt( index );
+                
+                if ( !Chars.isAlphaDigitMinus( c ) )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+            }
+
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OpenLdapObjectIdentifierMacro.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OpenLdapObjectIdentifierMacro.java
new file mode 100644
index 0000000..85cf763
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OpenLdapObjectIdentifierMacro.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+/**
+ * An OpenLDAP object identifier macro. 
+ * See http://www.openldap.org/doc/admin24/schema.html#OID%20Macros
+ * <br/>
+ * <code>objectIdentifier &lt;name&gt; { &lt;oid&gt; | &lt;name&gt;[:&lt;suffix&gt;] }</code>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OpenLdapObjectIdentifierMacro
+{
+    private String name;
+
+    private String rawOidOrNameSuffix;
+
+    private String resolvedOid;
+
+
+    /**
+     * Instantiates a new OpenLDAP object identifier macro.
+     */
+    public OpenLdapObjectIdentifierMacro()
+    {
+        name = null;
+        rawOidOrNameSuffix = null;
+        resolvedOid = null;
+    }
+
+
+    /**
+     * Gets the name.
+     * 
+     * @return the name
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * Sets the name.
+     * 
+     * @param name the new name
+     */
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * Gets the raw OID or name plus suffix.
+     * 
+     * @return the raw OID or name plus suffix
+     */
+    public String getRawOidOrNameSuffix()
+    {
+        return rawOidOrNameSuffix;
+    }
+
+
+    /**
+     * Sets the raw OID or name plus suffix.
+     * 
+     * @param rawOidOrNameSuffix the new raw OID or name plus suffix
+     */
+    public void setRawOidOrNameSuffix( String rawOidOrNameSuffix )
+    {
+        this.rawOidOrNameSuffix = rawOidOrNameSuffix;
+    }
+
+
+    /**
+     * Gets the resolved OID, null if not yet resolved.
+     * 
+     * @return the resolved OID
+     */
+    public String getResolvedOid()
+    {
+        return resolvedOid;
+    }
+
+
+    /**
+     * Checks if is resolved.
+     * 
+     * @return true, if is resolved
+     */
+    public boolean isResolved()
+    {
+        return getResolvedOid() != null;
+    }
+
+
+    /**
+     * Sets the resolved OID.
+     * 
+     * @param resolvedOid the new resolved OID
+     */
+    public void setResolvedOid( String resolvedOid )
+    {
+        this.resolvedOid = resolvedOid;
+    }
+
+
+    public String toString()
+    {
+        if ( isResolved() )
+        {
+            return "resolved: " + name + " " + resolvedOid;
+        }
+        else
+        {
+            return "unresolved: " + name + " " + rawOidOrNameSuffix;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OtherMailboxSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OtherMailboxSyntaxChecker.java
new file mode 100644
index 0000000..9f9aad5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/OtherMailboxSyntaxChecker.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is an OtherMailbox according to 
+ * RFC 4517 :
+ * 
+ * OtherMailbox = mailbox-type DOLLAR mailbox
+ * mailbox-type = PrintableString
+ * mailbox      = IA5String
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class OtherMailboxSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( OtherMailboxSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of OtherMailboxSyntaxChecker.
+     */
+    public OtherMailboxSyntaxChecker()
+    {
+        super( SchemaConstants.OTHER_MAILBOX_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Search for the '$' separator
+        int dollar = strValue.indexOf( '$' );
+
+        if ( dollar == -1 )
+        {
+            // No '$' => error
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        String mailboxType = strValue.substring( 0, dollar );
+
+        String mailbox = ( ( dollar < strValue.length() - 1 )
+            ? strValue.substring( dollar + 1 ) : "" );
+
+        // The mailbox should not contains a '$'
+        if ( mailbox.indexOf( '$' ) != -1 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Check that the mailboxType is a PrintableString
+        if ( !Strings.isPrintableString( mailboxType ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Check that the mailbox is an IA5String
+        boolean result = ( Strings.isIA5String( mailbox ) );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PostalAddressSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PostalAddressSyntaxChecker.java
new file mode 100644
index 0000000..80354fd
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PostalAddressSyntaxChecker.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a PostalAddress according to 
+ * RFC 4517 :
+ * 
+ * <postal-address> = <dstring> <dstring-list>
+ * <dstring-list> = "$" <dstring> <dstring-list> | e
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class PostalAddressSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( PostalAddressSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of PostalAddressSyntaxChecker.
+     */
+    public PostalAddressSyntaxChecker()
+    {
+        super( SchemaConstants.POSTAL_ADDRESS_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Search for the '$' separator
+        int dollar = strValue.indexOf( '$' );
+
+        if ( dollar == -1 )
+        {
+            // No '$' => only a dstring
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+
+        int pos = 0;
+        do
+        {
+            // check that the element between each '$' is not empty
+            String address = strValue.substring( pos, dollar );
+
+            if ( Strings.isEmpty( address ) )
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            pos = dollar + 1;
+
+            if ( pos == strValue.length() )
+            {
+                // we should not have a '$' at the end
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            dollar = strValue.indexOf( '$', pos );
+        }
+        while ( dollar > -1 );
+
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PresentationAddressSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PresentationAddressSyntaxChecker.java
new file mode 100644
index 0000000..3027b4a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PresentationAddressSyntaxChecker.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a PresentationAddressSyntax.
+ * 
+ * This syntax is defined in RFC 1278, but it has not been implemented.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class PresentationAddressSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( PresentationAddressSyntaxChecker.class );
+
+
+    /**
+     * Creates an instance of PresentationAddressSyntaxChecker
+     */
+    public PresentationAddressSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.PRESENTATION_ADDRESS_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PrintableStringSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PrintableStringSyntaxChecker.java
new file mode 100644
index 0000000..272c8be
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/PrintableStringSyntaxChecker.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Printable String according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * 
+ * PrintableString    = 1*PrintableCharacter
+ * PrintableCharacter = ALPHA | DIGIT | SQUOTE | LPAREN | RPAREN |
+ *                          PLUS | COMMA | HYPHEN | DOT | EQUALS |
+ *                          SLASH | COLON | QUESTION | SPACE
+ *                          
+ * SLASH   = %x2F                ; forward slash ("/")
+ * COLON   = %x3A                ; colon (":")
+ * QUESTION= %x3F                ; question mark ("?")
+ * 
+ * From RFC 4512 :
+ * ALPHA   = %x41-5A | %x61-7A   ; "A"-"Z" / "a"-"z"
+ * DIGIT   = %x30 | LDIGIT       ; "0"-"9"
+ * LDIGIT  = %x31-39             ; "1"-"9"
+ * SQUOTE  = %x27                ; single quote ("'")
+ * LPAREN  = %x28                ; left paren ("(")
+ * RPAREN  = %x29                ; right paren (")")
+ * PLUS    = %x2B                ; plus sign ("+")
+ * COMMA   = %x2C                ; comma (",")
+ * HYPHEN  = %x2D                ; hyphen ("-")
+ * DOT     = %x2E                ; period (".")
+ * EQUALS  = %x3D                ; equals sign ("=")
+ * SPACE   = %x20                ; space (" ")
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class PrintableStringSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( PrintableStringSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of PrintableStringSyntaxChecker.
+     */
+    public PrintableStringSyntaxChecker()
+    {
+        super( SchemaConstants.PRINTABLE_STRING_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // We must have at least one char
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        boolean result = Strings.isPrintableString( strValue );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ProtocolInformationSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ProtocolInformationSyntaxChecker.java
new file mode 100644
index 0000000..75c5a55
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/ProtocolInformationSyntaxChecker.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a protocol information 
+ * according to RFC 2252.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class ProtocolInformationSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ProtocolInformationSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of ProtocolInformationSyntaxChecker.
+     */
+    public ProtocolInformationSyntaxChecker()
+    {
+        super( SchemaConstants.PROTOCOL_INFORMATION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/RegexSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/RegexSyntaxChecker.java
new file mode 100644
index 0000000..aa1480c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/RegexSyntaxChecker.java
@@ -0,0 +1,150 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker implemented using Perl5 regular expressions to constrain
+ * values.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class RegexSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( RegexSyntaxChecker.class );
+
+    /** the set of regular expressions */
+    private List<String> expressions;
+
+
+    /**
+     * Creates a Syntax validator for a specific Syntax using Perl5 matching
+     * rules for validation.
+     * 
+     * @param oid
+     *            the oid of the Syntax values checked
+     * @param matchExprArray
+     *            the array of matching expressions
+     */
+    public RegexSyntaxChecker( String oid, String[] matchExprArray )
+    {
+        super( oid );
+
+        if ( ( matchExprArray != null ) && ( matchExprArray.length != 0 ) )
+        {
+            expressions = new ArrayList<String>( matchExprArray.length );
+
+            for ( String regexp : matchExprArray )
+            {
+                expressions.add( regexp );
+            }
+        }
+        else
+        {
+            expressions = new ArrayList<String>();
+        }
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of RegexSyntaxChecker.
+     * 
+     * @param oid the oid to associate with this new SyntaxChecker
+     *
+     */
+    public RegexSyntaxChecker( String oid )
+    {
+        super( oid );
+        expressions = new ArrayList<String>();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String str = null;
+        boolean match = true;
+
+        if ( value instanceof String )
+        {
+            str = ( String ) value;
+
+            for ( String regexp : expressions )
+            {
+                match = match && str.matches( regexp );
+
+                if ( !match )
+                {
+                    break;
+                }
+            }
+        }
+
+        if ( match )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return match;
+    }
+
+
+    /**
+     * Get the list of regexp stored into this SyntaxChecker
+     * 
+     * @return AN array containing all the stored regexp
+     */
+    public String[] getExpressions()
+    {
+        String[] exprs = new String[expressions.size()];
+        return expressions.toArray( exprs );
+    }
+
+
+    /**
+     * Add a list of regexp to be applied by this SyntaxChecker
+     * 
+     * @param expressions The regexp list to add
+     */
+    public void setExpressions( String[] expressions )
+    {
+        for ( String regexp : expressions )
+        {
+            this.expressions.add( regexp );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SearchScopeSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SearchScopeSyntaxChecker.java
new file mode 100644
index 0000000..5c01386
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SearchScopeSyntaxChecker.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a valid Search Scope. We
+ * have three possible values :
+ * <ul>
+ * <li>OBJECT</li>
+ * <li>ONE</li>
+ * <li>SUBTREE</li>
+ * </ul>
+ * The value is case insensitive
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SearchScopeSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SearchScopeSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of SearchScopeSyntaxChecker.
+     */
+    public SearchScopeSyntaxChecker()
+    {
+        super( SchemaConstants.SEARCH_SCOPE_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        strValue = Strings.trim( Strings.toLowerCase( strValue ) );
+
+        return ( "base".equals( strValue ) || "one".equals( strValue ) || "sub".equals( strValue ) );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SubstringAssertionSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SubstringAssertionSyntaxChecker.java
new file mode 100644
index 0000000..4a8ba6e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SubstringAssertionSyntaxChecker.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a SubstringAssertion 
+ * according to RFC 4517.
+ * 
+ * Implemented as binary right now ...
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SubstringAssertionSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SubstringAssertionSyntaxChecker.class );
+
+
+    /**
+     * Creates an instance of SubstringAssertionSyntaxChecker
+     */
+    public SubstringAssertionSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.SUBSTRING_ASSERTION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SubtreeSpecificationSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SubtreeSpecificationSyntaxChecker.java
new file mode 100644
index 0000000..f2cf706
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SubtreeSpecificationSyntaxChecker.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.subtree.SubtreeSpecificationChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a subtree specification.
+ * 
+ * It has been removed in RFC 4517
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SubtreeSpecificationSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SubtreeSpecificationSyntaxChecker.class );
+
+    /** The associated checker */
+    private SubtreeSpecificationChecker subtreeSpecificationChecker;
+
+
+    /**
+     * Creates an instance of SubtreeSpecificationSyntaxChecker
+     */
+    public SubtreeSpecificationSyntaxChecker()
+    {
+        super( SchemaConstants.SUBTREE_SPECIFICATION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        try
+        {
+            synchronized ( subtreeSpecificationChecker )
+            {
+                subtreeSpecificationChecker.parse( strValue );
+            }
+
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+        catch ( ParseException pe )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaManager( SchemaManager schemaManager )
+    {
+        subtreeSpecificationChecker = new SubtreeSpecificationChecker( schemaManager );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierAndConsumerSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierAndConsumerSyntaxChecker.java
new file mode 100644
index 0000000..cf2f39f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierAndConsumerSyntaxChecker.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a supplier and consummer according to RFC 2252.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SupplierAndConsumerSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SupplierAndConsumerSyntaxChecker.class );
+
+
+    /**
+     * Creates an instance of SupplierAndConsumerSyntaxChecker
+     */
+    public SupplierAndConsumerSyntaxChecker()
+    {
+        super( SchemaConstants.SUPPLIER_AND_CONSUMER_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierInformationSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierInformationSyntaxChecker.java
new file mode 100644
index 0000000..1d7bef8
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierInformationSyntaxChecker.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a supplier information according to RFC 2252.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SupplierInformationSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SupplierInformationSyntaxChecker.class );
+
+
+    /**
+     * Creates an instance of SupplierInformationSyntaxChecker
+     */
+    public SupplierInformationSyntaxChecker()
+    {
+        super( SchemaConstants.SUPPLIER_INFORMATION_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierOrConsumerSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierOrConsumerSyntaxChecker.java
new file mode 100644
index 0000000..a523483
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupplierOrConsumerSyntaxChecker.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a supplier or consummer according to RFC 2252.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SupplierOrConsumerSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SupplierOrConsumerSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of SupplierOrConsumerSyntaxChecker.
+     */
+    public SupplierOrConsumerSyntaxChecker()
+    {
+        super( SchemaConstants.SUPPLIER_OR_CONSUMER_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupportedAlgorithmSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupportedAlgorithmSyntaxChecker.java
new file mode 100644
index 0000000..f8fe218
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SupportedAlgorithmSyntaxChecker.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a SupportedAlgorithm according to RFC 2252.
+ * 
+ * It has been removed in RFC 4517
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SupportedAlgorithmSyntaxChecker extends BinarySyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( SupportedAlgorithmSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of SupportedAlgorithmSyntaxChecker.
+     */
+    public SupportedAlgorithmSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.SUPPORTED_ALGORITHM_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SyntaxCheckerSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SyntaxCheckerSyntaxChecker.java
new file mode 100644
index 0000000..ce2fd5c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/SyntaxCheckerSyntaxChecker.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+
+
+/**
+ * A SyntaxChecker for the SyntaxChecker schema element
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class SyntaxCheckerSyntaxChecker extends Ia5StringSyntaxChecker
+{
+    /**
+     * Creates a new instance of SyntaxCheckerSyntaxChecker.
+     */
+    public SyntaxCheckerSyntaxChecker()
+    {
+        super();
+        setOid( SchemaConstants.SYNTAX_CHECKER_SYNTAX );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TelephoneNumberSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TelephoneNumberSyntaxChecker.java
new file mode 100644
index 0000000..977f6c4
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TelephoneNumberSyntaxChecker.java
@@ -0,0 +1,212 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a TelephoneNumber according to ITU
+ * recommendation E.123 (which is quite vague ...).
+ * 
+ * A valid Telephone number respect more or less this syntax :
+ * 
+ * " *[+]? *((\([0-9- ]+\))|[0-9- ]+)+"
+ * 
+ * If needed, and to allow more syntaxes, a list of regexps has been added
+ * which can be initialized to other values
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class TelephoneNumberSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( TelephoneNumberSyntaxChecker.class );
+
+    /** Other regexps to extend the initial one */
+    private List<String> regexps;
+
+    /** Other regexp to extend the initial one, compiled */
+    private List<Pattern> compiledREs;
+
+    /** The default pattern used to check a TelephoneNumber */
+    private static final String DEFAULT_REGEXP = "^ *[+]? *((\\([0-9- ,;#*]+\\))|[0-9- ,;#*]+)+$";
+
+    /** The compiled default pattern */
+    private Pattern defaultPattern = Pattern.compile( DEFAULT_REGEXP );
+
+    /** A flag set when only the default regexp should be tested */
+    protected boolean defaultMandatory = false;
+
+
+    /**
+     * Creates a new instance of TelephoneNumberSyntaxChecker.
+     */
+    public TelephoneNumberSyntaxChecker()
+    {
+        super( SchemaConstants.TELEPHONE_NUMBER_SYNTAX );
+    }
+
+
+    /**
+     * Add a new valid regexp for a Telephone number
+     * @param regexp The new regexp to check
+     */
+    public void addRegexp( String regexp )
+    {
+        if ( defaultMandatory )
+        {
+            return;
+        }
+
+        try
+        {
+            Pattern compiledRE = Pattern.compile( regexp );
+
+            if ( regexps == null )
+            {
+                regexps = new ArrayList<String>();
+                compiledREs = new ArrayList<Pattern>();
+            }
+
+            regexps.add( regexp );
+            compiledREs.add( compiledRE );
+        }
+        catch ( PatternSyntaxException pse )
+        {
+            return;
+        }
+    }
+
+
+    /**
+     * Set the defaut regular expression for the Telephone number
+     * 
+     * @param regexp the default regular expression.
+     */
+    public void setDefaultRegexp( String regexp )
+    {
+        try
+        {
+            defaultPattern = Pattern.compile( regexp );
+
+            defaultMandatory = true;
+            regexps = null;
+            compiledREs = null;
+        }
+        catch ( PatternSyntaxException pse )
+        {
+            return;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // We will use a regexp to check the TelephoneNumber.
+        if ( defaultMandatory )
+        {
+            // We have a unique regexp to check, the default one
+            boolean result = defaultPattern.matcher( strValue ).matches();
+
+            if ( result )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+            }
+            else
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+            }
+
+            return result;
+        }
+        else
+        {
+            if ( defaultPattern.matcher( strValue ).matches() )
+            {
+                LOG.debug( "Syntax valid for '{}'", value );
+                return true;
+            }
+            else
+            {
+                if ( compiledREs == null )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                // The default is not enough, let's try
+                // the other regexps
+                for ( Pattern pattern : compiledREs )
+                {
+                    if ( pattern.matcher( strValue ).matches() )
+                    {
+                        LOG.debug( "Syntax valid for '{}'", value );
+                        return true;
+                    }
+                }
+
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TeletexTerminalIdentifierSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TeletexTerminalIdentifierSyntaxChecker.java
new file mode 100644
index 0000000..3399a3f
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TeletexTerminalIdentifierSyntaxChecker.java
@@ -0,0 +1,215 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a TeletexTerminalIdentifier according to 
+ * RFC 4517 :
+ * 
+ * teletex-id = ttx-term *(DOLLAR ttx-param)
+ * ttx-term   = PrintableString          ; terminal identifier
+ * ttx-param  = ttx-key COLON ttx-value  ; parameter
+ * ttx-key    = "graphic" | "control" | "misc" | "page" | "private"
+ * ttx-value  = *ttx-value-octet
+ *
+ * ttx-value-octet = %x00-23 | (%x5C "24") | %x25-5B | (%x5C "5C") | %x5D-FF
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class TeletexTerminalIdentifierSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( TeletexTerminalIdentifierSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of TeletexTerminalIdentifier.
+     */
+    public TeletexTerminalIdentifierSyntaxChecker()
+    {
+        super( SchemaConstants.TELETEX_TERMINAL_IDENTIFIER_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Search for the first '$' separator
+        int dollar = strValue.indexOf( '$' );
+
+        String terminalIdentifier = ( ( dollar == -1 ) ? strValue : strValue.substring( 0, dollar ) );
+
+        if ( terminalIdentifier.length() == 0 )
+        {
+            // It should not be null
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        if ( !Strings.isPrintableString( terminalIdentifier ) )
+        {
+            // It's not a valid PrintableString 
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        if ( dollar == -1 )
+        {
+            // No ttx-param : let's get out
+            LOG.debug( "Syntax valid for '{}'", value );
+            return true;
+        }
+
+        // Ok, now let's deal withh optional ttx-params
+        String[] ttxParams = strValue.substring( dollar + 1 ).split( "\\$" );
+
+        if ( ttxParams.length == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        for ( String ttxParam : ttxParams )
+        {
+            int colon = ttxParam.indexOf( ':' );
+
+            if ( colon == -1 )
+            {
+                // we must have a ':' separator
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+
+            String key = ttxParam.substring( 0, colon );
+
+            if ( key.startsWith( "graphic" )
+                || key.startsWith( "control" )
+                || key.startsWith( "misc" )
+                || key.startsWith( "page" )
+                || key.startsWith( "private" ) )
+            {
+                if ( colon + 1 == ttxParam.length() )
+                {
+                    LOG.debug( "Syntax invalid for '{}'", value );
+                    return false;
+                }
+
+                boolean hasEsc = false;
+
+                for ( byte b : Strings.getBytesUtf8( ttxParam ) )
+                {
+                    switch ( b )
+                    {
+                        case 0x24:
+                            // '$' is not accepted
+                            LOG.debug( "Syntax invalid for '{}'", value );
+                            return false;
+
+                        case 0x5c:
+                            if ( hasEsc )
+                            {
+                                // two following \ are not accepted
+                                LOG.debug( "Syntax invalid for '{}'", value );
+                                return false;
+                            }
+                            else
+                            {
+                                hasEsc = true;
+                            }
+
+                            continue;
+
+                        case '2':
+                            continue;
+
+                        case '4':
+                            // We have found a "\24"
+                            hasEsc = false;
+                            continue;
+
+                        case '5':
+                            continue;
+
+                        case 'c':
+                        case 'C':
+                            // We have found a "\5c" or a "\5C"
+                            hasEsc = false;
+                            continue;
+
+                        default:
+                            if ( hasEsc )
+                            {
+                                // A \ should be followed by "24" or "5c" or "5C"
+                                return false;
+                            }
+
+                            continue;
+                    }
+                }
+            }
+            else
+            {
+                LOG.debug( "Syntax invalid for '{}'", value );
+                return false;
+            }
+        }
+
+        LOG.debug( "Syntax valid for '{}'", value );
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TelexNumberSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TelexNumberSyntaxChecker.java
new file mode 100644
index 0000000..6566a1c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/TelexNumberSyntaxChecker.java
@@ -0,0 +1,174 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a Telex Number according to 
+ * RFC 4517 :
+ * 
+ * telex-number  = actual-number DOLLAR country-code DOLLAR answerback
+ * actual-number = PrintableString
+ * country-code  = PrintableString
+ * answerback    = PrintableString
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class TelexNumberSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( TelexNumberSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of TelexNumberSyntaxChecker.
+     */
+    public TelexNumberSyntaxChecker()
+    {
+        super( SchemaConstants.TELEX_NUMBER_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        if ( strValue.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Search for the first '$' separator
+        int dollar = strValue.indexOf( '$' );
+
+        // We must have one, and not on first position
+        if ( dollar <= 0 )
+        {
+            // No '$' => error
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        String actualNumber = strValue.substring( 0, dollar );
+
+        // The actualNumber must not be empty
+        if ( actualNumber.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The actual number should be a PrintableString 
+        if ( !Strings.isPrintableString( actualNumber ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Search for the second separator
+        int dollar2 = strValue.indexOf( '$', dollar + 1 );
+
+        // We must have one
+        if ( dollar2 == -1 )
+        {
+            // No '$' => error
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        String countryCode = strValue.substring( dollar + 1, dollar2 );
+
+        // The countryCode must not be empty
+        if ( countryCode.length() == 0 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // The country Code should be a PrintableString 
+        if ( !Strings.isPrintableString( countryCode ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Now, check for the answerBack
+        if ( dollar2 + 1 == strValue.length() )
+        {
+            // The last string should not be null
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        String answerBack = strValue.substring( dollar2 + 1 );
+
+        // The answerBack should be a PrintableString 
+        if ( !Strings.isPrintableString( answerBack ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Check that the mailboxType is a PrintableString
+        boolean result = Strings.isPrintableString( answerBack );
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/UtcTimeSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/UtcTimeSyntaxChecker.java
new file mode 100644
index 0000000..7126dc7
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/UtcTimeSyntaxChecker.java
@@ -0,0 +1,150 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A SyntaxChecker which verifies that a value is a UTC time
+ * according to RFC 4517.
+ * 
+ * From RFC 4517 :
+ * UTCTime         = year month day hour minute [ second ] [ u-time-zone ]
+ * u-time-zone     = %x5A          ; "Z" | u-differential
+ * u-differential  = ( MINUS | PLUS ) hour minute
+ *
+ * year    = 2(%x30-39)            ; "00" to "99"
+ * month   = ( %x30 %x31-39 )      ; "01" (January) to "09"
+ *           | ( %x31 %x30-32 )    ; "10" to "12"
+ * day     = ( %x30 %x31-39 )      ; "01" to "09"
+ *           | ( %x31-32 %x30-39 ) ; "10" to "29"
+ *           | ( %x33 %x30-31 )    ; "30" to "31"
+ * hour    = ( %x30-31 %x30-39 ) 
+ *           | ( %x32 %x30-33 )    ; "00" to "23"
+ * minute  = %x30-35 %x30-39       ; "00" to "59"
+ *
+ * second  = ( %x30-35 %x30-39 )   ; "00" to "59"
+ *
+ * g-time-zone = %x5A              ; "Z"
+ *               | g-differential
+ * g-differential = ( MINUS / PLUS ) hour [ minute ]
+ * MINUS   = %x2D  ; minus sign ("-")
+ * 
+ * From RFC 4512 :
+ * PLUS    = %x2B ; plus sign ("+")
+ * 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class UtcTimeSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( UtcTimeSyntaxChecker.class );
+
+    /** The GeneralizedDate pattern matching */
+    private static final String UTC_TIME_PATTERN =
+        // year : 00 to 99
+        "^\\d{2}"
+            // month : 01 to 12
+            + "(0[1-9]|1[0-2])"
+            // day : 01 to 31
+            + "(0[1-9]|[12]\\d|3[01])"
+            // hour: 00 to 23
+            + "([01]\\d|2[0-3])"
+            // minute : 00 to 59
+            + "([0-5]\\d)"
+            + "("
+            // optional second : 00 to 59
+            + "([0-5]\\d)?"
+            // optional time-zone
+            + "(Z|([+-]([01]\\d|2[0-3])[0-5]\\d))?"
+            + ")$";
+
+    // The regexp pattern, java.util.regex.Pattern is immutable so only one instance is needed.
+    private static final Pattern DATE_PATTERN = Pattern.compile( UTC_TIME_PATTERN );
+
+
+    /**
+     * 
+     * Creates a new instance of UtcTimeSyntaxChecker.
+     *
+     */
+    public UtcTimeSyntaxChecker()
+    {
+        super( SchemaConstants.UTC_TIME_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        String strValue = null;
+
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof String )
+        {
+            strValue = ( String ) value;
+        }
+        else if ( value instanceof byte[] )
+        {
+            strValue = Strings.utf8ToString( ( byte[] ) value );
+        }
+        else
+        {
+            strValue = value.toString();
+        }
+
+        // A generalized time must have a minimal length of 11 
+        if ( strValue.length() < 11 )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        // Start the date parsing
+        boolean result = DATE_PATTERN.matcher( strValue ).find();
+
+        if ( result )
+        {
+            LOG.debug( "Syntax valid for '{}'", value );
+        }
+        else
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+        }
+        return result;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/UuidSyntaxChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/UuidSyntaxChecker.java
new file mode 100644
index 0000000..f99ee8c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/UuidSyntaxChecker.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import java.util.UUID;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An UUID syntax checker.
+ * 
+ * UUID ::= OCTET STRING (SIZE(16)) -- constrained to an UUID [RFC4122]
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class UuidSyntaxChecker extends SyntaxChecker
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( UuidSyntaxChecker.class );
+
+
+    /**
+     * Creates a new instance of UUIDSyntaxChecker.
+     */
+    public UuidSyntaxChecker()
+    {
+        super( SchemaConstants.UUID_SYNTAX );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        if ( value == null )
+        {
+            LOG.debug( "Syntax invalid for 'null'" );
+            return false;
+        }
+
+        if ( value instanceof UUID )
+        {
+            return true;
+        }
+
+        if ( !( value instanceof String ) )
+        {
+            LOG.debug( "Syntax invalid for '{}'", value );
+            return false;
+        }
+
+        return Strings.isValidUuid( ( String ) value );
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/AdministrativeRole.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/AdministrativeRole.java
new file mode 100644
index 0000000..eaf2ab5
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/AdministrativeRole.java
@@ -0,0 +1,77 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * The Administrative roles
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum AdministrativeRole
+{
+    /** The AutonomousArea role */
+    AutonomousArea("autonomousArea"),
+
+    /** The AccessControlSpecificArea role */
+    AccessControlSpecificArea("accessControlSpecificArea"),
+
+    /** The AccessControlInnerArea role */
+    AccessControlInnerArea("accessControlInnerArea"),
+
+    /** The CollectiveAttributeSpecificArea role */
+    CollectiveAttributeSpecificArea("collectiveAttributeSpecificArea"),
+
+    /** The CollectiveAttributeInnerArea role */
+    CollectiveAttributeInnerArea("collectiveAttributeInnerArea"),
+
+    /** The SubSchemaSpecificArea role */
+    SubSchemaSpecificArea("subSchemaSpecificArea"),
+
+    /** The TriggerExecutionSpecificArea role */
+    TriggerExecutionSpecificArea("triggerExecutionSpecificArea"),
+
+    /** The TriggerExecutionInnerArea role */
+    TriggerExecutionInnerArea("triggerExecutionInnerArea");
+
+    /** The AdministrativeRole as a String */
+    private String role;
+
+
+    /**
+     * Creates an instance of AdministrativeRole
+     */
+    private AdministrativeRole( String role )
+    {
+        this.role = Strings.toLowerCase( Strings.trim( role ) );
+    }
+
+
+    /**
+     * @return The AdministrativeRole as a String
+     */
+    public String getRole()
+    {
+        return role;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/AndRefinement.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/AndRefinement.java
new file mode 100644
index 0000000..c8109c1
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/AndRefinement.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * A class holding a AND refinement, as defined in RFC 3672
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class AndRefinement implements Refinement
+{
+    /** The set of refinements */
+    private List<Refinement> refinements = new ArrayList<Refinement>();
+
+
+    /**
+     * Creates a new instance of AndRefinement.
+     *
+     * @param refinements The refinements. We may have more than one
+     */
+    public AndRefinement( List<Refinement> refinements )
+    {
+        this.refinements = refinements;
+    }
+
+
+    /**
+     * @return Gets the set of refinements
+     */
+    public List<Refinement> getRefinements()
+    {
+        return refinements;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "and: { " );
+
+        boolean isFirst = true;
+
+        for ( Refinement refinement : refinements )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            sb.append( refinement );
+        }
+
+        sb.append( " }" );
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/BaseSubtreeSpecification.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/BaseSubtreeSpecification.java
new file mode 100644
index 0000000..33f8598
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/BaseSubtreeSpecification.java
@@ -0,0 +1,373 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * A simple implementation of the SubtreeSpecification interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BaseSubtreeSpecification implements SubtreeSpecification
+{
+    /** the subtree base relative to the administration point */
+    private final Dn base;
+
+    /** the set of subordinates entries and their subordinates to exclude */
+    private final Set<Dn> chopBefore;
+
+    /** the set of subordinates entries whose subordinates are to be excluded */
+    private final Set<Dn> chopAfter;
+
+    /** the minimum distance below base to start including entries */
+    private final int minBaseDistance;
+
+    /** the maximum distance from base past which entries are excluded */
+    private final int maxBaseDistance;
+
+    /**
+     * a filter using only assertions on objectClass attributes for subtree
+     * refinement
+     */
+    private final ExprNode refinement;
+
+
+    // -----------------------------------------------------------------------
+    // C O N S T R U C T O R S
+    // -----------------------------------------------------------------------
+
+    /**
+     * Creates a simple subtree whose administrative point is necessarily the
+     * base and all subordinates underneath (excluding those that are part of
+     * inner areas) are part of the the subtree.
+     */
+    @SuppressWarnings("unchecked")
+    public BaseSubtreeSpecification()
+    {
+        this.base = new Dn();
+        this.minBaseDistance = 0;
+        this.maxBaseDistance = UNBOUNDED_MAX;
+        this.chopAfter = Collections.EMPTY_SET;
+        this.chopBefore = Collections.EMPTY_SET;
+        this.refinement = null;
+    }
+
+
+    /**
+     * Creates a simple subtree refinement whose administrative point is
+     * necessarily the base and only those subordinates selected by the
+     * refinement filter are included.
+     *
+     * @param refinement the filter expression only composed of objectClass attribute
+     *  value assertions
+     */
+    @SuppressWarnings("unchecked")
+    public BaseSubtreeSpecification( ExprNode refinement )
+    {
+        this.base = new Dn();
+        this.minBaseDistance = 0;
+        this.maxBaseDistance = UNBOUNDED_MAX;
+        this.chopAfter = Collections.EMPTY_SET;
+        this.chopBefore = Collections.EMPTY_SET;
+        this.refinement = refinement;
+    }
+
+
+    /**
+     * Creates a simple subtree whose administrative point above the base and
+     * all subordinates underneath the base (excluding those that are part of
+     * inner areas) are part of the the subtree.
+     *
+     * @param base the base of the subtree relative to the administrative point
+     */
+    @SuppressWarnings("unchecked")
+    public BaseSubtreeSpecification( Dn base )
+    {
+        this.base = base;
+        this.minBaseDistance = 0;
+        this.maxBaseDistance = UNBOUNDED_MAX;
+        this.chopAfter = Collections.EMPTY_SET;
+        this.chopBefore = Collections.EMPTY_SET;
+        this.refinement = null;
+    }
+
+
+    /**
+     * Creates a subtree without a refinement filter where all other aspects can
+     * be varied.
+     *
+     * @param base the base of the subtree relative to the administrative point
+     * @param minBaseDistance the minimum distance below base to start including entries
+     * @param maxBaseDistance the maximum distance from base past which entries are excluded
+     * @param chopAfter the set of subordinates entries whose subordinates are to be
+     *  excluded
+     * @param chopBefore the set of subordinates entries and their subordinates to
+     * exclude
+     */
+    public BaseSubtreeSpecification( Dn base, int minBaseDistance, int maxBaseDistance,
+        Set<Dn> chopAfter, Set<Dn> chopBefore )
+    {
+        this( base, minBaseDistance, maxBaseDistance, chopAfter, chopBefore, null );
+    }
+
+
+    /**
+     * Creates a subtree which may be a refinement filter where all aspects of
+     * the specification can be set. If the refinement filter is null this
+     * defaults to {@link #BaseSubtreeSpecification(org.apache.directory.api.ldap.model.name.Dn, int, int, Set, Set)}.
+     *
+     * @param base the base of the subtree relative to the administrative point
+     * @param minBaseDistance the minimum distance below base to start including entries
+     * @param maxBaseDistance the maximum distance from base past which entries are excluded
+     * @param chopAfter the set of subordinates entries whose subordinates are to be
+     * excluded
+     * @param chopBefore the set of subordinates entries and their subordinates to
+     * exclude
+     * @param refinement the filter expression only composed of objectClass attribute
+     * value assertions
+     */
+    public BaseSubtreeSpecification( Dn base, int minBaseDistance, int maxBaseDistance,
+        Set<Dn> chopAfter, Set<Dn> chopBefore, ExprNode refinement )
+    {
+        this.base = base;
+        this.minBaseDistance = minBaseDistance;
+
+        if ( maxBaseDistance < 0 )
+        {
+            this.maxBaseDistance = UNBOUNDED_MAX;
+        }
+        else
+        {
+            this.maxBaseDistance = maxBaseDistance;
+        }
+
+        this.chopAfter = chopAfter;
+        this.chopBefore = chopBefore;
+        this.refinement = refinement;
+    }
+
+
+    // -----------------------------------------------------------------------
+    // A C C E S S O R S
+    // -----------------------------------------------------------------------
+    /**
+     * @return The base
+     */
+    public Dn getBase()
+    {
+        return this.base;
+    }
+
+
+    /**
+     * @return The set of ChopBefore exclusions
+     */
+    public Set<Dn> getChopBeforeExclusions()
+    {
+        return this.chopBefore;
+    }
+
+
+    /**
+     * @return The set of ChopAfter exclusions
+     */
+    public Set<Dn> getChopAfterExclusions()
+    {
+        return this.chopAfter;
+    }
+
+
+    /**
+     * @return The mimimum distance from the base
+     */
+    public int getMinBaseDistance()
+    {
+        return this.minBaseDistance;
+    }
+
+
+    /**
+     * @return The maximum distance from the base
+     */
+    public int getMaxBaseDistance()
+    {
+        return this.maxBaseDistance;
+    }
+
+
+    /**
+     * @return The refinement
+     */
+    public ExprNode getRefinement()
+    {
+        return this.refinement;
+    }
+
+
+    /**
+     * Converts this item into its string representation as stored
+     * in directory.
+     *
+     * @param buffer the string buffer
+     */
+    public void toString( StringBuilder buffer )
+    {
+        buffer.append( toString() );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder buffer = new StringBuilder();
+        boolean isFirst = true;
+        buffer.append( '{' );
+
+        // The base
+        if ( !base.isEmpty() )
+        {
+            buffer.append( " base \"" );
+            buffer.append( base.getName() );
+            buffer.append( '"' );
+            isFirst = false;
+        }
+
+        // The minimum
+        if ( minBaseDistance > 0 )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+                buffer.append( " " );
+            }
+            else
+            {
+                buffer.append( ", " );
+            }
+
+            buffer.append( "minimum " );
+            buffer.append( minBaseDistance );
+        }
+
+        // The maximum
+        if ( maxBaseDistance > UNBOUNDED_MAX )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+                buffer.append( " " );
+            }
+            else
+            {
+                buffer.append( ", " );
+            }
+
+            buffer.append( "maximum " );
+            buffer.append( maxBaseDistance );
+        }
+
+        // The chopBefore exclusions
+        if ( ( ( chopBefore != null ) && !chopBefore.isEmpty() ) || ( ( chopAfter != null ) && !chopAfter.isEmpty() ) )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+                buffer.append( " " );
+            }
+            else
+            {
+                buffer.append( ", " );
+            }
+
+            buffer.append( "specificExclusions { " );
+
+            boolean isFirstExclusion = true;
+
+            if ( chopBefore != null )
+            {
+                for ( Dn exclusion : chopBefore )
+                {
+                    if ( isFirstExclusion )
+                    {
+                        isFirstExclusion = false;
+                    }
+                    else
+                    {
+                        buffer.append( ", " );
+                    }
+
+                    buffer.append( "chopBefore: \"" );
+                    buffer.append( exclusion.getName() );
+                    buffer.append( '"' );
+                }
+            }
+
+            if ( chopAfter != null )
+            {
+                for ( Dn exclusion : chopAfter )
+                {
+                    if ( isFirstExclusion )
+                    {
+                        isFirstExclusion = false;
+                    }
+                    else
+                    {
+                        buffer.append( ", " );
+                    }
+
+                    buffer.append( "chopAfter: \"" );
+                    buffer.append( exclusion.getName() );
+                    buffer.append( '"' );
+                }
+            }
+
+            buffer.append( " }" );
+        }
+
+        if ( refinement != null )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+                buffer.append( " " );
+            }
+            else
+            {
+                buffer.append( ", " );
+            }
+
+            buffer.append( "specificationFilter " );
+            buffer.append( refinement.toString() );
+        }
+
+        buffer.append( " }" );
+
+        return buffer.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ItemRefinement.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ItemRefinement.java
new file mode 100644
index 0000000..06fba4e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ItemRefinement.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+
+
+/**
+ * A class holding a n ITEM refinement, as defined in RFC 3672
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class ItemRefinement implements Refinement
+{
+    /** The item */
+    private ObjectClass item;
+
+
+    /**
+     * Creates a new instance of ItemRefinement.
+     *
+     * @param item The ObjectClass associated with this refinement
+     */
+    public ItemRefinement( ObjectClass item )
+    {
+        this.item = item;
+    }
+
+
+    /**
+     * @return the item
+     */
+    public ObjectClass getItem()
+    {
+        return item;
+    }
+
+
+    /**
+     * @param item the item to set
+     */
+    public void setItem( ObjectClass item )
+    {
+        this.item = item;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "item : " );
+        sb.append( item.getName() );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/NotRefinement.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/NotRefinement.java
new file mode 100644
index 0000000..a69669a
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/NotRefinement.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+/**
+ * A class holding a NOT refinement, as defined in RFC 3672
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class NotRefinement implements Refinement
+{
+    /** The refinement */
+    private Refinement refinement;
+
+
+    public NotRefinement( Refinement refinement )
+    {
+        this.refinement = refinement;
+    }
+
+
+    /**
+     * @return the refinement
+     */
+    public Refinement getRefinement()
+    {
+        return refinement;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "not: " );
+        sb.append( refinement );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/OrRefinement.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/OrRefinement.java
new file mode 100644
index 0000000..a0f7633
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/OrRefinement.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * A class holding a OR refinement, as defined in RFC 3672
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class OrRefinement implements Refinement
+{
+    /** The set of refinements */
+    private List<Refinement> refinements = new ArrayList<Refinement>();
+
+
+    /**
+     * Creates a new instance of OrRefinement.
+     *
+     * @param refinements The refinements. We may have more than one
+     */
+    public OrRefinement( List<Refinement> refinements )
+    {
+        this.refinements = refinements;
+    }
+
+
+    /**
+     * @return Gets the set of refinements
+     */
+    public List<Refinement> getRefinements()
+    {
+        return refinements;
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( "or: { " );
+
+        boolean isFirst = true;
+
+        for ( Refinement refinement : refinements )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            sb.append( refinement );
+        }
+
+        sb.append( " }" );
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/Refinement.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/Refinement.java
new file mode 100644
index 0000000..84c6c08
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/Refinement.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+/**
+ * An empty interface used for Refinements.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public interface Refinement
+{
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationChecker.java
new file mode 100644
index 0000000..d803476
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationChecker.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr parser without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrSubtreeSpecificationChecker extends AntlrSubtreeSpecificationChecker
+{
+    /**
+     * Creates a ReusableAntlrSubtreeSpecificationParser instance.
+     */
+    public ReusableAntlrSubtreeSpecificationChecker( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+
+        this.getInputState().reset();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationCheckerLexer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationCheckerLexer.java
new file mode 100644
index 0000000..5af10af
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationCheckerLexer.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.io.Reader;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+
+
+/**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr lexer without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ReusableAntlrSubtreeSpecificationCheckerLexer extends AntlrSubtreeSpecificationCheckerLexer
+{
+    private boolean savedCaseSensitive;
+
+    private boolean savedCaseSensitiveLiterals;
+
+
+    /**
+     * Creates a ReusableAntlrSubtreeSpecificationLexer instance.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public ReusableAntlrSubtreeSpecificationCheckerLexer( Reader in )
+    {
+        super( in );
+        savedCaseSensitive = getCaseSensitive();
+        savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+    }
+
+
+    /**
+     * Resets the state of an antlr lexer and initializes it with new input.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public void prepareNextInput( Reader in )
+    {
+        CharBuffer buf = new CharBuffer( in );
+        LexerSharedInputState state = new LexerSharedInputState( buf );
+        this.setInputState( state );
+
+        this.setCaseSensitive( savedCaseSensitive );
+
+        // no set method for this protected field.
+        this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationLexer.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationLexer.java
new file mode 100644
index 0000000..b696c70
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationLexer.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.io.Reader;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+
+
+/**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr lexer without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ReusableAntlrSubtreeSpecificationLexer extends AntlrSubtreeSpecificationLexer
+{
+    private boolean savedCaseSensitive;
+
+    private boolean savedCaseSensitiveLiterals;
+
+
+    /**
+     * Creates a ReusableAntlrSubtreeSpecificationLexer instance.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public ReusableAntlrSubtreeSpecificationLexer( Reader in )
+    {
+        super( in );
+        savedCaseSensitive = getCaseSensitive();
+        savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+    }
+
+
+    /**
+     * Resets the state of an antlr lexer and initializes it with new input.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public void prepareNextInput( Reader in )
+    {
+        CharBuffer buf = new CharBuffer( in );
+        LexerSharedInputState state = new LexerSharedInputState( buf );
+        this.setInputState( state );
+
+        this.setCaseSensitive( savedCaseSensitive );
+
+        // no set method for this protected field.
+        this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationParser.java
new file mode 100644
index 0000000..715022e
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/ReusableAntlrSubtreeSpecificationParser.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr parser without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class ReusableAntlrSubtreeSpecificationParser extends AntlrSubtreeSpecificationParser
+{
+    /**
+     * Creates a ReusableAntlrSubtreeSpecificationParser instance.
+     */
+    public ReusableAntlrSubtreeSpecificationParser( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+
+        this.getInputState().reset();
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/Subentry.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/Subentry.java
new file mode 100644
index 0000000..5ae1556
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/Subentry.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.util.Set;
+
+
+
+/**
+ * An operational view of a subentry within the system. A Subentry can have
+ * many types (Collective, Schema, AccessControl or Trigger) but only one
+ * Subtree Specification.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Subentry
+{
+    /** The Subtree Specification associated with this subentry */
+    private SubtreeSpecification ss;
+
+    /** The administratives roles */
+    private Set<AdministrativeRole> administrativeRoles;
+
+
+    /**
+     * Stores the subtree
+     *
+     * @param ss The subtree specification
+     */
+    public final void setSubtreeSpecification( SubtreeSpecification ss )
+    {
+        this.ss = ss;
+    }
+
+
+    /**
+     * @return The subtree specification
+     */
+    public final SubtreeSpecification getSubtreeSpecification()
+    {
+        return ss;
+    }
+
+
+    /**
+     *
+     * TODO setAdministrativeRoles.
+     *
+     * @param administrativeRoles
+     */
+    public final void setAdministrativeRoles( Set<AdministrativeRole> administrativeRoles )
+    {
+        this.administrativeRoles = administrativeRoles;
+    }
+
+
+    public final Set<AdministrativeRole> getAdministrativeRoles()
+    {
+        return administrativeRoles;
+    }
+
+
+    /**
+     * Tells if the type contains the Collective attribute Administrative Role
+     */
+    public final boolean isCollectiveAdminRole()
+    {
+        return administrativeRoles.contains( AdministrativeRole.CollectiveAttributeInnerArea )
+            || administrativeRoles.contains( AdministrativeRole.CollectiveAttributeSpecificArea );
+    }
+
+
+    /**
+     * Tells if the type contains the SubSchema Administrative Role
+     */
+    public final boolean isSchemaAdminRole()
+    {
+        return administrativeRoles.contains( AdministrativeRole.SubSchemaSpecificArea );
+    }
+
+
+    /**
+     * Tells if the type contains the Access Control Administrative Role
+     */
+    public final boolean isAccessControlAdminRole()
+    {
+        return administrativeRoles.contains( AdministrativeRole.AccessControlSpecificArea )
+            || administrativeRoles.contains( AdministrativeRole.AccessControlInnerArea );
+    }
+
+
+    /**
+     * Tells if the type contains the Triggers Administrative Role
+     */
+    public final boolean isTriggersAdminRole()
+    {
+        return administrativeRoles.contains( AdministrativeRole.TriggerExecutionSpecificArea )
+            || administrativeRoles.contains( AdministrativeRole.TriggerExecutionInnerArea );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return "Subentry[" + administrativeRoles + ", " + ss + "]";
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecification.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecification.java
new file mode 100644
index 0000000..9bdcf2c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecification.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a> defined a
+ * subtree specification to be included within subentries.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SubtreeSpecification
+{
+    /** an unbounded maximum depth value in a subtree specification */
+    int UNBOUNDED_MAX = -1;
+
+
+    /**
+     * Gets an Rdn relative to the administrative context where the subtree
+     * scope begins. All subentries containing these specifications are
+     * immediate subordinates to the administrative point, and are considered to
+     * be part of the same naming context. Hence the base for the subtree
+     * specification of a subentry immediately subordinate to dc=apache,dc=org
+     * would be relative to the dc=apache,dc=org context.
+     * 
+     * @return the Rdn representing the base of the subtree, or the empty name
+     *         if the base is the administrative point - note that this Name is
+     *         not Normalized according to matchingRules.
+     */
+    Dn getBase();
+
+
+    /**
+     * A set of RDNs relative to the base entry representing chopBefore
+     * specificExclusions from the subtree. According to RFC 3672: "If the
+     * chopBefore form is used then the specified entry and its subordinates are
+     * excluded from the subtree or subtree refinement."
+     * 
+     * @return a set of relative {@link javax.naming.Name}s to the subtree base
+     *         or the empty set
+     */
+    Set<Dn> getChopBeforeExclusions();
+
+
+    /**
+     * A set of RDNs relative to the base entry representing chopAfter
+     * specificExclusions from the subtree. According to RFC 3672: "If the
+     * chopAfter form is used then only the subordinates of the specified entry
+     * are excluded from the subtree or subtree refinement."
+     * 
+     * @return a set of relative {@link javax.naming.Name}s to the subtree base
+     *         or the empty set
+     */
+    Set<Dn> getChopAfterExclusions();
+
+
+    /**
+     * Gets the distance at which to start including entries in the subtree. All
+     * entries whose Rdn arcs relative to the base are less than the minimum are
+     * excluded from the subtree or subtree refinement. The default is zero and
+     * therefore excludes nothing.
+     * 
+     * @return the minimum number of Rdn arcs relative to base for inclusion
+     */
+    int getMinBaseDistance();
+
+
+    /**
+     * Gets the distance after which to start excluding entries in the subtree
+     * or subtree refinement. RFC 3672 Section 2.1.3 states: "Entries that are
+     * more than the maximum number of Rdn arcs below the base entry are
+     * excluded from the subtree or subtree refinement. An absent maximum
+     * component indicates that there is no upper limit on the number of Rdn
+     * arcs below the base entry for entries in the subtree or subtree
+     * refinement." If the maximum is limitless a negative value should be used
+     * to represent the maximum distance - which makes no sense other than to
+     * denote the lack of an upper limit.
+     * 
+     * @see #UNBOUNDED_MAX
+     * @return the number of arcs relative to the base after which entries are
+     *         excluded
+     */
+    int getMaxBaseDistance();
+
+
+    /**
+     * A subtree refinement represents a non-contiguous selection of entries
+     * using a limited filter expression where attribute assertions are based on
+     * the objectClass of the entries.
+     * 
+     * @return a refinement tree or null if one does not exist for this subtree
+     *         specification
+     */
+    ExprNode getRefinement();
+
+
+    /**
+     * Converts this item into its string representation as stored
+     * in directory.
+     *
+     * @param buffer the string buffer
+     */
+    void toString( StringBuilder buffer );
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationChecker.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationChecker.java
new file mode 100644
index 0000000..be28a01
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationChecker.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.io.StringReader;
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper around the antlr generated parser for an LDAP subtree
+ * specification as defined by <a href="http://www.faqs.org/rfcs/rfc3672.html">
+ * RFC 3672</a>. This class enables the reuse of the antlr parser/lexer pair
+ * without having to recreate the pair every time.
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubtreeSpecificationChecker
+{
+    /** the antlr generated parser being wrapped */
+    private ReusableAntlrSubtreeSpecificationChecker parser;
+
+    /** the antlr generated lexer being wrapped */
+    private ReusableAntlrSubtreeSpecificationCheckerLexer lexer;
+
+
+    /**
+     * Creates a normalizing subtree specification parser.
+     */
+    public SubtreeSpecificationChecker( SchemaManager schemaManager )
+    {
+        // place holder for the first input
+        StringReader in = new StringReader( "" );
+        this.lexer = new ReusableAntlrSubtreeSpecificationCheckerLexer( in );
+        this.parser = new ReusableAntlrSubtreeSpecificationChecker( lexer );
+
+        // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.parser.init( schemaManager );
+    }
+
+
+    /**
+     * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+     * pair with it. param spec the specification to be parsed
+     */
+    private synchronized void reset( String spec )
+    {
+        // append end of input token
+        StringReader in = new StringReader( spec + "end" );
+        this.lexer.prepareNextInput( in );
+        this.parser.resetState();
+    }
+
+
+    /**
+     * Parses a subtree specification without exhausting the parser.
+     * 
+     * @param spec
+     *            the specification to be parsed
+     * @throws ParseException
+     *             if there are any recognition errors (bad syntax)
+     */
+    public synchronized void parse( String spec ) throws ParseException
+    {
+        if ( spec == null || spec.trim().equals( "" ) )
+        {
+            return;
+        }
+
+        // reset and initialize the parser / lexer pair
+        reset( spec );
+
+        try
+        {
+            this.parser.wrapperEntryPoint();
+        }
+        catch ( TokenStreamException e )
+        {
+            String msg = I18n.err( I18n.ERR_04329, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, 0 );
+        }
+        catch ( RecognitionException e )
+        {
+            String msg = I18n.err( I18n.ERR_04329, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, e.getColumn() );
+        }
+        catch ( Exception e )
+        {
+            String msg = I18n.err( I18n.ERR_04329, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, 0 );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationModifier.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationModifier.java
new file mode 100644
index 0000000..c176465
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationModifier.java
@@ -0,0 +1,183 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.name.Dn;
+
+
+/**
+ * SubtreeSpecification contains no setters so they must be built by a
+ * modifiable object containing all the necessary parameters to build the base
+ * object.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubtreeSpecificationModifier
+{
+    /** the subtree base relative to the administration point */
+    private Dn base = new Dn();
+
+    /** the set of subordinates entries and their subordinates to exclude */
+    private Set<Dn> chopBefore = Collections.emptySet();
+
+    /** the set of subordinates entries whose subordinates are to be excluded */
+    private Set<Dn> chopAfter = Collections.emptySet();
+
+    /** the minimum distance below base to start including entries */
+    private int minBaseDistance = 0;
+
+    /** the maximum distance from base past which entries are excluded */
+    private int maxBaseDistance = SubtreeSpecification.UNBOUNDED_MAX;
+
+    /**
+     * a filter using only assertions on objectClass attributes for subtree
+     * refinement
+     */
+    private ExprNode filter;
+
+
+    // -----------------------------------------------------------------------
+    // F A C T O R Y M E T H O D
+    // -----------------------------------------------------------------------
+
+    /**
+     * Creates a SubtreeSpecification using any of the default paramters that
+     * may have been modified from their defaults.
+     * 
+     * @return the newly created subtree specification
+     */
+    public SubtreeSpecification getSubtreeSpecification()
+    {
+
+        return new BaseSubtreeSpecification( this.base, this.minBaseDistance, this.maxBaseDistance, this.chopAfter,
+            this.chopBefore, this.filter );
+    }
+
+
+    // -----------------------------------------------------------------------
+    // M U T A T O R S
+    // -----------------------------------------------------------------------
+
+    /**
+     * Sets the subtree base relative to the administration point.
+     * 
+     * @param base
+     *            subtree base relative to the administration point
+     */
+    public void setBase( Dn base )
+    {
+        this.base = base;
+    }
+
+
+    /**
+     * Sets the set of subordinates entries and their subordinates to exclude.
+     * 
+     * @param chopBeforeExclusions
+     *            the set of subordinates entries and their subordinates to
+     *            exclude
+     */
+    public void setChopBeforeExclusions( Set<Dn> chopBeforeExclusions )
+    {
+        this.chopBefore = chopBeforeExclusions;
+    }
+
+
+    /**
+     * Sets the set of subordinates entries whose subordinates are to be
+     * excluded.
+     * 
+     * @param chopAfterExclusions
+     *            the set of subordinates entries whose subordinates are to be
+     *            excluded
+     */
+    public void setChopAfterExclusions( Set<Dn> chopAfterExclusions )
+    {
+        this.chopAfter = chopAfterExclusions;
+    }
+
+
+    /**
+     * Sets the minimum distance below base to start including entries.
+     * 
+     * @param minBaseDistance
+     *            the minimum distance below base to start including entries
+     */
+    public void setMinBaseDistance( int minBaseDistance )
+    {
+        if ( minBaseDistance < 0 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04330 ) );
+        }
+
+        this.minBaseDistance = minBaseDistance;
+    }
+
+
+    /**
+     * Sets the maximum distance from base past which entries are excluded.
+     * 
+     * @param maxBaseDistance
+     *            the maximum distance from base past which entries are excluded
+     */
+    public void setMaxBaseDistance( int maxBaseDistance )
+    {
+        if ( maxBaseDistance < 0 )
+        {
+            this.maxBaseDistance = SubtreeSpecification.UNBOUNDED_MAX;
+        }
+        else
+        {
+            this.maxBaseDistance = maxBaseDistance;
+        }
+    }
+
+
+    /**
+     * Sets a filter using only assertions on objectClass attributes for subtree
+     * refinement.
+     * 
+     * TODO: there is a setFilter() method, remove this method?
+     * 
+     * @param refinement a filter using only assertions on objectClass attributes for
+     *            subtree refinement
+     */
+    public void setRefinement( ExprNode refinement )
+    {
+        this.filter = refinement;
+    }
+
+
+    /**
+     * Sets a filter
+     * 
+     * @param filter a filter
+     */
+    public void setFilter( ExprNode filter )
+    {
+        this.filter = filter;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationParser.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationParser.java
new file mode 100644
index 0000000..bc347b9
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/subtree/SubtreeSpecificationParser.java
@@ -0,0 +1,156 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.ldap.model.subtree;
+
+
+import java.io.StringReader;
+import java.text.ParseException;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.schema.NormalizerMappingResolver;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper around the antlr generated parser for an LDAP subtree
+ * specification as defined by <a href="http://www.faqs.org/rfcs/rfc3672.html">
+ * RFC 3672</a>. This class enables the reuse of the antlr parser/lexer pair
+ * without having to recreate the pair every time.
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubtreeSpecificationParser
+{
+    /** the antlr generated parser being wrapped */
+    private ReusableAntlrSubtreeSpecificationParser parser;
+
+    /** the antlr generated lexer being wrapped */
+    private ReusableAntlrSubtreeSpecificationLexer lexer;
+
+    private final boolean isNormalizing;
+
+
+    /**
+     * Creates a subtree specification parser.
+     */
+    public SubtreeSpecificationParser( SchemaManager schemaManager )
+    {
+        // place holder for the first input
+        StringReader in = new StringReader( "" );
+        this.lexer = new ReusableAntlrSubtreeSpecificationLexer( in );
+        this.parser = new ReusableAntlrSubtreeSpecificationParser( lexer );
+        // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.parser.init( schemaManager );
+        this.isNormalizing = false;
+    }
+
+
+    /**
+     * Creates a normalizing subtree specification parser.
+     */
+    public SubtreeSpecificationParser( @SuppressWarnings("rawtypes") NormalizerMappingResolver resolver,
+        SchemaManager schemaManager )
+    {
+        // place holder for the first input
+        StringReader in = new StringReader( "" );
+        this.lexer = new ReusableAntlrSubtreeSpecificationLexer( in );
+        this.parser = new ReusableAntlrSubtreeSpecificationParser( lexer );
+        this.parser.setNormalizerMappingResolver( resolver );
+        // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.parser.init( schemaManager );
+        this.isNormalizing = true;
+    }
+
+
+    /**
+     * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+     * pair with it. param spec the specification to be parsed
+     */
+    private synchronized void reset( String spec )
+    {
+        // append end of input token
+        StringReader in = new StringReader( spec + "end" );
+        this.lexer.prepareNextInput( in );
+        this.parser.resetState();
+    }
+
+
+    /**
+     * Parses a subtree specification without exhausting the parser.
+     * 
+     * @param spec
+     *            the specification to be parsed
+     * @return the specification bean
+     * @throws ParseException
+     *             if there are any recognition errors (bad syntax)
+     */
+    public synchronized SubtreeSpecification parse( String spec ) throws ParseException
+    {
+        SubtreeSpecification ss = null;
+
+        if ( spec == null || spec.trim().equals( "" ) )
+        {
+            return null;
+        }
+
+        // reset and initialize the parser / lexer pair
+        reset( spec );
+
+        try
+        {
+            ss = this.parser.wrapperEntryPoint();
+        }
+        catch ( TokenStreamException e )
+        {
+            String msg = I18n.err( I18n.ERR_04329, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, 0 );
+        }
+        catch ( RecognitionException e )
+        {
+            String msg = I18n.err( I18n.ERR_04329, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, e.getColumn() );
+        }
+        catch ( Exception e )
+        {
+            String msg = I18n.err( I18n.ERR_04329, spec, e.getLocalizedMessage() );
+            throw new ParseException( msg, 0 );
+        }
+
+        return ss;
+    }
+
+
+    /**
+     * Tests to see if this parser is normalizing.
+     * 
+     * @return true if it normalizes false otherwise
+     */
+    public boolean isNormizing()
+    {
+        return this.isNormalizing;
+    }
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/url/HostTypeEnum.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/url/HostTypeEnum.java
new file mode 100644
index 0000000..801458c
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/url/HostTypeEnum.java
@@ -0,0 +1,41 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.url;
+
+/**
+ * The type of Host we may have . One of :
+ * <ul>
+ * <li>IPV4 : IPV4 host</li>
+ * <li>IPV6 : IPV6 host</li>
+ * <li>IPV_FUTURE : IP v Future host</li>
+ * <li>REGULAR_NAME : A regular name</li>
+ * <li></li>
+ * </ul>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum HostTypeEnum
+{
+    IPV4,
+    IPV6,
+    IPV_FUTURE,
+    REGULAR_NAME
+}
diff --git a/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/url/LdapUrl.java b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/url/LdapUrl.java
new file mode 100644
index 0000000..bf072af
--- /dev/null
+++ b/trunk/ldap/model/src/main/java/org/apache/directory/api/ldap/model/url/LdapUrl.java
@@ -0,0 +1,2163 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.url;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.exception.LdapUriException;
+import org.apache.directory.api.ldap.model.exception.UrlDecoderException;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Chars;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.util.Unicode;
+
+
+/**
+ * Decodes a LdapUrl, and checks that it complies with
+ * the RFC 4516. The grammar is the following :
+ * <pre>
+ * ldapurl    = scheme "://" [host [ ":" port]] ["/"
+ *                   dn ["?" [attributes] ["?" [scope]
+ *                   ["?" [filter] ["?" extensions]]]]]
+ * scheme     = "ldap"
+ * dn         = Dn
+ * attributes = attrdesc ["," attrdesc]*
+ * attrdesc   = selector ["," selector]*
+ * selector   = attributeSelector (from Section 4.5.1 of RFC4511)
+ * scope      = "base" / "one" / "sub"
+ * extensions = extension ["," extension]*
+ * extension  = ["!"] extype ["=" exvalue]
+ * extype     = oid (from Section 1.4 of RFC4512)
+ * exvalue    = LDAPString (from Section 4.1.2 of RFC4511)
+ * host       = host from Section 3.2.2 of RFC3986
+ * port       = port from Section 3.2.3 of RFC3986
+ * filter     = filter from Section 3 of RFC 4515
+ * </pre>
+ * 
+ * From Section 3.2.1/2 of RFC3986
+ * <pre>
+ * host        = IP-literal / IPv4address / reg-name
+ * port        = *DIGIT
+ * IP-literal  = "[" ( IPv6address / IPvFuture  ) "]"
+ * IPvFuture   = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+ * IPv6address = 6( h16 ":" ) ls32 
+ *               | "::" 5( h16 ":" ) ls32
+ *               | [               h16 ] "::" 4( h16 ":" ) ls32
+ *               | [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ *               | [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ *               | [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
+ *               | [ *4( h16 ":" ) h16 ] "::"              ls32
+ *               | [ *5( h16 ":" ) h16 ] "::"              h16
+ *               | [ *6( h16 ":" ) h16 ] "::"
+ * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+ * dec-octet   = DIGIT | [1-9] DIGIT | "1" 2DIGIT | "2" [0-4] DIGIT | "25" [0-5]
+ * reg-name    = *( unreserved / pct-encoded / sub-delims )
+ * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * pct-encoded = "%" HEXDIG HEXDIG
+ * sub-delims  = "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="
+ * h16         = 1*4HEXDIG
+ * ls32        = ( h16 ":" h16 ) / IPv4address
+ * DIGIT       = 0..9
+ * ALPHA       = A-Z / a-z
+ * HEXDIG      = DIGIT / A-F / a-f
+ * </pre>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapUrl
+{
+    /** The constant for "ldaps://" scheme. */
+    public static final String LDAPS_SCHEME = "ldaps://";
+
+    /** The constant for "ldap://" scheme. */
+    public static final String LDAP_SCHEME = "ldap://";
+
+    /** A null LdapUrl */
+    public static final LdapUrl EMPTY_URL = new LdapUrl();
+
+    /** The scheme */
+    private String scheme;
+
+    /** The host */
+    private String host;
+
+    /** The port */
+    private int port;
+
+    /** The Dn */
+    private Dn dn;
+
+    /** The attributes */
+    private List<String> attributes;
+
+    /** The scope */
+    private SearchScope scope;
+
+    /** The filter as a string */
+    private String filter;
+
+    /** The extensions. */
+    private List<Extension> extensionList;
+
+    /** Stores the LdapUrl as a String */
+    private String string;
+
+    /** Stores the LdapUrl as a byte array */
+    private byte[] bytes;
+
+    /** modal parameter that forces explicit scope rendering in toString */
+    private boolean forceScopeRendering;
+    
+    /** The type of host we use */
+    private HostTypeEnum hostType = HostTypeEnum.REGULAR_NAME;
+
+    /** A regexp for attributes */
+    private static final Pattern ATTRIBUTE = Pattern
+        .compile( "(?:(?:\\d|[1-9]\\d*)(?:\\.(?:\\d|[1-9]\\d*))+)|(?:[a-zA-Z][a-zA-Z0-9-]*)" );
+
+
+    /**
+     * Construct an empty LdapUrl
+     */
+    public LdapUrl()
+    {
+        scheme = LDAP_SCHEME;
+        host = null;
+        port = -1;
+        dn = null;
+        attributes = new ArrayList<String>();
+        scope = SearchScope.OBJECT;
+        filter = null;
+        extensionList = new ArrayList<Extension>( 2 );
+    }
+
+
+    /**
+     * Parse a LdapUrl.
+     * 
+     * @param chars The chars containing the URL
+     * @throws org.apache.directory.api.ldap.model.exception.LdapURLEncodingException If the URL is invalid
+     */
+    private void parse( char[] chars ) throws LdapURLEncodingException
+    {
+        scheme = LDAP_SCHEME;
+        host = null;
+        port = -1;
+        dn = null;
+        attributes = new ArrayList<String>();
+        scope = SearchScope.OBJECT;
+        filter = null;
+        extensionList = new ArrayList<Extension>( 2 );
+
+        if ( ( chars == null ) || ( chars.length == 0 ) )
+        {
+            host = "";
+            return;
+        }
+
+        // ldapurl = scheme "://" [hostport] ["/"
+        // [dn ["?" [attributes] ["?" [scope]
+        // ["?" [filter] ["?" extensions]]]]]]
+        // scheme = "ldap"
+        int pos = 0;
+
+        // The scheme
+        pos = Strings.areEquals( chars, 0, LDAP_SCHEME );
+        if ( pos == StringConstants.NOT_EQUAL )
+        {
+            pos = Strings.areEquals( chars, 0, LDAPS_SCHEME );
+            if ( pos == StringConstants.NOT_EQUAL )
+            {
+                throw new LdapURLEncodingException( I18n.err( I18n.ERR_04398 ) );
+            }
+        }
+        scheme = new String( chars, 0, pos );
+
+        // The hostport
+        pos = parseHostPort( chars, pos );
+        if ( pos == -1 )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04399 ) );
+        }
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+
+        // An optional '/'
+        if ( !Chars.isCharASCII( chars, pos, '/' ) )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04400, pos, chars[pos] ) );
+        }
+
+        pos++;
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+
+        // An optional Dn
+        pos = parseDN( chars, pos );
+        if ( pos == -1 )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04401 ) );
+        }
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+
+        // Optionals attributes
+        if ( !Chars.isCharASCII( chars, pos, '?' ) )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04402, pos, chars[pos] ) );
+        }
+
+        pos++;
+
+        pos = parseAttributes( chars, pos );
+        if ( pos == -1 )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04403 ) );
+        }
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+
+        // Optional scope
+        if ( !Chars.isCharASCII( chars, pos, '?' ) )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04402, pos, chars[pos] ) );
+        }
+
+        pos++;
+
+        pos = parseScope( chars, pos );
+        if ( pos == -1 )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04404 ) );
+        }
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+
+        // Optional filter
+        if ( !Chars.isCharASCII( chars, pos, '?' ) )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04402, pos, chars[pos] ) );
+        }
+
+        pos++;
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+
+        pos = parseFilter( chars, pos );
+        if ( pos == -1 )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04405 ) );
+        }
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+
+        // Optional extensions
+        if ( !Chars.isCharASCII( chars, pos, '?' ) )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04402, pos, chars[pos] ) );
+        }
+
+        pos++;
+
+        pos = parseExtensions( chars, pos );
+        if ( pos == -1 )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04406 ) );
+        }
+
+        if ( pos == chars.length )
+        {
+            return;
+        }
+        else
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04407 ) );
+        }
+    }
+
+
+    /**
+     * Create a new LdapUrl from a String after having parsed it.
+     *
+     * @param string TheString that contains the LdapUrl
+     * @throws LdapURLEncodingException If the String does not comply with RFC 2255
+     */
+    public LdapUrl( String string ) throws LdapURLEncodingException
+    {
+        if ( string == null )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04408 ) );
+        }
+
+        try
+        {
+            bytes = string.getBytes( "UTF-8" );
+            this.string = string;
+            parse( string.toCharArray() );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            throw new LdapURLEncodingException( I18n.err( I18n.ERR_04409, string ) , uee );
+        }
+    }
+
+
+    /**
+     * Parse this rule : <br>
+     * <pre>
+     * host        = IP-literal / IPv4address / reg-name
+     * port        = *DIGIT
+     * <host> ::= <hostname> ':' <hostnumber><br>
+     * <hostname> ::= *[ <domainlabel> "." ] <toplabel><br>
+     * <domainlabel> ::= <alphadigit> | <alphadigit> *[
+     * <alphadigit> | "-" ] <alphadigit><br>
+     * <toplabel> ::= <alpha> | <alpha> *[ <alphadigit> |
+     * "-" ] <alphadigit><br>
+     * <hostnumber> ::= <digits> "." <digits> "."
+     * <digits> "." <digits>
+     * </pre>
+     *
+     * @param chars The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not
+     *         apply to the byte buffer TODO check that the topLabel is valid
+     *         (it must start with an alpha)
+     */
+    private int parseHost( char[] chars, int pos )
+    {
+        int start = pos;
+
+        // The host will be followed by a '/' or a ':', or by nothing if it's
+        // the end.
+        // We will search the end of the host part, and we will check some
+        // elements.
+        switch ( chars[pos] )
+        {
+            case '[' :
+                // This is an IP Literal address
+                return parseIpLiteral( chars, pos + 1 );
+                
+            case '0' :
+            case '1' :
+            case '2' :
+            case '3' :
+            case '4' :
+            case '5' :
+            case '6' :
+            case '7' :
+            case '8' :
+            case '9' :
+                // Probably an IPV4 address, but may be a reg-name
+                // try to parse an IPV4 address first
+                int currentPos = parseIPV4( chars, pos );
+                
+                if ( currentPos != -1 )
+                {
+                    host = new String( chars, start, currentPos - start );
+                    
+                    return currentPos;
+                }
+                //fallback to reg-name
+                
+            case 'a' : case 'b' : case 'c' : case 'd' : case 'e' :
+            case 'A' : case 'B' : case 'C' : case 'D' : case 'E' :
+            case 'f' : case 'g' : case 'h' : case 'i' : case 'j' :
+            case 'F' : case 'G' : case 'H' : case 'I' : case 'J' :
+            case 'k' : case 'l' : case 'm' : case 'n' : case 'o' :
+            case 'K' : case 'L' : case 'M' : case 'N' : case 'O' :
+            case 'p' : case 'q' : case 'r' : case 's' : case 't' :
+            case 'P' : case 'Q' : case 'R' : case 'S' : case 'T' :
+            case 'u' : case 'v' : case 'w' : case 'x' : case 'y' :
+            case 'U' : case 'V' : case 'W' : case 'X' : case 'Y' :
+            case 'z' : case 'Z' : case '-' : case '.' : case '_' :
+            case '~' : case '%' : case '!' : case '$' : case '&' :
+            case '\'' : case '(' : case ')' : case '*' : case '+' :
+            case ',' : case ';' : case '=' :
+                // A reg-name
+                return parseRegName( chars, pos );
+
+            default:
+                break;
+        }
+        
+        host = new String( chars, start, pos - start );
+
+        return pos;
+    }
+    
+    
+    /**
+     * parse these rules :
+     * <pre>
+     * IP-literal  = "[" ( IPv6address / IPvFuture  ) "]"
+     * IPvFuture   = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+     * IPv6address = 6( h16 ":" ) ls32 
+     *               | "::" 5( h16 ":" ) ls32
+     *               | [               h16 ] "::" 4( h16 ":" ) ls32
+     *               | [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+     *               | [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+     *               | [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
+     *               | [ *4( h16 ":" ) h16 ] "::"              ls32
+     *               | [ *5( h16 ":" ) h16 ] "::"              h16
+     *               | [ *6( h16 ":" ) h16 ] "::"
+     * h16         = 1*4HEXDIG
+     * ls32        = ( h16 ":" h16 ) / IPv4address
+     */
+    private int parseIpLiteral( char[] chars, int pos )
+    {
+        int start = pos;
+        
+        if ( Chars.isCharASCII( chars, pos, 'v' ) )
+        {
+            // This is an IPvFuture
+            pos++;
+            hostType = HostTypeEnum.IPV_FUTURE;
+            
+            pos = parseIPvFuture( chars, pos );
+            
+            if ( pos != -1 )
+            {
+                // We don't keep the last char, which is a ']'
+                host = new String( chars, start, pos - start - 1 );
+            }
+            
+            return pos;
+        }
+        else
+        {
+            // An IPV6 host
+            hostType = HostTypeEnum.IPV6;
+
+            return parseIPV6( chars, pos );
+        }
+    }
+    
+    
+    /**
+     * Parse the following rules :
+     * <pre>
+     * IPv6address = 6( h16 ":" ) ls32 
+     *               | "::" 5( h16 ":" ) ls32
+     *               | [               h16 ] "::" 4( h16 ":" ) ls32
+     *               | [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+     *               | [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+     *               | [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
+     *               | [ *4( h16 ":" ) h16 ] "::"              ls32
+     *               | [ *5( h16 ":" ) h16 ] "::"              h16
+     *               | [ *6( h16 ":" ) h16 ] "::"
+     * h16         = 1*4HEXDIG
+     * ls32        = ( h16 ":" h16 ) / IPv4address
+     * </pre>
+     */
+    private int parseIPV6( char[] chars, int pos )
+    {
+        // Search for the closing ']'
+        int start = pos;
+
+        while ( !Chars.isCharASCII( chars, pos, ']' ) )
+        {
+            pos++;
+        }
+
+        if ( Chars.isCharASCII( chars, pos, ']' ) )
+        {
+            String hostString = new String( chars, start, pos - start );
+            
+            if ( sun.net.util.IPAddressUtil.isIPv6LiteralAddress( hostString ) )
+            {
+                host = hostString;
+                
+                return  pos + 1;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+        
+        return -1;
+    }
+    
+
+    /**
+     * Parse these rules :
+     * <pre>
+     * IPvFuture   = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+     * </pre>
+     * (the "v" has already been parsed)
+     */
+    private int parseIPvFuture( char[] chars, int pos )
+    {
+        // We should have at least one hex digit
+        boolean hexFound = false;
+        
+        while ( Chars.isHex( chars, pos ) )
+        {
+            hexFound = true;
+            pos++;
+        }
+        
+        if ( !hexFound )
+        {
+            return -1;
+        }
+        
+        // a dot is expected
+        if ( !Chars.isCharASCII( chars, pos, '.' ) )
+        {
+            return -1;
+        }
+        
+        // Now, we should have at least one char in unreserved / sub-delims / ":"
+        boolean valueFound = false;
+        
+        while ( !Chars.isCharASCII( chars, pos, ']' ) )
+        {
+            switch ( chars[pos] )
+            {
+                // Unserserved
+                // ALPHA
+                case 'a' : case 'b' : case 'c' : case 'd' : case 'e' :
+                case 'A' : case 'B' : case 'C' : case 'D' : case 'E' :
+                case 'f' : case 'g' : case 'h' : case 'i' : case 'j' :
+                case 'F' : case 'G' : case 'H' : case 'I' : case 'J' :
+                case 'k' : case 'l' : case 'm' : case 'n' : case 'o' :
+                case 'K' : case 'L' : case 'M' : case 'N' : case 'O' :
+                case 'p' : case 'q' : case 'r' : case 's' : case 't' :
+                case 'P' : case 'Q' : case 'R' : case 'S' : case 'T' :
+                case 'u' : case 'v' : case 'w' : case 'x' : case 'y' :
+                case 'U' : case 'V' : case 'W' : case 'X' : case 'Y' :
+                case 'z' : case 'Z' : 
+                    
+                // DIGITs
+                case '0' : case '1' : case '2' : case '3' : case '4' : 
+                case '5' : case '6' : case '7' : case '8' : case '9' :
+                    
+                // others
+                case '-' : case '.' : case '_' : case '~' :  
+                
+                // sub-delims
+                case '!' : case '$' : case '&' : case '\'' : 
+                case '(' : case ')' : case '*' : case '+' : case ',' : 
+                case ';' : case '=' :
+                    
+                // Special case for ':'
+                case ':' :
+                    pos++;
+                    valueFound = true;
+                    break;
+                    
+                default :
+                    // Wrong char
+                    return -1;
+            }
+        }
+        
+        if ( !valueFound )
+        {
+            return -1;
+        }
+        
+        return pos;
+    }
+    
+    
+    /**
+     * parse these rules :
+     * <pre>
+     * reg-name    = *( unreserved / pct-encoded / sub-delims )
+     * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+     * pct-encoded = "%" HEXDIG HEXDIG
+     * sub-delims  = "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="
+     * HEXDIG      = DIGIT / A-F / a-f
+     * </pre>
+     */
+    private int parseRegName( char[] chars, int pos )
+    {
+        int start = pos;
+        
+        while ( !Chars.isCharASCII( chars, pos, ':' ) && !Chars.isCharASCII( chars, pos, '/' ) && ( pos < chars.length ) )
+        {
+            switch ( chars[pos] )
+            {
+                // Unserserved
+                // ALPHA
+                case 'a' : case 'b' : case 'c' : case 'd' : case 'e' :
+                case 'A' : case 'B' : case 'C' : case 'D' : case 'E' :
+                case 'f' : case 'g' : case 'h' : case 'i' : case 'j' :
+                case 'F' : case 'G' : case 'H' : case 'I' : case 'J' :
+                case 'k' : case 'l' : case 'm' : case 'n' : case 'o' :
+                case 'K' : case 'L' : case 'M' : case 'N' : case 'O' :
+                case 'p' : case 'q' : case 'r' : case 's' : case 't' :
+                case 'P' : case 'Q' : case 'R' : case 'S' : case 'T' :
+                case 'u' : case 'v' : case 'w' : case 'x' : case 'y' :
+                case 'U' : case 'V' : case 'W' : case 'X' : case 'Y' :
+                case 'z' : case 'Z' : 
+                    
+                // DIGITs
+                case '0' : case '1' : case '2' : case '3' : case '4' : 
+                case '5' : case '6' : case '7' : case '8' : case '9' :
+                    
+                // others
+                case '-' : case '.' : case '_' : case '~' :  
+                
+                // sub-delims
+                case '!' : case '$' : case '&' : case '\'' : 
+                case '(' : case ')' : case '*' : case '+' : case ',' : 
+                case ';' : case '=' :
+                    pos++;
+                    break;
+                    
+                // pct-encoded
+                case '%' : 
+                    if ( Chars.isHex( chars, pos + 1 ) && Chars.isHex( chars, pos + 2 ) )
+                    {
+                        pos += 3;
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                    
+                default :
+                    // Wrong char
+                    return -1;
+            }
+        }
+        
+        host = new String( chars, start, pos - start );
+        hostType = HostTypeEnum.REGULAR_NAME;
+        
+        return pos;
+    }
+
+    
+    /**
+     * Parse these rules :
+     * <pre>
+     * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+     * dec-octet   = DIGIT | [1-9] DIGIT | "1" 2DIGIT | "2" [0-4] DIGIT | "25" [0-5]
+     * </pre>
+     * @param chars The buffer to parse
+     * @param pos The current position in the byte buffer
+     * 
+     * @return The new position or -1 if this is not an IPV4 address
+     */
+    private int parseIPV4( char[] chars, int pos )
+    {
+        int[] ipElem = new int[4];
+        int ipPos = pos;
+        int start = pos;
+
+        for ( int i = 0; i < 3; i++ )
+        {
+            ipPos = parseDecOctet( chars, ipPos, ipElem, i );
+            
+            if ( ipPos == -1 )
+            {
+                // Not an IPV4 address
+                return -1;
+            }
+            
+            if ( chars[ipPos] != '.' )
+            {
+                // Not an IPV4 address
+                return -1;
+            }
+            else
+            {
+                ipPos++;
+            }
+        }
+
+        ipPos = parseDecOctet( chars, ipPos, ipElem, 3 );
+        
+        if ( ipPos == -1 )
+        {
+            // Not an IPV4 address
+            return -1;
+        }
+        else
+        {
+            pos = ipPos;
+            host = new String( chars, start, pos - start );
+            hostType = HostTypeEnum.IPV4;
+            
+            return pos;
+        }
+    }
+    
+    
+    /**
+     * Parse this rule :
+     * <pre>
+     * dec-octet   = DIGIT | [1-9] DIGIT | "1" 2DIGIT | "2" [0-4] DIGIT | "25" [0-5]
+     * </pre>
+     */
+    private int parseDecOctet( char[] chars, int pos, int[] ipElem, int octetNb )
+    {
+        int ipElemValue = 0;
+        boolean ipElemSeen = false;
+        boolean hasTailingZeroes = false;
+        
+        while ( Chars.isDigit( chars, pos ) )
+        {
+            ipElemSeen = true;
+            ipElemValue = ( ipElemValue * 10 ) + ( chars[pos] - '0' );
+            
+            if ( ( chars[pos] == '0' ) && hasTailingZeroes && ( ipElemValue > 0 ) )
+            {
+                // Two 0 at the beginning : not allowed
+                return -1;
+            }
+            
+            if ( ipElemValue > 255 )
+            {
+                // We don't allow IPV4 address with values > 255
+                return -1;
+            }
+
+            pos++;
+        }
+        
+        if ( ipElemSeen )
+        {
+            ipElem[octetNb] = ipElemValue;
+            
+            return pos;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+    
+
+    /**
+     * Parse this rule : <br>
+     * <pre>
+     * <port> ::= <digit>+<br>
+     * <digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
+     * </pre>
+     * The port must be between 0 and 65535.
+     *
+     * @param chars The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not
+     *         apply to the byte buffer
+     */
+    private int parsePort( char[] chars, int pos )
+    {
+
+        if ( !Chars.isDigit( chars, pos ) )
+        {
+            return -1;
+        }
+
+        port = chars[pos] - '0';
+
+        pos++;
+
+        while ( Chars.isDigit( chars, pos ) )
+        {
+            port = ( port * 10 ) + ( chars[pos] - '0' );
+
+            if ( port > 65535 )
+            {
+                return -1;
+            }
+
+            pos++;
+        }
+
+        return pos;
+    }
+
+
+    /**
+     * Parse this rule : <br>
+     * <pre>
+     *   &lt;hostport> ::= &lt;host> [':' &lt;port>]
+     * </pre>
+     *
+     * @param chars The char array to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not
+     *         apply to the byte buffer
+     */
+    private int parseHostPort( char[] chars, int pos )
+    {
+        int hostPos = pos;
+
+        pos = parseHost( chars, pos );
+        if ( pos == -1 )
+        {
+            return -1;
+        }
+
+        // We may have a port.
+        if ( Chars.isCharASCII( chars, pos, ':' ) )
+        {
+            if ( pos == hostPos )
+            {
+                // We should not have a port if we have no host
+                return -1;
+            }
+
+            pos++;
+        }
+        else
+        {
+            return pos;
+        }
+
+        // As we have a ':', we must have a valid port (between 0 and 65535).
+        pos = parsePort( chars, pos );
+        if ( pos == -1 )
+        {
+            return -1;
+        }
+
+        return pos;
+    }
+
+
+    /**
+     * Converts the specified string to byte array of ASCII characters.
+     *
+     * @param data the string to be encoded
+     * @return The string as a byte array.
+     * @throws org.apache.directory.api.ldap.model.exception.UrlDecoderException if encoding is not supported
+     */
+    private static byte[] getAsciiBytes( final String data ) throws UrlDecoderException
+    {
+
+        if ( data == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04411 ) );
+        }
+
+        try
+        {
+            return data.getBytes( "US-ASCII" );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            throw new UrlDecoderException( I18n.err( I18n.ERR_04413 ), uee );
+        }
+    }
+
+
+    /**
+     * From commons-codec. Decodes an array of URL safe 7-bit characters into an
+     * array of original bytes. Escaped characters are converted back to their
+     * original representation.
+     *
+     * @param bytes array of URL safe characters
+     * @return array of original bytes
+     * @throws UrlDecoderException Thrown if URL decoding is unsuccessful
+     */
+    private static byte[] decodeUrl( byte[] bytes ) throws UrlDecoderException
+    {
+        if ( bytes == null )
+        {
+            return StringConstants.EMPTY_BYTES;
+        }
+
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+        for ( int i = 0; i < bytes.length; i++ )
+        {
+            int b = bytes[i];
+
+            if ( b == '%' )
+            {
+                try
+                {
+                    int u = Character.digit( ( char ) bytes[++i], 16 );
+                    int l = Character.digit( ( char ) bytes[++i], 16 );
+
+                    if ( ( u == -1 ) || ( l == -1 ) )
+                    {
+                        throw new UrlDecoderException( I18n.err( I18n.ERR_04414 ) );
+                    }
+
+                    buffer.write( ( char ) ( ( u << 4 ) + l ) );
+                }
+                catch ( ArrayIndexOutOfBoundsException aioobe )
+                {
+                    throw new UrlDecoderException( I18n.err( I18n.ERR_04414 ) , aioobe );
+                }
+            }
+            else
+            {
+                buffer.write( b );
+            }
+        }
+
+        return buffer.toByteArray();
+    }
+
+
+    /**
+     * From commons-httpclients. Unescape and decode a given string regarded as
+     * an escaped string with the default protocol charset.
+     *
+     * @param escaped a string
+     * @return the unescaped string
+     * @throws LdapUriException if the string cannot be decoded (invalid)
+     */
+    private static String decode( String escaped ) throws LdapUriException
+    {
+        try
+        {
+            byte[] rawdata = decodeUrl( getAsciiBytes( escaped ) );
+            return Strings.getString( rawdata, "UTF-8" );
+        }
+        catch ( UrlDecoderException e )
+        {
+            throw new LdapUriException( e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * Parse a string and check that it complies with RFC 2253. Here, we will
+     * just call the Dn parser to do the job.
+     *
+     * @param chars The char array to be checked
+     * @param pos the starting position
+     * @return -1 if the char array does not contains a Dn
+     */
+    private int parseDN( char[] chars, int pos )
+    {
+
+        int end = pos;
+
+        for ( int i = pos; ( i < chars.length ) && ( chars[i] != '?' ); i++ )
+        {
+            end++;
+        }
+
+        try
+        {
+            String dnStr = new String( chars, pos, end - pos );
+            dn = new Dn( decode( dnStr ) );
+        }
+        catch ( LdapUriException ue )
+        {
+            return -1;
+        }
+        catch ( LdapInvalidDnException de )
+        {
+            return -1;
+        }
+
+        return end;
+    }
+
+
+    /**
+     * Parse the following rule :
+     * <pre>
+     * oid ::= numericOid | descr
+     * descr ::= keystring
+     * keystring ::= leadkeychar *keychar
+     * leadkeychar ::= [a-zA-Z]
+     * keychar ::= [a-zA-Z0-0-]
+     * numericOid ::= number 1*( DOT number )
+     * number ::= 0 | [1-9][0-9]* 
+     * 
+     * @param attribute
+     * @throws LdapURLEncodingException
+     */
+    private void validateAttribute( String attribute ) throws LdapURLEncodingException
+    {
+        Matcher matcher = ATTRIBUTE.matcher( attribute );
+
+        if ( !matcher.matches() )
+        {
+            throw new LdapURLEncodingException( "Attribute " + attribute + " is invalid" );
+        }
+    }
+
+
+    /**
+     * Parse the attributes part
+     *
+     * @param chars The char array to be checked
+     * @param pos the starting position
+     * @return -1 if the char array does not contains attributes
+     */
+    private int parseAttributes( char[] chars, int pos )
+    {
+        int start = pos;
+        int end = pos;
+        Set<String> hAttributes = new HashSet<String>();
+        boolean hadComma = false;
+
+        try
+        {
+
+            for ( int i = pos; ( i < chars.length ) && ( chars[i] != '?' ); i++ )
+            {
+
+                if ( Chars.isCharASCII( chars, i, ',' ) )
+                {
+                    hadComma = true;
+
+                    if ( ( end - start ) == 0 )
+                    {
+
+                        // An attributes must not be null
+                        return -1;
+                    }
+                    else
+                    {
+                        String attribute = null;
+
+                        // get the attribute. It must not be blank
+                        attribute = new String( chars, start, end - start ).trim();
+
+                        if ( attribute.length() == 0 )
+                        {
+                            return -1;
+                        }
+
+                        // Check that the attribute is valid
+                        try
+                        {
+                            validateAttribute( attribute );
+                        }
+                        catch ( LdapURLEncodingException luee )
+                        {
+                            return -1;
+                        }
+
+                        String decodedAttr = decode( attribute );
+
+                        if ( !hAttributes.contains( decodedAttr ) )
+                        {
+                            attributes.add( decodedAttr );
+                            hAttributes.add( decodedAttr );
+                        }
+                    }
+
+                    start = i + 1;
+                }
+                else
+                {
+                    hadComma = false;
+                }
+
+                end++;
+            }
+
+            if ( hadComma )
+            {
+
+                // We are not allowed to have a comma at the end of the
+                // attributes
+                return -1;
+            }
+            else
+            {
+
+                if ( end == start )
+                {
+
+                    // We don't have any attributes. This is valid.
+                    return end;
+                }
+
+                // Store the last attribute
+                // get the attribute. It must not be blank
+                String attribute = null;
+
+                attribute = new String( chars, start, end - start ).trim();
+
+                if ( attribute.length() == 0 )
+                {
+                    return -1;
+                }
+
+                String decodedAttr = decode( attribute );
+
+                if ( !hAttributes.contains( decodedAttr ) )
+                {
+                    attributes.add( decodedAttr );
+                    hAttributes.add( decodedAttr );
+                }
+            }
+
+            return end;
+        }
+        catch ( LdapUriException ue )
+        {
+            return -1;
+        }
+    }
+
+
+    /**
+     * Parse the filter part. We will use the FilterParserImpl class
+     *
+     * @param chars The char array to be checked
+     * @param pos the starting position
+     * @return -1 if the char array does not contains a filter
+     */
+    private int parseFilter( char[] chars, int pos )
+    {
+
+        int end = pos;
+
+        for ( int i = pos; ( i < chars.length ) && ( chars[i] != '?' ); i++ )
+        {
+            end++;
+        }
+
+        if ( end == pos )
+        {
+            // We have no filter
+            return end;
+        }
+
+        try
+        {
+            filter = decode( new String( chars, pos, end - pos ) );
+            FilterParser.parse( null, filter );
+        }
+        catch ( LdapUriException ue )
+        {
+            return -1;
+        }
+        catch ( ParseException pe )
+        {
+            return -1;
+        }
+
+        return end;
+    }
+
+
+    /**
+     * Parse the scope part.
+     *
+     * @param chars The char array to be checked
+     * @param pos the starting position
+     * @return -1 if the char array does not contains a scope
+     */
+    private int parseScope( char[] chars, int pos )
+    {
+
+        if ( Chars.isCharASCII( chars, pos, 'b' ) || Chars.isCharASCII( chars, pos, 'B' ) )
+        {
+            pos++;
+
+            if ( Chars.isCharASCII( chars, pos, 'a' ) || Chars.isCharASCII( chars, pos, 'A' ) )
+            {
+                pos++;
+
+                if ( Chars.isCharASCII( chars, pos, 's' ) || Chars.isCharASCII( chars, pos, 'S' ) )
+                {
+                    pos++;
+
+                    if ( Chars.isCharASCII( chars, pos, 'e' ) || Chars.isCharASCII( chars, pos, 'E' ) )
+                    {
+                        pos++;
+                        scope = SearchScope.OBJECT;
+                        return pos;
+                    }
+                }
+            }
+        }
+        else if ( Chars.isCharASCII( chars, pos, 'o' ) || Chars.isCharASCII( chars, pos, 'O' ) )
+        {
+            pos++;
+
+            if ( Chars.isCharASCII( chars, pos, 'n' ) || Chars.isCharASCII( chars, pos, 'N' ) )
+            {
+                pos++;
+
+                if ( Chars.isCharASCII( chars, pos, 'e' ) || Chars.isCharASCII( chars, pos, 'E' ) )
+                {
+                    pos++;
+
+                    scope = SearchScope.ONELEVEL;
+                    return pos;
+                }
+            }
+        }
+        else if ( Chars.isCharASCII( chars, pos, 's' ) || Chars.isCharASCII( chars, pos, 'S' ) )
+        {
+            pos++;
+
+            if ( Chars.isCharASCII( chars, pos, 'u' ) || Chars.isCharASCII( chars, pos, 'U' ) )
+            {
+                pos++;
+
+                if ( Chars.isCharASCII( chars, pos, 'b' ) || Chars.isCharASCII( chars, pos, 'B' ) )
+                {
+                    pos++;
+
+                    scope = SearchScope.SUBTREE;
+                    return pos;
+                }
+            }
+        }
+        else if ( Chars.isCharASCII( chars, pos, '?' ) )
+        {
+            // An empty scope. This is valid
+            return pos;
+        }
+        else if ( pos == chars.length )
+        {
+            // An empty scope at the end of the URL. This is valid
+            return pos;
+        }
+
+        // The scope is not one of "one", "sub" or "base". It's an error
+        return -1;
+    }
+
+
+    /**
+     * Parse extensions and critical extensions.
+     *
+     * The grammar is :
+     * extensions ::= extension [ ',' extension ]*
+     * extension ::= [ '!' ] ( token | ( 'x-' | 'X-' ) token ) ) [ '=' exvalue ]
+     *
+     * @param chars The char array to be checked
+     * @param pos the starting position
+     * @return -1 if the char array does not contains valid extensions or
+     *         critical extensions
+     */
+    private int parseExtensions( char[] chars, int pos )
+    {
+        int start = pos;
+        boolean isCritical = false;
+        boolean isNewExtension = true;
+        boolean hasValue = false;
+        String extension = null;
+        String value = null;
+
+        if ( pos == chars.length )
+        {
+            return pos;
+        }
+
+        try
+        {
+            for ( int i = pos; ( i < chars.length ); i++ )
+            {
+                if ( Chars.isCharASCII( chars, i, ',' ) )
+                {
+                    if ( isNewExtension )
+                    {
+                        // a ',' is not allowed when we have already had one
+                        // or if we just started to parse the extensions.
+                        return -1;
+                    }
+                    else
+                    {
+                        if ( extension == null )
+                        {
+                            extension = decode( new String( chars, start, i - start ) ).trim();
+                        }
+                        else
+                        {
+                            value = decode( new String( chars, start, i - start ) ).trim();
+                        }
+
+                        Extension ext = new Extension( isCritical, extension, value );
+                        extensionList.add( ext );
+
+                        isNewExtension = true;
+                        hasValue = false;
+                        isCritical = false;
+                        start = i + 1;
+                        extension = null;
+                        value = null;
+                    }
+                }
+                else if ( Chars.isCharASCII( chars, i, '=' ) )
+                {
+                    if ( hasValue )
+                    {
+                        // We may have two '=' for the same extension
+                        continue;
+                    }
+
+                    // An optionnal value
+                    extension = decode( new String( chars, start, i - start ) ).trim();
+
+                    if ( extension.length() == 0 )
+                    {
+                        // We must have an extension
+                        return -1;
+                    }
+
+                    hasValue = true;
+                    start = i + 1;
+                }
+                else if ( Chars.isCharASCII( chars, i, '!' ) )
+                {
+                    if ( hasValue )
+                    {
+                        // We may have two '!' in the value
+                        continue;
+                    }
+
+                    if ( !isNewExtension )
+                    {
+                        // '!' must appears first
+                        return -1;
+                    }
+
+                    isCritical = true;
+                    start++;
+                }
+                else
+                {
+                    isNewExtension = false;
+                }
+            }
+
+            if ( extension == null )
+            {
+                extension = decode( new String( chars, start, chars.length - start ) ).trim();
+            }
+            else
+            {
+                value = decode( new String( chars, start, chars.length - start ) ).trim();
+            }
+
+            Extension ext = new Extension( isCritical, extension, value );
+            extensionList.add( ext );
+
+            return chars.length;
+        }
+        catch ( LdapUriException ue )
+        {
+            return -1;
+        }
+    }
+
+
+    /**
+     * Encode a String to avoid special characters.
+     *
+     *
+     * RFC 4516, section 2.1. (Percent-Encoding)
+     *
+     * A generated LDAP URL MUST consist only of the restricted set of
+     * characters included in one of the following three productions defined
+     * in [RFC3986]:
+     *
+     *   <reserved>
+     *   <unreserved>
+     *   <pct-encoded>
+     *
+     * Implementations SHOULD accept other valid UTF-8 strings [RFC3629] as
+     * input.  An octet MUST be encoded using the percent-encoding mechanism
+     * described in section 2.1 of [RFC3986] in any of these situations:
+     *
+     *  The octet is not in the reserved set defined in section 2.2 of
+     *  [RFC3986] or in the unreserved set defined in section 2.3 of
+     *  [RFC3986].
+     *
+     *  It is the single Reserved character '?' and occurs inside a <dn>,
+     *  <filter>, or other element of an LDAP URL.
+     *
+     *  It is a comma character ',' that occurs inside an <exvalue>.
+     *
+     *
+     * RFC 3986, section 2.2 (Reserved Characters)
+     *
+     * reserved    = gen-delims / sub-delims
+     * gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+     * sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+     *              / "*" / "+" / "," / ";" / "="
+     *
+     *
+     * RFC 3986, section 2.3 (Unreserved Characters)
+     *
+     * unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+     *
+     *
+     * @param url The String to encode
+     * @param doubleEncode Set if we need to encode the comma
+     * @return An encoded string
+     */
+    public static String urlEncode( String url, boolean doubleEncode )
+    {
+        StringBuffer sb = new StringBuffer();
+
+        for ( int i = 0; i < url.length(); i++ )
+        {
+            char c = url.charAt( i );
+
+            switch ( c )
+
+            {
+            // reserved and unreserved characters:
+            // just append to the buffer
+
+            // reserved gen-delims, excluding '?'
+            // gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+                case ':':
+                case '/':
+                case '#':
+                case '[':
+                case ']':
+                case '@':
+
+                    // reserved sub-delims, excluding ','
+                    // sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+                    //               / "*" / "+" / "," / ";" / "="
+                case '!':
+                case '$':
+                case '&':
+                case '\'':
+                case '(':
+                case ')':
+                case '*':
+                case '+':
+                case ';':
+                case '=':
+
+                    // unreserved
+                    // unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+                case 'a':
+                case 'b':
+                case 'c':
+                case 'd':
+                case 'e':
+                case 'f':
+                case 'g':
+                case 'h':
+                case 'i':
+                case 'j':
+                case 'k':
+                case 'l':
+                case 'm':
+                case 'n':
+                case 'o':
+                case 'p':
+                case 'q':
+                case 'r':
+                case 's':
+                case 't':
+                case 'u':
+                case 'v':
+                case 'w':
+                case 'x':
+                case 'y':
+                case 'z':
+
+                case 'A':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'E':
+                case 'F':
+                case 'G':
+                case 'H':
+                case 'I':
+                case 'J':
+                case 'K':
+                case 'L':
+                case 'M':
+                case 'N':
+                case 'O':
+                case 'P':
+                case 'Q':
+                case 'R':
+                case 'S':
+                case 'T':
+                case 'U':
+                case 'V':
+                case 'W':
+                case 'X':
+                case 'Y':
+                case 'Z':
+
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+
+                case '-':
+                case '.':
+                case '_':
+                case '~':
+
+                    sb.append( c );
+                    break;
+
+                case ',':
+
+                    // special case for comma
+                    if ( doubleEncode )
+                    {
+                        sb.append( "%2c" );
+                    }
+                    else
+                    {
+                        sb.append( c );
+                    }
+                    break;
+
+                default:
+
+                    // percent encoding
+                    byte[] bytes = Unicode.charToBytes( c );
+                    char[] hex = Strings.toHexString( bytes ).toCharArray();
+                    for ( int j = 0; j < hex.length; j++ )
+                    {
+                        if ( j % 2 == 0 )
+                        {
+                            sb.append( '%' );
+                        }
+                        sb.append( hex[j] );
+
+                    }
+
+                    break;
+            }
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Get a string representation of a LdapUrl.
+     *
+     * @return A LdapUrl string
+     * @see LdapUrl#forceScopeRendering
+     */
+    @Override
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append( scheme );
+
+        if ( host != null )
+        {
+            switch ( hostType )
+            {
+                case IPV4 :
+                case REGULAR_NAME :
+                    sb.append( host );
+                    break;
+                    
+                case IPV6 :
+                case IPV_FUTURE :
+                    sb.append( '[' ).append( host ).append( ']' );
+                    break;
+
+                default:
+                    throw new IllegalArgumentException( "Unexpected HostTypeEnum " + hostType );
+            }
+        }
+
+        if ( port != -1 )
+        {
+            sb.append( ':' ).append( port );
+        }
+
+        if ( dn != null )
+        {
+            sb.append( '/' ).append( urlEncode( dn.getName(), false ) );
+
+            if ( ( attributes.size() != 0 ) || forceScopeRendering
+                || ( ( scope != SearchScope.OBJECT ) || ( filter != null ) || ( extensionList.size() != 0 ) ) )
+            {
+                sb.append( '?' );
+
+                boolean isFirst = true;
+
+                for ( String attribute : attributes )
+                {
+                    if ( isFirst )
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        sb.append( ',' );
+                    }
+
+                    sb.append( urlEncode( attribute, false ) );
+                }
+            }
+
+            if ( forceScopeRendering )
+            {
+                sb.append( '?' );
+
+                sb.append( scope.getLdapUrlValue() );
+            }
+            else
+            {
+                if ( ( scope != SearchScope.OBJECT ) || ( filter != null ) || ( extensionList.size() != 0 ) )
+                {
+                    sb.append( '?' );
+
+                    switch ( scope )
+                    {
+                        case ONELEVEL:
+                        case SUBTREE:
+                            sb.append( scope.getLdapUrlValue() );
+                            break;
+
+                        default:
+                            break;
+                    }
+
+                    if ( ( filter != null ) || ( ( extensionList.size() != 0 ) ) )
+                    {
+                        sb.append( "?" );
+
+                        if ( filter != null )
+                        {
+                            sb.append( urlEncode( filter, false ) );
+                        }
+
+                        if ( ( extensionList.size() != 0 ) )
+                        {
+                            sb.append( '?' );
+
+                            boolean isFirst = true;
+
+                            if ( extensionList.size() != 0 )
+                            {
+                                for ( Extension extension : extensionList )
+                                {
+                                    if ( !isFirst )
+                                    {
+                                        sb.append( ',' );
+                                    }
+                                    else
+                                    {
+                                        isFirst = false;
+                                    }
+
+                                    if ( extension.isCritical )
+                                    {
+                                        sb.append( '!' );
+                                    }
+                                    sb.append( urlEncode( extension.type, false ) );
+
+                                    if ( extension.value != null )
+                                    {
+                                        sb.append( '=' );
+                                        sb.append( urlEncode( extension.value, true ) );
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            sb.append( '/' );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * @return Returns the attributes.
+     */
+    public List<String> getAttributes()
+    {
+        return attributes;
+    }
+
+
+    /**
+     * @return Returns the dn.
+     */
+    public Dn getDn()
+    {
+        return dn;
+    }
+
+
+    /**
+     * @return Returns the extensions.
+     */
+    public List<Extension> getExtensions()
+    {
+        return extensionList;
+    }
+
+
+    /**
+     * Gets the extension.
+     *
+     * @param type the extension type, case-insensitive
+     *
+     * @return Returns the extension, null if this URL does not contain
+     *         such an extension.
+     */
+    public Extension getExtension( String type )
+    {
+        for ( Extension extension : getExtensions() )
+        {
+            if ( extension.getType().equalsIgnoreCase( type ) )
+            {
+                return extension;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Gets the extension value.
+     *
+     * @param type the extension type, case-insensitive
+     *
+     * @return Returns the extension value, null if this URL does not
+     *         contain such an extension or if the extension value is null.
+     */
+    public String getExtensionValue( String type )
+    {
+        for ( Extension extension : getExtensions() )
+        {
+            if ( extension.getType().equalsIgnoreCase( type ) )
+            {
+                return extension.getValue();
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * @return Returns the filter.
+     */
+    public String getFilter()
+    {
+        return filter;
+    }
+
+
+    /**
+     * @return Returns the host.
+     */
+    public String getHost()
+    {
+        return host;
+    }
+
+
+    /**
+     * @return Returns the port.
+     */
+    public int getPort()
+    {
+        return port;
+    }
+
+
+    /**
+     * Returns the scope, one of {@link SearchScope#OBJECT},
+     * {@link SearchScope#ONELEVEL} or {@link SearchScope#SUBTREE}.
+     *
+     * @return Returns the scope.
+     */
+    public SearchScope getScope()
+    {
+        return scope;
+    }
+
+
+    /**
+     * @return Returns the scheme.
+     */
+    public String getScheme()
+    {
+        return scheme;
+    }
+
+
+    /**
+     * @return the number of bytes for this LdapUrl
+     */
+    public int getNbBytes()
+    {
+        return ( bytes != null ? bytes.length : 0 );
+    }
+
+
+    /**
+     * @return a reference on the interned bytes representing this LdapUrl
+     */
+    public byte[] getBytesReference()
+    {
+        return bytes;
+    }
+
+
+    /**
+     * @return a copy of the bytes representing this LdapUrl
+     */
+    public byte[] getBytesCopy()
+    {
+        if ( bytes != null )
+        {
+            byte[] copy = new byte[bytes.length];
+            System.arraycopy( bytes, 0, copy, 0, bytes.length );
+            return copy;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * @return the LdapUrl as a String
+     */
+    public String getString()
+    {
+        return string;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode()
+    {
+        return this.toString().hashCode();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+
+        final LdapUrl other = ( LdapUrl ) obj;
+        return this.toString().equals( other.toString() );
+    }
+
+
+    /**
+     * Sets the scheme. Must be "ldap://" or "ldaps://", otherwise "ldap://" is assumed as default.
+     *
+     * @param scheme the new scheme
+     */
+    public void setScheme( String scheme )
+    {
+        if ( ( ( scheme != null ) && LDAP_SCHEME.equals( scheme ) ) || LDAPS_SCHEME.equals( scheme ) )
+        {
+            this.scheme = scheme;
+        }
+        else
+        {
+            this.scheme = LDAP_SCHEME;
+        }
+
+    }
+
+
+    /**
+     * Sets the host.
+     *
+     * @param host the new host
+     */
+    public void setHost( String host )
+    {
+        this.host = host;
+    }
+
+
+    /**
+     * Sets the port. Must be between 1 and 65535, otherwise -1 is assumed as default.
+     *
+     * @param port the new port
+     */
+    public void setPort( int port )
+    {
+        if ( ( port < 1 ) || ( port > 65535 ) )
+        {
+            this.port = -1;
+        }
+        else
+        {
+            this.port = port;
+        }
+    }
+
+
+    /**
+     * Sets the dn.
+     *
+     * @param dn the new dn
+     */
+    public void setDn( Dn dn )
+    {
+        this.dn = dn;
+    }
+
+
+    /**
+     * Sets the attributes, null removes all existing attributes.
+     *
+     * @param attributes the new attributes
+     */
+    public void setAttributes( List<String> attributes )
+    {
+        if ( attributes == null )
+        {
+            this.attributes.clear();
+        }
+        else
+        {
+            this.attributes = attributes;
+        }
+    }
+
+
+    /**
+     * Sets the scope. Must be one of {@link SearchScope#OBJECT},
+     * {@link SearchScope#ONELEVEL} or {@link SearchScope#SUBTREE},
+     * otherwise {@link SearchScope#OBJECT} is assumed as default.
+     *
+     * @param scope the new scope
+     */
+    public void setScope( int scope )
+    {
+        try
+        {
+            this.scope = SearchScope.getSearchScope( scope );
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            this.scope = SearchScope.OBJECT;
+        }
+    }
+
+
+    /**
+     * Sets the scope. Must be one of {@link SearchScope#OBJECT},
+     * {@link SearchScope#ONELEVEL} or {@link SearchScope#SUBTREE},
+     * otherwise {@link SearchScope#OBJECT} is assumed as default.
+     *
+     * @param scope the new scope
+     */
+    public void setScope( SearchScope scope )
+    {
+        if ( scope == null )
+        {
+            this.scope = SearchScope.OBJECT;
+        }
+        else
+        {
+            this.scope = scope;
+        }
+    }
+
+
+    /**
+     * Sets the filter.
+     *
+     * @param filter the new filter
+     */
+    public void setFilter( String filter )
+    {
+        this.filter = filter;
+    }
+
+
+    /**
+     * If set to true forces the toString method to render the scope
+     * regardless of optional nature.  Use this when you want explicit
+     * search URL scope rendering.
+     *
+     * @param forceScopeRendering the forceScopeRendering to set
+     */
+    public void setForceScopeRendering( boolean forceScopeRendering )
+    {
+        this.forceScopeRendering = forceScopeRendering;
+    }
+
+    /**
+     * An inner bean to hold extension information.
+     *
+     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+         */
+    public static class Extension
+    {
+        private boolean isCritical;
+        private String type;
+        private String value;
+
+
+        /**
+         * Creates a new instance of Extension.
+         *
+         * @param isCritical true for critical extension
+         * @param type the extension type
+         * @param value the extension value
+         */
+        public Extension( boolean isCritical, String type, String value )
+        {
+            super();
+            this.isCritical = isCritical;
+            this.type = type;
+            this.value = value;
+        }
+
+
+        /**
+         * Checks if is critical.
+         *
+         * @return true, if is critical
+         */
+        public boolean isCritical()
+        {
+            return isCritical;
+        }
+
+
+        /**
+         * Sets the critical flag.
+         *
+         * @param critical the new critical flag
+         */
+        public void setCritical( boolean critical )
+        {
+            this.isCritical = critical;
+        }
+
+
+        /**
+         * Gets the type.
+         *
+         * @return the type
+         */
+        public String getType()
+        {
+            return type;
+        }
+
+
+        /**
+         * Sets the type.
+         *
+         * @param type the new type
+         */
+        public void setType( String type )
+        {
+            this.type = type;
+        }
+
+
+        /**
+         * Gets the value.
+         *
+         * @return the value
+         */
+        public String getValue()
+        {
+            return value;
+        }
+
+
+        /**
+         * Sets the value.
+         *
+         * @param value the new value
+         */
+        public void setValue( String value )
+        {
+            this.value = value;
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/site/site.xml b/trunk/ldap/model/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/model/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/csn/CsnFactoryTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/csn/CsnFactoryTest.java
new file mode 100644
index 0000000..70db221
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/csn/CsnFactoryTest.java
@@ -0,0 +1,72 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.csn;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.csn.Csn;
+import org.apache.directory.api.ldap.model.csn.CsnFactory;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertFalse;
+
+
+/**
+ * Test case for the DefaultCSNFactory class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CsnFactoryTest
+{
+    private static final int NUM_GENERATES = 10;
+
+
+    /**
+     * Ensure all CSN's generated by a CSNFactory are unique.
+     *
+     */
+    @Test
+    public void testUnique()
+    {
+        int replicaId = 001;
+        CsnFactory defaultCSNFactory = new CsnFactory( replicaId );
+
+        Csn[] csns = new Csn[NUM_GENERATES];
+
+        for ( int i = 0; i < NUM_GENERATES; i++ )
+        {
+            csns[i] = defaultCSNFactory.newInstance();
+        }
+
+        for ( int i = 0; i < NUM_GENERATES; i++ )
+        {
+            for ( int j = i + 1; j < NUM_GENERATES; j++ )
+            {
+                assertFalse( csns[i].equals( csns[j] ) );
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/csn/CsnTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/csn/CsnTest.java
new file mode 100644
index 0000000..fbf3eed
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/csn/CsnTest.java
@@ -0,0 +1,372 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.csn;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.directory.api.ldap.model.csn.Csn;
+import org.apache.directory.api.ldap.model.csn.InvalidCSNException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * 
+ * Test for the CSN class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CsnTest
+{
+    private static final SimpleDateFormat SDF = new SimpleDateFormat( "yyyyMMddHHmmss.123456'Z'" );
+
+    private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
+    
+    static
+    {
+        SDF.setTimeZone( UTC_TIME_ZONE );
+    }
+
+
+    @Test
+    public void testCSN()
+    {
+        synchronized ( SDF )
+        {
+            long ts = System.currentTimeMillis();
+
+            Csn csn = new Csn( SDF.format( new Date( ts ) ) + "#123456#abc#654321" );
+
+            assertEquals( ts / 1000, csn.getTimestamp() / 1000 );
+
+            // ALl the value are converted from hex to int
+            assertEquals( 1193046, csn.getChangeCount() );
+            assertEquals( 6636321, csn.getOperationNumber() );
+            assertEquals( 2748, csn.getReplicaId() );
+        }
+    }
+
+
+    @Test
+    public void testCSNNull()
+    {
+        try
+        {
+            new Csn( ( String ) null );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNEmpty()
+    {
+        try
+        {
+            new Csn( "" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNTimestampOnly()
+    {
+        try
+        {
+            synchronized ( SDF )
+            {
+                new Csn( SDF.format( new Date( System.currentTimeMillis() ) ) );
+            }
+
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNInvalidTS()
+    {
+        try
+        {
+            // A missing 'Z'
+            new Csn( "20010101000000.000000#000001#abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            // Missing milliseconds
+            new Csn( "20000101000000.Z#000001#abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            // Missing dot
+            new Csn( "20010101000000000000Z#0x1#abc#0x1" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            // Missing dot and millis
+            new Csn( "20010101000000Z#000001#abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            // Invalid date
+            new Csn( "200A01010000Z#000001#abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNNoTimestamp()
+    {
+        try
+        {
+            new Csn( "#000001#abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNNoChangeCount()
+    {
+        try
+        {
+            new Csn( "20010101000000.000000Z##abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNInvalidChangeCount()
+    {
+        try
+        {
+            new Csn( "20010101000000.000000Z#00#abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            new Csn( "20010101000000.000000Z#00000G#abc#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNNoReplica()
+    {
+        try
+        {
+            new Csn( "20010101000000.000000Z#000001##000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNInvalidReplica()
+    {
+        try
+        {
+            new Csn( "20010101000000.000000Z#000001#a12-b3é#000001" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNNoOpNumber()
+    {
+        try
+        {
+            new Csn( "20010101000000.000000Z#000000#abc" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            new Csn( "20010101000000.000000Z#000000#abc#  " );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNInvalidOpNumber()
+    {
+        try
+        {
+            new Csn( "20010101000000.000000Z#000000#abc#000zzz" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            new Csn( "20010101000000.000000Z#000000#abc#00000" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            new Csn( "20010101000000.000000Z#000000#abc#" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            new Csn( "20010101000000.000000Z#000000#abc#00000G" );
+            fail();
+        }
+        catch ( InvalidCSNException ice )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testCSNToBytes()
+    {
+        Csn csn = new Csn( "20010101000000.000000Z#000000#abc#000001" );
+
+        byte[] bytes = csn.getBytes();
+
+        byte[] expected = new byte[]
+            {
+                '2', '0', '0', '1', '0', '1', '0', '1',
+                '0', '0', '0', '0', '0', '0', '.', '0',
+                '0', '0', '0', '0', '0', 'Z', '#', '0',
+                '0', '0', '0', '0', '0', '#', 'a', 'b',
+                'c', '#', '0', '0', '0', '0', '0', '1'
+        };
+
+        assertTrue( Arrays.equals( expected, bytes ) );
+
+        Csn deserializedCSN = new Csn( bytes );
+        assertEquals( csn, deserializedCSN );
+    }
+    
+    
+    @Test 
+    public void testIsValidCsn()
+    {
+        assertTrue( Csn.isValid( "20100111202217.914000Z#000000#000#000000" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/cursor/ListCursorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/cursor/ListCursorTest.java
new file mode 100755
index 0000000..157bc95
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/cursor/ListCursorTest.java
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.cursor;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.cursor.Cursor;
+import org.apache.directory.api.ldap.model.cursor.ListCursor;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+
+/**
+ * Tests the ListCursor class.  The assertXxxx() methods defined in this class
+ * can be collected in an abstract test case class that can be used to test
+ * the behavior of any Cursor implementation down the line.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ListCursorTest
+{
+    @Test
+    public void testEmptyList() throws Exception
+    {
+        ListCursor<String> cursor = new ListCursor<String>();
+
+        // close test
+        cursor.close();
+        assertClosed( cursor, "cursor.isClosed() should return true after closing the cursor", true );
+    }
+
+
+    @Test
+    public void testSingleElementList() throws Exception
+    {
+        ListCursor<String> cursor = new ListCursor<String>( Collections.singletonList( "singleton" ) );
+
+        // close test
+        cursor.close();
+        assertClosed( cursor, "cursor.isClosed() should return true after closing the cursor", true );
+
+        // bad bounds: start = end is senseless
+        try
+        {
+            cursor = new ListCursor<String>( Collections.singletonList( "singleton" ), 0 );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: start = end is senseless
+        try
+        {
+            cursor = new ListCursor<String>( 1, Collections.singletonList( "singleton" ) );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: start > end is senseless
+        try
+        {
+            cursor = new ListCursor<String>( 5, Collections.singletonList( "singleton" ) );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: end < start is senseless too in another way :)
+        try
+        {
+            cursor = new ListCursor<String>( Collections.singletonList( "singleton" ), -5 );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: start out of range
+        try
+        {
+            cursor = new ListCursor<String>( -5, Collections.singletonList( "singleton" ) );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: end out of range
+        try
+        {
+            cursor = new ListCursor<String>( Collections.singletonList( "singleton" ), 5 );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    @Test
+    public void testManyElementList() throws Exception
+    {
+        List<String> list = new ArrayList<String>();
+        list.add( "item 1" );
+        list.add( "item 2" );
+        list.add( "item 3" );
+        list.add( "item 4" );
+        list.add( "item 5" );
+
+        // test with bounds of the list itself
+        ListCursor<String> cursor = new ListCursor<String>( list );
+        cursor.close();
+
+        // test with nonzero lower bound
+        cursor = new ListCursor<String>( 1, list );
+        cursor.close();
+
+        // test with nonzero lower bound and upper bound
+        cursor = new ListCursor<String>( 1, list, 4 );
+
+        // close test
+        cursor.close();
+        assertClosed( cursor, "cursor.isClosed() should return true after closing the cursor", true );
+
+        // bad bounds: start = end is senseless
+        try
+        {
+            cursor = new ListCursor<String>( list, 0 );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: start = end is senseless
+        try
+        {
+            cursor = new ListCursor<String>( 5, list );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: start > end is senseless
+        try
+        {
+            cursor = new ListCursor<String>( 10, list );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: end < start is senseless too in another way :)
+        try
+        {
+            cursor = new ListCursor<String>( list, -5 );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: start out of range
+        try
+        {
+            cursor = new ListCursor<String>( -5, list );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+
+        // bad bounds: end out of range
+        try
+        {
+            cursor = new ListCursor<String>( list, 10 );
+            cursor.close();
+            fail( "when the start = end bounds this is senseless and should complain" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    protected void assertClosed( Cursor<?> cursor, String msg, boolean expected )
+    {
+        try
+        {
+            assertEquals( msg, expected, cursor.isClosed() );
+        }
+        catch ( Exception e )
+        {
+            fail( "cursor.isClosed() test should not fail after closing the cursor" );
+        }
+
+        try
+        {
+            cursor.close();
+        }
+        catch ( Exception e )
+        {
+            fail( "cursor.close() after closing the cursor should not fail with exceptions" );
+        }
+
+        try
+        {
+            cursor.afterLast();
+            fail( "cursor.afterLast() after closing the cursor should fail with an IOException" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+
+        try
+        {
+            cursor.beforeFirst();
+            fail( "cursor.beforeFirst() after closing the cursor should fail with an IOException" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+
+        try
+        {
+            cursor.first();
+            fail( "cursor.first() after closing the cursor should fail with an IOException" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+
+        try
+        {
+            cursor.get();
+            fail( "cursor.get() after closing the cursor should fail with an IOException" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+
+        try
+        {
+            cursor.last();
+            fail( "cursor.last() after closing the cursor should fail with an IOException" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+
+        try
+        {
+            cursor.next();
+            fail( "cursor.next() after closing the cursor should fail with an IOException" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+
+        try
+        {
+            cursor.previous();
+            fail( "cursor.previous() after closing the cursor should fail with an IOException" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeSerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeSerializationTest.java
new file mode 100644
index 0000000..05cf71a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeSerializationTest.java
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the EntryAttribute Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeSerializationTest
+{
+    private static byte[] data1 = new byte[]
+        { 0x01, 0x02, 0x03, 0x04 };
+    private static byte[] data2 = new byte[]
+        { 0x05, 0x06, 0x07, 0x08 };
+    private static byte[] data3 = new byte[]
+        { 0x09, 0x0A, 0x0B, 0x0C };
+
+
+    @Test
+    public void testEntryAttributeNoStringValueSerialization() throws IOException, ClassNotFoundException
+    {
+        Attribute attribute1 = new DefaultAttribute( "CN" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutput out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute();
+        attribute2.readExternal( in );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeOneStringValueSerialization() throws IOException, ClassNotFoundException
+    {
+        Attribute attribute1 = new DefaultAttribute( "CN", "test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute();
+        attribute2.readExternal( in );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeManyStringValuesSerialization() throws IOException, ClassNotFoundException
+    {
+        Attribute attribute1 = new DefaultAttribute( "CN", "test1", "test2", "test3" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute();
+        attribute2.readExternal( in );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeNoBinaryValueSerialization() throws IOException, ClassNotFoundException
+    {
+        Attribute attribute1 = new DefaultAttribute( "UserCertificate" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute();
+        attribute2.readExternal( in );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeOneBinaryValueSerialization() throws IOException, ClassNotFoundException
+    {
+        Attribute attribute1 = new DefaultAttribute( "UserCertificate", data1 );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute();
+        attribute2.readExternal( in );
+
+        assertEquals( attribute1, attribute2 );
+    }
+
+
+    @Test
+    public void testEntryAttributeManyBinaryValuesSerialization() throws IOException, ClassNotFoundException
+    {
+        Attribute attribute1 = new DefaultAttribute( "UserCertificate", data1, data2, data3 );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        attribute1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Attribute attribute2 = new DefaultAttribute();
+        attribute2.readExternal( in );
+
+        assertEquals( attribute1, attribute2 );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeTest.java
new file mode 100644
index 0000000..f3b9738
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeTest.java
@@ -0,0 +1,1533 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.naming.directory.InvalidAttributeValueException;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the DefaultEntryAttribute class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeTest
+{
+    private static final Value<String> NULL_STRING_VALUE = new StringValue( ( String ) null );
+    private static final Value<byte[]> NULL_BINARY_VALUE = new BinaryValue( ( byte[] ) null );
+    private static final byte[] BYTES1 = new byte[]
+        { 'a', 'b' };
+    private static final byte[] BYTES2 = new byte[]
+        { 'b' };
+    private static final byte[] BYTES3 = new byte[]
+        { 'c' };
+    private static final byte[] BYTES4 = new byte[]
+        { 'd' };
+
+    private static final StringValue STR_VALUE1 = new StringValue( "a" );
+    private static final StringValue STR_VALUE2 = new StringValue( "b" );
+    private static final StringValue STR_VALUE3 = new StringValue( "c" );
+    private static final StringValue STR_VALUE4 = new StringValue( "d" );
+
+    private static final BinaryValue BIN_VALUE1 = new BinaryValue( BYTES1 );
+    private static final BinaryValue BIN_VALUE2 = new BinaryValue( BYTES2 );
+    private static final BinaryValue BIN_VALUE3 = new BinaryValue( BYTES3 );
+    private static final BinaryValue BIN_VALUE4 = new BinaryValue( BYTES4 );
+
+
+    /**
+     * Serialize a DefaultEntryAttribute
+     */
+    private ByteArrayOutputStream serializeValue( DefaultAttribute value ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+            value.writeExternal( oOut );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a DefaultEntryAttribute
+     */
+    private DefaultAttribute deserializeValue( ByteArrayOutputStream out ) throws IOException, ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+
+            DefaultAttribute value = new DefaultAttribute();
+            value.readExternal( oIn );
+
+            return value;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception
+    {
+    }
+
+
+    /**
+     * Test method new DefaultEntryAttribute()
+     */
+    @Test
+    public void testDefaultClientAttribute()
+    {
+        Attribute attr = new DefaultAttribute();
+
+        assertFalse( attr.isHumanReadable() );
+        assertEquals( 0, attr.size() );
+        assertNull( attr.getId() );
+        assertNull( attr.getUpId() );
+    }
+
+
+    /**
+     * Test method new DefaultEntryAttribute( String )
+     */
+    @Test
+    public void testDefaultClientAttributeString()
+    {
+        Attribute attr = new DefaultAttribute( "TEST" );
+
+        assertFalse( attr.isHumanReadable() );
+        assertEquals( 0, attr.size() );
+        assertEquals( "test", attr.getId() );
+        assertEquals( "TEST", attr.getUpId() );
+    }
+
+
+    /**
+     * Test method new DefaultEntryAttribute( String, Value... )
+     */
+    @Test
+    public void testDefaultClientAttributeStringValueArray()
+    {
+        Attribute attr = new DefaultAttribute( "Test", STR_VALUE1, STR_VALUE2 );
+
+        assertTrue( attr.isHumanReadable() );
+        assertEquals( 2, attr.size() );
+        assertTrue( attr.contains( "a" ) );
+        assertTrue( attr.contains( "b" ) );
+        assertEquals( "test", attr.getId() );
+        assertEquals( "Test", attr.getUpId() );
+    }
+
+
+    /**
+     * Test method 
+     */
+    @Test
+    public void testDefaultClientAttributeStringStringArray()
+    {
+        Attribute attr = new DefaultAttribute( "Test", "a", "b" );
+
+        assertTrue( attr.isHumanReadable() );
+        assertEquals( 2, attr.size() );
+        assertTrue( attr.contains( "a" ) );
+        assertTrue( attr.contains( "b" ) );
+        assertEquals( "test", attr.getId() );
+        assertEquals( "Test", attr.getUpId() );
+    }
+
+
+    /**
+     * Test method 
+     */
+    @Test
+    public void testDefaultClientAttributeStringBytesArray()
+    {
+        Attribute attr = new DefaultAttribute( "Test", BYTES1, BYTES2 );
+
+        assertFalse( attr.isHumanReadable() );
+        assertEquals( 2, attr.size() );
+        assertTrue( attr.contains( BYTES1 ) );
+        assertTrue( attr.contains( BYTES2 ) );
+        assertEquals( "test", attr.getId() );
+        assertEquals( "Test", attr.getUpId() );
+    }
+
+
+    /**
+     * Test method getBytes()
+     */
+    @Test
+    public void testGetBytes() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        attr1.add( ( byte[] ) null );
+        assertNull( attr1.getBytes() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( BYTES1, BYTES2 );
+        assertTrue( Arrays.equals( BYTES1, attr2.getBytes() ) );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        attr3.add( "a", "b" );
+
+        try
+        {
+            attr3.getBytes();
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException ivae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test method getString()
+     */
+    @Test
+    public void testGetString() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        attr1.add( ( String ) null );
+        assertEquals( "", attr1.getString() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( "a", "b" );
+        assertEquals( "a", attr2.getString() );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        attr3.add( BYTES1, BYTES2 );
+
+        try
+        {
+            attr3.getString();
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException ivae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test method getId()
+     */
+    @Test
+    public void testGetId()
+    {
+        Attribute attr = new DefaultAttribute();
+
+        assertNull( attr.getId() );
+
+        attr.setUpId( "test" );
+        assertEquals( "test", attr.getId() );
+
+        attr.setUpId( "  TEST  " );
+        assertEquals( "test", attr.getId() );
+    }
+
+
+    /**
+     * Test method SetId(String)
+     */
+    @Test
+    public void testSetId()
+    {
+        Attribute attr = new DefaultAttribute();
+
+        try
+        {
+            attr.setUpId( null );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            attr.setUpId( "" );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            attr.setUpId( "  " );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        attr.setUpId( "Test" );
+        assertEquals( "test", attr.getId() );
+
+        attr.setUpId( " Test " );
+        assertEquals( "test", attr.getId() );
+    }
+
+
+    /**
+     * Test method getUpId()
+     */
+    @Test
+    public void testGetUpId()
+    {
+        Attribute attr = new DefaultAttribute();
+
+        assertNull( attr.getUpId() );
+
+        attr.setUpId( "test" );
+        assertEquals( "test", attr.getUpId() );
+
+        attr.setUpId( "  TEST  " );
+        assertEquals( "  TEST  ", attr.getUpId() );
+    }
+
+
+    /**
+     * Test method setUpId(String)
+     */
+    @Test
+    public void testSetUpId()
+    {
+        Attribute attr = new DefaultAttribute();
+
+        try
+        {
+            attr.setUpId( null );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            attr.setUpId( "" );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            attr.setUpId( "  " );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+
+        attr.setUpId( "Test" );
+        assertEquals( "Test", attr.getUpId() );
+        assertEquals( "test", attr.getId() );
+
+        attr.setUpId( " Test " );
+        assertEquals( " Test ", attr.getUpId() );
+        assertEquals( "test", attr.getId() );
+    }
+
+
+    /**
+     * Test method iterator()
+     */
+    @Test
+    public void testIterator() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute();
+        attr.add( "a", "b", "c" );
+
+        Iterator<Value<?>> iter = attr.iterator();
+
+        assertTrue( iter.hasNext() );
+
+        String[] values = new String[]
+            { "a", "b", "c" };
+        int pos = 0;
+
+        for ( Value<?> val : attr )
+        {
+            assertTrue( val instanceof StringValue );
+            assertEquals( values[pos++], val.getString() );
+        }
+    }
+
+
+    /**
+     * Test method add(Value...)
+     */
+    @Test
+    public void testAddValueArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        int nbAdded = attr1.add( new StringValue( ( String ) null ) );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( NULL_STRING_VALUE, attr1.get() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        nbAdded = attr2.add( new BinaryValue( ( byte[] ) null ) );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr2.isHumanReadable() );
+        assertEquals( NULL_BINARY_VALUE, attr2.get() );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        nbAdded = attr3.add( new StringValue( "a" ), new StringValue( "b" ) );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr3.isHumanReadable() );
+        assertTrue( attr3.contains( "a" ) );
+        assertTrue( attr3.contains( "b" ) );
+
+        Attribute attr4 = new DefaultAttribute( "test" );
+
+        nbAdded = attr4.add( new BinaryValue( BYTES1 ), new BinaryValue( BYTES2 ) );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( BYTES1 ) );
+        assertTrue( attr4.contains( BYTES2 ) );
+
+        Attribute attr5 = new DefaultAttribute( "test" );
+
+        nbAdded = attr5.add( new StringValue( "c" ), new BinaryValue( BYTES1 ) );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( "ab" ) );
+        assertTrue( attr5.contains( "c" ) );
+
+        Attribute attr6 = new DefaultAttribute( "test" );
+
+        nbAdded = attr6.add( new BinaryValue( BYTES1 ), new StringValue( "c" ) );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr6.isHumanReadable() );
+        assertTrue( attr6.contains( BYTES1 ) );
+        assertTrue( attr6.contains( BYTES3 ) );
+
+        Attribute attr7 = new DefaultAttribute( "test" );
+
+        nbAdded = attr7.add( new BinaryValue( ( byte[] ) null ), new StringValue( "c" ) );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr7.isHumanReadable() );
+        assertTrue( attr7.contains( NULL_BINARY_VALUE ) );
+        assertTrue( attr7.contains( BYTES3 ) );
+
+        Attribute attr8 = new DefaultAttribute( "test" );
+
+        nbAdded = attr8.add( new StringValue( ( String ) null ), new BinaryValue( BYTES1 ) );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr8.isHumanReadable() );
+        assertTrue( attr8.contains( NULL_STRING_VALUE ) );
+        assertTrue( attr8.contains( "ab" ) );
+    }
+
+
+    /**
+     * Test method add( String... )
+     */
+    @Test
+    public void testAddStringArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+        assertEquals( 0, attr1.size() );
+
+        int nbAdded = attr1.add( ( String ) null );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( NULL_STRING_VALUE, attr1.get() );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        nbAdded = attr2.add( "" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( "", attr2.getString() );
+        assertEquals( 1, attr2.size() );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        nbAdded = attr3.add( "t" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr3.isHumanReadable() );
+        assertEquals( "t", attr3.getString() );
+
+        Attribute attr4 = new DefaultAttribute( "test" );
+
+        nbAdded = attr4.add( "a", "b", "c", "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "a", attr4.getString() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+
+        nbAdded = attr4.add( "e" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "a", attr4.getString() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+        assertTrue( attr4.contains( "e" ) );
+
+        nbAdded = attr4.add( BYTES1 );
+        assertEquals( 0, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertEquals( "a", attr4.getString() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+        assertTrue( attr4.contains( "e" ) );
+        assertFalse( attr4.contains( "ab" ) );
+
+        Attribute attr5 = new DefaultAttribute( "test" );
+
+        nbAdded = attr5.add( "a", "b", ( String ) null, "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( "a" ) );
+        assertTrue( attr5.contains( "b" ) );
+        assertTrue( attr5.contains( ( String ) null ) );
+        assertTrue( attr5.contains( "d" ) );
+
+        Attribute attr6 = new DefaultAttribute( "test" );
+
+        nbAdded = attr6.add( "a", ( String ) null );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr6.isHumanReadable() );
+        assertTrue( attr6.contains( "a" ) );
+        assertTrue( attr6.contains( ( String ) null ) );
+
+        Attribute attr7 = new DefaultAttribute( "test" );
+
+        attr7.add( "a", "b" );
+        assertEquals( 2, attr7.size() );
+
+        assertEquals( 1, attr7.add( "b", "c" ) );
+        assertEquals( 3, attr7.size() );
+        assertTrue( attr7.contains( "a", "b", "c" ) );
+    }
+
+
+    /**
+     * Test method add( byte[]... )
+     */
+    @Test
+    public void testAddByteArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+        assertEquals( 0, attr1.size() );
+
+        int nbAdded = attr1.add( ( byte[] ) null );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr1.isHumanReadable() );
+        assertTrue( Arrays.equals( NULL_BINARY_VALUE.getBytes(), attr1.getBytes() ) );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        nbAdded = attr2.add( StringConstants.EMPTY_BYTES );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr2.isHumanReadable() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, attr2.getBytes() ) );
+        assertEquals( 1, attr2.size() );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        nbAdded = attr3.add( BYTES1 );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr3.isHumanReadable() );
+        assertTrue( Arrays.equals( BYTES1, attr3.getBytes() ) );
+
+        Attribute attr4 = new DefaultAttribute( "test" );
+
+        nbAdded = attr4.add( BYTES1, BYTES2, BYTES3, BYTES4 );
+        assertEquals( 4, nbAdded );
+        assertFalse( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( BYTES1 ) );
+        assertTrue( attr4.contains( BYTES2 ) );
+        assertTrue( attr4.contains( BYTES3 ) );
+        assertTrue( attr4.contains( BYTES4 ) );
+
+        Attribute attr5 = new DefaultAttribute( "test" );
+
+        nbAdded = attr5.add( BYTES1, BYTES2, ( byte[] ) null, BYTES3 );
+        assertEquals( 4, nbAdded );
+        assertFalse( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( BYTES1 ) );
+        assertTrue( attr5.contains( BYTES2 ) );
+        assertTrue( attr5.contains( ( byte[] ) null ) );
+        assertTrue( attr5.contains( BYTES3 ) );
+
+        Attribute attr6 = new DefaultAttribute( "test" );
+
+        nbAdded = attr6.add( BYTES1, ( byte[] ) null );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr6.isHumanReadable() );
+        assertTrue( attr6.contains( "ab" ) );
+        assertTrue( attr6.contains( ( byte[] ) null ) );
+    }
+
+
+    /**
+     * Test method clear()
+     */
+    @Test
+    public void testClear() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( ( String ) null );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.isHumanReadable() );
+        attr1.clear();
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( 0, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+        attr2.add( BYTES1, BYTES2 );
+        assertEquals( 2, attr2.size() );
+        assertFalse( attr2.isHumanReadable() );
+        attr2.clear();
+        assertFalse( attr2.isHumanReadable() );
+        assertEquals( 0, attr2.size() );
+    }
+
+
+    /**
+     * Test method contains( Value... )
+     */
+    @Test
+    public void testContainsValueArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertEquals( 0, attr1.size() );
+        assertFalse( attr1.contains( STR_VALUE1 ) );
+        assertFalse( attr1.contains( NULL_STRING_VALUE ) );
+
+        attr1.add( ( String ) null );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( NULL_STRING_VALUE ) );
+
+        attr1.remove( ( String ) null );
+        assertFalse( attr1.contains( NULL_STRING_VALUE ) );
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( "a", "b", "c" );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( STR_VALUE1 ) );
+        assertTrue( attr1.contains( STR_VALUE2 ) );
+        assertTrue( attr1.contains( STR_VALUE3 ) );
+        assertTrue( attr1.contains( STR_VALUE1, STR_VALUE3 ) );
+        assertFalse( attr1.contains( STR_VALUE4 ) );
+        assertFalse( attr1.contains( NULL_STRING_VALUE ) );
+        assertTrue( attr1.contains( STR_VALUE1, BIN_VALUE2 ) );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+        assertEquals( 0, attr2.size() );
+        assertFalse( attr2.contains( BYTES1 ) );
+        assertFalse( attr2.contains( NULL_BINARY_VALUE ) );
+
+        attr2.add( ( byte[] ) null );
+        assertEquals( 1, attr2.size() );
+        assertTrue( attr2.contains( NULL_BINARY_VALUE ) );
+
+        attr2.remove( ( byte[] ) null );
+        assertFalse( attr2.contains( NULL_BINARY_VALUE ) );
+        assertEquals( 0, attr2.size() );
+
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+        assertEquals( 3, attr2.size() );
+        assertTrue( attr2.contains( BIN_VALUE1 ) );
+        assertTrue( attr2.contains( BIN_VALUE2 ) );
+        assertTrue( attr2.contains( BIN_VALUE3 ) );
+        assertFalse( attr2.contains( NULL_BINARY_VALUE ) );
+        assertTrue( attr2.contains( STR_VALUE2, BIN_VALUE1 ) );
+    }
+
+
+    /**
+     * Test method contains( String... )
+     */
+    @Test
+    public void testContainsStringArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertEquals( 0, attr1.size() );
+        assertFalse( attr1.contains( "a" ) );
+        assertFalse( attr1.contains( ( String ) null ) );
+
+        attr1.add( ( String ) null );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( ( String ) null ) );
+
+        attr1.remove( ( String ) null );
+        assertFalse( attr1.contains( ( String ) null ) );
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( "a", "b", "c" );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( "a" ) );
+        assertTrue( attr1.contains( "b" ) );
+        assertTrue( attr1.contains( "c" ) );
+        assertFalse( attr1.contains( "e" ) );
+        assertFalse( attr1.contains( ( String ) null ) );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+        assertEquals( 0, attr2.size() );
+        assertFalse( attr2.contains( BYTES1 ) );
+        assertFalse( attr2.contains( ( byte[] ) null ) );
+
+        attr2.add( ( byte[] ) null );
+        assertEquals( 1, attr2.size() );
+        assertTrue( attr2.contains( ( byte[] ) null ) );
+
+        attr2.remove( ( byte[] ) null );
+        assertFalse( attr2.contains( ( byte[] ) null ) );
+        assertEquals( 0, attr2.size() );
+
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+        assertEquals( 3, attr2.size() );
+        assertTrue( attr2.contains( "ab" ) );
+        assertTrue( attr2.contains( "b" ) );
+        assertTrue( attr2.contains( "c" ) );
+        assertFalse( attr2.contains( ( String ) null ) );
+    }
+
+
+    /**
+     * Test method contains( byte... )
+     */
+    @Test
+    public void testContainsByteArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertEquals( 0, attr1.size() );
+        assertFalse( attr1.contains( BYTES1 ) );
+        assertFalse( attr1.contains( ( byte[] ) null ) );
+
+        attr1.add( ( byte[] ) null );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( ( byte[] ) null ) );
+
+        attr1.remove( ( byte[] ) null );
+        assertFalse( attr1.contains( ( byte[] ) null ) );
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( BYTES1, BYTES2, BYTES3 );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( BYTES1 ) );
+        assertTrue( attr1.contains( BYTES2 ) );
+        assertTrue( attr1.contains( BYTES3 ) );
+        assertFalse( attr1.contains( BYTES4 ) );
+        assertFalse( attr1.contains( ( byte[] ) null ) );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+        assertEquals( 0, attr2.size() );
+        assertFalse( attr2.contains( "a" ) );
+        assertFalse( attr2.contains( ( String ) null ) );
+
+        attr2.add( ( String ) null );
+        assertEquals( 1, attr2.size() );
+        assertTrue( attr2.contains( ( String ) null ) );
+
+        attr2.remove( ( String ) null );
+        assertFalse( attr2.contains( ( String ) null ) );
+        assertEquals( 0, attr2.size() );
+
+        attr2.add( "ab", "b", "c" );
+        assertEquals( 3, attr2.size() );
+        assertTrue( attr2.contains( BYTES1 ) );
+        assertTrue( attr2.contains( BYTES2 ) );
+        assertTrue( attr2.contains( BYTES3 ) );
+        assertFalse( attr2.contains( ( byte[] ) null ) );
+    }
+
+
+    /**
+     * Test method get()
+     */
+    @Test
+    public void testGet() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        attr1.add( ( String ) null );
+        assertEquals( NULL_STRING_VALUE, attr1.get() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( "a", "b", "c" );
+        assertEquals( "a", attr2.get().getString() );
+
+        attr2.remove( "a" );
+        assertEquals( "b", attr2.get().getString() );
+
+        attr2.remove( "b" );
+        assertEquals( "c", attr2.get().getString() );
+
+        attr2.remove( "c" );
+        assertNull( attr2.get() );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        attr3.add( BYTES1, BYTES2, BYTES3 );
+        assertTrue( Arrays.equals( BYTES1, attr3.get().getBytes() ) );
+
+        attr3.remove( BYTES1 );
+        assertTrue( Arrays.equals( BYTES2, attr3.get().getBytes() ) );
+
+        attr3.remove( BYTES2 );
+        assertTrue( Arrays.equals( BYTES3, attr3.get().getBytes() ) );
+
+        attr3.remove( BYTES3 );
+        assertNull( attr2.get() );
+    }
+
+
+    /**
+     * Test method getAll()
+     */
+    @Test
+    public void testIterator2() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( "test" );
+
+        Iterator<Value<?>> iterator = attr.iterator();
+        assertFalse( iterator.hasNext() );
+
+        attr.add( NULL_STRING_VALUE );
+        iterator = attr.iterator();
+        assertTrue( iterator.hasNext() );
+
+        Value<?> value = iterator.next();
+        assertEquals( NULL_STRING_VALUE, value );
+
+        attr.clear();
+        iterator = attr.iterator();
+        assertFalse( iterator.hasNext() );
+
+        attr.add( "a", "b", "c" );
+        iterator = attr.iterator();
+        assertTrue( iterator.hasNext() );
+        assertEquals( "a", iterator.next().getString() );
+        assertEquals( "b", iterator.next().getString() );
+        assertEquals( "c", iterator.next().getString() );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    /**
+     * Test method size()
+     */
+    @Test
+    public void testSize() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( ( String ) null );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( "a", "b" );
+        assertEquals( 2, attr2.size() );
+
+        attr2.clear();
+        assertEquals( 0, attr2.size() );
+    }
+
+
+    /**
+     * Test method remove( Value... )
+     */
+    @Test
+    public void testRemoveValueArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertFalse( attr1.remove( STR_VALUE1 ) );
+        assertFalse( attr1.remove( STR_VALUE1 ) );
+
+        attr1.add( "a", "b", "c" );
+        assertTrue( attr1.remove( STR_VALUE1 ) );
+        assertEquals( 2, attr1.size() );
+
+        assertTrue( attr1.remove( STR_VALUE2, STR_VALUE3 ) );
+        assertEquals( 0, attr1.size() );
+
+        assertFalse( attr1.remove( STR_VALUE4 ) );
+
+        attr1.clear();
+        attr1.add( "a", "b", "c" );
+        assertFalse( attr1.remove( STR_VALUE2, STR_VALUE4 ) );
+        assertEquals( 2, attr1.size() );
+
+        attr1.clear();
+        attr1.add( "a", ( String ) null, "b" );
+        assertTrue( attr1.remove( NULL_STRING_VALUE, STR_VALUE1 ) );
+        assertEquals( 1, attr1.size() );
+
+        attr1.clear();
+        attr1.add( "a", ( String ) null, "b" );
+        attr1.add( BYTES3 );
+        assertTrue( attr1.remove( NULL_STRING_VALUE, STR_VALUE1 ) );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        assertFalse( attr2.remove( BIN_VALUE1 ) );
+
+        attr2.clear();
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+        assertTrue( attr2.remove( BIN_VALUE1 ) );
+        assertEquals( 2, attr2.size() );
+
+        assertTrue( attr2.remove( BIN_VALUE2, BIN_VALUE3 ) );
+        assertEquals( 0, attr2.size() );
+
+        assertFalse( attr2.remove( BIN_VALUE4 ) );
+
+        attr2.clear();
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+        assertFalse( attr2.remove( BIN_VALUE2, STR_VALUE4 ) );
+        assertEquals( 2, attr2.size() );
+
+        attr2.clear();
+        attr2.add( BYTES1, ( byte[] ) null, BYTES3 );
+        assertFalse( attr2.remove( NULL_STRING_VALUE, BIN_VALUE1 ) );
+        assertEquals( 2, attr2.size() );
+
+        attr2.clear();
+        attr2.add( BYTES1, ( byte[] ) null, BYTES2 );
+        attr2.add( "c" );
+        assertEquals( 4, attr2.size() );
+        assertFalse( attr2.remove( NULL_STRING_VALUE, BIN_VALUE1, STR_VALUE3 ) );
+        assertEquals( 3, attr2.size() );
+    }
+
+
+    /**
+     * Test method remove( byte... )
+     */
+    @Test
+    public void testRemoveByteArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertFalse( attr1.remove( BYTES1 ) );
+
+        attr1.add( BYTES1, BYTES2, BYTES3 );
+        assertTrue( attr1.remove( BYTES1 ) );
+        assertEquals( 2, attr1.size() );
+
+        assertTrue( attr1.remove( BYTES2, BYTES3 ) );
+        assertEquals( 0, attr1.size() );
+
+        assertFalse( attr1.remove( BYTES4 ) );
+
+        attr1.clear();
+        attr1.add( BYTES1, BYTES2, BYTES3 );
+        assertFalse( attr1.remove( BYTES3, BYTES4 ) );
+        assertEquals( 2, attr1.size() );
+
+        attr1.clear();
+        attr1.add( BYTES1, ( byte[] ) null, BYTES2 );
+        assertTrue( attr1.remove( ( byte[] ) null, BYTES1 ) );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( "ab", "b", "c" );
+
+        assertFalse( attr2.remove( ( byte[] ) null ) );
+        assertTrue( attr2.remove( BYTES1, BYTES2 ) );
+        assertFalse( attr2.remove( BYTES4 ) );
+    }
+
+
+    /**
+     * Test method remove( String... )
+     */
+    @Test
+    public void testRemoveStringArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertFalse( attr1.remove( "a" ) );
+
+        attr1.add( "a", "b", "c" );
+        assertTrue( attr1.remove( "a" ) );
+        assertEquals( 2, attr1.size() );
+
+        assertTrue( attr1.remove( "b", "c" ) );
+        assertEquals( 0, attr1.size() );
+
+        assertFalse( attr1.remove( "d" ) );
+
+        attr1.clear();
+        attr1.add( "a", "b", "c" );
+        assertFalse( attr1.remove( "b", "e" ) );
+        assertEquals( 2, attr1.size() );
+
+        attr1.clear();
+        attr1.add( "a", ( String ) null, "b" );
+        assertTrue( attr1.remove( ( String ) null, "a" ) );
+        assertEquals( 1, attr1.size() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( BYTES1, BYTES2, BYTES3 );
+
+        assertFalse( attr2.remove( ( String ) null ) );
+        assertTrue( attr2.remove( "ab", "c" ) );
+        assertFalse( attr2.remove( "d" ) );
+    }
+
+
+    /**
+     * Test method put( String... )
+     */
+    @Test
+    public void testPutStringArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        int nbAdded = attr1.add( ( String ) null );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr1.isHumanReadable() );
+        assertEquals( NULL_STRING_VALUE, attr1.get() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        nbAdded = attr2.add( "" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr2.isHumanReadable() );
+        assertEquals( "", attr2.getString() );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        nbAdded = attr3.add( "t" );
+        assertEquals( 1, nbAdded );
+        assertTrue( attr3.isHumanReadable() );
+        assertEquals( "t", attr3.getString() );
+
+        Attribute attr4 = new DefaultAttribute( "test" );
+
+        nbAdded = attr4.add( "a", "b", "c", "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( "a" ) );
+        assertTrue( attr4.contains( "b" ) );
+        assertTrue( attr4.contains( "c" ) );
+        assertTrue( attr4.contains( "d" ) );
+
+        Attribute attr5 = new DefaultAttribute( "test" );
+
+        nbAdded = attr5.add( "a", "b", ( String ) null, "d" );
+        assertEquals( 4, nbAdded );
+        assertTrue( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( "a" ) );
+        assertTrue( attr5.contains( "b" ) );
+        assertTrue( attr5.contains( ( String ) null ) );
+        assertTrue( attr5.contains( "d" ) );
+
+        Attribute attr6 = new DefaultAttribute( "test" );
+
+        nbAdded = attr6.add( "a", ( String ) null );
+        assertEquals( 2, nbAdded );
+        assertTrue( attr6.isHumanReadable() );
+        assertTrue( attr6.contains( "a" ) );
+        assertTrue( attr6.contains( ( String ) null ) );
+    }
+
+
+    /**
+     * Test method put( byte[]... )
+     */
+    @Test
+    public void testPutByteArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        int nbAdded = attr1.add( ( byte[] ) null );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr1.isHumanReadable() );
+        assertTrue( Arrays.equals( NULL_BINARY_VALUE.getBytes(), attr1.getBytes() ) );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        nbAdded = attr2.add( StringConstants.EMPTY_BYTES );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr2.isHumanReadable() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, attr2.getBytes() ) );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+
+        nbAdded = attr3.add( BYTES1 );
+        assertEquals( 1, nbAdded );
+        assertFalse( attr3.isHumanReadable() );
+        assertTrue( Arrays.equals( BYTES1, attr3.getBytes() ) );
+
+        Attribute attr4 = new DefaultAttribute( "test" );
+
+        nbAdded = attr4.add( BYTES1, BYTES2 );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( BYTES1 ) );
+        assertTrue( attr4.contains( BYTES2 ) );
+
+        nbAdded = attr4.add( BYTES3, BYTES4 );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr4.isHumanReadable() );
+        assertTrue( attr4.contains( BYTES3 ) );
+        assertTrue( attr4.contains( BYTES4 ) );
+
+        Attribute attr5 = new DefaultAttribute( "test" );
+
+        nbAdded = attr5.add( BYTES1, BYTES2, ( byte[] ) null, BYTES3 );
+        assertEquals( 4, nbAdded );
+        assertFalse( attr5.isHumanReadable() );
+        assertTrue( attr5.contains( BYTES1 ) );
+        assertTrue( attr5.contains( BYTES2 ) );
+        assertTrue( attr5.contains( ( byte[] ) null ) );
+        assertTrue( attr5.contains( BYTES3 ) );
+
+        Attribute attr6 = new DefaultAttribute( "test" );
+
+        nbAdded = attr6.add( BYTES1, ( byte[] ) null );
+        assertEquals( 2, nbAdded );
+        assertFalse( attr6.isHumanReadable() );
+        assertTrue( attr6.contains( "ab" ) );
+        assertTrue( attr6.contains( ( byte[] ) null ) );
+    }
+
+
+    /**
+     * Test method put( Value... )
+     */
+    @Test
+    public void testPutValueArray() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertEquals( 0, attr1.size() );
+
+        attr1.add( NULL_STRING_VALUE );
+        assertEquals( 1, attr1.size() );
+        assertTrue( attr1.contains( NULL_STRING_VALUE ) );
+
+        attr1.clear();
+        attr1.add( STR_VALUE1, STR_VALUE2, STR_VALUE3 );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( STR_VALUE1 ) );
+        assertTrue( attr1.contains( STR_VALUE2 ) );
+        assertTrue( attr1.contains( STR_VALUE3 ) );
+
+        attr1.clear();
+        attr1.add( STR_VALUE1, NULL_STRING_VALUE, STR_VALUE3 );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( STR_VALUE1 ) );
+        assertTrue( attr1.contains( NULL_STRING_VALUE ) );
+        assertTrue( attr1.contains( STR_VALUE3 ) );
+
+        attr1.clear();
+        attr1.add( STR_VALUE1, NULL_STRING_VALUE, BIN_VALUE3 );
+        assertEquals( 3, attr1.size() );
+        assertTrue( attr1.contains( STR_VALUE1 ) );
+        assertTrue( attr1.contains( NULL_STRING_VALUE ) );
+        assertTrue( attr1.contains( STR_VALUE3 ) );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+        assertEquals( 0, attr2.size() );
+
+        attr2.add( NULL_BINARY_VALUE );
+        assertEquals( 1, attr2.size() );
+        assertTrue( attr2.contains( NULL_BINARY_VALUE ) );
+
+        attr2.clear();
+        attr2.add( BIN_VALUE1, BIN_VALUE2, BIN_VALUE3 );
+        assertEquals( 3, attr2.size() );
+        assertTrue( attr2.contains( BIN_VALUE1 ) );
+        assertTrue( attr2.contains( BIN_VALUE2 ) );
+        assertTrue( attr2.contains( BIN_VALUE3 ) );
+
+        attr2.clear();
+        attr2.add( BIN_VALUE1, NULL_BINARY_VALUE, STR_VALUE3 );
+        assertEquals( 3, attr2.size() );
+        assertTrue( attr2.contains( BIN_VALUE1 ) );
+        assertTrue( attr2.contains( NULL_BINARY_VALUE ) );
+        assertTrue( attr2.contains( BIN_VALUE3 ) );
+    }
+
+
+    /**
+     * Test method toString()
+     */
+    @Test
+    public void testToString() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertEquals( "test: (null)", attr1.toString() );
+
+        attr1.add( "a" );
+        assertEquals( "test: a", attr1.toString() );
+
+        attr1.add( "b" );
+        assertEquals( "test: a\ntest: b", attr1.toString() );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        attr2.add( BYTES1 );
+        assertEquals( "test: 0x61 0x62 ", attr2.toString() );
+
+        attr2.add( BYTES3 );
+        assertEquals( "test: 0x61 0x62 \ntest: 0x63 ", attr2.toString() );
+    }
+
+
+    /**
+     * Test method hashCode()
+     */
+    @Test
+    public void testHashCode() throws InvalidAttributeValueException, LdapException
+    {
+        Attribute attr = new DefaultAttribute();
+        assertEquals( 37, attr.hashCode() );
+
+        Attribute attr1 = new DefaultAttribute( "test" );
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        assertEquals( attr1.hashCode(), attr2.hashCode() );
+
+        attr1.add( "a", "b", "c" );
+        attr2.add( "a", "b", "c" );
+        assertEquals( attr1.hashCode(), attr2.hashCode() );
+
+        attr1.add( "d" );
+        attr2.add( "d" );
+        assertEquals( attr1.hashCode(), attr2.hashCode() );
+
+        attr1.add( NULL_STRING_VALUE );
+        attr2.add( NULL_STRING_VALUE );
+        assertEquals( attr1.hashCode(), attr2.hashCode() );
+
+        // Order mess up the hashCode
+        attr1.clear();
+        attr2.clear();
+        attr1.add( "a", "b", "c" );
+        attr2.add( "c", "b", "a" );
+        assertNotSame( attr1.hashCode(), attr2.hashCode() );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+        Attribute attr4 = new DefaultAttribute( "test" );
+
+        attr3.add( BYTES1, BYTES2 );
+        attr4.add( BYTES1, BYTES2 );
+        assertEquals( attr3.hashCode(), attr4.hashCode() );
+
+        attr3.add( BYTES3 );
+        attr4.add( BYTES3 );
+        assertEquals( attr3.hashCode(), attr4.hashCode() );
+
+        attr3.add( NULL_BINARY_VALUE );
+        attr4.add( NULL_BINARY_VALUE );
+        assertEquals( attr3.hashCode(), attr4.hashCode() );
+
+        // Order mess up the hashCode
+        attr3.clear();
+        attr4.clear();
+        attr3.add( BYTES1, BYTES2 );
+        attr4.add( BYTES2, BYTES1 );
+        assertNotSame( attr3.hashCode(), attr4.hashCode() );
+    }
+
+
+    /**
+     * Test method testEquals()
+     */
+    @Test
+    public void testEquals() throws LdapException
+    {
+        Attribute attr1 = new DefaultAttribute( "test" );
+
+        assertFalse( attr1.equals( null ) );
+
+        Attribute attr2 = new DefaultAttribute( "test" );
+
+        assertTrue( attr1.equals( attr2 ) );
+
+        attr2.setUpId( "TEST" );
+        assertTrue( attr1.equals( attr2 ) );
+
+        attr1.setUpId( "tset" );
+        assertFalse( attr1.equals( attr2 ) );
+
+        attr1.setUpId( "TEST" );
+        assertTrue( attr1.equals( attr2 ) );
+
+        attr1.add( "a", "b", "c" );
+        attr2.add( "c", "b", "a" );
+        assertTrue( attr1.equals( attr2 ) );
+
+        assertTrue( attr1.equals( attr2 ) );
+
+        Attribute attr3 = new DefaultAttribute( "test" );
+        Attribute attr4 = new DefaultAttribute( "test" );
+
+        attr3.add( NULL_BINARY_VALUE );
+        attr4.add( NULL_BINARY_VALUE );
+        assertTrue( attr3.equals( attr4 ) );
+
+        Attribute attr5 = new DefaultAttribute( "test" );
+        Attribute attr6 = new DefaultAttribute( "test" );
+
+        attr5.add( NULL_BINARY_VALUE );
+        attr6.add( NULL_STRING_VALUE );
+        assertFalse( attr5.equals( attr6 ) );
+
+        Attribute attr7 = new DefaultAttribute( "test" );
+        Attribute attr8 = new DefaultAttribute( "test" );
+
+        attr7.add( "a" );
+        attr8.add( BYTES2 );
+        assertFalse( attr7.equals( attr8 ) );
+
+        Attribute attr9 = new DefaultAttribute( "test" );
+        Attribute attr10 = new DefaultAttribute( "test" );
+
+        attr7.add( "a" );
+        attr7.add( BYTES2 );
+        attr8.add( "a", "b" );
+        assertTrue( attr9.equals( attr10 ) );
+    }
+
+
+    /**
+     * Test method testClone()
+     */
+    @Test
+    public void testClone() throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( "test" );
+
+        Attribute clone = attr.clone();
+
+        assertEquals( attr, clone );
+        attr.setUpId( "new" );
+        assertEquals( "test", clone.getId() );
+
+        attr.add( "a", ( String ) null, "b" );
+        clone = attr.clone();
+        assertEquals( attr, clone );
+
+        attr.remove( "a" );
+        assertNotSame( attr, clone );
+
+        clone = attr.clone();
+        assertEquals( attr, clone );
+    }
+
+
+    /**
+     * Test the serialization of a complete client attribute
+     */
+    @Test
+    public void testSerializeCompleteAttribute() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dca = new DefaultAttribute( "CommonName" );
+        dca.setUpId( "CN" );
+        dca.add( "test1", "test2" );
+
+        DefaultAttribute dcaSer = deserializeValue( serializeValue( dca ) );
+        assertEquals( dca.toString(), dcaSer.toString() );
+        assertEquals( "cn", dcaSer.getId() );
+        assertEquals( "CN", dcaSer.getUpId() );
+        assertEquals( "test1", dcaSer.getString() );
+        assertTrue( dcaSer.contains( "test2", "test1" ) );
+        assertTrue( dcaSer.isHumanReadable() );
+    }
+
+
+    /**
+     * Test the serialization of a client attribute with no value
+     */
+    @Test
+    public void testSerializeAttributeWithNoValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dca = new DefaultAttribute( "CommonName" );
+        dca.setUpId( "CN" );
+
+        DefaultAttribute dcaSer = deserializeValue( serializeValue( dca ) );
+        assertEquals( dca.toString(), dcaSer.toString() );
+        assertEquals( "cn", dcaSer.getId() );
+        assertEquals( "CN", dcaSer.getUpId() );
+        assertEquals( 0, dcaSer.size() );
+        assertFalse( dcaSer.isHumanReadable() );
+    }
+
+
+    /**
+     * Test the serialization of a client attribute with a null value
+     */
+    @Test
+    public void testSerializeAttributeNullValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dca = new DefaultAttribute( "CommonName" );
+        dca.setUpId( "CN" );
+        dca.add( ( String ) null );
+
+        DefaultAttribute dcaSer = deserializeValue( serializeValue( dca ) );
+        assertEquals( dca.toString(), dcaSer.toString() );
+        assertEquals( "cn", dcaSer.getId() );
+        assertEquals( "CN", dcaSer.getUpId() );
+        assertEquals( "", dcaSer.getString() );
+        assertEquals( 1, dcaSer.size() );
+        assertTrue( dcaSer.contains( ( String ) null ) );
+        assertTrue( dcaSer.isHumanReadable() );
+    }
+
+
+    /**
+     * Test the serialization of a client attribute with a binary value
+     */
+    @Test
+    public void testSerializeAttributeBinaryValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        DefaultAttribute dca = new DefaultAttribute( "UserPassword" );
+        byte[] password = Strings.getBytesUtf8( "secret" );
+        dca.add( password );
+
+        DefaultAttribute dcaSer = deserializeValue( serializeValue( dca ) );
+        assertEquals( dca.toString(), dcaSer.toString() );
+        assertEquals( "userpassword", dcaSer.getId() );
+        assertEquals( "UserPassword", dcaSer.getUpId() );
+        assertTrue( Arrays.equals( dca.getBytes(), dcaSer.getBytes() ) );
+        assertEquals( 1, dcaSer.size() );
+        assertTrue( dcaSer.contains( password ) );
+        assertFalse( dcaSer.isHumanReadable() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeUtilsTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeUtilsTest.java
new file mode 100644
index 0000000..25b6b0f
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/AttributeUtilsTest.java
@@ -0,0 +1,426 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.AttributeUtils;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test case for the AttributeUtils methods 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeUtilsTest
+{
+
+    byte[] byteArrayA;
+    byte[] byteArrayACopy;
+    byte[] byteArrayB;
+    byte[] byteArrayC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        byte[] b = "aa".getBytes();
+        byteArrayA = b;
+        byteArrayACopy = b;
+        byteArrayB = "aa".getBytes();
+        byteArrayC = "cc".getBytes();
+    }
+
+
+    /**
+     * Test a addModification applied to an empty entry
+     */
+    @Test
+    public void testApplyAddModificationToEmptyEntry() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+        Modification modification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        AttributeUtils.applyModification( entry, modification );
+        assertNotNull( entry.get( "cn" ) );
+        assertEquals( 1, entry.size() );
+        assertEquals( attr, entry.get( "cn" ) );
+    }
+
+
+    /**
+     * Test a addModification applied to an entry 
+     */
+    @Test
+    public void testApplyAddModificationToEntry() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        entry.add( "dc", "apache" );
+        assertEquals( 1, entry.size() );
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+        Modification modification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+
+        AttributeUtils.applyModification( entry, modification );
+        assertNotNull( entry.get( "cn" ) );
+        assertEquals( 2, entry.size() );
+        assertEquals( attr, entry.get( "cn" ) );
+    }
+
+
+    /**
+     * Test a addModification applied to an entry with the same attribute
+     * but with another value 
+     */
+    @Test
+    public void testApplyAddModificationToEntryWithValues() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        entry.put( "cn", "apache" );
+        assertEquals( 1, entry.size() );
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+        Modification modification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        AttributeUtils.applyModification( entry, modification );
+        assertNotNull( entry.get( "cn" ) );
+        assertEquals( 1, entry.size() );
+
+        Attribute attribute = entry.get( "cn" );
+
+        assertTrue( attribute.size() != 0 );
+
+        Set<String> expectedValues = new HashSet<String>();
+        expectedValues.add( "apache" );
+        expectedValues.add( "test" );
+
+        for ( Value<?> value : attribute )
+        {
+            String valueStr = value.getString();
+
+            assertTrue( expectedValues.contains( valueStr ) );
+
+            expectedValues.remove( valueStr );
+        }
+
+        assertEquals( 0, expectedValues.size() );
+    }
+
+
+    /**
+     * Test a addModification applied to an entry with the same attribute
+     * and the same value 
+     */
+    @Test
+    public void testApplyAddModificationToEntryWithSameValue() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        entry.put( "cn", "test", "apache" );
+        assertEquals( 1, entry.size() );
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+        Modification modification = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        AttributeUtils.applyModification( entry, modification );
+        assertNotNull( entry.get( "cn" ) );
+        assertEquals( 1, entry.size() );
+
+        Attribute cnAttr = entry.get( "cn" );
+
+        assertTrue( cnAttr.size() != 0 );
+
+        Set<String> expectedValues = new HashSet<String>();
+        expectedValues.add( "apache" );
+        expectedValues.add( "test" );
+
+        for ( Value<?> value : cnAttr )
+        {
+            String valueStr = value.getString();
+
+            assertTrue( expectedValues.contains( valueStr ) );
+
+            expectedValues.remove( valueStr );
+        }
+
+        assertEquals( 0, expectedValues.size() );
+    }
+
+
+    /**
+     * Test the deletion of an attribute into an empty entry
+     */
+    @Test
+    public void testApplyRemoveModificationFromEmptyEntry() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
+        AttributeUtils.applyModification( entry, modification );
+        assertNull( entry.get( "cn" ) );
+        assertEquals( 0, entry.size() );
+    }
+
+
+    /**
+     * Test the deletion of an attribute into an entry which does not contain the attribute
+     */
+    @Test
+    public void testApplyRemoveModificationFromEntryAttributeNotPresent() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        Attribute dc = new DefaultAttribute( "dc", "apache" );
+        entry.put( dc );
+
+        Attribute cn = new DefaultAttribute( "cn", "test" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, cn );
+
+        AttributeUtils.applyModification( entry, modification );
+
+        assertNull( entry.get( "cn" ) );
+        assertNotNull( entry.get( "dc" ) );
+        assertEquals( 1, entry.size() );
+        assertEquals( dc, entry.get( "dc" ) );
+    }
+
+
+    /**
+     * Test the deletion of an attribute into an entry which contains the attribute
+     * but without the value to be deleted
+     */
+    @Test
+    public void testApplyRemoveModificationFromEntryAttributeNotSameValue() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        Attribute cn = new DefaultAttribute( "cn", "apache" );
+        entry.put( cn );
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
+
+        AttributeUtils.applyModification( entry, modification );
+
+        assertNotNull( entry.get( "cn" ) );
+        assertEquals( 1, entry.size() );
+        assertEquals( cn, entry.get( "cn" ) );
+    }
+
+
+    /**
+     * Test the deletion of an attribute into an entry which contains the attribute.
+     * 
+     * The entry should not contain the attribute after the operation
+     */
+    @Test
+    public void testApplyRemoveModificationFromEntrySameAttributeSameValue() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        entry.put( "cn", "test" );
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
+
+        AttributeUtils.applyModification( entry, modification );
+
+        assertNull( entry.get( "cn" ) );
+        assertEquals( 0, entry.size() );
+    }
+
+
+    /**
+     * Test the deletion of an attribute into an entry which contains the attribute
+     * with more than one value
+     * 
+     * The entry should contain the attribute after the operation, but with one less value
+     */
+    @Test
+    public void testApplyRemoveModificationFromEntrySameAttributeValues() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        entry.put( "cn", "test", "apache" );
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
+
+        AttributeUtils.applyModification( entry, modification );
+
+        assertNotNull( entry.get( "cn" ) );
+        assertEquals( 1, entry.size() );
+
+        Attribute modifiedAttr = entry.get( "cn" );
+
+        assertTrue( modifiedAttr.size() != 0 );
+
+        boolean isFirst = true;
+
+        for ( Value<?> value : modifiedAttr )
+        {
+            assertTrue( isFirst );
+
+            isFirst = false;
+            assertEquals( "apache", value.getString() );
+        }
+    }
+
+
+    /**
+     * test the addition by modification of an attribute in an empty entry.
+     * 
+     * As we are replacing a non existing attribute, it should be added.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testApplyModifyModificationFromEmptyEntry() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        Attribute attr = new DefaultAttribute( "cn", "test" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attr );
+        AttributeUtils.applyModification( entry, modification );
+        assertNotNull( entry.get( "cn" ) );
+        assertEquals( 1, entry.size() );
+    }
+
+
+    /**
+     * Test the replacement by modification of an attribute in an empty entry.
+     * 
+     * As we are replacing a non existing attribute, it should not change the entry.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testApplyModifyEmptyModificationFromEmptyEntry() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        Attribute attr = new DefaultAttribute( "cn" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attr );
+        AttributeUtils.applyModification( entry, modification );
+        assertNull( entry.get( "cn" ) );
+        assertEquals( 0, entry.size() );
+    }
+
+
+    /**
+     * Test the replacement by modification of an attribute in an empty entry.
+     * 
+     * As we are replacing a non existing attribute, it should not change the entry.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testApplyModifyAttributeModification() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        entry.put( "cn", "test" );
+        entry.put( "ou", "apache", "acme corp" );
+
+        Attribute newOu = new DefaultAttribute( "ou", "Big Company", "directory" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, newOu );
+
+        AttributeUtils.applyModification( entry, modification );
+
+        assertEquals( 2, entry.size() );
+
+        assertNotNull( entry.get( "cn" ) );
+        assertNotNull( entry.get( "ou" ) );
+
+        Attribute modifiedAttr = entry.get( "ou" );
+
+        assertTrue( modifiedAttr.size() != 0 );
+
+        Set<String> expectedValues = new HashSet<String>();
+        expectedValues.add( "Big Company" );
+        expectedValues.add( "directory" );
+
+        for ( Value<?> value : modifiedAttr )
+        {
+            String valueStr = value.getString();
+
+            assertTrue( expectedValues.contains( valueStr ) );
+
+            expectedValues.remove( valueStr );
+        }
+
+        assertEquals( 0, expectedValues.size() );
+    }
+
+
+    /**
+     * Test the removing by modification of an existing attribute in an .
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testApplyModifyModificationRemoveAttribute() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+        entry.put( "cn", "test" );
+        entry.put( "ou", "apache", "acme corp" );
+
+        Attribute newOu = new DefaultAttribute( "ou" );
+
+        Modification modification = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, newOu );
+
+        AttributeUtils.applyModification( entry, modification );
+
+        assertEquals( 1, entry.size() );
+
+        assertNotNull( entry.get( "cn" ) );
+        assertNull( entry.get( "ou" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/BinaryValueAttributeTypeTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/BinaryValueAttributeTypeTest.java
new file mode 100644
index 0000000..a84ecfb
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/BinaryValueAttributeTypeTest.java
@@ -0,0 +1,678 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests that the BinaryValue class works properly as expected.
+ *
+ * Some notes while conducting tests:
+ *
+ * <ul>
+ *   <li>comparing values with different types - how does this behave</li>
+ *   <li>exposing access to at from value or to a comparator?</li>
+ * </ul>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BinaryValueAttributeTypeTest
+{
+    private LdapSyntax s;
+    private MutableAttributeType at;
+    private MutableMatchingRule mr;
+
+    private static final byte[] BYTES1 = new byte[]
+        { 0x01, 0x02, 0x03, 0x04 };
+    private static final byte[] BYTES2 = new byte[]
+        { ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83, ( byte ) 0x84 };
+
+
+    /**
+     * Initialize an AttributeType and the associated MatchingRule
+     * and Syntax
+     */
+    @Before
+    public void initAT()
+    {
+        s = EntryUtils.syntaxFactory( "1.1.1.1", false );
+        s.setSyntaxChecker( new OctetStringSyntaxChecker() );
+        mr = EntryUtils.matchingRuleFactory( "1.1.2.1" );
+        mr.setSyntax( s );
+
+        mr.setLdapComparator( new ByteArrayComparator( "1.1.1" ) );
+        mr.setNormalizer( new Normalizer( "1.1.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public Value<?> normalize( Value<?> value ) throws LdapException
+            {
+                if ( !value.isHumanReadable() )
+                {
+                    byte[] val = value.getBytes();
+                    // each byte will be changed to be > 0, and spaces will be trimmed
+                    byte[] newVal = new byte[val.length];
+                    int i = 0;
+
+                    for ( byte b : val )
+                    {
+                        newVal[i++] = ( byte ) ( b & 0x007F );
+                    }
+
+                    return new BinaryValue( Strings.trim( newVal ) );
+                }
+
+                throw new IllegalStateException( "expected byte[] to normalize" );
+            }
+
+
+            public String normalize( String value ) throws LdapException
+            {
+                throw new IllegalStateException( "expected byte[] to normalize" );
+            }
+        } );
+
+        at = new MutableAttributeType( "1.1.3.1" );
+        at.setEquality( mr );
+        at.setOrdering( mr );
+        at.setSubstring( mr );
+        at.setSyntax( s );
+    }
+
+
+    /**
+     * Serialize a BinaryValue
+     */
+    private ByteArrayOutputStream serializeValue( BinaryValue value ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+            value.writeExternal( oOut );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a BinaryValue
+     */
+    private BinaryValue deserializeValue( ByteArrayOutputStream out, AttributeType at ) throws IOException,
+        ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+
+            BinaryValue value = new BinaryValue( ( AttributeType ) null );
+            value.readExternal( oIn );
+
+            return value;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    /**
+     * Test the constructor with bad AttributeType
+     */
+    @Test
+    public void testBadConstructor()
+    {
+        // create a AT without no syntax
+        MutableAttributeType attribute = new MutableAttributeType( "1.1.3.1" );
+
+        try
+        {
+            new BinaryValue( attribute );
+            fail();
+        }
+        catch ( IllegalArgumentException ae )
+        {
+            // Expected...
+        }
+    }
+
+
+    /**
+     * Test the constructor with a null value
+     */
+    @Test
+    public void testServerBinaryValueNullValue() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+
+        BinaryValue value = new BinaryValue( attribute, null );
+
+        assertNull( value.getReference() );
+        assertTrue( value.isNull() );
+    }
+
+
+    /**
+     * Test the constructor with an empty value
+     */
+    @Test
+    public void testServerBinaryValueEmptyValue() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+
+        BinaryValue value = new BinaryValue( attribute, StringConstants.EMPTY_BYTES );
+
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, value.getReference() ) );
+        assertFalse( value.isNull() );
+    }
+
+
+    /**
+     * Test the constructor with a value
+     */
+    @Test
+    public void testServerBinaryValueNoValue()
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+        byte[] val = new byte[]
+            { 0x01 };
+        BinaryValue bv = new BinaryValue( attribute );
+
+        bv = new BinaryValue( val );
+        assertTrue( Arrays.equals( val, bv.getReference() ) );
+        assertFalse( bv.isNull() );
+        assertTrue( Arrays.equals( val, bv.getValue() ) );
+    }
+
+
+    /**
+     * Test the constructor with a value
+     */
+    @Test
+    public void testServerBinaryValue() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+        byte[] val = new byte[]
+            { 0x01 };
+        BinaryValue value = new BinaryValue( attribute, val );
+
+        assertTrue( Arrays.equals( val, value.getReference() ) );
+        assertFalse( value.isNull() );
+        assertTrue( Arrays.equals( val, value.getValue() ) );
+    }
+
+
+    /**
+     * Test the clone method
+     */
+    @Test
+    public void testClone() throws LdapException
+    {
+        AttributeType at1 = EntryUtils.getBytesAttributeType();
+        BinaryValue bv = new BinaryValue( at1, null );
+        BinaryValue bv1 = bv.clone();
+
+        assertEquals( bv, bv1 );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+
+        assertNotSame( bv, bv1 );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getBytes() ) );
+
+        bv = new BinaryValue( BYTES2 );
+        bv1 = bv.clone();
+
+        assertEquals( bv, bv1 );
+
+        bv.apply( at );
+
+        // Even if we didn't normalized sbv2, it should be equal to sbv,
+        // as if they have the same AT, and the same value, they are equal.
+        assertEquals( bv, bv1 );
+    }
+
+
+    /**
+     * Test the equals method
+     */
+    @Test
+    public void testEquals() throws LdapInvalidAttributeValueException
+    {
+        AttributeType at1 = EntryUtils.getBytesAttributeType();
+
+        BinaryValue value1 = new BinaryValue( at1, new byte[]
+            { 0x01, ( byte ) 0x02 } );
+        BinaryValue value2 = new BinaryValue( at1, new byte[]
+            { 0x01, ( byte ) 0x02 } );
+        BinaryValue value3 = new BinaryValue( at1, new byte[]
+            { 0x01, ( byte ) 0x82 } );
+        BinaryValue value4 = new BinaryValue( at1, new byte[]
+            { 0x01 } );
+        BinaryValue value5 = new BinaryValue( at1, null );
+        BinaryValue value6 = new BinaryValue( at, new byte[]
+            { 0x01, 0x02 } );
+        StringValue value7 = new StringValue( EntryUtils.getIA5StringAttributeType(),
+            "test" );
+
+        assertTrue( value1.equals( value1 ) );
+        assertTrue( value1.equals( value2 ) );
+        assertTrue( value1.equals( value3 ) );
+        assertFalse( value1.equals( value4 ) );
+        assertFalse( value1.equals( value5 ) );
+        assertFalse( value1.equals( "test" ) );
+        assertFalse( value1.equals( null ) );
+
+        assertFalse( value1.equals( value6 ) );
+        assertFalse( value1.equals( value7 ) );
+    }
+
+
+    /**
+     * Test the getNormValue method
+     */
+    @Test
+    public void testGetNormalizedValue() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+
+        BinaryValue value = new BinaryValue( attribute, null );
+        assertNull( value.getNormValue() );
+
+        value = new BinaryValue( attribute, StringConstants.EMPTY_BYTES );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, value.getNormValue() ) );
+
+        value = new BinaryValue( attribute, BYTES2 );
+        assertTrue( Arrays.equals( BYTES1, value.getNormValue() ) );
+    }
+
+
+    /**
+     * Test the getNormValue method
+     */
+    @Test
+    public void testGetNormalizedValueCopy() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+
+        BinaryValue value = new BinaryValue( attribute, null );
+        assertNull( value.getNormValue() );
+
+        value = new BinaryValue( attribute, StringConstants.EMPTY_BYTES );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, value.getNormValue() ) );
+
+        value = new BinaryValue( attribute, BYTES2 );
+        assertTrue( Arrays.equals( BYTES1, value.getNormValue() ) );
+    }
+
+
+    /**
+     * Test the getNormValue method
+     */
+    @Test
+    public void testGetNormalizedValueReference() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+
+        BinaryValue value = new BinaryValue( attribute, null );
+        assertNull( value.getNormReference() );
+
+        value = new BinaryValue( attribute, StringConstants.EMPTY_BYTES );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, value.getNormReference() ) );
+
+        value = new BinaryValue( attribute, BYTES2 );
+        assertTrue( Arrays.equals( BYTES1, value.getNormReference() ) );
+    }
+
+
+    /**
+     * Test the getAttributeType method
+     */
+    @Test
+    public void testgetAttributeType()
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+        BinaryValue sbv = new BinaryValue( attribute );
+
+        assertEquals( attribute, sbv.getAttributeType() );
+    }
+
+
+    /**
+     * Test the isValid method
+     * 
+     * The SyntaxChecker does not accept values longer than 5 chars.
+     */
+    @Test
+    public void testIsValid() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+
+        new BinaryValue( attribute, null );
+        new BinaryValue( attribute, StringConstants.EMPTY_BYTES );
+        new BinaryValue( attribute, new byte[]
+            { 0x01, 0x02 } );
+
+        try
+        {
+            new BinaryValue( attribute, new byte[]
+                { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } );
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException liave )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Tests to make sure the hashCode method is working properly.
+     * @throws Exception on errors
+     */
+    @Test
+    public void testHashCode() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+        BinaryValue v0 = new BinaryValue( attribute, new byte[]
+            { 0x01, 0x02 } );
+        BinaryValue v1 = new BinaryValue( attribute, new byte[]
+            { ( byte ) 0x81, ( byte ) 0x82 } );
+        BinaryValue v2 = new BinaryValue( attribute, new byte[]
+            { 0x01, 0x02 } );
+        assertEquals( v0.hashCode(), v1.hashCode() );
+        assertEquals( v1.hashCode(), v2.hashCode() );
+        assertEquals( v0.hashCode(), v2.hashCode() );
+        assertEquals( v0, v1 );
+        assertEquals( v0, v2 );
+        assertEquals( v1, v2 );
+
+        BinaryValue v3 = new BinaryValue( attribute, new byte[]
+            { 0x01, 0x03 } );
+        assertFalse( v3.equals( v0 ) );
+        assertFalse( v3.equals( v1 ) );
+        assertFalse( v3.equals( v2 ) );
+    }
+
+
+    /**
+     * Test the instanceOf method
+     */
+    @Test
+    public void testInstanceOf() throws LdapException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+        BinaryValue sbv = new BinaryValue( attribute );
+
+        assertTrue( sbv.isInstanceOf( attribute ) );
+
+        attribute = EntryUtils.getIA5StringAttributeType();
+
+        assertFalse( sbv.isInstanceOf( attribute ) );
+    }
+
+
+    /**
+     * Test the normalize method
+     */
+    @Test
+    public void testNormalize() throws LdapException
+    {
+        AttributeType attribute = EntryUtils.getBytesAttributeType();
+        BinaryValue bv = new BinaryValue( attribute );
+
+        bv.apply( at );
+        assertEquals( null, bv.getNormValue() );
+
+        bv = new BinaryValue( attribute, StringConstants.EMPTY_BYTES );
+        bv.apply( at );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getNormValue() ) );
+
+        bv = new BinaryValue( attribute, BYTES2 );
+        bv.apply( at );
+        assertTrue( Arrays.equals( BYTES1, bv.getNormValue() ) );
+    }
+
+
+    /**
+     * Test the compareTo method
+     */
+    @Test
+    public void testCompareTo() throws LdapInvalidAttributeValueException
+    {
+        AttributeType at1 = EntryUtils.getBytesAttributeType();
+        BinaryValue v0 = new BinaryValue( at1, BYTES1 );
+        BinaryValue v1 = new BinaryValue( at1, BYTES2 );
+
+        assertEquals( 0, v0.compareTo( v1 ) );
+        assertEquals( 0, v1.compareTo( v0 ) );
+
+        BinaryValue v2 = new BinaryValue( at1, null );
+
+        assertEquals( 1, v0.compareTo( v2 ) );
+        assertEquals( -1, v2.compareTo( v0 ) );
+    }
+
+
+    /**
+     * Test serialization of a BinaryValue which has a normalized value
+     */
+    @Test
+    public void testNormalizedBinaryValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] v1 = Strings.getBytesUtf8( "  Test   Test  " );
+        byte[] v1Norm = Strings.getBytesUtf8( "Test   Test" );
+
+        // First check with a value which will be normalized
+        BinaryValue sbv = new BinaryValue( at, v1 );
+
+        sbv.apply( at );
+        byte[] normalized = sbv.getNormReference();
+
+        assertTrue( Arrays.equals( v1Norm, normalized ) );
+        assertTrue( Arrays.equals( v1, sbv.getReference() ) );
+
+        BinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
+
+        assertEquals( sbv, sbvSer );
+    }
+
+
+    /**
+     * Test serialization of a BinaryValue which normalized value is the same
+     * than the value
+     */
+    @Test
+    public void testNormalizedBinarySameValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] v1 = Strings.getBytesUtf8( "Test   Test" );
+
+        // First check with a value which will be normalized
+        BinaryValue sbv = new BinaryValue( at, v1 );
+
+        BinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
+
+        assertEquals( sbv, sbvSer );
+    }
+
+
+    /**
+     * Test serialization of a BinaryValue which does not have a normalized value
+     */
+    @Test
+    public void testNoNormalizedBinaryValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] v1 = Strings.getBytesUtf8( "test" );
+        byte[] v1Norm = Strings.getBytesUtf8( "test" );
+
+        // First check with a value which will be normalized
+        BinaryValue sbv = new BinaryValue( at, v1 );
+
+        sbv.apply( at );
+        byte[] normalized = sbv.getNormReference();
+
+        assertTrue( Arrays.equals( v1Norm, normalized ) );
+        assertTrue( Arrays.equals( v1, sbv.getBytes() ) );
+
+        BinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
+
+        assertEquals( sbv, sbvSer );
+    }
+
+
+    /**
+     * Test serialization of a null BinaryValue
+     */
+    @Test
+    public void testNullBinaryValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        // First check with a value which will be normalized
+        BinaryValue sbv = new BinaryValue( at );
+
+        sbv.apply( at );
+        byte[] normalized = sbv.getNormReference();
+
+        assertEquals( null, normalized );
+        assertEquals( null, sbv.getValue() );
+
+        BinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
+
+        assertEquals( sbv, sbvSer );
+    }
+
+
+    /**
+     * Test serialization of an empty BinaryValue
+     */
+    @Test
+    public void testEmptyBinaryValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        // First check with a value which will be normalized
+        BinaryValue sbv = new BinaryValue( at, StringConstants.EMPTY_BYTES );
+
+        sbv.apply( at );
+        byte[] normalized = sbv.getNormReference();
+
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, normalized ) );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, sbv.getBytes() ) );
+
+        BinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
+
+        assertEquals( sbv, sbvSer );
+    }
+
+
+    /**
+     * Test serialization of a BinaryValue which is the same than the value
+     */
+    @Test
+    public void testSameNormalizedBinaryValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] v1 = Strings.getBytesUtf8( "test" );
+        byte[] v1Norm = Strings.getBytesUtf8( "test" );
+
+        // First check with a value which will be normalized
+        BinaryValue sbv = new BinaryValue( at, v1 );
+
+        sbv.apply( at );
+        byte[] normalized = sbv.getNormReference();
+
+        assertTrue( Arrays.equals( v1Norm, normalized ) );
+        assertTrue( Arrays.equals( v1, sbv.getBytes() ) );
+
+        BinaryValue sbvSer = deserializeValue( serializeValue( sbv ), at );
+
+        assertEquals( sbv, sbvSer );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/BinaryValueTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/BinaryValueTest.java
new file mode 100644
index 0000000..1356ed0
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/BinaryValueTest.java
@@ -0,0 +1,825 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * 
+ * Test the BinaryValue class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BinaryValueTest
+{
+    private static final byte[] BYTES1 = new byte[]
+        { 0x01, 0x02, 0x03, 0x04 };
+    private static final byte[] BYTES2 = new byte[]
+        { ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83, ( byte ) 0x84 };
+    private static final byte[] INVALID_BYTES = new byte[]
+        { 0x01, 0x02, 0x03, 0x04, 0x05 };
+    private static final byte[] BYTES_MOD = new byte[]
+        { 0x11, 0x02, 0x03, 0x04 };
+    private LdapSyntax s;
+    private MutableAttributeType at;
+    private MutableMatchingRule mr;
+
+
+    /**
+     * Initialize an AttributeType and the associated MatchingRule
+     * and Syntax
+     */
+    @Before
+    public void initAT()
+    {
+        s = EntryUtils.syntaxFactory( "1.1.1.1", false );
+        s.setSyntaxChecker( new OctetStringSyntaxChecker() );
+        mr = EntryUtils.matchingRuleFactory( "1.1.2.1" );
+        mr.setSyntax( s );
+
+        mr.setLdapComparator( new ByteArrayComparator( "1.1.1" ) );
+        mr.setNormalizer( new Normalizer( "1.1.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public Value<?> normalize( Value<?> value ) throws LdapException
+            {
+                if ( !value.isHumanReadable() )
+                {
+                    byte[] val = value.getBytes();
+                    // each byte will be changed to be > 0, and spaces will be trimmed
+                    byte[] newVal = new byte[val.length];
+                    int i = 0;
+
+                    for ( byte b : val )
+                    {
+                        newVal[i++] = ( byte ) ( b & 0x007F );
+                    }
+
+                    return new BinaryValue( Strings.trim( newVal ) );
+                }
+
+                throw new IllegalStateException( "expected byte[] to normalize" );
+            }
+
+
+            public String normalize( String value ) throws LdapException
+            {
+                throw new IllegalStateException( "expected byte[] to normalize" );
+            }
+        } );
+
+        at = new MutableAttributeType( "1.1.3.1" );
+        at.setEquality( mr );
+        at.setOrdering( mr );
+        at.setSubstring( mr );
+        at.setSyntax( s );
+    }
+
+    private static final SyntaxChecker BINARY_CHECKER = new SyntaxChecker( "1.1.1" )
+    {
+        public static final long serialVersionUID = 1L;
+
+
+        public boolean isValidSyntax( Object value )
+        {
+            if ( value == null )
+            {
+                return true;
+            }
+
+            return ( ( byte[] ) value ).length < 5;
+        }
+    };
+
+
+    /**
+     * Serialize a BinaryValue
+     */
+    private ByteArrayOutputStream serializeValue( BinaryValue value ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+            value.writeExternal( oOut );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a BinaryValue
+     */
+    private BinaryValue deserializeValue( AttributeType at, ByteArrayOutputStream out ) throws IOException,
+        ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+
+            BinaryValue value = new BinaryValue( at );
+            value.readExternal( oIn );
+
+            return value;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    @Test
+    public void testHashCode()
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        assertEquals( 0, bv.hashCode() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        int h = Arrays.hashCode( StringConstants.EMPTY_BYTES );
+        assertEquals( h, bv.hashCode() );
+
+        h = Arrays.hashCode( BYTES1 );
+        bv = new BinaryValue( BYTES1 );
+        assertEquals( h, bv.hashCode() );
+    }
+
+
+    @Test
+    public void testBinaryValueNull() throws LdapException
+    {
+        BinaryValue cbv = new BinaryValue( ( byte[] ) null );
+
+        assertNull( cbv.getValue() );
+        assertFalse( cbv.isSchemaAware() );
+        assertTrue( cbv.isValid( BINARY_CHECKER ) );
+        assertTrue( cbv.isNull() );
+        assertNull( cbv.getNormValue() );
+    }
+
+
+    @Test
+    public void testBinaryValueEmpty() throws LdapException
+    {
+        BinaryValue cbv = new BinaryValue( StringConstants.EMPTY_BYTES );
+
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, cbv.getBytes() ) );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, cbv.getValue() ) );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, cbv.getReference() ) );
+        assertFalse( cbv.isSchemaAware() );
+        assertTrue( cbv.isValid( BINARY_CHECKER ) );
+        assertFalse( cbv.isNull() );
+        assertNotNull( cbv.getNormValue() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, cbv.getNormValue() ) );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, cbv.getNormReference() ) );
+    }
+
+
+    @Test
+    public void testBinaryValue() throws LdapException
+    {
+        BinaryValue cbv = new BinaryValue( BYTES1 );
+
+        assertTrue( Arrays.equals( BYTES1, cbv.getBytes() ) );
+        assertTrue( Arrays.equals( BYTES1, cbv.getValue() ) );
+        assertTrue( Arrays.equals( BYTES1, cbv.getReference() ) );
+        assertFalse( cbv.isSchemaAware() );
+        assertTrue( cbv.isValid( BINARY_CHECKER ) );
+        assertFalse( cbv.isNull() );
+        assertNotNull( cbv.getNormValue() );
+        assertTrue( Arrays.equals( BYTES1, cbv.getNormValue() ) );
+    }
+
+
+    @Test
+    public void testSetByteArray() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        bv = new BinaryValue( BYTES1 );
+
+        assertTrue( Arrays.equals( BYTES1, bv.getBytes() ) );
+        assertTrue( Arrays.equals( BYTES1, bv.getValue() ) );
+        assertTrue( Arrays.equals( BYTES1, bv.getReference() ) );
+        assertFalse( bv.isSchemaAware() );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+        assertFalse( bv.isNull() );
+        assertNotNull( bv.getNormValue() );
+        assertTrue( Arrays.equals( BYTES1, bv.getNormValue() ) );
+    }
+
+
+    @Test
+    public void testGetNormalizedValueCopy() throws LdapException
+    {
+        BinaryValue cbv = new BinaryValue( BYTES2 );
+
+        assertTrue( Arrays.equals( BYTES2, cbv.getBytes() ) );
+        assertTrue( Arrays.equals( BYTES2, cbv.getValue() ) );
+        assertTrue( Arrays.equals( BYTES2, cbv.getReference() ) );
+        assertFalse( cbv.isSchemaAware() );
+        assertTrue( cbv.isValid( BINARY_CHECKER ) );
+        assertFalse( cbv.isNull() );
+        assertNotNull( cbv.getNormValue() );
+        assertTrue( Arrays.equals( BYTES2, cbv.getNormValue() ) );
+
+        cbv.apply( at );
+        byte[] copy = cbv.getNormValue();
+        assertTrue( Arrays.equals( BYTES1, copy ) );
+        cbv.getNormReference()[0] = 0x11;
+        assertTrue( Arrays.equals( BYTES1, copy ) );
+    }
+
+
+    @Test
+    public void testNormalizeNormalizer() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        bv.apply( at );
+        assertTrue( bv.isSchemaAware() );
+        assertEquals( null, bv.getNormValue() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        bv.apply( at );
+        assertTrue( bv.isSchemaAware() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getBytes() ) );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getNormValue() ) );
+
+        bv = new BinaryValue( BYTES1 );
+        bv.apply( at );
+        assertTrue( bv.isSchemaAware() );
+        assertTrue( Arrays.equals( BYTES1, bv.getBytes() ) );
+        assertTrue( Arrays.equals( BYTES1, bv.getNormValue() ) );
+
+        bv = new BinaryValue( BYTES2 );
+        bv.apply( at );
+        assertTrue( bv.isSchemaAware() );
+        assertTrue( Arrays.equals( BYTES2, bv.getBytes() ) );
+        assertTrue( Arrays.equals( BYTES1, bv.getNormValue() ) );
+    }
+
+
+    @Test
+    public void testCompareToValueOfbyte() throws LdapException
+    {
+        BinaryValue bv1 = new BinaryValue( ( byte[] ) null );
+        BinaryValue bv2 = new BinaryValue( ( byte[] ) null );
+
+        assertEquals( 0, bv1.compareTo( bv2 ) );
+
+        bv1 = new BinaryValue( BYTES1 );
+        assertEquals( 1, bv1.compareTo( bv2 ) );
+
+        bv2 = new BinaryValue( BYTES2 );
+        assertEquals( 1, bv1.compareTo( bv2 ) );
+
+        bv2.apply( at );
+        assertEquals( 0, bv1.compareTo( bv2 ) );
+
+        bv1 = new BinaryValue( BYTES2 );
+        assertEquals( -1, bv1.compareTo( bv2 ) );
+    }
+
+
+    @Test
+    public void testEquals() throws LdapException
+    {
+        BinaryValue bv1 = new BinaryValue( ( byte[] ) null );
+        BinaryValue bv2 = new BinaryValue( ( byte[] ) null );
+
+        assertEquals( bv1, bv2 );
+
+        bv1 = new BinaryValue( BYTES1 );
+        assertNotSame( bv1, bv2 );
+
+        bv2 = new BinaryValue( BYTES2 );
+        assertNotSame( bv1, bv2 );
+
+        bv2.apply( at );
+        assertEquals( bv1, bv2 );
+
+        bv1 = new BinaryValue( BYTES2 );
+        assertNotSame( bv1, bv2 );
+    }
+
+
+    @Test
+    public void testClone()
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        BinaryValue copy = bv.clone();
+
+        assertEquals( bv, copy );
+
+        bv = new BinaryValue( BYTES1 );
+        assertNotSame( bv, copy );
+
+        copy = bv.clone();
+        assertEquals( bv, copy );
+
+        bv.getReference()[0] = 0x11;
+
+        assertTrue( Arrays.equals( BYTES_MOD, bv.getBytes() ) );
+        assertTrue( Arrays.equals( BYTES1, copy.getBytes() ) );
+    }
+
+
+    @Test
+    public void testGetCopy()
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertNull( bv.getValue() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertNotNull( bv.getValue() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getValue() ) );
+
+        bv = new BinaryValue( BYTES1 );
+        byte[] copy = bv.getValue();
+
+        assertTrue( Arrays.equals( BYTES1, copy ) );
+
+        bv.getReference()[0] = 0x11;
+        assertTrue( Arrays.equals( BYTES1, copy ) );
+        assertTrue( Arrays.equals( BYTES_MOD, bv.getBytes() ) );
+    }
+
+
+    @Test
+    public void testCompareTo() throws LdapException
+    {
+        BinaryValue bv1 = new BinaryValue( ( byte[] ) null );
+        BinaryValue bv2 = new BinaryValue( ( byte[] ) null );
+
+        assertEquals( 0, bv1.compareTo( bv2 ) );
+
+        bv1 = new BinaryValue( BYTES1 );
+        assertEquals( 1, bv1.compareTo( bv2 ) );
+        assertEquals( -1, bv2.compareTo( bv1 ) );
+
+        bv2 = new BinaryValue( BYTES1 );
+        assertEquals( 0, bv1.compareTo( bv2 ) );
+
+        // Now check that the equals method works on normalized values.
+        bv1 = new BinaryValue( BYTES2 );
+        bv2 = new BinaryValue( BYTES1 );
+        bv1.apply( at );
+        assertEquals( 0, bv1.compareTo( bv2 ) );
+
+        bv1 = new BinaryValue( BYTES1 );
+        bv2 = new BinaryValue( BYTES2 );
+        assertEquals( 1, bv1.compareTo( bv2 ) );
+
+        bv1 = new BinaryValue( BYTES2 );
+        bv2 = new BinaryValue( BYTES1 );
+        assertEquals( -1, bv1.compareTo( bv2 ) );
+    }
+
+
+    @Test
+    public void testToString()
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertEquals( "null", bv.toString() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertEquals( "", bv.toString() );
+
+        bv = new BinaryValue( BYTES1 );
+        assertEquals( "0x01 0x02 0x03 0x04 ", bv.toString() );
+    }
+
+
+    @Test
+    public void testGetReference()
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertNull( bv.getReference() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertNotNull( bv.getReference() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getReference() ) );
+
+        bv = new BinaryValue( BYTES1 );
+        byte[] reference = bv.getReference();
+
+        assertTrue( Arrays.equals( BYTES1, reference ) );
+
+        bv.getReference()[0] = 0x11;
+        assertTrue( Arrays.equals( BYTES_MOD, reference ) );
+        assertTrue( Arrays.equals( BYTES_MOD, bv.getBytes() ) );
+    }
+
+
+    @Test
+    public void testGet()
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertNull( bv.getValue() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertNotNull( bv.getValue() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getBytes() ) );
+
+        bv = new BinaryValue( BYTES1 );
+        byte[] get = bv.getBytes();
+
+        assertTrue( Arrays.equals( BYTES1, get ) );
+
+        bv.getReference()[0] = 0x11;
+        assertTrue( Arrays.equals( BYTES1, get ) );
+        assertTrue( Arrays.equals( BYTES_MOD, bv.getBytes() ) );
+    }
+
+
+    @Test
+    public void testGetNormalizedValue() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertFalse( bv.isSchemaAware() );
+
+        bv.apply( at );
+        byte[] value = bv.getNormValue();
+        assertNull( value );
+        assertTrue( bv.isSchemaAware() );
+
+        bv = new BinaryValue( BYTES2 );
+        bv.apply( at );
+        value = bv.getNormValue();
+        assertTrue( Arrays.equals( BYTES1, value ) );
+        bv.getNormReference()[0] = 0x11;
+        assertFalse( Arrays.equals( BYTES_MOD, value ) );
+    }
+
+
+    @Test
+    public void testGetNormalizedValueReference() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertFalse( bv.isSchemaAware() );
+
+        bv.apply( at );
+        byte[] value = bv.getNormReference();
+        assertNull( value );
+        assertTrue( bv.isSchemaAware() );
+
+        bv = new BinaryValue( BYTES2 );
+        bv.apply( at );
+        value = bv.getNormReference();
+        assertTrue( Arrays.equals( BYTES1, value ) );
+        bv.getNormReference()[0] = 0x11;
+        assertTrue( Arrays.equals( BYTES_MOD, value ) );
+    }
+
+
+    @Test
+    public void testIsNull()
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertTrue( bv.isNull() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertFalse( bv.isNull() );
+
+        bv = new BinaryValue( BYTES1 );
+        assertFalse( bv.isNull() );
+    }
+
+
+    @Test
+    public void testIsValid() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+
+        bv = new BinaryValue( BYTES1 );
+        assertFalse( bv.isNull() );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+
+        bv = new BinaryValue( INVALID_BYTES );
+        assertFalse( bv.isNull() );
+        assertFalse( bv.isValid( BINARY_CHECKER ) );
+    }
+
+
+    @Test
+    public void testIsValidSyntaxChecker() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+
+        bv = new BinaryValue( BYTES1 );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+
+        bv = new BinaryValue( INVALID_BYTES );
+        assertFalse( bv.isValid( BINARY_CHECKER ) );
+    }
+
+
+    @Test
+    public void testNormalize() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        bv.apply( at );
+        assertTrue( bv.isSchemaAware() );
+        assertEquals( null, bv.getNormValue() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        bv.apply( at );
+        assertTrue( bv.isSchemaAware() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getNormValue() ) );
+
+        bv = new BinaryValue( BYTES2 );
+        bv.apply( at );
+        assertTrue( bv.isSchemaAware() );
+        assertTrue( Arrays.equals( BYTES2, bv.getValue() ) );
+        assertTrue( Arrays.equals( BYTES1, bv.getNormValue() ) );
+    }
+
+
+    @Test
+    public void testSet() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertNull( bv.getValue() );
+        assertFalse( bv.isSchemaAware() );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+        assertTrue( bv.isNull() );
+
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        assertNotNull( bv.getValue() );
+        assertTrue( Arrays.equals( StringConstants.EMPTY_BYTES, bv.getBytes() ) );
+        assertFalse( bv.isSchemaAware() );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+        assertFalse( bv.isNull() );
+
+        bv = new BinaryValue( BYTES1 );
+        assertNotNull( bv.getValue() );
+        assertTrue( Arrays.equals( BYTES1, bv.getBytes() ) );
+        assertFalse( bv.isSchemaAware() );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+        assertFalse( bv.isNull() );
+    }
+
+
+    @Test
+    public void testIsNormalized() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        assertFalse( bv.isSchemaAware() );
+
+        bv = new BinaryValue( BYTES2 );
+        assertFalse( bv.isSchemaAware() );
+
+        bv.apply( at );
+
+        assertTrue( Arrays.equals( BYTES1, bv.getNormValue() ) );
+        assertTrue( bv.isSchemaAware() );
+
+        bv = new BinaryValue( BYTES2 );
+        assertFalse( bv.isSchemaAware() );
+
+        bv = new BinaryValue( BYTES_MOD );
+        assertFalse( bv.isSchemaAware() );
+    }
+
+
+    @Test
+    public void testSetNormalized() throws LdapException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+
+        assertFalse( bv.isSchemaAware() );
+
+        bv = new BinaryValue( BYTES2 );
+        assertFalse( bv.isSchemaAware() );
+
+        bv.apply( at );
+
+        assertTrue( Arrays.equals( BYTES1, bv.getNormValue() ) );
+        assertTrue( bv.isSchemaAware() );
+
+        assertTrue( Arrays.equals( BYTES2, bv.getValue() ) );
+    }
+
+
+    /**
+     * Test the serialization of a CBV with a value and a normalized value
+     */
+    @Test
+    public void testSerializeStandard() throws LdapException, IOException, ClassNotFoundException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        bv = new BinaryValue( BYTES2 );
+        bv.apply( at );
+        assertTrue( bv.isValid( BINARY_CHECKER ) );
+
+        BinaryValue cbvSer = deserializeValue( at, serializeValue( bv ) );
+        assertNotSame( bv, cbvSer );
+        assertTrue( Arrays.equals( bv.getReference(), cbvSer.getReference() ) );
+        assertTrue( Arrays.equals( bv.getNormReference(), cbvSer.getNormReference() ) );
+        assertTrue( cbvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CBV with a value and no normalized value
+     */
+    @Test
+    public void testSerializeNotNormalized() throws LdapException, IOException, ClassNotFoundException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        bv = new BinaryValue( BYTES2 );
+        bv.isValid( BINARY_CHECKER );
+
+        BinaryValue cbvSer = deserializeValue( null, serializeValue( bv ) );
+        assertNotSame( bv, cbvSer );
+        assertTrue( Arrays.equals( bv.getReference(), cbvSer.getReference() ) );
+        assertTrue( Arrays.equals( bv.getReference(), cbvSer.getNormReference() ) );
+        assertFalse( cbvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CBV with a value and an empty normalized value
+     */
+    @Test
+    public void testSerializeEmptyNormalized() throws LdapException, IOException, ClassNotFoundException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        bv = new BinaryValue( BYTES2 );
+        bv.isValid( BINARY_CHECKER );
+        bv.apply( at );
+
+        BinaryValue cbvSer = deserializeValue( at, serializeValue( bv ) );
+        assertNotSame( bv, cbvSer );
+        assertTrue( Arrays.equals( bv.getReference(), cbvSer.getReference() ) );
+        assertTrue( Arrays.equals( bv.getNormReference(), cbvSer.getNormReference() ) );
+        assertTrue( cbvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CBV with a null value
+     */
+    @Test
+    public void testSerializeNullValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        bv = new BinaryValue( ( byte[] ) null );
+        bv.isValid( BINARY_CHECKER );
+        bv.apply( at );
+
+        BinaryValue cbvSer = deserializeValue( at, serializeValue( bv ) );
+        assertNotSame( bv, cbvSer );
+        assertTrue( Arrays.equals( bv.getReference(), cbvSer.getReference() ) );
+        assertTrue( Arrays.equals( bv.getNormReference(), cbvSer.getNormReference() ) );
+        assertTrue( cbvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CBV with an empty value
+     */
+    @Test
+    public void testSerializeEmptyValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        bv.isValid( BINARY_CHECKER );
+        bv.apply( at );
+
+        BinaryValue cbvSer = deserializeValue( at, serializeValue( bv ) );
+        assertNotSame( bv, cbvSer );
+        assertTrue( Arrays.equals( bv.getReference(), cbvSer.getReference() ) );
+        assertTrue( Arrays.equals( bv.getNormReference(), cbvSer.getNormReference() ) );
+        assertTrue( cbvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CBV with an empty value not normalized
+     */
+    @Test
+    public void testSerializeEmptyValueNotNormalized() throws LdapException, IOException, ClassNotFoundException
+    {
+        BinaryValue bv = new BinaryValue( ( byte[] ) null );
+        bv = new BinaryValue( StringConstants.EMPTY_BYTES );
+        bv.isValid( BINARY_CHECKER );
+
+        BinaryValue cbvSer = deserializeValue( null, serializeValue( bv ) );
+        assertNotSame( bv, cbvSer );
+        assertTrue( Arrays.equals( bv.getReference(), cbvSer.getReference() ) );
+        assertTrue( Arrays.equals( bv.getNormReference(), cbvSer.getNormReference() ) );
+        assertFalse( cbvSer.isSchemaAware() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntrySerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntrySerializationTest.java
new file mode 100644
index 0000000..c8c35b7
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntrySerializationTest.java
@@ -0,0 +1,150 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Entry Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class EntrySerializationTest
+{
+    @Test
+    public void testEntryFullSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry(
+            "dc=example, dc=com",
+            "ObjectClass: top",
+            "ObjectClass: domain",
+            "dc: example",
+            "l: test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry();
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertTrue( entry2.contains( "ObjectClass", "top", "domain" ) );
+    }
+
+
+    @Test
+    public void testEntryNoDnSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry(
+            "",
+            "ObjectClass: top",
+            "ObjectClass: domain",
+            "dc: example",
+            "l: test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry();
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertTrue( entry2.contains( "ObjectClass", "top", "domain" ) );
+        assertEquals( "", entry2.getDn().toString() );
+    }
+
+
+    @Test
+    public void testEntryNoAttributesSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry( "dc=example, dc=com" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry();
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertEquals( 0, entry2.size() );
+    }
+
+
+    @Test
+    public void testEntryNoAttributesNoDnSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Entry entry1 = new DefaultEntry( "" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        entry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Entry entry2 = new DefaultEntry();
+        entry2.readExternal( in );
+
+        assertEquals( entry1, entry2 );
+        assertEquals( 0, entry2.size() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntryTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntryTest.java
new file mode 100644
index 0000000..cb0d13d
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntryTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+
+
+/**
+ * Test the Entry class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EntryTest
+{
+    @Test
+    public void testEntryCreation() throws LdapException
+    {
+        Entry entry = new DefaultEntry();
+
+        entry.setDn( "dc=example, dc=com" );
+        entry.add( "objectClass", "top", "domain" );
+        entry.add( "dc", "example" );
+
+        assertNotNull( entry.getDn() );
+        assertEquals( new Dn( "dc=example, dc=com" ), entry.getDn() );
+        assertNotNull( entry.getAttributes() );
+        assertEquals( 2, entry.size() );
+        assertTrue( entry.contains( "objectClass", "top", "domain" ) );
+        assertTrue( entry.contains( "dc", "example" ) );
+        assertFalse( entry.isSchemaAware() );
+
+        Entry entry2 = new DefaultEntry( "dc=example, dc=com" );
+        entry2.add( "objectClass", "top", "domain" );
+        entry2.add( "dc", "example" );
+
+        assertEquals( entry, entry2 );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntryUtils.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntryUtils.java
new file mode 100644
index 0000000..d3f3ac7
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/EntryUtils.java
@@ -0,0 +1,289 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * Some common declaration used by the serverEntry tests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EntryUtils
+{
+    /**
+     * A local Syntax class for tests
+     */
+    static class AT extends MutableAttributeType
+    {
+        private static final long serialVersionUID = 0L;
+
+
+        protected AT( String oid )
+        {
+            super( oid );
+        }
+    }
+
+
+    public static MutableMatchingRule matchingRuleFactory( String oid )
+    {
+        MutableMatchingRule matchingRule = new MutableMatchingRule( oid );
+
+        return matchingRule;
+    }
+
+    /**
+     * A local MatchingRule class for tests
+     */
+    static class MR extends MutableMatchingRule
+    {
+        public static final long serialVersionUID = 1L;
+
+
+        protected MR( String oid )
+        {
+            super( oid );
+        }
+    }
+
+
+    /**
+     * A local Syntax class used for the tests
+     */
+    public static LdapSyntax syntaxFactory( String oid, boolean humanReadable )
+    {
+        LdapSyntax ldapSyntax = new LdapSyntax( oid );
+
+        ldapSyntax.setHumanReadable( humanReadable );
+
+        return ldapSyntax;
+    }
+
+    static class S extends LdapSyntax
+    {
+        public static final long serialVersionUID = 1L;
+
+
+        public S( String oid, boolean humanReadable )
+        {
+            super( oid, "", humanReadable );
+        }
+    }
+
+
+    /* no protection*/static AttributeType getCaseIgnoringAttributeNoNumbersType()
+    {
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.3.1" );
+        LdapSyntax syntax = new LdapSyntax( "1.1.1.1", "", true );
+
+        syntax.setSyntaxChecker( new SyntaxChecker( "1.1.2.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public boolean isValidSyntax( Object value )
+            {
+                if ( value == null )
+                {
+                    return true;
+                }
+
+                if ( !( value instanceof String ) )
+                {
+                    return false;
+                }
+
+                String strval = ( String ) value;
+
+                for ( char c : strval.toCharArray() )
+                {
+                    if ( Character.isDigit( c ) )
+                    {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        } );
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.2.1" );
+        matchingRule.setSyntax( syntax );
+
+        matchingRule.setLdapComparator( new LdapComparator<String>( matchingRule.getOid() )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public int compare( String o1, String o2 )
+            {
+                return ( o1 == null ?
+                    ( o2 == null ? 0 : -1 ) :
+                    ( o2 == null ? 1 : o1.compareTo( o2 ) ) );
+            }
+        } );
+
+        Normalizer normalizer = new Normalizer( "1.1.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public Value<?> normalize( Value<?> value ) throws LdapException
+            {
+                if ( value.isHumanReadable() )
+                {
+                    return new StringValue( Strings.toLowerCase( value.getString() ) );
+                }
+
+                throw new IllegalStateException( I18n.err( I18n.ERR_04474 ) );
+            }
+
+
+            public String normalize( String value ) throws LdapException
+            {
+                return Strings.toLowerCase( value );
+            }
+        };
+
+        matchingRule.setNormalizer( normalizer );
+
+        attributeType.setEquality( matchingRule );
+        attributeType.setSyntax( syntax );
+
+        return attributeType;
+    }
+
+
+    /* no protection*/static AttributeType getIA5StringAttributeType()
+    {
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1" );
+        attributeType.addName( "1.1" );
+        LdapSyntax syntax = new LdapSyntax( "1.1.1", "", true );
+
+        syntax.setSyntaxChecker( new SyntaxChecker( "1.1.2" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public boolean isValidSyntax( Object value )
+            {
+                return ( ( String ) value == null ) || ( ( ( String ) value ).length() < 7 );
+            }
+        } );
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.2" );
+        matchingRule.setSyntax( syntax );
+
+        matchingRule.setLdapComparator( new LdapComparator<String>( matchingRule.getOid() )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public int compare( String o1, String o2 )
+            {
+                return ( ( o1 == null ) ?
+                    ( o2 == null ? 0 : -1 ) :
+                    ( o2 == null ? 1 : o1.compareTo( o2 ) ) );
+            }
+        } );
+
+        matchingRule.setNormalizer( new DeepTrimToLowerNormalizer( matchingRule.getOid() ) );
+
+        attributeType.setEquality( matchingRule );
+        attributeType.setSyntax( syntax );
+
+        return attributeType;
+    }
+
+
+    /* No protection */static AttributeType getBytesAttributeType()
+    {
+        MutableAttributeType attributeType = new MutableAttributeType( "1.2" );
+        LdapSyntax syntax = new LdapSyntax( "1.2.1", "", false );
+
+        syntax.setSyntaxChecker( new SyntaxChecker( "1.2.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public boolean isValidSyntax( Object value )
+            {
+                return ( value == null ) || ( ( ( byte[] ) value ).length < 5 );
+            }
+        } );
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.2.2" );
+        matchingRule.setSyntax( syntax );
+
+        matchingRule.setLdapComparator( new ByteArrayComparator( "1.2.2" ) );
+
+        matchingRule.setNormalizer( new Normalizer( "1.1.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public Value<?> normalize( Value<?> value ) throws LdapException
+            {
+                if ( !value.isHumanReadable() )
+                {
+                    byte[] val = value.getBytes();
+
+                    // each byte will be changed to be > 0, and spaces will be trimmed
+                    byte[] newVal = new byte[val.length];
+
+                    int i = 0;
+
+                    for ( byte b : val )
+                    {
+                        newVal[i++] = ( byte ) ( b & 0x007F );
+                    }
+
+                    return new BinaryValue( Strings.trim( newVal ) );
+                }
+
+                throw new IllegalStateException( I18n.err( I18n.ERR_04475 ) );
+            }
+
+
+            public String normalize( String value ) throws LdapException
+            {
+                throw new IllegalStateException( I18n.err( I18n.ERR_04475 ) );
+            }
+        } );
+
+        attributeType.setEquality( matchingRule );
+        attributeType.setSyntax( syntax );
+
+        return attributeType;
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/ModificationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/ModificationTest.java
new file mode 100644
index 0000000..40c1419
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/ModificationTest.java
@@ -0,0 +1,205 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the DefaultModification class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModificationTest
+{
+    /**
+     * Serialize a DefaultModification
+     */
+    private ByteArrayOutputStream serializeValue( Modification modification ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+            modification.writeExternal( oOut );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a DefaultModification
+     */
+    private Modification deserializeValue( ByteArrayOutputStream out ) throws IOException, ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            Modification modification = new DefaultModification();
+
+            oIn = new ObjectInputStream( in );
+
+            modification.readExternal( oIn );
+
+            return modification;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    @Test
+    public void testCreateServerModification() throws LdapException
+    {
+        Attribute attribute = new DefaultAttribute( "cn" );
+        attribute.add( "test1", "test2" );
+
+        Modification mod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attribute );
+        Modification clone = mod.clone();
+
+        attribute.remove( "test2" );
+
+        Attribute clonedAttribute = clone.getAttribute();
+
+        assertEquals( 1, mod.getAttribute().size() );
+        assertTrue( mod.getAttribute().contains( "test1" ) );
+
+        assertEquals( 2, clonedAttribute.size() );
+        assertTrue( clone.getAttribute().contains( "test1" ) );
+        assertTrue( clone.getAttribute().contains( "test2" ) );
+    }
+
+
+    @Test
+    public void testSerializationModificationADD() throws ClassNotFoundException, IOException, LdapException
+    {
+        Attribute attribute = new DefaultAttribute( "cn" );
+        attribute.add( "test1", "test2" );
+
+        DefaultModification mod = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attribute );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+
+
+    @Test
+    public void testSerializationModificationREPLACE() throws ClassNotFoundException, IOException, LdapException
+    {
+        Attribute attribute = new DefaultAttribute( "cn" );
+        attribute.add( "test1", "test2" );
+
+        DefaultModification mod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+
+
+    @Test
+    public void testSerializationModificationREMOVE() throws ClassNotFoundException, IOException, LdapException
+    {
+        Attribute attribute = new DefaultAttribute( "cn" );
+        attribute.add( "test1", "test2" );
+
+        DefaultModification mod = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attribute );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+
+
+    @Test
+    public void testSerializationModificationNoAttribute() throws ClassNotFoundException, IOException
+    {
+        DefaultModification mod = new DefaultModification();
+
+        mod.setOperation( ModificationOperation.ADD_ATTRIBUTE );
+
+        Modification modSer = deserializeValue( serializeValue( mod ) );
+
+        assertEquals( mod, modSer );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/StringValueAttributeTypeTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/StringValueAttributeTypeTest.java
new file mode 100644
index 0000000..89a24cf
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/StringValueAttributeTypeTest.java
@@ -0,0 +1,768 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.comparators.StringComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests that the StringValue class works properly as expected.
+ *
+ * Some notes while conducting tests:
+ *
+ * <ul>
+ *   <li>comparing values with different types - how does this behave</li>
+ *   <li>exposing access to at from value or to a comparator?</li>
+ * </ul>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class StringValueAttributeTypeTest
+{
+    private EntryUtils.S s;
+    private EntryUtils.AT at;
+    private EntryUtils.MR mr;
+
+
+    /**
+     * Initialize an AttributeType and the associated MatchingRule 
+     * and Syntax
+     */
+    @Before
+    public void initAT()
+    {
+        s = new EntryUtils.S( "1.1.1.1", true );
+        s.setSyntaxChecker( new OctetStringSyntaxChecker() );
+        mr = new EntryUtils.MR( "1.1.2.1" );
+        mr.setSyntax( s );
+        mr.setLdapComparator( new StringComparator( "1.1.2.1" ) );
+        mr.setNormalizer( new DeepTrimToLowerNormalizer( "1.1.2.1" ) );
+        at = new EntryUtils.AT( "1.1.3.1" );
+        at.setEquality( mr );
+        at.setOrdering( mr );
+        at.setSubstring( mr );
+        at.setSyntax( s );
+    }
+
+
+    /**
+     * Serialize a StringValue
+     */
+    private ByteArrayOutputStream serializeValue( StringValue value ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try
+        {
+            oOut = new ObjectOutputStream( out );
+            value.writeExternal( oOut );
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oOut != null )
+                {
+                    oOut.flush();
+                    oOut.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a StringValue
+     */
+    private StringValue deserializeValue( ByteArrayOutputStream out ) throws IOException, ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+
+            StringValue value = new StringValue( at );
+
+            value.readExternal( oIn );
+
+            return value;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    /**
+     * Test the constructor with a null value
+     */
+    @Test
+    public void testClientStringValueNullValue() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getIA5StringAttributeType();
+
+        StringValue value = new StringValue( attribute, null );
+
+        assertNull( value.getValue() );
+        assertTrue( value.isNull() );
+    }
+
+
+    /**
+     * Test the getNormValue method
+     */
+    @Test
+    public void testGetNormalizedValue() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getIA5StringAttributeType();
+
+        StringValue sv = new StringValue( attribute, null );
+
+        assertTrue( sv.isSchemaAware() );
+        assertNull( sv.getNormValue() );
+        assertTrue( sv.isSchemaAware() );
+
+        sv = new StringValue( attribute, "" );
+        assertTrue( sv.isSchemaAware() );
+        assertEquals( "", sv.getNormValue() );
+        assertTrue( sv.isSchemaAware() );
+
+        sv = new StringValue( attribute, "TEST" );
+        assertTrue( sv.isSchemaAware() );
+        assertEquals( "test", sv.getNormValue() );
+    }
+
+
+    /**
+     * Test the isValid method
+     * 
+     * The SyntaxChecker does not accept values longer than 5 chars.
+     */
+    @Test
+    public void testIsValid() throws LdapInvalidAttributeValueException
+    {
+        AttributeType attribute = EntryUtils.getIA5StringAttributeType();
+
+        new StringValue( attribute, null );
+        new StringValue( attribute, "" );
+        new StringValue( attribute, "TEST" );
+
+        try
+        {
+            new StringValue( attribute, "testlong" );
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException liave )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test the normalize method
+     */
+    @Test
+    public void testApply() throws LdapException
+    {
+        AttributeType attribute = EntryUtils.getIA5StringAttributeType();
+        StringValue sv = new StringValue( attribute );
+
+        sv.apply( at );
+        assertEquals( null, sv.getNormValue() );
+
+        sv = new StringValue( attribute, "" );
+        sv.apply( at );
+        assertEquals( "", sv.getNormValue() );
+
+        sv = new StringValue( attribute, "  A   TEST  " );
+        assertEquals( "a test", sv.getNormValue() );
+    }
+
+
+    /**
+     * Test the instanceOf method
+     */
+    @Test
+    public void testInstanceOf() throws LdapException
+    {
+        AttributeType attribute = EntryUtils.getIA5StringAttributeType();
+        StringValue ssv = new StringValue( attribute );
+
+        assertTrue( ssv.isInstanceOf( attribute ) );
+
+        attribute = EntryUtils.getBytesAttributeType();
+
+        assertFalse( ssv.isInstanceOf( attribute ) );
+    }
+
+
+    /**
+     * Test the getAttributeType method
+     */
+    @Test
+    public void testgetAttributeType()
+    {
+        AttributeType attribute = EntryUtils.getIA5StringAttributeType();
+        StringValue ssv = new StringValue( attribute );
+
+        assertEquals( attribute, ssv.getAttributeType() );
+    }
+
+
+    /**
+     * Test the equals method
+     */
+    @Test
+    public void testEquals() throws LdapInvalidAttributeValueException
+    {
+        AttributeType at1 = EntryUtils.getIA5StringAttributeType();
+        AttributeType at2 = EntryUtils.getBytesAttributeType();
+
+        StringValue value1 = new StringValue( at1, "test" );
+        StringValue value2 = new StringValue( at1, "test" );
+        StringValue value3 = new StringValue( at1, "TEST" );
+        StringValue value4 = new StringValue( at1, "tes" );
+        StringValue value5 = new StringValue( at1, null );
+        BinaryValue valueBytes = new BinaryValue( at2, new byte[]
+            { 0x01 } );
+        StringValue valueString = new StringValue( at, "test" );
+
+        assertTrue( value1.equals( value1 ) );
+        assertTrue( value1.equals( value2 ) );
+        assertTrue( value1.equals( value3 ) );
+        assertFalse( value1.equals( value4 ) );
+        assertFalse( value1.equals( value5 ) );
+        assertFalse( value1.equals( "test" ) );
+        assertFalse( value1.equals( null ) );
+
+        assertFalse( value1.equals( valueString ) );
+        assertFalse( value1.equals( valueBytes ) );
+    }
+
+
+    /**
+     * Test the constructor with bad AttributeType
+     */
+    @Test
+    public void testBadConstructor()
+    {
+        // create a AT without any syntax
+        AttributeType attribute = new EntryUtils.AT( "1.1.3.1" );
+
+        try
+        {
+            new StringValue( attribute );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // Expected...
+        }
+    }
+
+
+    /**
+     * Tests to make sure the hashCode method is working properly.
+     * @throws Exception on errors
+     */
+    @Test
+    public void testHashCode() throws LdapInvalidAttributeValueException
+    {
+        AttributeType at1 = EntryUtils.getCaseIgnoringAttributeNoNumbersType();
+        StringValue v0 = new StringValue( at1, "Alex" );
+        StringValue v1 = new StringValue( at1, "ALEX" );
+        StringValue v2 = new StringValue( at1, "alex" );
+
+        assertEquals( v0.hashCode(), v1.hashCode() );
+        assertEquals( v0.hashCode(), v2.hashCode() );
+        assertEquals( v1.hashCode(), v2.hashCode() );
+
+        assertEquals( v0, v1 );
+        assertEquals( v0, v2 );
+        assertEquals( v1, v2 );
+
+        StringValue v3 = new StringValue( at1, "Timber" );
+
+        assertNotSame( v0.hashCode(), v3.hashCode() );
+
+        StringValue v4 = new StringValue( at, "Alex" );
+
+        assertNotSame( v0.hashCode(), v4.hashCode() );
+    }
+
+
+    /**
+     * Test the compareTo method
+     */
+    @Test
+    public void testCompareTo() throws LdapInvalidAttributeValueException
+    {
+        AttributeType at1 = EntryUtils.getCaseIgnoringAttributeNoNumbersType();
+        StringValue v0 = new StringValue( at1, "Alex" );
+        StringValue v1 = new StringValue( at1, "ALEX" );
+
+        assertEquals( 0, v0.compareTo( v1 ) );
+        assertEquals( 0, v1.compareTo( v0 ) );
+
+        StringValue v2 = new StringValue( at1, null );
+
+        assertEquals( 1, v0.compareTo( v2 ) );
+        assertEquals( -1, v2.compareTo( v0 ) );
+    }
+
+
+    /**
+     * Test the clone method
+     */
+    @Test
+    public void testClone() throws LdapException
+    {
+        AttributeType at1 = EntryUtils.getCaseIgnoringAttributeNoNumbersType();
+        StringValue sv = new StringValue( at1, "Test" );
+
+        StringValue sv1 = sv.clone();
+
+        assertEquals( sv, sv1 );
+
+        sv = new StringValue( "" );
+
+        assertNotSame( sv, sv1 );
+        assertEquals( "", sv.getString() );
+
+        sv = new StringValue( "  This is    a   TEST  " );
+        sv1 = sv.clone();
+
+        assertEquals( sv, sv1 );
+        assertEquals( sv, sv1 );
+    }
+
+
+    /**
+     * Presumes an attribute which constrains it's values to some constant
+     * strings: LOW, MEDIUM, HIGH.  Normalization does nothing. MatchingRules
+     * are exact case matching.
+     *
+     * @throws Exception on errors
+     */
+    @Test
+    public void testConstrainedString() throws LdapInvalidAttributeValueException
+    {
+        s.setSyntaxChecker( new SyntaxChecker( "1.1.1.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public boolean isValidSyntax( Object value )
+            {
+                if ( value instanceof String )
+                {
+                    String strval = ( String ) value;
+                    return strval.equals( "HIGH" ) || strval.equals( "LOW" ) || strval.equals( "MEDIUM" );
+                }
+                return false;
+            }
+        } );
+
+        mr.setSyntax( s );
+        mr.setLdapComparator( new LdapComparator<String>( mr.getOid() )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public int compare( String o1, String o2 )
+            {
+                if ( o1 == null )
+                {
+                    if ( o2 == null )
+                    {
+                        return 0;
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else if ( o2 == null )
+                {
+                    return 1;
+                }
+
+                int i1 = getValue( o1 );
+                int i2 = getValue( o2 );
+
+                if ( i1 == i2 )
+                {
+                    return 0;
+                }
+                if ( i1 > i2 )
+                {
+                    return 1;
+                }
+                if ( i1 < i2 )
+                {
+                    return -1;
+                }
+
+                throw new IllegalStateException( "should not get here at all" );
+            }
+
+
+            public int getValue( String val )
+            {
+                if ( val.equals( "LOW" ) )
+                {
+                    return 0;
+                }
+                if ( val.equals( "MEDIUM" ) )
+                {
+                    return 1;
+                }
+                if ( val.equals( "HIGH" ) )
+                {
+                    return 2;
+                }
+                throw new IllegalArgumentException( "Not a valid value" );
+            }
+        } );
+
+        mr.setNormalizer( new NoOpNormalizer( mr.getOid() ) );
+        at.setEquality( mr );
+        at.setSyntax( s );
+
+        // check that normalization and syntax checks work as expected
+        StringValue value = new StringValue( at, "HIGH" );
+        assertEquals( value.getValue(), value.getValue() );
+
+        try
+        {
+            new StringValue( at, "high" );
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException liave )
+        {
+            // expected
+        }
+
+        // create a bunch to best tested for equals and in containers
+        StringValue v0 = new StringValue( at, "LOW" );
+        StringValue v1 = new StringValue( at, "LOW" );
+        StringValue v2 = new StringValue( at, "MEDIUM" );
+        StringValue v3 = new StringValue( at, "HIGH" );
+
+        // check equals
+        assertTrue( v0.equals( v1 ) );
+        assertTrue( v1.equals( v0 ) );
+        assertEquals( 0, v0.compareTo( v1 ) );
+
+        assertFalse( v2.equals( v3 ) );
+        assertFalse( v3.equals( v2 ) );
+        assertTrue( v2.compareTo( v3 ) < 0 );
+        assertTrue( v3.compareTo( v2 ) > 0 );
+
+        // add all except v1 and v5 to a set
+        HashSet<StringValue> set = new HashSet<StringValue>();
+        set.add( v0 );
+        set.add( v2 );
+        set.add( v3 );
+
+        // check contains method
+        assertTrue( "since v1.equals( v0 ) and v0 was added then this should be true", set.contains( v1 ) );
+
+        // check ordering based on the comparator
+        List<Value<String>> list = new ArrayList<Value<String>>();
+        list.add( v1 );
+        list.add( v3 );
+        list.add( v0 );
+        list.add( v2 );
+
+        Collections.sort( list );
+
+        // low ones are at the 3rd and 4th indices
+        assertTrue( "since v0 equals v1 either could be at index 0 & 1", list.get( 0 ).equals( v0 ) );
+        assertTrue( "since v0 equals v1 either could be at index 0 & 1", list.get( 1 ).equals( v1 ) );
+
+        // medium then high next
+        assertTrue( "since v2 \"MEDIUM\" should be at index 2", list.get( 2 ).equals( v2 ) );
+        assertTrue( "since v3 \"HIGH\" should be at index 3", list.get( 3 ).equals( v3 ) );
+
+        assertEquals( 4, list.size() );
+    }
+
+
+    /**
+     * Creates a string value with an attribute type that is of a syntax
+     * which accepts anything.  Also there is no normalization since the
+     * value is the same as the normalized value.  This makes the at technically
+     * a binary value however it can be dealt with as a string so this test
+     * is still OK.
+     * @throws Exception on errors
+     */
+    @Test
+    public void testAcceptAllNoNormalization() throws LdapInvalidAttributeValueException
+    {
+        // check that normalization and syntax checks work as expected
+        StringValue value = new StringValue( at, "hello" );
+        assertEquals( value.getValue(), value.getValue() );
+
+        // create a bunch to best tested for equals and in containers
+        StringValue v0 = new StringValue( at, "hello" );
+        StringValue v1 = new StringValue( at, "hello" );
+        StringValue v2 = new StringValue( at, "next0" );
+        StringValue v3 = new StringValue( at, "next1" );
+        StringValue v4 = new StringValue( at );
+        StringValue v5 = new StringValue( at );
+
+        // check equals
+        assertTrue( v0.equals( v1 ) );
+        assertTrue( v1.equals( v0 ) );
+        assertTrue( v4.equals( v5 ) );
+        assertTrue( v5.equals( v4 ) );
+        assertFalse( v2.equals( v3 ) );
+        assertFalse( v3.equals( v2 ) );
+
+        // add all except v1 and v5 to a set
+        HashSet<StringValue> set = new HashSet<StringValue>();
+        set.add( v0 );
+        set.add( v2 );
+        set.add( v3 );
+        set.add( v4 );
+
+        // check contains method
+        assertTrue( "since v1.equals( v0 ) and v0 was added then this should be true", set.contains( v1 ) );
+        assertTrue( "since v4.equals( v5 ) and v4 was added then this should be true", set.contains( v5 ) );
+
+        // check ordering based on the comparator
+        ArrayList<StringValue> list = new ArrayList<StringValue>();
+        list.add( v1 );
+        list.add( v3 );
+        list.add( v5 );
+        list.add( v0 );
+        list.add( v2 );
+        list.add( v4 );
+
+        Comparator<StringValue> c = new Comparator<StringValue>()
+        {
+            public int compare( StringValue o1, StringValue o2 )
+            {
+                String n1 = null;
+                String n2 = null;
+
+                if ( o1 != null )
+                {
+                    n1 = o1.getString();
+                }
+
+                if ( o2 != null )
+                {
+                    n2 = o2.getString();
+                }
+
+                if ( n1 == null )
+                {
+                    return ( n2 == null ) ? 0 : -1;
+                }
+                else if ( n2 == null )
+                {
+                    return 1;
+                }
+
+                return mr.getLdapComparator().compare( n1, n2 );
+            }
+        };
+
+        Collections.sort( list, c );
+
+        assertTrue( "since v4 equals v5 and has no value either could be at index 0 & 1", list.get( 0 ).equals( v4 ) );
+        assertTrue( "since v4 equals v5 and has no value either could be at index 0 & 1", list.get( 0 ).equals( v5 ) );
+        assertTrue( "since v4 equals v5 and has no value either could be at index 0 & 1", list.get( 1 ).equals( v4 ) );
+        assertTrue( "since v4 equals v5 and has no value either could be at index 0 & 1", list.get( 1 ).equals( v5 ) );
+
+        assertTrue( "since v0 equals v1 either could be at index 2 & 3", list.get( 2 ).equals( v0 ) );
+        assertTrue( "since v0 equals v1 either could be at index 2 & 3", list.get( 2 ).equals( v1 ) );
+        assertTrue( "since v0 equals v1 either could be at index 2 & 3", list.get( 3 ).equals( v0 ) );
+        assertTrue( "since v0 equals v1 either could be at index 2 & 3", list.get( 3 ).equals( v1 ) );
+
+        assertTrue( "since v2 \"next0\" should be at index 4", list.get( 4 ).equals( v2 ) );
+        assertTrue( "since v3 \"next1\" should be at index 5", list.get( 5 ).equals( v3 ) );
+
+        assertEquals( 6, list.size() );
+    }
+
+
+    /**
+     * Test serialization of a StringValue which has a normalized value
+     */
+    @Test
+    public void testNormalizedStringValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        // First check with a value which will be normalized
+        StringValue ssv = new StringValue( at, "  Test   Test  " );
+
+        String normalized = ssv.getNormValue();
+
+        assertEquals( "test test", normalized );
+        assertEquals( "  Test   Test  ", ssv.getString() );
+
+        StringValue ssvSer = deserializeValue( serializeValue( ssv ) );
+
+        assertEquals( ssv, ssvSer );
+    }
+
+
+    /**
+     * Test serialization of a StringValue which does not have a normalized value
+     */
+    @Test
+    public void testNoNormalizedStringValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        // First check with a value which will be normalized
+        StringValue ssv = new StringValue( at, "test" );
+
+        String normalized = ssv.getNormValue();
+
+        assertEquals( "test", normalized );
+        assertEquals( "test", ssv.getString() );
+
+        StringValue ssvSer = deserializeValue( serializeValue( ssv ) );
+
+        assertEquals( ssv, ssvSer );
+    }
+
+
+    /**
+     * Test serialization of a null StringValue
+     */
+    @Test
+    public void testNullStringValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        // First check with a value which will be normalized
+        StringValue ssv = new StringValue( at );
+
+        String normalized = ssv.getNormValue();
+
+        assertNull( normalized );
+        assertNull( ssv.getValue() );
+
+        StringValue ssvSer = deserializeValue( serializeValue( ssv ) );
+
+        assertEquals( ssv, ssvSer );
+    }
+
+
+    /**
+     * Test serialization of an empty StringValue
+     */
+    @Test
+    public void testEmptyStringValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        // First check with a value which will be normalized
+        StringValue ssv = new StringValue( at, "" );
+
+        String normalized = ssv.getNormValue();
+
+        assertEquals( "", normalized );
+        assertEquals( "", ssv.getString() );
+
+        StringValue ssvSer = deserializeValue( serializeValue( ssv ) );
+
+        assertEquals( ssv, ssvSer );
+    }
+
+
+    /**
+     * Test serialization of an empty StringValue
+     */
+    @Test
+    public void testStringValueEmptyNormalizedSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        // First check with a value which will be normalized
+        StringValue ssv = new StringValue( "  " );
+
+        assertEquals( "  ", ssv.getString() );
+
+        StringValue ssvSer = deserializeValue( serializeValue( ssv ) );
+
+        assertEquals( ssv, ssvSer );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/StringValueTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/StringValueTest.java
new file mode 100644
index 0000000..304f633
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/StringValueTest.java
@@ -0,0 +1,629 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.comparators.StringComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.Ia5StringSyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * 
+ * Test the StringValue class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class StringValueTest
+{
+    private static EntryUtils.S s;
+    private static EntryUtils.AT at;
+    private static EntryUtils.MR mr;
+
+
+    /**
+     * Initialize an AttributeType and the associated MatchingRule 
+     * and Syntax
+     */
+    @BeforeClass
+    public static void initAT()
+    {
+        s = new EntryUtils.S( "1.1.1.1", true );
+        s.setSyntaxChecker( new OctetStringSyntaxChecker() );
+        mr = new EntryUtils.MR( "1.1.2.1" );
+        mr.setSyntax( s );
+        mr.setLdapComparator( new StringComparator( "1.1.2.1" ) );
+        mr.setNormalizer( new DeepTrimToLowerNormalizer( "1.1.2.1" ) );
+        at = new EntryUtils.AT( "1.1.3.1" );
+        at.setEquality( mr );
+        at.setOrdering( mr );
+        at.setSubstring( mr );
+        at.setSyntax( s );
+    }
+
+
+    //----------------------------------------------------------------------------------
+    // Helper method
+    //----------------------------------------------------------------------------------
+    /**
+     * Serialize a StringValue
+     */
+    private ByteArrayOutputStream serializeValue( StringValue value ) throws IOException
+    {
+        ObjectOutputStream oOut = null;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        oOut = new ObjectOutputStream( out );
+        value.writeExternal( oOut );
+
+        return out;
+    }
+
+
+    /**
+     * Deserialize a StringValue
+     */
+    private StringValue deserializeValue( AttributeType at, ByteArrayOutputStream out ) throws IOException,
+        ClassNotFoundException
+    {
+        ObjectInputStream oIn = null;
+        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
+
+        try
+        {
+            oIn = new ObjectInputStream( in );
+
+            StringValue value = new StringValue( at );
+            value.readExternal( oIn );
+
+            return value;
+        }
+        catch ( IOException ioe )
+        {
+            throw ioe;
+        }
+        finally
+        {
+            try
+            {
+                if ( oIn != null )
+                {
+                    oIn.close();
+                }
+            }
+            catch ( IOException ioe )
+            {
+                throw ioe;
+            }
+        }
+    }
+
+
+    //----------------------------------------------------------------------------------
+    // Test the clone() method
+    //----------------------------------------------------------------------------------
+    /**
+     * Test cloning an empty value
+     */
+    @Test
+    public void testCloneEmptyValue() throws LdapException
+    {
+        StringValue sv = new StringValue( ( String ) null );
+
+        StringValue sv1 = ( StringValue ) sv.clone();
+
+        assertEquals( sv, sv1 );
+
+        StringValue sv2 = new StringValue( "" );
+
+        assertNotSame( sv2, sv1 );
+        assertNull( sv1.getValue() );
+        assertEquals( "", sv2.getString() );
+    }
+
+
+    /**
+     * Test cloning a value
+     */
+    @Test
+    public void testCloneValue() throws LdapException
+    {
+        StringValue sv = new StringValue( "  This is    a   TEST  " );
+
+        StringValue sv1 = ( StringValue ) sv.clone();
+
+        sv1 = sv.clone();
+
+        assertEquals( sv, sv1 );
+        assertEquals( "  This is    a   TEST  ", sv.getString() );
+
+        sv.apply( at );
+
+        assertNotSame( sv, sv1 );
+        assertEquals( "  This is    a   TEST  ", sv1.getString() );
+        assertEquals( "  This is    a   TEST  ", sv1.getNormValue() );
+        assertEquals( "  This is    a   TEST  ", sv.getString() );
+        assertEquals( "this is a test", sv.getNormValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#hashCode()}.
+     */
+    @Test
+    public void testHashCode()
+    {
+        StringValue csv = new StringValue( "test" );
+
+        int hash = "test".hashCode();
+        assertEquals( hash, csv.hashCode() );
+
+        csv = new StringValue( ( String ) null );
+        hash = "".hashCode();
+        assertEquals( hash, csv.hashCode() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#ClientStringValue()}.
+     */
+    @Test
+    public void testClientStringValueNull() throws LdapException
+    {
+        StringValue csv = new StringValue( ( String ) null );
+
+        assertNull( csv.getValue() );
+        assertFalse( csv.isSchemaAware() );
+        assertTrue( csv.isValid( new Ia5StringSyntaxChecker() ) );
+        assertTrue( csv.isNull() );
+        assertNull( csv.getNormValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#ClientStringValue(java.lang.String)}.
+     */
+    @Test
+    public void testClientStringValueEmpty() throws LdapException
+    {
+        StringValue csv = new StringValue( "" );
+
+        assertNotNull( csv.getValue() );
+        assertEquals( "", csv.getString() );
+        assertFalse( csv.isSchemaAware() );
+        assertTrue( csv.isValid( new Ia5StringSyntaxChecker() ) );
+        assertFalse( csv.isNull() );
+        assertNotNull( csv.getNormValue() );
+        assertEquals( "", csv.getNormValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#ClientStringValue(java.lang.String)}.
+     */
+    @Test
+    public void testClientStringValueString() throws LdapException
+    {
+        StringValue csv = new StringValue( "test" );
+
+        assertEquals( "test", csv.getValue() );
+        assertFalse( csv.isSchemaAware() );
+        assertTrue( csv.isValid( new Ia5StringSyntaxChecker() ) );
+        assertFalse( csv.isNull() );
+        assertNotNull( csv.getNormValue() );
+        assertEquals( "test", csv.getNormValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#getValue()}.
+     */
+    @Test
+    public void testGet()
+    {
+        StringValue sv = new StringValue( "test" );
+        assertEquals( "test", sv.getValue() );
+
+        StringValue sv2 = new StringValue( "" );
+        assertEquals( "", sv2.getValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#getCopy()}.
+     */
+    @Test
+    public void testGetCopy()
+    {
+        StringValue sv = new StringValue( "test" );
+
+        assertEquals( "test", sv.getValue() );
+
+        StringValue sv2 = new StringValue( "" );
+        assertEquals( "", sv2.getValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#set(java.lang.String)}.
+     */
+    @Test
+    public void testSet() throws LdapException
+    {
+        StringValue sv = new StringValue( ( String ) null );
+
+        assertNull( sv.getValue() );
+        assertFalse( sv.isSchemaAware() );
+        assertTrue( sv.isValid( new Ia5StringSyntaxChecker() ) );
+        assertTrue( sv.isNull() );
+
+        sv = new StringValue( "" );
+        assertNotNull( sv.getValue() );
+        assertEquals( "", sv.getValue() );
+        assertFalse( sv.isSchemaAware() );
+        assertTrue( sv.isValid( new Ia5StringSyntaxChecker() ) );
+        assertFalse( sv.isNull() );
+
+        sv = new StringValue( "Test" );
+        assertNotNull( sv.getValue() );
+        assertEquals( "Test", sv.getValue() );
+        assertFalse( sv.isSchemaAware() );
+        assertTrue( sv.isValid( new Ia5StringSyntaxChecker() ) );
+        assertFalse( sv.isNull() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#isNull()}.
+     */
+    @Test
+    public void testIsNull()
+    {
+        StringValue sv = new StringValue( ( String ) null );
+        assertTrue( sv.isNull() );
+
+        sv = new StringValue( "test" );
+        assertFalse( sv.isNull() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#isSchemaAware()}.
+     */
+    @Test
+    public void testIsNormalized() throws LdapException
+    {
+        StringValue sv = new StringValue( "  This is    a   TEST  " );
+
+        assertFalse( sv.isSchemaAware() );
+
+        sv.apply( at );
+
+        assertEquals( "this is a test", sv.getNormValue() );
+        assertTrue( sv.isSchemaAware() );
+
+        sv = new StringValue( "test" );
+        assertFalse( sv.isSchemaAware() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#setNormalized(boolean)}.
+     */
+    @Test
+    public void testSetNormalized() throws LdapException
+    {
+        StringValue sv = new StringValue( ( String ) null );
+
+        assertFalse( sv.isSchemaAware() );
+
+        sv = new StringValue( "  This is    a   TEST  " );
+        assertFalse( sv.isSchemaAware() );
+
+        sv.apply( at );
+
+        assertEquals( "this is a test", sv.getNormValue() );
+        assertTrue( sv.isSchemaAware() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#getNormValue()}.
+     */
+    @Test
+    public void testGetNormalizedValue() throws LdapException
+    {
+        StringValue sv = new StringValue( ( String ) null );
+
+        assertEquals( null, sv.getNormValue() );
+
+        sv = new StringValue( "  This is    a   TEST  " );
+        assertEquals( "  This is    a   TEST  ", sv.getNormValue() );
+
+        sv.apply( at );
+
+        assertEquals( "this is a test", sv.getNormValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#getNormValue()}.
+     */
+    @Test
+    public void getNormValueCopy() throws LdapException
+    {
+        StringValue sv = new StringValue( ( String ) null );
+
+        assertEquals( null, sv.getNormValue() );
+
+        sv = new StringValue( "  This is    a   TEST  " );
+        assertEquals( "  This is    a   TEST  ", sv.getNormValue() );
+
+        sv.apply( at );
+
+        assertEquals( "this is a test", sv.getNormValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#normalize(org.apache.directory.api.ldap.model.schema.Normalizer)}.
+     */
+    @Test
+    public void testNormalize() throws LdapException
+    {
+        StringValue sv = new StringValue( ( String ) null );
+
+        sv.apply( at );
+        assertEquals( null, sv.getNormValue() );
+
+        sv = new StringValue( "" );
+        sv.apply( at );
+        assertEquals( "", sv.getNormValue() );
+
+        sv = new StringValue( "  This is    a   TEST  " );
+        assertEquals( "  This is    a   TEST  ", sv.getNormValue() );
+
+        sv.apply( at );
+
+        assertEquals( "this is a test", sv.getNormValue() );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#isValid(org.apache.directory.api.ldap.model.schema.SyntaxChecker)}.
+     */
+    @Test
+    public void testIsValid() throws LdapException
+    {
+        StringValue sv = new StringValue( "Test" );
+
+        assertTrue( sv.isValid( new Ia5StringSyntaxChecker() ) );
+
+        sv = new StringValue( "é" );
+        assertFalse( sv.isValid( new Ia5StringSyntaxChecker() ) );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#compareTo(org.apache.directory.api.ldap.model.entry.Value)}.
+     */
+    @Test
+    public void testCompareTo() throws LdapException
+    {
+        StringValue sv1 = new StringValue( ( String ) null );
+        StringValue sv2 = new StringValue( ( String ) null );
+
+        assertEquals( 0, sv1.compareTo( sv2 ) );
+
+        sv1 = new StringValue( "Test" );
+        assertEquals( 1, sv1.compareTo( sv2 ) );
+        assertEquals( -1, sv2.compareTo( sv1 ) );
+
+        sv2 = new StringValue( "Test" );
+        assertEquals( 0, sv1.compareTo( sv2 ) );
+
+        // Now check that the equals method works on normalized values.
+        sv1 = new StringValue( "  This is    a TEST   " );
+        sv2 = new StringValue( "this is a test" );
+        sv1.apply( at );
+        assertEquals( 0, sv1.compareTo( sv2 ) );
+
+        sv1 = new StringValue( "a" );
+        sv2 = new StringValue( "b" );
+        assertEquals( -1, sv1.compareTo( sv2 ) );
+
+        sv1 = new StringValue( "b" );
+        sv2 = new StringValue( "a" );
+        assertEquals( 1, sv1.compareTo( sv2 ) );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#equals(java.lang.Object)}.
+     */
+    @Test
+    public void testEquals() throws LdapException
+    {
+        StringValue sv1 = new StringValue( ( String ) null );
+        StringValue sv2 = new StringValue( ( String ) null );
+
+        assertEquals( sv1, sv2 );
+
+        sv1 = new StringValue( "Test" );
+        assertNotSame( sv1, sv2 );
+
+        sv2 = new StringValue( "Test" );
+        assertEquals( sv1, sv2 );
+
+        // Now check that the equals method works on normalized values.
+        sv1 = new StringValue( "  This is    a TEST   " );
+        sv2 = new StringValue( "this is a test" );
+        sv1.apply( at );
+        assertEquals( sv1, sv2 );
+    }
+
+
+    /**
+     * Test method for {@link org.apache.directory.api.ldap.model.entry.StringValue#toString()}.
+     */
+    @Test
+    public void testToString()
+    {
+        StringValue sv = new StringValue( ( String ) null );
+
+        assertEquals( "null", sv.toString() );
+
+        sv = new StringValue( "" );
+        assertEquals( "", sv.toString() );
+
+        sv = new StringValue( "Test" );
+        assertEquals( "Test", sv.toString() );
+    }
+
+
+    /**
+     * Test the serialization of a CSV with a value and a normalized value
+     */
+    @Test
+    public void testSerializeStandard() throws LdapException, IOException, ClassNotFoundException
+    {
+        StringValue csv = new StringValue( "TEST" );
+        csv.apply( at );
+        csv.isValid( new Ia5StringSyntaxChecker() );
+
+        StringValue csvSer = deserializeValue( at, serializeValue( csv ) );
+        assertNotSame( csv, csvSer );
+        assertEquals( csv.getValue(), csvSer.getValue() );
+        assertEquals( csv.getNormValue(), csvSer.getNormValue() );
+        assertTrue( csvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CSV with a value and no normalized value
+     */
+    @Test
+    public void testSerializeNotNormalized() throws LdapException, IOException, ClassNotFoundException
+    {
+        StringValue csv = new StringValue( "Test" );
+        csv.isValid( new Ia5StringSyntaxChecker() );
+
+        StringValue csvSer = deserializeValue( null, serializeValue( csv ) );
+        assertNotSame( csv, csvSer );
+        assertEquals( csv.getValue(), csvSer.getValue() );
+        assertEquals( csv.getValue(), csvSer.getNormValue() );
+        assertFalse( csvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CSV with a value and an empty normalized value
+     */
+    @Test
+    public void testSerializeEmptyNormalized() throws LdapException, IOException, ClassNotFoundException
+    {
+        StringValue csv = new StringValue( "  " );
+        csv.isValid( new Ia5StringSyntaxChecker() );
+        csv.apply( at );
+
+        StringValue csvSer = deserializeValue( at, serializeValue( csv ) );
+        assertNotSame( csv, csvSer );
+        assertEquals( csv.getValue(), csvSer.getValue() );
+        assertEquals( csv.getNormValue(), csvSer.getNormValue() );
+        assertTrue( csvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CSV with a null value
+     */
+    @Test
+    public void testSerializeNullValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        StringValue csv = new StringValue( ( String ) null );
+        csv.isValid( new Ia5StringSyntaxChecker() );
+        csv.apply( at );
+
+        StringValue csvSer = deserializeValue( at, serializeValue( csv ) );
+        assertNotSame( csv, csvSer );
+        assertEquals( csv.getValue(), csvSer.getValue() );
+        assertEquals( csv.getNormValue(), csvSer.getNormValue() );
+        assertTrue( csvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CSV with an empty value
+     */
+    @Test
+    public void testSerializeEmptyValue() throws LdapException, IOException, ClassNotFoundException
+    {
+        StringValue csv = new StringValue( "" );
+        csv.isValid( new Ia5StringSyntaxChecker() );
+        csv.apply( at );
+
+        StringValue csvSer = deserializeValue( at, serializeValue( csv ) );
+        assertNotSame( csv, csvSer );
+        assertEquals( csv.getValue(), csvSer.getValue() );
+        assertEquals( csv.getNormValue(), csvSer.getNormValue() );
+        assertTrue( csvSer.isSchemaAware() );
+    }
+
+
+    /**
+     * Test the serialization of a CSV with an empty value not normalized
+     */
+    @Test
+    public void testSerializeEmptyValueNotNormalized() throws LdapException, IOException, ClassNotFoundException
+    {
+        StringValue csv = new StringValue( "" );
+        csv.isValid( new Ia5StringSyntaxChecker() );
+
+        StringValue csvSer = deserializeValue( null, serializeValue( csv ) );
+        assertNotSame( csv, csvSer );
+        assertEquals( csv.getValue(), csvSer.getValue() );
+        assertEquals( csv.getNormValue(), csvSer.getNormValue() );
+        assertFalse( csvSer.isSchemaAware() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/ValueSerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/ValueSerializationTest.java
new file mode 100644
index 0000000..3ba3240
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/entry/ValueSerializationTest.java
@@ -0,0 +1,549 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.entry;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator;
+import org.apache.directory.api.ldap.model.schema.comparators.StringComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Value Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ValueSerializationTest
+{
+    private static byte[] data = new byte[]
+        { 0x01, 0x02, 0x03, 0x04 };
+    BinaryValue bv1 = new BinaryValue( data );
+    BinaryValue bv2 = new BinaryValue( StringConstants.EMPTY_BYTES );
+    BinaryValue bv3 = new BinaryValue( ( byte[] ) null );
+    BinaryValue bv1n = new BinaryValue( data );
+    BinaryValue bv2n = new BinaryValue( StringConstants.EMPTY_BYTES );
+    BinaryValue bv3n = new BinaryValue( ( byte[] ) null );
+    StringValue sv1 = new StringValue( "test" );
+    StringValue sv2 = new StringValue( "" );
+    StringValue sv3 = new StringValue( ( String ) null );
+    StringValue sv1n = new StringValue( "test" );
+    StringValue sv2n = new StringValue( "" );
+    StringValue sv3n = new StringValue( ( String ) null );
+
+    private EntryUtils.S sb;
+    private EntryUtils.AT atb;
+    private EntryUtils.MR mrb;
+
+    private EntryUtils.S ss;
+    private EntryUtils.AT ats;
+    private EntryUtils.MR mrs;
+
+
+    /**
+     * Initialize an AttributeType and the associated MatchingRule 
+     * and Syntax
+     */
+    @Before
+    public void initAT()
+    {
+        sb = new EntryUtils.S( "1.1.1.1", false );
+        sb.setSyntaxChecker( new OctetStringSyntaxChecker() );
+        mrb = new EntryUtils.MR( "1.1.2.1" );
+        mrb.setSyntax( sb );
+
+        mrb.setLdapComparator( new ByteArrayComparator( "1.1.1" ) );
+        mrb.setNormalizer( new Normalizer( "1.1.1" )
+        {
+            public static final long serialVersionUID = 1L;
+
+
+            public Value<?> normalize( Value<?> value ) throws LdapException
+            {
+                if ( !value.isHumanReadable() )
+                {
+                    byte[] val = value.getBytes();
+                    // each byte will be changed to be > 0, and spaces will be trimmed
+                    byte[] newVal = new byte[val.length];
+                    int i = 0;
+
+                    for ( byte b : val )
+                    {
+                        newVal[i++] = ( byte ) ( b & 0x007F );
+                    }
+
+                    return new BinaryValue( Strings.trim( newVal ) );
+                }
+
+                throw new IllegalStateException( "expected byte[] to normalize" );
+            }
+
+
+            public String normalize( String value ) throws LdapException
+            {
+                throw new IllegalStateException( "expected byte[] to normalize" );
+            }
+        } );
+
+        atb = new EntryUtils.AT( "1.1.3.1" );
+        atb.setEquality( mrb );
+        atb.setOrdering( mrb );
+        atb.setSubstring( mrb );
+        atb.setSyntax( sb );
+
+        ss = new EntryUtils.S( "1.1.1.1", true );
+        ss.setSyntaxChecker( new OctetStringSyntaxChecker() );
+        mrs = new EntryUtils.MR( "1.1.2.1" );
+        mrs.setSyntax( ss );
+        mrs.setLdapComparator( new StringComparator( "1.1.2.1" ) );
+        mrs.setNormalizer( new DeepTrimToLowerNormalizer( "1.1.2.1" ) );
+        ats = new EntryUtils.AT( "1.1.3.1" );
+        ats.setEquality( mrs );
+        ats.setOrdering( mrs );
+        ats.setSubstring( mrs );
+        ats.setSyntax( ss );
+    }
+
+
+    @Test
+    public void testBinaryValueWithDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        bv1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = new BinaryValue( ( AttributeType ) null );
+        bvDeser.readExternal( in );
+
+        assertEquals( bv1, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueWithEmptyDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        bv2.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = new BinaryValue( ( AttributeType ) null );
+        bvDeser.readExternal( in );
+
+        assertEquals( bv2, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueNoDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        bv3.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = new BinaryValue( ( AttributeType ) null );
+        bvDeser.readExternal( in );
+
+        assertEquals( bv3, bvDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        sv1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = new StringValue( ( AttributeType ) null );
+        svDeser.readExternal( in );
+
+        assertEquals( sv1, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithEmptyDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        sv2.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = new StringValue( ( AttributeType ) null );
+        svDeser.readExternal( in );
+
+        assertEquals( sv2, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueNoDataSerialization() throws IOException, ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        sv3.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = new StringValue( ( AttributeType ) null );
+        svDeser.readExternal( in );
+
+        assertEquals( sv3, svDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueWithDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        bv1n.apply( atb );
+
+        bv1n.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = new BinaryValue( ( AttributeType ) null );
+        bvDeser.readExternal( in );
+
+        assertEquals( bv1n, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueWithEmptyDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        bv2n.apply( atb );
+
+        bv2n.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = new BinaryValue( ( AttributeType ) null );
+        bvDeser.readExternal( in );
+
+        assertEquals( bv2n, bvDeser );
+    }
+
+
+    @Test
+    public void testBinaryValueNoDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        bv3n.apply( atb );
+
+        bv3n.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        BinaryValue bvDeser = new BinaryValue( ( AttributeType ) null );
+        bvDeser.readExternal( in );
+
+        assertEquals( bv3n, bvDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        sv1n.apply( ats );
+
+        sv1n.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = new StringValue( ats );
+        svDeser.readExternal( in );
+
+        assertEquals( sv1n, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithEmptyDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        sv2n.apply( ats );
+
+        sv2n.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = new StringValue( ats );
+        svDeser.readExternal( in );
+
+        assertEquals( sv2n, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueNoDataNormalizedSerialization() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        sv3n.apply( ats );
+
+        sv3n.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        StringValue svDeser = new StringValue( ats );
+        svDeser.readExternal( in );
+
+        assertEquals( sv3n, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithDataNormalizedSerializationBytes() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        sv1n.apply( ats );
+
+        int pos = sv1n.serialize( buffer, 0 );
+
+        StringValue svDeser = new StringValue( ats );
+
+        int pos2 = svDeser.deserialize( buffer, 0 );
+
+        assertEquals( pos, pos2 );
+        assertEquals( sv1n, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithEmptyDataNormalizedSerializationBytes() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        sv2n.apply( ats );
+
+        int pos = sv2n.serialize( buffer, 0 );
+
+        StringValue svDeser = new StringValue( ats );
+
+        int pos2 = svDeser.deserialize( buffer, 0 );
+
+        assertEquals( pos, pos2 );
+        assertEquals( sv2n, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueNoDataNormalizedSerializationBytes() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+        sv3n.apply( ats );
+
+        int pos = sv3n.serialize( buffer, 0 );
+
+        StringValue svDeser = new StringValue( ats );
+        int pos2 = svDeser.deserialize( buffer, 0 );
+
+        assertEquals( pos, pos2 );
+        assertEquals( sv3n, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithDataSerializationBytes() throws IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+
+        int pos = sv1.serialize( buffer, 0 );
+
+        StringValue svDeser = new StringValue( ( AttributeType ) null );
+
+        int pos2 = svDeser.deserialize( buffer, 0 );
+
+        assertEquals( pos, pos2 );
+        assertEquals( sv1, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueWithEmptyDataSerializationBytes() throws IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+
+        int pos = sv2.serialize( buffer, 0 );
+
+        StringValue svDeser = new StringValue( ( AttributeType ) null );
+
+        int pos2 = svDeser.deserialize( buffer, 0 );
+
+        assertEquals( pos, pos2 );
+        assertEquals( sv2, svDeser );
+    }
+
+
+    @Test
+    public void testStringValueNoDataSerializationBytes() throws IOException, ClassNotFoundException
+    {
+        byte[] buffer = new byte[128];
+
+        int pos = sv3.serialize( buffer, 0 );
+
+        StringValue svDeser = new StringValue( ( AttributeType ) null );
+
+        int pos2 = svDeser.deserialize( buffer, 0 );
+
+        assertEquals( pos, pos2 );
+        assertEquals( sv3, svDeser );
+    }
+
+
+    @Ignore
+    @Test
+    public void testStringValueWithDataNormalizedSerializationPerf() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        sv1n.apply( ats );
+        StringValue svDeser = new StringValue( ats );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 10000000; i++ )
+        {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream out = new ObjectOutputStream( baos );
+            sv1n.writeExternal( out );
+            out.close();
+            byte[] data = baos.toByteArray();
+            ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+            svDeser.readExternal( in );
+            in.close();
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        System.out.println( "Delta ser slow = " + ( t1 - t0 ) );
+    }
+
+
+    @Ignore
+    @Test
+    public void testStringValueWithDataNormalizedSerializationBytesPerf() throws IOException, LdapException,
+        ClassNotFoundException
+    {
+        sv1n.apply( ats );
+        StringValue svDeser = new StringValue( ats );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 10000000; i++ )
+        {
+            byte[] buffer = new byte[128];
+            sv1n.serialize( buffer, 0 );
+            svDeser.deserialize( buffer, 0 );
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        System.out.println( "Delta ser fast = " + ( t1 - t0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/BranchNormalizedVisitorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/BranchNormalizedVisitorTest.java
new file mode 100644
index 0000000..63f62df
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/BranchNormalizedVisitorTest.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.filter.BranchNormalizedVisitor;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the BranchNormalizedVisitor.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BranchNormalizedVisitorTest
+{
+    @Test
+    public void testBranchNormalizedVisitor0() throws Exception
+    {
+        String filter = "(ou=Human Resources)";
+
+        ExprNode ori = FilterParser.parse( filter );
+
+        ExprNode altered = FilterParser.parse( filter );
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+
+        visitor.visit( altered );
+
+        assertEquals( ori.toString(), altered.toString() );
+    }
+
+
+    @Test
+    public void testBranchNormalizedVisitor1() throws Exception
+    {
+        String filter = "(&(ou=Human Resources)(uid=akarasulu))";
+
+        ExprNode ori = FilterParser.parse( filter );
+
+        ExprNode altered = FilterParser.parse( filter );
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+
+        visitor.visit( altered );
+
+        assertEquals( ori.toString(), altered.toString() );
+    }
+
+
+    @Test
+    public void testBranchNormalizedVisitor2() throws Exception
+    {
+        String filter = "(&(uid=akarasulu)(ou=Human Resources)";
+
+        filter += "(|(uid=akarasulu)(ou=Human Resources))) ";
+
+        ExprNode ori = FilterParser.parse( filter );
+
+        ExprNode altered = FilterParser.parse( filter );
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+
+        visitor.visit( altered );
+
+        assertFalse( ori.toString().equals( altered.toString() ) );
+    }
+
+
+    @Test
+    public void testBranchNormalizedVisitor3() throws Exception
+    {
+        String filter = "(&(ou=Human Resources)(uid=akarasulu)";
+
+        filter += "(|(ou=Human Resources)(uid=akarasulu)))";
+
+        ExprNode ori = FilterParser.parse( filter );
+
+        ExprNode altered = FilterParser.parse( filter );
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+
+        visitor.visit( altered );
+
+        assertTrue( ori.toString().equals( altered.toString() ) );
+    }
+
+
+    @Test
+    public void testBranchNormalizedComplex() throws Exception
+    {
+        String filter1 = "(&(a=A)(|(b=B)(c=C)))";
+
+        String filter2 = "(&(a=A)(|(c=C)(b=B)))";
+
+        String normalizedFilter1 = BranchNormalizedVisitor.getNormalizedFilter( null, filter1 );
+
+        String normalizedFilter2 = BranchNormalizedVisitor.getNormalizedFilter( null, filter2 );
+
+        assertEquals( normalizedFilter1, normalizedFilter2 );
+    }
+
+
+    public void testBranchNormalizedVisitor4() throws Exception
+    {
+        ExprNode ori = FilterParser.parse( "(&(!(sn=Bob))(ou=Human Resources)(uid=akarasulu))" );
+
+        ExprNode altered = FilterParser.parse( "(&(ou=Human Resources)(uid=akarasulu)(!(sn=Bob)))" );
+
+        BranchNormalizedVisitor visitor = new BranchNormalizedVisitor();
+
+        visitor.visit( altered );
+
+        assertTrue( ori.toString().equals( altered.toString() ) );
+
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterCloneTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterCloneTest.java
new file mode 100644
index 0000000..72c72f7
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterCloneTest.java
@@ -0,0 +1,551 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.text.ParseException;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.ApproximateNode;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.apache.directory.api.ldap.model.filter.SimpleNode;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the FilterParserImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class FilterCloneTest
+{
+    @Test
+    public void testItemFilter() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null, "(ou~=people)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "people", node.getValue().getString() );
+        assertTrue( node instanceof ApproximateNode );
+    }
+
+
+    @Test
+    public void testAndFilter() throws ParseException
+    {
+        BranchNode node = ( BranchNode ) FilterParser.parse( null, "(&(ou~=people)(age>=30))" );
+        // just check that it doesn't throw for now
+        node = ( BranchNode ) node.clone();
+        assertEquals( 2, node.getChildren().size() );
+        assertTrue( node instanceof AndNode );
+    }
+
+
+    @Test
+    public void testAndFilterOneChildOnly() throws ParseException
+    {
+        BranchNode node = ( BranchNode ) FilterParser.parse( null, "(&(ou~=people))" );
+        // just check that it doesn't throw for now
+        node = ( BranchNode ) node.clone();
+        assertEquals( 1, node.getChildren().size() );
+        assertTrue( node instanceof AndNode );
+    }
+
+
+    @Test
+    public void testOrFilter() throws ParseException
+    {
+        BranchNode node = ( BranchNode ) FilterParser.parse( null, "(|(ou~=people)(age>=30))" );
+        // just check that it doesn't throw for now
+        node = ( BranchNode ) node.clone();
+        assertEquals( 2, node.getChildren().size() );
+        assertTrue( node instanceof OrNode );
+    }
+
+
+    @Test
+    public void testOrFilterOneChildOnly() throws ParseException
+    {
+        BranchNode node = ( BranchNode ) FilterParser.parse( null, "(|(age>=30))" );
+        // just check that it doesn't throw for now
+        node = ( BranchNode ) node.clone();
+        assertEquals( 1, node.getChildren().size() );
+        assertTrue( node instanceof OrNode );
+    }
+
+
+    @Test
+    public void testNotFilter() throws ParseException
+    {
+        BranchNode node = ( BranchNode ) FilterParser.parse( null, "(!(&(ou~= people)(age>=30)))" );
+        // just check that it doesn't throw for now
+        node = ( BranchNode ) node.clone();
+        assertEquals( 1, node.getChildren().size() );
+        assertTrue( node instanceof NotNode );
+    }
+
+
+    @Test
+    public void testOptionAndEscapesFilter() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null, "(ou;lang-de>=\\23\\42asdl fkajsd)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+        assertEquals( "ou;lang-de", node.getAttribute() );
+        assertEquals( "#Basdl fkajsd", node.getValue().getString() );
+    }
+
+
+    @Test
+    public void testOptionsAndEscapesFilter() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null,
+            "(ou;lang-de;version-124>=\\23\\42asdl fkajsd)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+        assertEquals( "ou;lang-de;version-124", node.getAttribute() );
+        assertEquals( "#Basdl fkajsd", node.getValue().getString() );
+    }
+
+
+    @Test
+    public void testNumericoidOptionsAndEscapesFilter() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null,
+            "(1.3.4.2;lang-de;version-124>=\\23\\42asdl fkajsd)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+        assertEquals( "1.3.4.2;lang-de;version-124", node.getAttribute() );
+        assertEquals( "#Basdl fkajsd", node.getValue().getString() );
+    }
+
+
+    @Test
+    public void testPresentFilter() throws ParseException
+    {
+        PresenceNode node = ( PresenceNode ) FilterParser.parse( null, "(ou=*)" );
+        // just check that it doesn't throw for now
+        node = ( PresenceNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof PresenceNode );
+    }
+
+
+    @Test
+    public void testNumericoidPresentFilter() throws ParseException
+    {
+        PresenceNode node = ( PresenceNode ) FilterParser.parse( null, "(1.2.3.4=*)" );
+        // just check that it doesn't throw for now
+        node = ( PresenceNode ) node.clone();
+        assertEquals( "1.2.3.4", node.getAttribute() );
+        assertTrue( node instanceof PresenceNode );
+    }
+
+
+    @Test
+    public void testEqualsFilter() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null, "(ou=people)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "people", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+    }
+
+
+    @Test
+    public void testEqualsWithForwardSlashFilter() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null, "(ou=people/in/my/company)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "people/in/my/company", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1() throws ParseException
+    {
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( null,
+            "(ou:dn:stupidMatch:=dummyAssertion\\23\\2A)" );
+        // just check that it doesn't throw for now
+        node = ( ExtensibleNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1WithNumericOid() throws ParseException
+    {
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( null,
+            "(1.2.3.4:dn:1.3434.23.2:=dummyAssertion\\23\\2A)" );
+        // just check that it doesn't throw for now
+        node = ( ExtensibleNode ) node.clone();
+        assertEquals( "1.2.3.4", node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( "1.3434.23.2", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1NoDnAttr() throws ParseException
+    {
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( null, "(ou:stupidMatch:=dummyAssertion\\23\\2A)" );
+        // just check that it doesn't throw for now
+        node = ( ExtensibleNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1NoAttrNoMatchingRule() throws ParseException
+    {
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( null, "(ou:=dummyAssertion\\23\\2A)" );
+        // just check that it doesn't throw for now
+        node = ( ExtensibleNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( null, node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2() throws ParseException
+    {
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( null, "(:dn:stupidMatch:=dummyAssertion\\23\\2A)" );
+        // just check that it doesn't throw for now
+        node = ( ExtensibleNode ) node.clone();
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2WithNumericOid() throws ParseException
+    {
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( null, "(:dn:1.3434.23.2:=dummyAssertion\\23\\2A)" );
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( "1.3434.23.2", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2NoDnAttr() throws ParseException
+    {
+        ExtensibleNode node1 = ( ExtensibleNode ) FilterParser.parse( null, "(:stupidMatch:=dummyAssertion\\23\\2A)" );
+        // just check that it doesn't throw for now
+        ExtensibleNode node = ( ExtensibleNode ) node1.clone();
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2NoDnAttrWithNumericOidNoAttr() throws ParseException
+    {
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( null, "(:1.3434.23.2:=dummyAssertion\\23\\2A)" );
+        // just check that it doesn't throw for now
+        node = ( ExtensibleNode ) node.clone();
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#*", node.getValue().getString() );
+        assertEquals( "1.3434.23.2", node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testSubstringNoAnyNoFinal() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=foo*)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 0, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( null, node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringNoAny() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=foo*bar)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 0, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringNoAnyNoIni() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=*bar)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 0, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertEquals( null, node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringOneAny() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=foo*guy*bar)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 1, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "guy" ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringManyAny() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=a*b*c*d*e*f)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertEquals( "a", node.getInitial() );
+        assertEquals( "f", node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringNoIniManyAny() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=*b*c*d*e*f)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertEquals( null, node.getInitial() );
+        assertEquals( "f", node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringManyAnyNoFinal() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=a*b*c*d*e*)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertEquals( "a", node.getInitial() );
+        assertEquals( null, node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringNoIniManyAnyNoFinal() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=*b*c*d*e*)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertEquals( null, node.getInitial() );
+        assertEquals( null, node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringNoAnyDoubleSpaceStar() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=foo* *bar)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 1, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( " " ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+    }
+
+
+    @Test
+    public void testSubstringAnyDoubleSpaceStar() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=foo* a *bar)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 1, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( " a " ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+    }
+
+
+    /**
+     * Enrique just found this bug with the filter parser when parsing substring
+     * expressions like *any*. Here's the JIRA issue: <a
+     * href="http://nagoya.apache.org/jira/browse/DIRLDAP-21">DIRLDAP-21</a>.
+     */
+    @Test
+    public void testSubstringStarAnyStar() throws ParseException
+    {
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( null, "(ou=*foo*)" );
+        // just check that it doesn't throw for now
+        node = ( SubstringNode ) node.clone();
+
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+        assertEquals( 1, node.getAny().size() );
+        assertTrue( node.getAny().contains( "foo" ) );
+        assertNull( node.getInitial() );
+        assertNull( node.getFinal() );
+    }
+
+
+    @Test
+    public void testEqualsFilterNullValue() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null, "(ou=)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+    }
+
+
+    /**
+     * test a filter with a # in value
+     */
+    @Test
+    public void testEqualsFilterWithPoundInValue() throws ParseException
+    {
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( null, "(uid=#f1)" );
+        // just check that it doesn't throw for now
+        node = ( SimpleNode<?> ) node.clone();
+        assertEquals( "uid", node.getAttribute() );
+        assertEquals( "#f1", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+    }
+
+
+    @Test
+    public void testLargeBusyFilter() throws ParseException
+    {
+        ExprNode node1 = FilterParser
+            .parse(
+                null,
+                "(&(|(2.5.4.3=h*)(2.5.4.4=h*)(2.16.840.1.113730.3.1.241=h*)(2.5.4.42=h*))(!(objectClass=computer))(|(objectClass=person)(objectClass=group)(objectClass=organizationalUnit)(objectClass=domain))(!(&(userAccountControl:1.2.840.113556.1.4.803:=2))))" );
+        // just check that it doesn't throw for now
+        ExprNode node = node1.clone();
+        assertTrue( node instanceof AndNode );
+        //TODO test full structure
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterEncoderTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterEncoderTest.java
new file mode 100644
index 0000000..8aa80e6
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterEncoderTest.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+
+/**
+ * Tests for {@link FilterEncoder}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class FilterEncoderTest
+{
+
+    private static final String[] ZERO = new String[0];
+    private static final String[] ONE = new String[]
+        { "foo" };
+    private static final String[] TWO = new String[]
+        { "foo", "bar" };
+    private static final String[] SPECIAL_CHARS = new String[]
+        { "(\\*\0)" };
+
+
+    @Test
+    public void testFormatWithNoPlaceholdersAndCorrectArgumentCount()
+    {
+        assertEquals( "(cn=foo)", FilterEncoder.format( "(cn=foo)", null ) );
+        assertEquals( "(cn=foo)", FilterEncoder.format( "(cn=foo)", ZERO ) );
+    }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testFormatWithNoPlaceholdersAndTooManyArguments()
+    {
+        FilterEncoder.format( "(cn=foo)", ONE );
+    }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testFormatWithPlaceholdersAndTooFewArguments()
+    {
+        FilterEncoder.format( "(cn={0})", ZERO );
+    }
+
+
+    @Test
+    public void testFormatWithPlaceholdersAndCorrectArgumentCount()
+    {
+        assertEquals( "(cn=foo)", FilterEncoder.format( "(cn={0})", ONE ) );
+        assertEquals( "(&(cn=foo)(uid=bar))", FilterEncoder.format( "(&(cn={0})(uid={1}))", TWO ) );
+    }
+
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testFormatWithPlaceholdersAndTooManyArguments()
+    {
+        FilterEncoder.format( "(cn={0})", TWO );
+    }
+
+
+    @Test
+    public void testFormatWithPlaceholdersAndSpecialChars()
+    {
+        assertEquals( "(cn=\\28\\5C\\2A\\00\\29)", FilterEncoder.format( "(cn={0})", SPECIAL_CHARS ) );
+    }
+
+
+    @Test
+    public void testExceptionMessage()
+    {
+        try
+        {
+            FilterEncoder.format( "(&(cn={0})(uid={1}))", ONE );
+            fail( "IllegalArgumentException expected" );
+        }
+        catch ( IllegalArgumentException e )
+        {
+            String message = e.getMessage();
+            assertTrue( message.contains( " (&(cn={0})(uid={1})) " ) );
+            assertTrue( message.contains( " 2 " ) );
+            assertTrue( message.contains( " 1 " ) );
+        }
+    }
+
+
+    @Test
+    public void testEncodeFilterValue()
+    {
+        assertEquals( "1234567890", FilterEncoder.encodeFilterValue( "1234567890" ) );
+        assertEquals( "\\28", FilterEncoder.encodeFilterValue( "(" ) );
+        assertEquals( "\\29", FilterEncoder.encodeFilterValue( ")" ) );
+        assertEquals( "\\2A", FilterEncoder.encodeFilterValue( "*" ) );
+        assertEquals( "\\5C", FilterEncoder.encodeFilterValue( "\\" ) );
+        assertEquals( "\\00", FilterEncoder.encodeFilterValue( "\0" ) );
+        assertEquals( "\\28\\2A\\29", FilterEncoder.encodeFilterValue( "(*)" ) );
+        assertEquals( "a test \\2A \\5Cend", FilterEncoder.encodeFilterValue( "a test \\2A \\end" ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterNodeEqualityTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterNodeEqualityTest.java
new file mode 100644
index 0000000..07dceb1
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterNodeEqualityTest.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.filter.ApproximateNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.api.ldap.model.filter.LessEqNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+
+/**
+ * Tests the equals() methods of filter nodes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class FilterNodeEqualityTest
+{
+    @Test
+    public void testEqualityEquals()
+    {
+        EqualityNode<String> eqNode1 = new EqualityNode<String>( "attr1", new StringValue( "test" ) );
+        EqualityNode<String> eqNode2 = new EqualityNode<String>( "attr1", new StringValue( "test" ) );
+
+        assertEquals( "two exact nodes should be equal", eqNode1, eqNode2 );
+
+        eqNode2 = new EqualityNode<String>( "attr2", new StringValue( "test" ) );
+        assertFalse( "different attribute in node should return false on equals()", eqNode1.equals( eqNode2 ) );
+
+        eqNode2 = new EqualityNode<String>( "attr2", new StringValue( "foobar" ) );
+        assertFalse( "different value in node should return false on equals()", eqNode1.equals( eqNode2 ) );
+
+        PresenceNode presenceNode = new PresenceNode( "attr1" );
+        assertFalse( "two different leaf nodes should not be equal", eqNode1.equals( presenceNode ) );
+        assertFalse( "two different leaf nodes should not be equal", presenceNode.equals( eqNode1 ) );
+
+        GreaterEqNode<String> greaterEqNode = new GreaterEqNode<String>( "attr1", new StringValue( "test" ) );
+        assertFalse( "two different simple nodes should not be equal", eqNode1.equals( greaterEqNode ) );
+        assertFalse( "two different simple nodes should not be equal", greaterEqNode.equals( eqNode1 ) );
+    }
+
+
+    @Test
+    public void testGreaterEqEquals()
+    {
+        GreaterEqNode<String> greaterEqNode1 = new GreaterEqNode<String>( "attr1", new StringValue( "test" ) );
+        GreaterEqNode<String> greaterEqNode2 = new GreaterEqNode<String>( "attr1", new StringValue( "test" ) );
+
+        assertEquals( "two exact nodes should be equal", greaterEqNode1, greaterEqNode2 );
+
+        greaterEqNode2 = new GreaterEqNode<String>( "attr2", new StringValue( "test" ) );
+        assertFalse( "different attribute in node should return false on equals()", greaterEqNode1
+            .equals( greaterEqNode2 ) );
+
+        greaterEqNode2 = new GreaterEqNode<String>( "attr2", new StringValue( "foobar" ) );
+        assertFalse( "different value in node should return false on equals()", greaterEqNode1.equals( greaterEqNode2 ) );
+    }
+
+
+    @Test
+    public void testLessEqEquals()
+    {
+        LessEqNode<String> lessEqNode1 = new LessEqNode<String>( "attr1", new StringValue( "test" ) );
+        LessEqNode<String> lessEqNode2 = new LessEqNode<String>( "attr1", new StringValue( "test" ) );
+
+        assertEquals( "two exact nodes should be equal", lessEqNode1, lessEqNode2 );
+
+        lessEqNode2 = new LessEqNode<String>( "attr2", new StringValue( "test" ) );
+        assertFalse( "different attribute in node should return false on equals()", lessEqNode1.equals( lessEqNode2 ) );
+
+        lessEqNode2 = new LessEqNode<String>( "attr2", new StringValue( "foobar" ) );
+        assertFalse( "different value in node should return false on equals()", lessEqNode1.equals( lessEqNode2 ) );
+    }
+
+
+    @Test
+    public void testApproximateEqEquals()
+    {
+        ApproximateNode<String> approximateNode1 = new ApproximateNode<String>( "attr1", new StringValue( "test" ) );
+        ApproximateNode<String> approximateNode2 = new ApproximateNode<String>( "attr1", new StringValue( "test" ) );
+
+        assertEquals( "two exact nodes should be equal", approximateNode1, approximateNode2 );
+
+        approximateNode2 = new ApproximateNode<String>( "attr2", new StringValue( "test" ) );
+        assertFalse( "different attribute in node should return false on equals()", approximateNode1
+            .equals( approximateNode2 ) );
+
+        approximateNode2 = new ApproximateNode<String>( "attr2", new StringValue( "foobar" ) );
+        assertFalse( "different value in node should return false on equals()", approximateNode1
+            .equals( approximateNode2 ) );
+    }
+
+
+    @Test
+    public void testPresenceEquals()
+    {
+        PresenceNode presenceNode1 = new PresenceNode( "attr1" );
+        PresenceNode presenceNode2 = new PresenceNode( "attr1" );
+
+        assertEquals( "two exact presence nodes on same attribute should be equal", presenceNode1, presenceNode2 );
+
+        presenceNode2 = new PresenceNode( "attr2" );
+        assertFalse( "presence nodes on different attributes should not be equal", presenceNode1.equals( presenceNode2 ) );
+    }
+
+
+    @Test
+    public void testSubstringEquals()
+    {
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterParserTest.java
new file mode 100644
index 0000000..c15cc36
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterParserTest.java
@@ -0,0 +1,1190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.UnsupportedEncodingException;
+import java.text.ParseException;
+import java.util.List;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.ApproximateNode;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.apache.directory.api.ldap.model.filter.SimpleNode;
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the FilterParserImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class FilterParserTest
+{
+    private boolean checkWrongFilter( String filter )
+    {
+        try
+        {
+            return FilterParser.parse( filter ) == null;
+        }
+        catch ( ParseException pe )
+        {
+            return true;
+        }
+    }
+
+
+    /**
+     * Tests to avoid deadlocks for invalid filters.
+     * 
+     */
+    @Test
+    public void testInvalidFilters()
+    {
+        assertTrue( checkWrongFilter( "" ) );
+        assertTrue( checkWrongFilter( "   " ) );
+        assertTrue( checkWrongFilter( "(" ) );
+        assertTrue( checkWrongFilter( "  (" ) );
+        assertTrue( checkWrongFilter( "(  " ) );
+        assertTrue( checkWrongFilter( ")" ) );
+        assertTrue( checkWrongFilter( "  )" ) );
+        assertTrue( checkWrongFilter( "()" ) );
+        assertTrue( checkWrongFilter( "(  )" ) );
+        assertTrue( checkWrongFilter( "  ()  " ) );
+        assertTrue( checkWrongFilter( "(cn=test(" ) );
+        assertTrue( checkWrongFilter( "(cn=aaaaa" ) );
+        assertTrue( checkWrongFilter( "(&(cn=abc)" ) );
+    }
+
+
+    @Test
+    public void testItemFilter() throws ParseException
+    {
+        String str = "(ou~=people)";
+
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "people", node.getValue().getString() );
+        assertTrue( node instanceof ApproximateNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testAndFilter() throws ParseException
+    {
+        String str = "(&(ou~=people)(age>=30))";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str );
+        assertEquals( 2, node.getChildren().size() );
+        assertTrue( node instanceof AndNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testAndFilterOneChildOnly() throws ParseException
+    {
+        String str = "(&(ou~=people))";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str );
+        assertEquals( 1, node.getChildren().size() );
+        assertTrue( node instanceof AndNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testOrFilter() throws ParseException
+    {
+        String str = "(|(ou~=people)(age>=30))";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str );
+        assertEquals( 2, node.getChildren().size() );
+        assertTrue( node instanceof OrNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testOrFilterOneChildOnly() throws ParseException
+    {
+        String str = "(|(age>=30))";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str );
+        assertEquals( 1, node.getChildren().size() );
+        assertTrue( node instanceof OrNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testNotFilter() throws ParseException
+    {
+        String str = "(!(&(ou~= people)(age>=30)))";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str );
+        assertEquals( 1, node.getChildren().size() );
+        assertTrue( node instanceof NotNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testOptionAndEscapesFilter() throws ParseException
+    {
+        String str = "(ou;lang-de>=\\23\\42asdl fkajsd)"; // \23 = '#'
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+        assertEquals( "ou;lang-de", node.getAttribute() );
+        assertEquals( "#Basdl fkajsd", node.getValue().getString() );
+        String str2 = node.toString();
+        assertEquals( "(ou;lang-de>=#Basdl fkajsd)", str2 );
+    }
+
+
+    @Test
+    public void testOptionsAndEscapesFilter() throws ParseException
+    {
+        String str = "(ou;lang-de;version-124>=\\23\\42asdl fkajsd)";
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+        assertEquals( "ou;lang-de;version-124", node.getAttribute() );
+        assertEquals( "#Basdl fkajsd", node.getValue().getString() );
+        String str2 = node.toString();
+        assertEquals( "(ou;lang-de;version-124>=#Basdl fkajsd)", str2 );
+    }
+
+
+    @Test
+    public void testNumericoidOptionsAndEscapesFilter() throws ParseException
+    {
+        String str = "(1.3.4.2;lang-de;version-124>=\\23\\42afdl fkajsd)";
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+        assertEquals( "1.3.4.2;lang-de;version-124", node.getAttribute() );
+        assertEquals( "#Bafdl fkajsd", node.getValue().getString() );
+        String str2 = node.toString();
+        assertEquals( "(1.3.4.2;lang-de;version-124>=#Bafdl fkajsd)", str2 );
+    }
+
+
+    @Test
+    public void testPresentFilter() throws ParseException
+    {
+        String str = "(ou=*)";
+        PresenceNode node = ( PresenceNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof PresenceNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testNumericoidPresentFilter() throws ParseException
+    {
+        String str = "(1.2.3.4=*)";
+        PresenceNode node = ( PresenceNode ) FilterParser.parse( str );
+        assertEquals( "1.2.3.4", node.getAttribute() );
+        assertTrue( node instanceof PresenceNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testEqualsFilter() throws ParseException
+    {
+        String str = "(ou=people)";
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "people", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testBadEqualsFilter()
+    {
+        try
+        {
+            FilterParser.parse( "ou=people" );
+
+            // The parsing should fail
+            fail( "should fail with bad filter" );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testEqualsWithForwardSlashFilter() throws ParseException
+    {
+        String str = "(ou=people/in/my/company)";
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "people/in/my/company", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1() throws ParseException
+    {
+        String str = "(ou:dn:stupidMatch:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1WithNumericOid() throws ParseException
+    {
+        String str = "(1.2.3.4:dn:1.3434.23.2:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( "1.2.3.4", node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( "1.3434.23.2", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1NoDnAttr() throws ParseException
+    {
+        String str = "(ou:stupidMatch:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1OptionOnRule()
+    {
+        try
+        {
+            FilterParser.parse( "(ou:stupidMatch;lang-de:=dummyAssertion\\23\\c4\\8d)" );
+            fail( "we should never get here" );
+        }
+        catch ( ParseException e )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm1NoAttrNoMatchingRule() throws ParseException
+    {
+        String str = "(ou:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( null, node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2() throws ParseException
+    {
+        String str = "(:dn:stupidMatch:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2OptionOnRule()
+    {
+        try
+        {
+            FilterParser.parse( "(:dn:stupidMatch;lang-en:=dummyAssertion\\23\\c4\\8d)" );
+            fail( "we should never get here" );
+        }
+        catch ( ParseException e )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2WithNumericOid() throws ParseException
+    {
+        String str = "(:dn:1.3434.23.2:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( "1.3434.23.2", node.getMatchingRuleId() );
+        assertTrue( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2NoDnAttr() throws ParseException
+    {
+        String str = "(:stupidMatch:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( "stupidMatch", node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm2NoDnAttrWithNumericOidNoAttr() throws ParseException
+    {
+        String str = "(:1.3434.23.2:=dummyAssertion\\23\\c4\\8d)";
+        ExtensibleNode node = ( ExtensibleNode ) FilterParser.parse( str );
+        assertEquals( null, node.getAttribute() );
+        assertEquals( "dummyAssertion#\u010D", node.getValue().getString() );
+        assertEquals( "1.3434.23.2", node.getMatchingRuleId() );
+        assertFalse( node.hasDnAttributes() );
+        assertTrue( node instanceof ExtensibleNode );
+    }
+
+
+    @Test
+    public void testExtensibleFilterForm3() throws ParseException
+    {
+        try
+        {
+            FilterParser.parse( "(:=dummyAssertion)" );
+            fail( "Should never reach this point" );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testReuseParser() throws ParseException
+    {
+        FilterParser.parse( "(ou~=people)" );
+        FilterParser.parse( "(&(ou~=people)(age>=30)) " );
+        FilterParser.parse( "(|(ou~=people)(age>=30)) " );
+        FilterParser.parse( "(!(&(ou~=people)(age>=30)))" );
+        FilterParser.parse( "(ou;lang-de>=\\23\\42asdl fkajsd)" );
+        FilterParser.parse( "(ou;lang-de;version-124>=\\23\\42asdl fkajsd)" );
+        FilterParser.parse( "(1.3.4.2;lang-de;version-124>=\\23\\42asdl fkajsd)" );
+        FilterParser.parse( "(ou=*)" );
+        FilterParser.parse( "(1.2.3.4=*)" );
+        FilterParser.parse( "(ou=people)" );
+        FilterParser.parse( "(ou=people/in/my/company)" );
+        FilterParser.parse( "(ou:dn:stupidMatch:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(1.2.3.4:dn:1.3434.23.2:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(ou:stupidMatch:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(ou:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(1.2.3.4:1.3434.23.2:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(:dn:stupidMatch:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(:dn:1.3434.23.2:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(:stupidMatch:=dummyAssertion\\23\\c4\\8d)" );
+        FilterParser.parse( "(:1.3434.23.2:=dummyAssertion\\23\\c4\\8d)" );
+    }
+
+
+    @Test
+    public void testReuseParserAfterFailures() throws ParseException
+    {
+        FilterParser.parse( "(ou~=people)" );
+        FilterParser.parse( "(&(ou~=people)(age>=30)) " );
+        FilterParser.parse( "(|(ou~=people)(age>=30)) " );
+        FilterParser.parse( "(!(&(ou~=people)(age>=30)))" );
+        FilterParser.parse( "(ou;lang-de>=\\23\\42asdl fkajsd)" );
+        FilterParser.parse( "(ou;lang-de;version-124>=\\23\\42asdl fkajsd)" );
+        FilterParser.parse( "(1.3.4.2;lang-de;version-124>=\\23\\42asdl fkajsd)" );
+
+        try
+        {
+            FilterParser.parse( "(ou:stupidMatch;lang-de:=dummyAssertion\\23\\ac)" );
+            fail( "we should never get here" );
+        }
+        catch ( ParseException e )
+        {
+            assertTrue( true );
+        }
+
+        FilterParser.parse( "(ou=*)" );
+        FilterParser.parse( "(1.2.3.4=*)" );
+        FilterParser.parse( "(ou=people)" );
+        FilterParser.parse( "(ou=people/in/my/company)" );
+        FilterParser.parse( "(ou:dn:stupidMatch:=dummyAssertion\\23\\ac)" );
+        FilterParser.parse( "(1.2.3.4:dn:1.3434.23.2:=dummyAssertion\\23\\ac)" );
+        FilterParser.parse( "(ou:stupidMatch:=dummyAssertion\\23\\ac)" );
+
+        try
+        {
+            FilterParser.parse( "(:dn:stupidMatch;lang-en:=dummyAssertion\\23\\ac)" );
+            fail( "we should never get here" );
+        }
+        catch ( ParseException e )
+        {
+            assertTrue( true );
+        }
+
+        FilterParser.parse( "(ou:=dummyAssertion\\23\\ac)" );
+        FilterParser.parse( "(1.2.3.4:1.3434.23.2:=dummyAssertion\\23\\ac)" );
+        FilterParser.parse( "(:dn:stupidMatch:=dummyAssertion\\23\\ac)" );
+        FilterParser.parse( "(:dn:1.3434.23.2:=dummyAssertion\\23\\ac)" );
+        FilterParser.parse( "(:stupidMatch:=dummyAssertion\\23\\ac)" );
+        FilterParser.parse( "(:1.3434.23.2:=dummyAssertion\\23\\ac)" );
+    }
+
+
+    @Test
+    public void testNullOrEmptyString() throws ParseException
+    {
+        try
+        {
+            FilterParser.parse( (String)null );
+            fail( "Should not reach this point " );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+
+        try
+        {
+            FilterParser.parse( "" );
+            fail( "Should not reach this point " );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testSubstringNoAnyNoFinal() throws ParseException
+    {
+        String str = "(ou=foo*)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 0, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( null, node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringNoAny() throws ParseException
+    {
+        String str = "(ou=foo*bar)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 0, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringNoAnyNoIni() throws ParseException
+    {
+        String str = "(ou=*bar)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 0, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertEquals( null, node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringOneAny() throws ParseException
+    {
+        String str = "(ou=foo*guy*bar)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 1, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "guy" ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringManyAny() throws ParseException
+    {
+        String str = "(ou=a*b*c*d*e*f)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertEquals( "a", node.getInitial() );
+        assertEquals( "f", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringNoIniManyAny() throws ParseException
+    {
+        String str = "(ou=*b*c*d*e*f)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( new StringValue( "" ) ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertEquals( null, node.getInitial() );
+        assertEquals( "f", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringManyAnyNoFinal() throws ParseException
+    {
+        String str = "(ou=a*b*c*d*e*)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertEquals( "a", node.getInitial() );
+        assertEquals( null, node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringNoIniManyAnyNoFinal() throws ParseException
+    {
+        String str = "(ou=*b*c*d*e*)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 4, node.getAny().size() );
+        assertFalse( node.getAny().contains( new StringValue( "" ) ) );
+        assertTrue( node.getAny().contains( "e" ) );
+        assertTrue( node.getAny().contains( "b" ) );
+        assertTrue( node.getAny().contains( "c" ) );
+        assertTrue( node.getAny().contains( "d" ) );
+        assertEquals( null, node.getInitial() );
+        assertEquals( null, node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringNoAnyDoubleSpaceStar() throws ParseException
+    {
+        String str = "(ou=foo* *bar)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 1, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( " " ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testSubstringAnyDoubleSpaceStar() throws ParseException
+    {
+        String str = "(ou=foo* a *bar)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 1, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertTrue( node.getAny().contains( " a " ) );
+        assertEquals( "foo", node.getInitial() );
+        assertEquals( "bar", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    /**
+     * Enrique just found this bug with the filter parser when parsing substring
+     * expressions like *any*. Here's the JIRA issue: <a
+     * href="http://nagoya.apache.org/jira/browse/DIRLDAP-21">DIRLDAP-21</a>.
+     */
+    @Test
+    public void testSubstringStarAnyStar() throws ParseException
+    {
+        String str = "(ou=*foo*)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 1, node.getAny().size() );
+        assertTrue( node.getAny().contains( "foo" ) );
+        assertNull( node.getInitial() );
+        assertNull( node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testTwoByteUTF8Raw() throws ParseException
+    {
+        byte[] bytes =
+            { ( byte ) 0xC2, ( byte ) 0xA2 }; // unicode U+00A2: cents sign
+
+        try
+        {
+            new String( bytes, "UTF-8" );
+            String str = "(cn=\\C2\\A2)";
+            SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+
+            assertEquals( "cn", node.getAttribute() );
+            String val = node.getValue().getString();
+            assertEquals( "a2", Integer.toHexString( val.charAt( 0 ) ) ); // char is U+00A2
+            String str2 = node.toString();
+            assertEquals( str, str2 );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testTwoByteUTF8Escaped() throws ParseException
+    {
+        byte[] bytes =
+            { ( byte ) 0xC2, ( byte ) 0xA2 }; // unicode U+00A2: cents sign
+
+        try
+        {
+            String str = "(cn=\\C2\\A2)";
+            new String( bytes, "UTF-8" );
+
+            SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+
+            assertEquals( "cn", node.getAttribute() );
+            String val = node.getValue().getString();
+            assertEquals( "a2", Integer.toHexString( val.charAt( 0 ) ) ); // char is U+00A2
+            String str2 = node.toString();
+            assertEquals( str, str2 );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testThreeByteUTF8Raw() throws ParseException
+    {
+        byte[] bytes =
+            { ( byte ) 0xE2, ( byte ) 0x89, ( byte ) 0xA0 }; // unicode U+2260: "not equal to" sign in decimal signed bytes is -30, -119, -96
+
+        try
+        {
+            new String( bytes, "UTF-8" );
+            String str = "(cn=\\E2\\89\\A0)";
+            SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+
+            assertEquals( "cn", node.getAttribute() );
+            String val = node.getValue().getString();
+            assertEquals( "2260", Integer.toHexString( val.charAt( 0 ) ) );
+            String str2 = node.toString();
+            assertEquals( str, str2 );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testThreeByteUTF8Escaped() throws ParseException
+    {
+        byte[] bytes =
+            { ( byte ) 0xE2, ( byte ) 0x89, ( byte ) 0xA0 }; // unicode U+2260: "not equal to" sign in decimal signed bytes is -30, -119, -96
+
+        try
+        {
+            String str = "(cn=\\E2\\89\\A0aa)";
+            new String( bytes, "UTF-8" );
+
+            SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+
+            assertEquals( "cn", node.getAttribute() );
+            String val = node.getValue().getString();
+            assertEquals( "2260", Integer.toHexString( val.charAt( 0 ) ) );
+            String str2 = node.toString();
+            assertEquals( str, str2 );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testThreeByteJapaneseUTF8Raw() throws ParseException
+    {
+        byte[] bytes =
+            { ( byte ) 0xE3, ( byte ) 0x81, ( byte ) 0x99 }; // unicode U+3059: Japanese 'T' with squiggle on down-stroke.
+
+        try
+        {
+            new String( bytes, "UTF-8" );
+            String str = "(cn=\\E3\\81\\99)";
+            SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+
+            assertEquals( "cn", node.getAttribute() );
+            String val = node.getValue().getString();
+            assertEquals( "3059", Integer.toHexString( val.charAt( 0 ) ) );
+            String str2 = node.toString();
+            assertEquals( str, str2 );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    @Test
+    public void testThreeByteJapaneseUTF8Escaped() throws ParseException
+    {
+        byte[] bytes =
+            { ( byte ) 0xE3, ( byte ) 0x81, ( byte ) 0x99 }; // unicode U+3059: Japanese 'T' with squiggle on down-stroke.
+
+        try
+        {
+            String str = "(cn=\\E3\\81\\99)";
+            new String( bytes, "UTF-8" );
+
+            SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+            assertEquals( "cn", node.getAttribute() );
+            String val = node.getValue().getString();
+            assertEquals( "3059", Integer.toHexString( val.charAt( 0 ) ) );
+            String str2 = node.toString();
+            assertEquals( str, str2 );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * test a filter with a # in value
+     */
+    @Test
+    public void testEqualsFilterWithPoundInValue() throws ParseException
+    {
+        String str = "(uid=#f1)";
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str );
+        assertEquals( "uid", node.getAttribute() );
+        assertEquals( "#f1", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+        assertEquals( str, node.toString() );
+    }
+
+
+    /**
+     * Test that special and non allowed chars into an assertionValue are not
+     * accepted. ((cf DIRSERVER-1196)
+     *
+     */
+    @Test
+    public void testSpecialCharsInMemberOf()
+    {
+        try
+        {
+            FilterParser
+                .parse( "(memberOf=1.2.840.113556.1.4.1301=$#@&*()==,2.5.4.11=local,2.5.4.11=users,2.5.4.11=readimanager)" );
+            fail();
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test that filters like (&(a=b)(|(c=d)(e=f))) are correctly parsed
+     */
+    @Test
+    public void testAndEqOr_EqEq()
+    {
+        try
+        {
+            BranchNode node = ( BranchNode ) FilterParser
+                .parse( "(&(objectClass=nisNetgroup)(|(nisNetGroupTriple=a*a)(nisNetGroupTriple=\\28*,acc1,*\\29)))" );
+            assertEquals( 2, node.getChildren().size() );
+
+            assertTrue( node instanceof AndNode );
+
+            // Check the (a=b) part
+            ExprNode aEqb = node.getFirstChild();
+            assertTrue( aEqb instanceof EqualityNode );
+            assertEquals( "objectClass", ( ( EqualityNode<?> ) aEqb ).getAttribute() );
+            assertEquals( "nisNetgroup", ( ( EqualityNode<?> ) aEqb ).getValue().getString() );
+
+            // Check the or node
+            ExprNode orNode = node.getChildren().get( 1 );
+            assertTrue( orNode instanceof OrNode );
+
+            assertEquals( 2, ( ( OrNode ) orNode ).getChildren().size() );
+
+            ExprNode leftNode = ( ( OrNode ) orNode ).getChildren().get( 0 );
+
+            assertTrue( leftNode instanceof SubstringNode );
+            assertEquals( "nisNetGroupTriple", ( ( SubstringNode ) leftNode ).getAttribute() );
+            assertEquals( "a", ( ( SubstringNode ) leftNode ).getInitial() );
+            assertEquals( 0, ( ( SubstringNode ) leftNode ).getAny().size() );
+            assertEquals( "a", ( ( SubstringNode ) leftNode ).getFinal() );
+
+            ExprNode rightNode = ( ( OrNode ) orNode ).getChildren().get( 1 );
+
+            assertTrue( rightNode instanceof SubstringNode );
+            assertEquals( "nisNetGroupTriple", ( ( SubstringNode ) rightNode ).getAttribute() );
+            assertEquals( "(", ( ( SubstringNode ) rightNode ).getInitial() );
+            assertEquals( 1, ( ( SubstringNode ) rightNode ).getAny().size() );
+            assertEquals( ",acc1,", ( ( SubstringNode ) rightNode ).getAny().get( 0 ) );
+            assertEquals( ")", ( ( SubstringNode ) rightNode ).getFinal() );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testObjectClassAndFilterWithSpaces() throws ParseException
+    {
+        String str = "(&(objectClass=person)(objectClass=organizationalUnit))";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str );
+        assertEquals( 2, node.getChildren().size() );
+        assertTrue( node instanceof AndNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testQuotedChars() throws ParseException
+    {
+        String str = "(cn='~%\\28'$'\\5C)"; // note \28='(' and \5c='\'
+        ExprNode node = FilterParser.parse( str );
+        assertTrue( node instanceof EqualityNode );
+        assertEquals( "'~%('$'\\", ( ( EqualityNode<?> ) node ).getValue().getString() );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test
+    public void testQuotedCharsCase() throws ParseException
+    {
+        String str = "(cn='~%\\28'$'\\5Cac)"; // note \28='(' and \5c='\'
+        ExprNode node = FilterParser.parse( str );
+        assertTrue( node instanceof EqualityNode );
+        assertEquals( "'~%('$'\\ac", ( ( EqualityNode<?> ) node ).getValue().getString() );
+        String str2 = node.toString();
+        assertEquals( str.toUpperCase(), str2.toUpperCase() );
+    }
+
+
+    @Test
+    public void testQuotedSubstringManyAny() throws ParseException
+    {
+        String str = "(ou=\\5C*\\00*\\3D*\\2Abb)";
+        SubstringNode node = ( SubstringNode ) FilterParser.parse( str );
+        assertEquals( "ou", node.getAttribute() );
+        assertTrue( node instanceof SubstringNode );
+
+        assertEquals( 2, node.getAny().size() );
+        assertFalse( node.getAny().contains( "" ) );
+        assertEquals( "\\", node.getInitial() );
+        assertTrue( node.getAny().contains( "\0" ) );
+        assertTrue( node.getAny().contains( "=" ) );
+        assertEquals( "*bb", node.getFinal() );
+        String str2 = node.toString();
+        assertEquals( "(ou=\\5C*\\00*=*\\2Abb)", str2 );
+    }
+
+
+    /*
+    @Test
+    public void testPerf() throws ParseException
+    {
+        String filter = "(&(ou=abcdefg)(!(ou=hijkl))(&(a=bcd)(ew=fgh)))";
+        FilterParser parser = new FilterParserImpl();
+        
+        long t0 = System.currentTimeMillis();
+        
+        for ( int i = 0; i < 1000000; i++ )
+        {
+            parser.parse( filter );
+        }
+        
+        long t1 = System.currentTimeMillis();
+        
+        System.out.println( " Delta = " + (t1 - t0) );
+
+        long t2 = System.currentTimeMillis();
+        
+        for ( int i = 0; i < 10000000; i++ )
+        {
+            FastFilterParserImpl.parse( filter );
+        }
+        
+        long t3 = System.currentTimeMillis();
+        
+        System.out.println( " Delta = " + (t3 - t2) );
+    }
+    */
+
+    @Test
+    public void testBinaryValueEscaped() throws ParseException
+    {
+        String str = "(objectguid=\\29\\4C\\04\\B5\\D4\\ED\\38\\46\\87\\EE\\77\\58\\5C\\32\\AD\\91)";
+        FilterParser.parse( str );
+    }
+
+
+    @Test
+    public void testAndFilterFollowed() throws ParseException
+    {
+        String str = "(&(ou~=people)(age>=30))} some more text";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str );
+        assertEquals( 2, node.getChildren().size() );
+        assertTrue( node instanceof AndNode );
+        String str2 = node.toString();
+        assertTrue( str.startsWith( str2 ) );
+        assertEquals( "(&(ou~=people)(age>=30))", str2 );
+    }
+
+
+    @Test
+    public void testFilterOrder() throws ParseException
+    {
+        String filterStr1 = "(&(&(jagplayUserGroup=Active)(!(jagplayUserGroup=Banned))(jagplayUserNickname=admin)))";
+        String filterStr2 = "(&(jagplayUserNickname=admin)(&(jagplayUserGroup=Active)(!(jagplayUserGroup=Banned)))) ";
+
+        BranchNode node1 = ( BranchNode ) FilterParser.parse( filterStr1 );
+        BranchNode node2 = ( BranchNode ) FilterParser.parse( filterStr2 );
+
+        // Check Node 1
+        assertEquals( 1, node1.getChildren().size() );
+
+        assertTrue( node1 instanceof AndNode );
+        ExprNode andNode1 = node1.getChildren().get( 0 );
+        assertTrue( andNode1 instanceof AndNode );
+        List<ExprNode> children1 = ( ( AndNode ) andNode1 ).getChildren();
+        assertEquals( 3, children1.size() );
+
+        // First child : (jagplayUserGroup=Active)
+        ExprNode child1 = children1.get( 0 );
+        assertTrue( child1 instanceof EqualityNode );
+        assertEquals( "jagplayUserGroup", ( ( EqualityNode<?> ) child1 ).getAttribute() );
+        assertEquals( "Active", ( ( EqualityNode<?> ) child1 ).getValue().getString() );
+
+        // Second child : (!(jagplayUserGroup=Banned))
+        ExprNode child2 = children1.get( 1 );
+        assertTrue( child2 instanceof NotNode );
+        NotNode notNode1 = ( NotNode ) child2;
+
+        ExprNode notNodeChild1 = notNode1.getFirstChild();
+        assertTrue( notNodeChild1 instanceof EqualityNode );
+        assertEquals( "jagplayUserGroup", ( ( EqualityNode<?> ) notNodeChild1 ).getAttribute() );
+        assertEquals( "Banned", ( ( EqualityNode<?> ) notNodeChild1 ).getValue().getString() );
+
+        // Third child : (jagplayUserNickname=admin)
+        ExprNode child3 = children1.get( 2 );
+        assertTrue( child3 instanceof EqualityNode );
+        assertEquals( "jagplayUserNickname", ( ( EqualityNode<?> ) child3 ).getAttribute() );
+        assertEquals( "admin", ( ( EqualityNode<?> ) child3 ).getValue().getString() );
+
+        // Check Node 2 : (&(jagplayUserNickname=admin)(&(jagplayUserGroup=Active)(!(jagplayUserGroup=Banned))))
+        assertEquals( 2, node2.getChildren().size() );
+        assertTrue( node2 instanceof AndNode );
+
+        child1 = node2.getChildren().get( 0 );
+        assertTrue( child1 instanceof EqualityNode );
+        assertEquals( "jagplayUserNickname", ( ( EqualityNode<?> ) child1 ).getAttribute() );
+        assertEquals( "admin", ( ( EqualityNode<?> ) child1 ).getValue().getString() );
+
+        child2 = node2.getChildren().get( 1 );
+        assertTrue( child2 instanceof AndNode );
+        AndNode andNode2 = ( ( AndNode ) child2 );
+        assertEquals( 2, andNode2.getChildren().size() );
+
+        // First child : (jagplayUserGroup=Active)
+        child1 = andNode2.getChildren().get( 0 );
+        assertTrue( child1 instanceof EqualityNode );
+        assertEquals( "jagplayUserGroup", ( ( EqualityNode<?> ) child1 ).getAttribute() );
+        assertEquals( "Active", ( ( EqualityNode<?> ) child1 ).getValue().getString() );
+
+        // second child : (!(jagplayUserGroup=Banned))
+        child2 = andNode2.getChildren().get( 1 );
+        assertTrue( child2 instanceof NotNode );
+        notNode1 = ( NotNode ) child2;
+
+        notNodeChild1 = notNode1.getFirstChild();
+        assertTrue( notNodeChild1 instanceof EqualityNode );
+        assertEquals( "jagplayUserGroup", ( ( EqualityNode<?> ) notNodeChild1 ).getAttribute() );
+        assertEquals( "Banned", ( ( EqualityNode<?> ) notNodeChild1 ).getValue().getString() );
+    }
+
+
+    @Test
+    public void testEqualsFilterWithUnderscoreRelaxed() throws ParseException
+    {
+        String str = "(a_b_=people)";
+        SimpleNode<?> node = ( SimpleNode<?> ) FilterParser.parse( str, true );
+        assertEquals( "a_b_", node.getAttribute() );
+        assertEquals( "people", node.getValue().getString() );
+        assertTrue( node instanceof EqualityNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test(expected = ParseException.class)
+    public void testEqualsFilterWithUnderscoreNotRelaxed() throws ParseException
+    {
+        String str = "(a_b_=people)";
+        FilterParser.parse( str, false );
+    }
+
+
+    @Test
+    public void testAndFilterWithUnderscoreRelaxed() throws ParseException
+    {
+        String str = "(&(o_u~=people)(a_g_e>=30))";
+        BranchNode node = ( BranchNode ) FilterParser.parse( str, true );
+        assertEquals( 2, node.getChildren().size() );
+        assertTrue( node instanceof AndNode );
+        String str2 = node.toString();
+        assertEquals( str, str2 );
+    }
+
+
+    @Test(expected = ParseException.class)
+    public void testAndFilterWithUnderscoreNotRelaxed() throws ParseException
+    {
+        String str = "(&(o_u~=people)(a_g_e>=30))";
+        FilterParser.parse( str, false );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterToStringTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterToStringTest.java
new file mode 100644
index 0000000..c18c858
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/FilterToStringTest.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.text.ParseException;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.FilterParser;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the Filter.toString() method
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class FilterToStringTest
+{
+    @Test
+    public void testSimpleToString() throws ParseException
+    {
+        String str = "(ou=test)";
+        ExprNode node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+
+        str = "(ou~=test)";
+        node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+
+        str = "(ou>=test)";
+        node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+
+        str = "(ou<=test)";
+        node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+
+        str = "(ou=)";
+        node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+
+        str = "(ou~=)";
+        node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+
+        str = "(ou>=)";
+        node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+
+        str = "(ou<=)";
+        node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+    }
+
+
+    @Test
+    public void testToStringWithEscaped() throws ParseException
+    {
+        String str = "(cn=jims group\\28not bob\\29)";
+        ExprNode node = FilterParser.parse( str );
+        assertEquals( str, node.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/SubstringNodeTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/SubstringNodeTest.java
new file mode 100644
index 0000000..edf51f4
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/SubstringNodeTest.java
@@ -0,0 +1,142 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.filter;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.filter.SubstringNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Unit tests class SubstringNode.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SubstringNodeTest
+{
+    @Test
+    public void testGetRegexpEmpty() throws Exception
+    {
+        Pattern pattern = SubstringNode.getRegex( "", new String[]
+            { "" }, "" );
+
+        boolean b1 = pattern.matcher( "" ).matches();
+
+        assertTrue( b1 );
+    }
+
+
+    @Test
+    public void testGetRegexpInitial() throws Exception
+    {
+        Pattern pattern = SubstringNode.getRegex( "Test", new String[]
+            { "" }, "" );
+
+        boolean b1 = pattern.matcher( "Test just a test" ).matches();
+
+        assertTrue( b1 );
+
+        boolean b3 = pattern.matcher( "test just a test" ).matches();
+
+        assertFalse( b3 );
+    }
+
+
+    @Test
+    public void testGetRegexpFinal() throws Exception
+    {
+        Pattern pattern = SubstringNode.getRegex( "", new String[]
+            { "" }, "Test" );
+
+        boolean b1 = pattern.matcher( "test just a Test" ).matches();
+
+        assertTrue( b1 );
+
+        boolean b3 = pattern.matcher( "test just a test" ).matches();
+
+        assertFalse( b3 );
+    }
+
+
+    @Test
+    public void testGetRegexpAny() throws Exception
+    {
+        Pattern pattern = SubstringNode.getRegex( "", new String[]
+            { "just", "a" }, "" );
+
+        boolean b1 = pattern.matcher( "test just a Test" ).matches();
+
+        assertTrue( b1 );
+
+        boolean b3 = pattern.matcher( "test just A test" ).matches();
+
+        assertFalse( b3 );
+    }
+
+
+    @Test
+    public void testGetRegexpFull() throws Exception
+    {
+        Pattern pattern = SubstringNode.getRegex( "Test", new String[]
+            { "just", "a" }, "test" );
+
+        boolean b1 = pattern.matcher( "Test (this is) just (truly !) a (little) test" ).matches();
+
+        assertTrue( b1 );
+
+        boolean b3 = pattern.matcher( "Test (this is) just (truly !) A (little) test" ).matches();
+
+        assertFalse( b3 );
+    }
+
+
+    /**
+     * Tests StringTools.getRegex() with some LDAP filter special characters.
+     */
+    @Test
+    public void testGetRegexpWithLdapFilterSpecialChars() throws Exception
+    {
+        Pattern[] patterns = new Pattern[]
+            { SubstringNode.getRegex( null, new String[]
+                { "(" }, null ), SubstringNode.getRegex( null, new String[]
+                { ")" }, null ), SubstringNode.getRegex( null, new String[]
+                { "*" }, null ), SubstringNode.getRegex( null, new String[]
+                { "\\" }, null ), };
+
+        for ( Pattern pattern : patterns )
+        {
+            boolean b1 = pattern.matcher( "a(b*c\\d)e" ).matches();
+            assertTrue( b1 );
+
+            boolean b3 = pattern.matcher( "Test test" ).matches();
+            assertFalse( b3 );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/UndefinedNodeTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/UndefinedNodeTest.java
new file mode 100644
index 0000000..81f7488
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/filter/UndefinedNodeTest.java
@@ -0,0 +1,107 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.filter;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import java.util.List;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.filter.AssertionType;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.FilterVisitor;
+import org.apache.directory.api.ldap.model.filter.UndefinedNode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class UndefinedNode.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UndefinedNodeTest
+{
+
+    ExprNode undefinedNode = UndefinedNode.UNDEFINED_NODE;
+
+
+    @Test
+    public void testIsLeaf() throws Exception
+    {
+        assertFalse( undefinedNode.isLeaf() );
+    }
+
+
+    @Test
+    public void testIsSchemaAware() throws Exception
+    {
+        assertFalse( undefinedNode.isSchemaAware() );
+    }
+
+
+    @Test
+    public void testAssertationType() throws Exception
+    {
+        assertEquals( undefinedNode.getAssertionType(), AssertionType.UNDEFINED );
+    }
+
+
+    @Test
+    public void testAccept() throws Exception
+    {
+        assertNull( undefinedNode.accept( new FilterVisitor()
+        {
+
+            public Object visit( ExprNode node )
+            {
+                return null;
+            }
+
+
+            public boolean isPrefix()
+            {
+                return false;
+            }
+
+
+            public List<ExprNode> getOrder( BranchNode node, List<ExprNode> children )
+            {
+                return null;
+            }
+
+
+            public boolean canVisit( ExprNode node )
+            {
+                return false;
+            }
+        } ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifAttributesReaderTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifAttributesReaderTest.java
new file mode 100644
index 0000000..c4bd98e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifAttributesReaderTest.java
@@ -0,0 +1,810 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.ldif.LdapLdifException;
+import org.apache.directory.api.ldap.model.ldif.LdifAttributesReader;
+import org.apache.directory.api.util.Strings;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifAttributesReaderTest
+{
+    /** Uses a temporary folder rule */
+    @Rule 
+    public TemporaryFolder tmpFolder= new TemporaryFolder();
+
+    private byte[] data;
+
+    private File HJENSEN_JPEG_FILE = null;
+
+
+    private File createFile( String name, byte[] data ) throws IOException
+    {
+        File jpeg = tmpFolder.newFile( name + ".jpg" );
+
+        DataOutputStream os = new DataOutputStream( new FileOutputStream( jpeg ) );
+
+        os.write( data );
+        os.close();
+
+        return jpeg;
+    }
+
+
+    /**
+     * Create a file to be used by ":<" values
+     */
+    @Before
+    public void setUp() throws Exception
+    {
+        data = new byte[256];
+
+        for ( int i = 0; i < 256; i++ )
+        {
+            data[i] = ( byte ) i;
+        }
+
+        HJENSEN_JPEG_FILE = createFile( "hjensen", data );
+    }
+
+
+    @Test
+    public void testLdifNull() throws LdapLdifException
+    {
+        String ldif = null;
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertEquals( 0, entry.size() );
+    }
+
+
+    @Test
+    public void testLdifEmpty() throws LdapLdifException
+    {
+        String ldif = "";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertEquals( 0, entry.size() );
+    }
+
+
+    @Test
+    public void testLdifEmptyLines() throws LdapLdifException
+    {
+        String ldif = "\n\n\r\r\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+        assertNull( entry );
+    }
+
+
+    @Test
+    public void testLdifComments() throws LdapLdifException
+    {
+        String ldif = 
+              "#Comment 1\r" 
+            + "#\r" 
+            + " th\n" 
+            + " is is still a comment\n" 
+            + "\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertNull( entry );
+    }
+
+
+    @Test
+    public void testLdifVersionStart() throws LdapLdifException
+    {
+        String ldif = 
+              "cn: app1\n" 
+            + "objectClass: top\n" 
+            + "objectClass: apApplication\n" 
+            + "displayName:   app1   \n"
+            + "dependencies:\n" 
+            + "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertEquals( 1, reader.getVersion() );
+        assertNotNull( entry );
+
+        Attribute attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+    }
+
+
+    /**
+     * Spaces at the end of values should not be included into values.
+     * 
+     * @throws NamingException
+     */
+    @Test
+    public void testLdifParserEndSpaces() throws LdapLdifException
+    {
+        String ldif = 
+              "cn: app1\n" 
+            + "objectClass: top\n" 
+            + "objectClass: apApplication\n" 
+            + "displayName:   app1   \n"
+            + "dependencies:\n" 
+            + "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+
+        Entry entry = reader.parseEntry( ldif );
+        assertNotNull( entry );
+
+        Attribute attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+    }
+
+
+    @Test
+    public void testLdifParser() throws LdapLdifException, LdapInvalidAttributeValueException
+    {
+        String ldif = 
+              "cn: app1\n" 
+            + "objectClass: top\n" 
+            + "objectClass: apApplication\n" 
+            + "displayName: app1   \n"
+            + "dependencies:\n" 
+            + "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertNotNull( entry );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserMuiltiLineComments() throws LdapLdifException
+    {
+        String ldif = 
+              "#comment\n" 
+            + " still a comment\n" 
+            + "cn: app1#another comment\n" 
+            + "objectClass: top\n"
+            + "objectClass: apApplication\n" 
+            + "displayName: app1\n" 
+            + "serviceType: http\n" 
+            + "dependencies:\n"
+            + "httpHeaders:\n" 
+            + "startupOptions:\n" 
+            + "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertNotNull( entry );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "app1#another comment" ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserMultiLineEntries() throws LdapLdifException
+    {
+        String ldif = 
+              "#comment\n" 
+            + "cn: app1#another comment\n" 
+            + "objectClass: top\n" 
+            + "objectClass: apAppli\n"
+            + " cation\n" 
+            + "displayName: app1\n" 
+            + "serviceType: http\n" 
+            + "dependencies:\n" 
+            + "httpHeaders:\n"
+            + "startupOptions:\n" 
+            + "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertNotNull( entry );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "app1#another comment" ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserBase64() throws LdapLdifException, UnsupportedEncodingException
+    {
+        String ldif = 
+              "#comment\n" 
+            + "cn:: RW1tYW51ZWwgTMOpY2hhcm55\n" 
+            + "objectClass: top\n"
+            + "objectClass: apApplication\n" 
+            + "displayName: app1\n" 
+            + "serviceType: http\n" 
+            + "dependencies:\n"
+            + "httpHeaders:\n" 
+            + "startupOptions:\n" 
+            + "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertNotNull( entry );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Emmanuel L\u00e9charny".getBytes( "UTF-8" ) ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserBase64MultiLine() throws LdapLdifException, UnsupportedEncodingException
+    {
+        String ldif = 
+              "#comment\n" 
+            + "cn:: RW1tYW51ZWwg\n" 
+            + " TMOpY2hhcm55ICA=\n" 
+            + "objectClass: top\n"
+            + "objectClass: apApplication\n" 
+            + "displayName: app1\n" 
+            + "serviceType: http\n" 
+            + "dependencies:\n"
+            + "httpHeaders:\n" 
+            + "startupOptions:\n" 
+            + "envVars:";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        assertNotNull( entry );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Emmanuel L\u00e9charny  ".getBytes( "UTF-8" ) ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample1() throws LdapLdifException
+    {
+        String ldif = 
+              "objectclass: top\n" 
+            + "objectclass: person\n" 
+            + "objectclass: organizationalPerson\n"
+            + "cn: Barbara Jensen\n" 
+            + "cn: Barbara J Jensen\n" 
+            + "cn: Babs Jensen\n" 
+            + "sn: Jensen\n"
+            + "uid: bjensen\n" 
+            + "telephonenumber: +1 408 555 1212\n" 
+            + "description: A big sailing fan.\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Barbara Jensen" ) );
+        assertTrue( attr.contains( "Barbara J Jensen" ) );
+        assertTrue( attr.contains( "Babs Jensen" ) );
+
+        attr = entry.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = entry.get( "uid" );
+        assertTrue( attr.contains( "bjensen" ) );
+
+        attr = entry.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = entry.get( "description" );
+        assertTrue( attr.contains( "A big sailing fan." ) );
+
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample2() throws LdapLdifException
+    {
+        String ldif = 
+              "objectclass: top\n" 
+            + "objectclass: person\n" 
+            + "objectclass: organizationalPerson\n"
+            + "cn: Barbara Jensen\n" 
+            + "cn: Barbara J Jensen\n" 
+            + "cn: Babs Jensen\n" 
+            + "sn: Jensen\n"
+            + "uid: bjensen\n" 
+            + "telephonenumber: +1 408 555 1212\n"
+            + "description:Babs is a big sailing fan, and travels extensively in sea\n"
+            + " rch of perfect sailing conditions.\n" 
+            + "title:Product Manager, Rod and Reel Division";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Entry entry = reader.parseEntry( ldif );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Barbara Jensen" ) );
+        assertTrue( attr.contains( "Barbara J Jensen" ) );
+        assertTrue( attr.contains( "Babs Jensen" ) );
+
+        attr = entry.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = entry.get( "uid" );
+        assertTrue( attr.contains( "bjensen" ) );
+
+        attr = entry.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = entry.get( "description" );
+        assertTrue( attr
+            .contains( "Babs is a big sailing fan, and travels extensively in search of perfect sailing conditions." ) );
+
+        attr = entry.get( "title" );
+        assertTrue( attr.contains( "Product Manager, Rod and Reel Division" ) );
+
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample3() throws LdapLdifException, Exception
+    {
+        String ldif = 
+              "objectclass: top\n" 
+            + "objectclass: person\n" 
+            + "objectclass: organizationalPerson\n"
+            + "cn: Gern Jensen\n" 
+            + "cn: Gern O Jensen\n" 
+            + "sn: Jensen\n" 
+            + "uid: gernj\n"
+            + "telephonenumber: +1 408 555 1212\n"
+            + "description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl\n"
+            + " IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG\n"
+            + " VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg\n" 
+            + " b3V0IG1vcmUu";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        javax.naming.directory.Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Gern Jensen" ) );
+        assertTrue( attr.contains( "Gern O Jensen" ) );
+
+        attr = attributes.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = attributes.get( "uid" );
+        assertTrue( attr.contains( "gernj" ) );
+
+        attr = attributes.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = attributes.get( "description" );
+        assertTrue( attr
+            .contains( "What a careful reader you are!  This value is base-64-encoded because it has a control character in it (a CR).\r  By the way, you should really get out more."
+                .getBytes( "UTF-8" ) ) );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample3VariousSpacing() throws LdapLdifException, Exception
+    {
+        String ldif = 
+              "objectclass:top\n" 
+            + "objectclass:   person   \n" 
+            + "objectclass:organizationalPerson\n"
+            + "cn:Gern Jensen\n" 
+            + "cn:Gern O Jensen\n" 
+            + "sn:Jensen\n" 
+            + "uid:gernj\n"
+            + "telephonenumber:+1 408 555 1212  \n"
+            + "description::  V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl\n"
+            + " IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG\n"
+            + " VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg\n" 
+            + " b3V0IG1vcmUu  ";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        javax.naming.directory.Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = attributes.get( "cn" );
+        assertTrue( attr.contains( "Gern Jensen" ) );
+        assertTrue( attr.contains( "Gern O Jensen" ) );
+
+        attr = attributes.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = attributes.get( "uid" );
+        assertTrue( attr.contains( "gernj" ) );
+
+        attr = attributes.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = attributes.get( "description" );
+        assertTrue( attr
+            .contains( "What a careful reader you are!  This value is base-64-encoded because it has a control character in it (a CR).\r  By the way, you should really get out more."
+                .getBytes( "UTF-8" ) ) );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample4() throws NamingException, Exception
+    {
+        String ldif = 
+              "# dn:: ou=���������,o=Airius\n" 
+            + "objectclass: top\n"
+            + "objectclass: organizationalUnit\n" 
+            + "ou:: 5Za25qWt6YOo\n" 
+            + "# ou:: ���������\n"
+            + "ou;lang-ja:: 5Za25qWt6YOo\n" 
+            + "# ou;lang-ja:: ���������\n"
+            + "ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2\n"
+            + "# ou;lang-ja:: ������������������\n" 
+            + "ou;lang-en: Sales\n"
+            + "description: Japanese office\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        String[][] values =
+            {
+                { "objectclass", "top" },
+                { "objectclass", "organizationalUnit" },
+                { "ou", "\u55b6\u696d\u90e8" },
+                { "ou;lang-ja", "\u55b6\u696d\u90e8" },
+                { "ou;lang-ja;phonetic", "\u3048\u3044\u304e\u3087\u3046\u3076" }, // 3048 = ���, 3044 = ���, 304e = ���
+                    // 3087 = ���, 3046 = ���, 3076 = ���
+                    { "ou;lang-en", "Sales" },
+                    { "description", "Japanese office" } };
+
+        for ( int j = 0; j < values.length; j++ )
+        {
+            javax.naming.directory.Attribute attr = attributes.get( values[j][0] );
+
+            if ( attr.contains( values[j][1] ) )
+            {
+                assertTrue( true );
+            }
+            else
+            {
+                assertTrue( attr.contains( values[j][1].getBytes( "UTF-8" ) ) );
+            }
+        }
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample5() throws NamingException, Exception
+    {
+        String ldif = 
+              "objectclass: top\n" 
+            + "objectclass: person\n" 
+            + "objectclass: organizationalPerson\n"
+            + "cn: Horatio Jensen\n" 
+            + "cn: Horatio N Jensen\n" 
+            + "sn: Jensen\n" 
+            + "uid: hjensen\n"
+            + "telephonenumber: +1 408 555 1212\n" 
+            + "jpegphoto:< file:" 
+            + HJENSEN_JPEG_FILE.getAbsolutePath() 
+            + "\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        String[][] values =
+            {
+                { "objectclass", "top" },
+                { "objectclass", "person" },
+                { "objectclass", "organizationalPerson" },
+                { "cn", "Horatio Jensen" },
+                { "cn", "Horatio N Jensen" },
+                { "sn", "Jensen" },
+                { "uid", "hjensen" },
+                { "telephonenumber", "+1 408 555 1212" },
+                { "jpegphoto", null } };
+
+        for ( int i = 0; i < values.length; i++ )
+        {
+            if ( "jpegphoto".equalsIgnoreCase( values[i][0] ) )
+            {
+                javax.naming.directory.Attribute attr = attributes.get( values[i][0] );
+                assertEquals( Strings.dumpBytes( data ), Strings.dumpBytes( ( byte[] ) attr.get() ) );
+            }
+            else
+            {
+                javax.naming.directory.Attribute attr = attributes.get( values[i][0] );
+
+                if ( attr.contains( values[i][1] ) )
+                {
+                    assertTrue( true );
+                }
+                else
+                {
+                    assertTrue( attr.contains( values[i][1].getBytes( "UTF-8" ) ) );
+                }
+            }
+        }
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample5WithSizeLimit() throws Exception
+    {
+        String ldif = 
+              "objectclass: top\n" 
+            + "objectclass: person\n" 
+            + "objectclass: organizationalPerson\n"
+            + "cn: Horatio Jensen\n"
+            + "cn: Horatio N Jensen\n" 
+            + "sn: Jensen\n" 
+            + "uid: hjensen\n"
+            + "telephonenumber: +1 408 555 1212\n" 
+            + "jpegphoto:< file:" 
+            + HJENSEN_JPEG_FILE.getAbsolutePath() 
+            + "\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        reader.setSizeLimit( 128 );
+
+        try
+        {
+            reader.parseEntry( ldif );
+            fail();
+        }
+        catch ( LdapLdifException ne )
+        {
+            assertTrue( I18n.err( I18n.ERR_12009_ERROR_PARSING_LDIF_BUFFER ), ne.getMessage().startsWith(
+                I18n.ERR_12009_ERROR_PARSING_LDIF_BUFFER.getErrorCode() ) );
+        }
+    }
+
+
+    @Test
+    public void testLdifAttributesReaderDirServer() throws NamingException, Exception
+    {
+        String ldif = 
+              "# -------------------------------------------------------------------\n" 
+            + "#\n"
+            + "#  Licensed to the Apache Software Foundation (ASF) under one\n"
+            + "#  or more contributor license agreements.  See the NOTICE file\n"
+            + "#  distributed with this work for additional information\n"
+            + "#  regarding copyright ownership.  The ASF licenses this file\n"
+            + "#  to you under the Apache License, Version 2.0 (the\n"
+            + "#  \"License\"); you may not use this file except in compliance\n"
+            + "#  with the License.  You may obtain a copy of the License at\n" 
+            + "#  \n"
+            + "#    http://www.apache.org/licenses/LICENSE-2.0\n" 
+            + "#  \n"
+            + "#  Unless required by applicable law or agreed to in writing,\n"
+            + "#  software distributed under the License is distributed on an\n"
+            + "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n"
+            + "#  KIND, either express or implied.  See the License for the\n"
+            + "#  specific language governing permissions and limitations\n" 
+            + "#  under the License. \n" 
+            + "#  \n"
+            + "#\n" 
+            + "# EXAMPLE.COM is freely and reserved for testing according to this RFC:\n" 
+            + "#\n"
+            + "# http://www.rfc-editor.org/rfc/rfc2606.txt\n" 
+            + "#\n"
+            + "# -------------------------------------------------------------------\n" 
+            + "\n" 
+            + "objectclass: top\n"
+            + "objectclass: organizationalunit\n" 
+            + "ou: Users";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        javax.naming.directory.Attribute attr = attributes.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "organizationalunit" ) );
+
+        attr = attributes.get( "ou" );
+        assertTrue( attr.contains( "Users" ) );
+    }
+
+
+    @Test
+    public void testLdifParserCommentsEmptyLines() throws NamingException, Exception
+    {
+        String ldif = "#\n"
+            + "#  Licensed to the Apache Software Foundation (ASF) under one\n"
+            + "#  or more contributor license agreements.  See the NOTICE file\n"
+            + "#  distributed with this work for additional information\n"
+            + "#  regarding copyright ownership.  The ASF licenses this file\n"
+            + "#  to you under the Apache License, Version 2.0 (the\n"
+            + "#  \"License\"); you may not use this file except in compliance\n"
+            + "#  with the License.  You may obtain a copy of the License at\n"
+            + "#  \n"
+            + "#    http://www.apache.org/licenses/LICENSE-2.0\n"
+            + "#  \n"
+            + "#  Unless required by applicable law or agreed to in writing,\n"
+            + "#  software distributed under the License is distributed on an\n"
+            + "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n"
+            + "#  KIND, either express or implied.  See the License for the\n"
+            + "#  specific language governing permissions and limitations\n"
+            + "#  under the License. \n"
+            + "#  \n"
+            + "#\n"
+            + "#\n"
+            + "#   EXAMPLE.COM is freely and reserved for testing according to this RFC:\n"
+            + "#\n"
+            + "#   http://www.rfc-editor.org/rfc/rfc2606.txt\n"
+            + "#\n"
+            + "#\n"
+            + "\n"
+            + "#\n"
+            + "# This ACI allows brouse access to the root suffix and one level below that to anyone.\n"
+            + "# At this level there is nothing critical exposed.  Everything that matters is one or\n"
+            + "# more levels below this.\n"
+            + "#\n"
+            + "\n"
+            + "objectClass: top\n"
+            + "objectClass: subentry\n"
+            + "objectClass: accessControlSubentry\n"
+            + "subtreeSpecification: { maximum 1 }\n"
+            + "prescriptiveACI: { identificationTag \"browseRoot\", precedence 100, authenticationLevel none, itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { protectedItems {entry}, grantsAndDenials { grantReturnDN, grantBrowse } } } } }\n";
+
+        LdifAttributesReader reader = new LdifAttributesReader();
+        Attributes attributes = reader.parseAttributes( ldif );
+
+        javax.naming.directory.Attribute attr = attributes.get( "objectClass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( SchemaConstants.SUBENTRY_OC ) );
+        assertTrue( attr.contains( "accessControlSubentry" ) );
+
+        attr = attributes.get( "subtreeSpecification" );
+        assertTrue( attr.contains( "{ maximum 1 }" ) );
+
+        attr = attributes.get( "prescriptiveACI" );
+        assertTrue( attr
+            .contains( "{ identificationTag \"browseRoot\", precedence 100, authenticationLevel none, itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { protectedItems {entry}, grantsAndDenials { grantReturnDN, grantBrowse } } } } }" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifControlSerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifControlSerializationTest.java
new file mode 100644
index 0000000..c02196e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifControlSerializationTest.java
@@ -0,0 +1,228 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.ldif.LdifControl;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.api.util.StringConstants;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the LdifControlSerializer class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifControlSerializationTest
+{
+    private static Control controlCriticalWithData;
+    private static Control controlCriticalNoData;
+    private static Control controlCriticalEmptyData;
+    private static Control controlNoCriticalWithData;
+    private static Control controlNoCriticalNoData;
+    private static Control controlNoCriticalEmptyData;
+    private static byte[] data = new byte[]
+        { 0x01, 0x02, 0x03, 0x04 };
+
+
+    @BeforeClass
+    public static void setup()
+    {
+        controlCriticalWithData = new OpaqueControl( "1.2.3.4.1" );
+        controlCriticalWithData.setCritical( true );
+        ( ( OpaqueControl ) controlCriticalWithData ).setEncodedValue( data );
+
+        controlCriticalNoData = new OpaqueControl( "1.2.3.4.2" );
+        controlCriticalNoData.setCritical( true );
+
+        controlCriticalEmptyData = new OpaqueControl( "1.2.3.4.3" );
+        controlCriticalEmptyData.setCritical( true );
+        ( ( OpaqueControl ) controlCriticalEmptyData ).setEncodedValue( StringConstants.EMPTY_BYTES );
+
+        controlNoCriticalWithData = new OpaqueControl( "1.2.3.4.4" );
+        controlNoCriticalWithData.setCritical( false );
+        ( ( OpaqueControl ) controlNoCriticalWithData ).setEncodedValue( data );
+
+        controlNoCriticalNoData = new OpaqueControl( "1.2.3.4.5" );
+        controlNoCriticalNoData.setCritical( false );
+
+        controlNoCriticalEmptyData = new OpaqueControl( "1.2.3.4.6" );
+        controlNoCriticalEmptyData.setCritical( false );
+    }
+
+
+    @Test
+    public void testControlCriticalWithDataSerialization() throws IOException, ClassNotFoundException
+    {
+        LdifControl ldifControl1 = new LdifControl( controlCriticalWithData.getOid() );
+        ldifControl1.setCritical( controlCriticalWithData.isCritical() );
+        ldifControl1.setValue( ( ( OpaqueControl ) controlCriticalWithData ).getEncodedValue() );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifControl1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifControl ldifControl2 = new LdifControl();
+        ldifControl2.readExternal( in );
+
+        assertEquals( ldifControl1, ldifControl2 );
+    }
+
+
+    @Test
+    public void testControlCriticalNoDataSerialization() throws IOException, ClassNotFoundException
+    {
+        LdifControl ldifControl1 = new LdifControl( controlCriticalNoData.getOid() );
+        ldifControl1.setCritical( controlCriticalNoData.isCritical() );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifControl1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifControl ldifControl2 = new LdifControl();
+        ldifControl2.readExternal( in );
+
+        assertEquals( ldifControl1, ldifControl2 );
+    }
+
+
+    @Test
+    public void testControlCriticalEmptyDataSerialization() throws IOException, ClassNotFoundException
+    {
+        LdifControl ldifControl1 = new LdifControl( controlCriticalEmptyData.getOid() );
+        ldifControl1.setCritical( controlCriticalEmptyData.isCritical() );
+        ldifControl1.setValue( ( ( OpaqueControl ) controlCriticalEmptyData ).getEncodedValue() );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifControl1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifControl ldifControl2 = new LdifControl();
+        ldifControl2.readExternal( in );
+
+        assertEquals( ldifControl1, ldifControl2 );
+    }
+
+
+    @Test
+    public void testControlNoCriticalWithDataSerialization() throws IOException, ClassNotFoundException
+    {
+        LdifControl ldifControl1 = new LdifControl( controlNoCriticalWithData.getOid() );
+        ldifControl1.setCritical( controlNoCriticalWithData.isCritical() );
+        ldifControl1.setValue( ( ( OpaqueControl ) controlNoCriticalWithData ).getEncodedValue() );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifControl1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifControl ldifControl2 = new LdifControl();
+        ldifControl2.readExternal( in );
+
+        assertEquals( ldifControl1, ldifControl2 );
+    }
+
+
+    @Test
+    public void testControlNoCriticalNoDataSerialization() throws IOException, ClassNotFoundException
+    {
+        LdifControl ldifControl1 = new LdifControl( controlNoCriticalNoData.getOid() );
+        ldifControl1.setCritical( controlNoCriticalNoData.isCritical() );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifControl1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifControl ldifControl2 = new LdifControl();
+        ldifControl2.readExternal( in );
+
+        assertEquals( ldifControl1, ldifControl2 );
+    }
+
+
+    @Test
+    public void testControlNoCriticalEmptyDataSerialization() throws IOException, ClassNotFoundException
+    {
+        LdifControl ldifControl1 = new LdifControl( controlNoCriticalEmptyData.getOid() );
+        ldifControl1.setCritical( controlNoCriticalEmptyData.isCritical() );
+        ldifControl1.setValue( ( ( OpaqueControl ) controlNoCriticalEmptyData ).getEncodedValue() );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifControl1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifControl ldifControl2 = new LdifControl();
+        ldifControl2.readExternal( in );
+
+        assertEquals( ldifControl1, ldifControl2 );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntrySerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntrySerializationTest.java
new file mode 100644
index 0000000..70baae6
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntrySerializationTest.java
@@ -0,0 +1,542 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the LdifEntry class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifEntrySerializationTest
+{
+    @Test
+    public void testLdifEntrySimple() throws Exception
+    {
+        String ldif =
+            "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a simple LdifEntry
+     * @throws Exception
+     */
+    @Test
+    public void testSimpleLdifEntry() throws Exception
+    {
+        String ldif =
+            "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Delete changeType LdifEntry with no control
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserChangeTypeDeleteNoControl() throws Exception
+    {
+        String ldif =
+            "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "changetype: delete\n";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Delete changeType LdifEntry with one control
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserChangeTypeDeleteWithControl() throws Exception
+    {
+        String ldif =
+            "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: delete\n";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Delete changeType LdifEntry with controls
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserChangeTypeDeleteWithControls() throws Exception
+    {
+        String ldif =
+            "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: delete\n";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Add changeType LdifEntry with no control
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeAddNoControl() throws Exception
+    {
+        String ldif =
+            "changetype: add\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Add changeType LdifEntry with a control
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeAddWithControl() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: add\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Add changeType LdifEntry with controls
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeAddWithControls() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: add\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with no control
+     */
+    @Test
+    public void testLdifEntryChangeTypeModDnNoControl() throws Exception
+    {
+        String ldif =
+            "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with no control and a newSuperior
+     */
+    @Test
+    public void testLdifEntryChangeTypeModDnRenameNoControlNewSuperior() throws Exception
+    {
+        String ldif =
+            "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n" +
+                "newsuperior: dc=example, dc=com";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with a control
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeModdnWithControl() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a ModDN changeType LdifEntry with controls
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeModddnWithControls() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no control
+     */
+    @Test
+    public void testLdifEntryChangeTypeModifySimple() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "add: cn\n" +
+                "cn: v1\n" +
+                "cn: v2\n" +
+                "-";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no attributes
+     */
+    @Test
+    public void testLdifEntryChangeTypeModifyNoAttribute() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "add: cn\n" +
+                "-";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no attributes and controls
+     */
+    @Test
+    public void testLdifEntryChangeTypeModifyNoAttributeWithControls() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: modify\n" +
+                "add: cn\n" +
+                "-";
+
+        LdifEntry ldifEntry1 = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        ldifEntry1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        LdifEntry ldifEntry2 = new LdifEntry();
+        ldifEntry2.readExternal( in );
+
+        assertEquals( ldifEntry1, ldifEntry2 );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntryTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntryTest.java
new file mode 100644
index 0000000..c00b3cf
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifEntryTest.java
@@ -0,0 +1,702 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.ldif.ChangeType;
+import org.apache.directory.api.ldap.model.ldif.LdapLdifException;
+import org.apache.directory.api.ldap.model.ldif.LdifControl;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the LdifEntry class
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifEntryTest
+{
+    /**
+     * Check that we can't create an empty LdifEntry
+     */
+    @Test(expected = LdapInvalidAttributeValueException.class)
+    public void testLdifEntryEmpty() throws Exception
+    {
+        new LdifEntry( "", "" );
+    }
+
+
+    /**
+     * Check that we can create an LdifEntry with an Empty Dn
+     */
+    @Test
+    public void testLdifEntryEmptyDn() throws Exception
+    {
+        Entry entry = new DefaultEntry( "", "cn: test" );
+        LdifEntry ldifEntry = new LdifEntry( "", "cn: test" );
+
+        assertNotNull( ldifEntry );
+        assertEquals( Dn.EMPTY_DN, ldifEntry.getDn() );
+        assertEquals( ChangeType.None, ldifEntry.getChangeType() );
+        assertEquals( entry, ldifEntry.getEntry() );
+    }
+
+
+    /**
+     * Check that we can create an LdifEntry with a null Dn
+     */
+    @Test
+    public void testLdifEntryNullDn() throws Exception
+    {
+        Entry entry = new DefaultEntry( "", "cn: test" );
+        LdifEntry ldifEntry = new LdifEntry( ( Dn ) null, "cn: test" );
+
+        assertNotNull( ldifEntry );
+        assertEquals( Dn.EMPTY_DN, ldifEntry.getDn() );
+        assertEquals( ChangeType.None, ldifEntry.getChangeType() );
+        assertEquals( entry, ldifEntry.getEntry() );
+    }
+
+
+    /**
+     * Test a simple LdifEntry
+     * @throws Exception
+     */
+    @Test
+    public void testSimpleLdifEntry() throws Exception
+    {
+        String cn = "app1";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org",
+            "cn", cn,
+            "objectClass: top",
+            "objectClass: apApplication",
+            "displayName:   app1   ",
+            "dependencies:",
+            "envVars:" );
+
+        assertNotNull( ldifEntry );
+        assertTrue( ldifEntry.isLdifContent() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+
+        Attribute attr = ldifEntry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        Attribute cnAttr = ldifEntry.get( "cn" );
+        assertTrue( cnAttr.contains( "app1" ) );
+    }
+
+
+    /**
+     * Test a Delete changeType LdifEntry with no control
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserChangeTypeDeleteNoControl() throws Exception
+    {
+        String ldif =
+            "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "changetype: delete\n";
+
+        LdifEntry ldifEntry = new LdifEntry( "ou=Product Development, dc=airius, dc=com", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Delete, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "ou=Product Development, dc=airius, dc=com", ldifEntry.getDn().getName() );
+        assertFalse( ldifEntry.hasControls() );
+    }
+
+
+    /**
+     * Test a Delete changeType LdifEntry with no control and following Attrs :
+     * should get an exception
+     * 
+     * @throws Exception
+     */
+    @Test(expected = LdapLdifException.class)
+    public void testLdifParserChangeTypeDeleteNoControlAttribute() throws Exception
+    {
+        String ldif =
+            "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "changetype: delete\n" +
+                "cn: bad !!\n";
+
+        new LdifEntry( "ou=Product Development, dc=airius, dc=com", ldif );
+    }
+
+
+    /**
+     * Test a Delete changeType LdifEntry with one control
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserChangeTypeDeleteWithControl() throws Exception
+    {
+        String ldif =
+            "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: delete\n";
+
+        LdifEntry ldifEntry = new LdifEntry( "ou=Product Development, dc=airius, dc=com", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Delete, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "ou=Product Development, dc=airius, dc=com", ldifEntry.getDn().getName() );
+        assertTrue( ldifEntry.hasControls() );
+
+        LdifControl ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.805" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.805", ldifControl.getOid() );
+        assertTrue( ldifControl.isCritical() );
+        assertNull( ldifControl.getValue() );
+    }
+
+
+    /**
+     * Test a Delete changeType LdifEntry with controls
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserChangeTypeDeleteWithControls() throws Exception
+    {
+        String ldif =
+            "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: delete\n";
+
+        LdifEntry ldifEntry = new LdifEntry( "ou=Product Development, dc=airius, dc=com", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Delete, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "ou=Product Development, dc=airius, dc=com", ldifEntry.getDn().getName() );
+        assertTrue( ldifEntry.hasControls() );
+
+        LdifControl ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.805" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.805", ldifControl.getOid() );
+        assertTrue( ldifControl.isCritical() );
+        assertNull( ldifControl.getValue() );
+
+        ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.806" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.806", ldifControl.getOid() );
+        assertFalse( ldifControl.isCritical() );
+        assertNotNull( ldifControl.getValue() );
+        assertEquals( "test", Strings.utf8ToString( ldifControl.getValue() ) );
+    }
+
+
+    /**
+     * Test a Add changeType LdifEntry with no control
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeAddNoControl() throws Exception
+    {
+        String ldif =
+            "changetype: add\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Add, ldifEntry.getChangeType() );
+        assertNotNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertFalse( ldifEntry.hasControls() );
+        assertTrue( ldifEntry.isLdifChange() );
+
+        Attribute attr = ldifEntry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+    }
+
+
+    /**
+     * Test a Add changeType LdifEntry with a control
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeAddWithControl() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: add\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Add, ldifEntry.getChangeType() );
+        assertNotNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertTrue( ldifEntry.isLdifChange() );
+
+        Attribute attr = ldifEntry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+        assertTrue( ldifEntry.hasControls() );
+
+        LdifControl ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.805" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.805", ldifControl.getOid() );
+        assertTrue( ldifControl.isCritical() );
+        assertNull( ldifControl.getValue() );
+    }
+
+
+    /**
+     * Test a Add changeType LdifEntry with controls
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeAddWithControls() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: add\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Add, ldifEntry.getChangeType() );
+        assertNotNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertTrue( ldifEntry.isLdifChange() );
+
+        Attribute attr = ldifEntry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+        assertTrue( ldifEntry.hasControls() );
+
+        LdifControl ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.805" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.805", ldifControl.getOid() );
+        assertTrue( ldifControl.isCritical() );
+        assertNull( ldifControl.getValue() );
+
+        ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.806" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.806", ldifControl.getOid() );
+        assertFalse( ldifControl.isCritical() );
+        assertNotNull( ldifControl.getValue() );
+        assertEquals( "test", Strings.utf8ToString( ldifControl.getValue() ) );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with no control
+     */
+    @Test
+    public void testLdifEntryChangeTypeModDnNoControl() throws Exception
+    {
+        String ldif =
+            "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.ModDn, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertFalse( ldifEntry.hasControls() );
+        assertTrue( ldifEntry.isLdifChange() );
+        assertEquals( "cn=app2", ldifEntry.getNewRdn() );
+        assertTrue( ldifEntry.isDeleteOldRdn() );
+        assertNull( ldifEntry.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with no newRdn
+     */
+    @Test(expected = LdapLdifException.class)
+    public void testLdifEntryChangeTypeModDnNoNewRdn() throws Exception
+    {
+        String ldif =
+            "changetype: moddn\n" +
+                "deleteoldrdn: 1\n";
+
+        new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with no deleteOldRdn flag
+     */
+    @Test(expected = LdapLdifException.class)
+    public void testLdifEntryChangeTypeModDnNoDeleteOldRdn() throws Exception
+    {
+        String ldif =
+            "changetype: moddn\n" +
+                "newrdn: cn=app2\n";
+
+        new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with no control and a newSuperior
+     */
+    @Test
+    public void testLdifEntryChangeTypeModDnRenameNoControlNewSuperior() throws Exception
+    {
+        String ldif =
+            "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n" +
+                "newsuperior: dc=example, dc=com";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.ModDn, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertFalse( ldifEntry.hasControls() );
+        assertTrue( ldifEntry.isLdifChange() );
+        assertEquals( "cn=app2", ldifEntry.getNewRdn() );
+        assertTrue( ldifEntry.isDeleteOldRdn() );
+        assertEquals( "dc=example, dc=com", ldifEntry.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a ModDn changeType LdifEntry with a control
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeModdnWithControl() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.ModDn, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertTrue( ldifEntry.isLdifChange() );
+        assertEquals( "cn=app2", ldifEntry.getNewRdn() );
+        assertNull( ldifEntry.getNewSuperior() );
+        assertTrue( ldifEntry.isDeleteOldRdn() );
+
+        assertTrue( ldifEntry.hasControls() );
+
+        LdifControl ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.805" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.805", ldifControl.getOid() );
+        assertTrue( ldifControl.isCritical() );
+        assertNull( ldifControl.getValue() );
+    }
+
+
+    /**
+     * Test a ModDN changeType LdifEntry with controls
+     * @throws Exception
+     */
+    @Test
+    public void testLdifEntryChangeTypeModddnWithControls() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: moddn\n" +
+                "newrdn: cn=app2\n" +
+                "deleteoldrdn: 1\n";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.ModDn, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertTrue( ldifEntry.isLdifChange() );
+        assertEquals( "cn=app2", ldifEntry.getNewRdn() );
+        assertTrue( ldifEntry.isDeleteOldRdn() );
+        assertNull( ldifEntry.getNewSuperior() );
+        assertTrue( ldifEntry.hasControls() );
+
+        LdifControl ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.805" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.805", ldifControl.getOid() );
+        assertTrue( ldifControl.isCritical() );
+        assertNull( ldifControl.getValue() );
+
+        ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.806" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.806", ldifControl.getOid() );
+        assertFalse( ldifControl.isCritical() );
+        assertNotNull( ldifControl.getValue() );
+        assertEquals( "test", Strings.utf8ToString( ldifControl.getValue() ) );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no control
+     */
+    @Test
+    public void testLdifEntryChangeTypeModifySimple() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "add: cn\n" +
+                "cn: v1\n" +
+                "cn: v2\n" +
+                "-";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Modify, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertFalse( ldifEntry.hasControls() );
+        assertTrue( ldifEntry.isLdifChange() );
+
+        // Check the modification
+        assertNotNull( ldifEntry.getModifications() );
+
+        for ( Modification modification : ldifEntry.getModifications() )
+        {
+            assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+            Attribute attribute = modification.getAttribute();
+
+            assertNotNull( attribute );
+            assertEquals( "cn", attribute.getId() );
+            assertTrue( attribute.contains( "v1", "v2" ) );
+
+        }
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no end separator ("-")
+     */
+    @Test(expected = LdapLdifException.class)
+    public void testLdifEntryChangeTypeModifyNoEndSeparator() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "add: cn\n" +
+                "cn: v1\n" +
+                "cn: v2\n";
+
+        new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no operation
+     */
+    @Test(expected = LdapLdifException.class)
+    public void testLdifEntryChangeTypeModifyNoOperator() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "cn: v1\n" +
+                "dn: v2\n" +
+                "-";
+
+        new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no attributes
+     */
+    @Test
+    public void testLdifEntryChangeTypeModifyNoAttribute() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "add: cn\n" +
+                "-";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Modify, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertFalse( ldifEntry.hasControls() );
+        assertTrue( ldifEntry.isLdifChange() );
+
+        // Check the modification
+        assertNotNull( ldifEntry.getModifications() );
+
+        for ( Modification modification : ldifEntry.getModifications() )
+        {
+            assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+            Attribute attribute = modification.getAttribute();
+
+            assertNotNull( attribute );
+            assertEquals( "cn", attribute.getId() );
+            assertNotNull( attribute.get() );
+            assertTrue( attribute.get().isNull() );
+        }
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with a different attribute used
+     */
+    @Test(expected = LdapLdifException.class)
+    public void testLdifEntryChangeTypeModifyNotSameAttr() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "add: cn\n" +
+                "sn: v1\n" +
+                "sn: v2\n" +
+                "-";
+
+        new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with a different attribute used
+     */
+    @Test(expected = LdapLdifException.class)
+    public void testLdifEntryChangeTypeModifyNotSameAttr2() throws Exception
+    {
+        String ldif =
+            "changetype: modify\n" +
+                "add: cn\n" +
+                "cn: v1\n" +
+                "sn: v2\n" +
+                "-";
+
+        new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+    }
+
+
+    /**
+     * Test a Modify changeType LdifEntry with no attributes and controls
+     */
+    @Test
+    public void testLdifEntryChangeTypeModifyNoAttributeWithControls() throws Exception
+    {
+        String ldif =
+            "control: 1.2.840.113556.1.4.805 true\n" +
+                "control: 1.2.840.113556.1.4.806 false: test\n" +
+                "changetype: modify\n" +
+                "add: cn\n" +
+                "-";
+
+        LdifEntry ldifEntry = new LdifEntry( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldif );
+
+        assertNotNull( ldifEntry );
+        assertEquals( ChangeType.Modify, ldifEntry.getChangeType() );
+        assertNull( ldifEntry.getEntry() );
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", ldifEntry.getDn().getName() );
+        assertTrue( ldifEntry.isLdifChange() );
+
+        // Check the modification
+        assertNotNull( ldifEntry.getModifications() );
+
+        for ( Modification modification : ldifEntry.getModifications() )
+        {
+            assertEquals( ModificationOperation.ADD_ATTRIBUTE, modification.getOperation() );
+            Attribute attribute = modification.getAttribute();
+
+            assertNotNull( attribute );
+            assertEquals( "cn", attribute.getId() );
+            assertEquals( 1, attribute.size() );
+            assertTrue( attribute.get().isNull() );
+        }
+
+        assertTrue( ldifEntry.hasControls() );
+
+        LdifControl ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.805" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.805", ldifControl.getOid() );
+        assertTrue( ldifControl.isCritical() );
+        assertNull( ldifControl.getValue() );
+
+        ldifControl = ldifEntry.getControl( "1.2.840.113556.1.4.806" );
+        assertNotNull( ldifControl );
+        assertEquals( "1.2.840.113556.1.4.806", ldifControl.getOid() );
+        assertFalse( ldifControl.isCritical() );
+        assertNotNull( ldifControl.getValue() );
+        assertEquals( "test", Strings.utf8ToString( ldifControl.getValue() ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifReaderTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifReaderTest.java
new file mode 100644
index 0000000..f3ebb55
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifReaderTest.java
@@ -0,0 +1,2515 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the LdifReader class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifReaderTest
+{
+    private static byte[] data;
+
+    private static File HJENSEN_JPEG_FILE = null;
+    private static File FIONA_JPEG_FILE = null;
+
+
+    private static File createFile( String name, byte[] data ) throws IOException
+    {
+        File jpeg = File.createTempFile( name, "jpg" );
+
+        jpeg.createNewFile();
+
+        DataOutputStream os = new DataOutputStream( new FileOutputStream( jpeg ) );
+
+        os.write( data );
+        os.close();
+
+        // This file will be deleted when the JVM
+        // will exit.
+        jpeg.deleteOnExit();
+
+        return jpeg;
+    }
+
+
+    /**
+     * Create a file to be used by ":<" values
+     */
+    @BeforeClass
+    public static void setUp() throws Exception
+    {
+        data = new byte[256];
+
+        for ( int i = 0; i < 256; i++ )
+        {
+            data[i] = ( byte ) i;
+        }
+
+        HJENSEN_JPEG_FILE = createFile( "hjensen", data );
+        FIONA_JPEG_FILE = createFile( "fiona", data );
+    }
+
+
+    @Test
+    public void testLdifNull() throws Exception
+    {
+        String ldif = null;
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+
+        assertEquals( 0, entries.size() );
+    }
+
+
+    @Test
+    public void testLdifEmpty() throws Exception
+    {
+        String ldif = "";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 0, entries.size() );
+    }
+
+
+    @Test
+    public void testLdifEmptyLines() throws Exception
+    {
+        String ldif = "\n\n\r\r\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 0, entries.size() );
+    }
+
+
+    @Test
+    public void testLdifComments() throws Exception
+    {
+        String ldif =
+            "#Comment 1\r" +
+                "#\r" +
+                " th\n" +
+                " is is still a comment\n" +
+                "\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 0, entries.size() );
+    }
+
+
+    @Test
+    public void testLdifVersion() throws Exception
+    {
+        String ldif =
+            "#Comment 1\r" +
+                "#\r" +
+                " th\n" +
+                " is is still a comment\n" +
+                "\n" +
+                "version:\n" +
+                " 1\n" +
+                "# end";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 0, entries.size() );
+        assertEquals( 1, reader.getVersion() );
+    }
+
+
+    @Test
+    public void testLdifVersionStart() throws Exception
+    {
+        String ldif =
+            "version:\n" +
+                " 1\n" +
+                "\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, reader.getVersion() );
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( ldif.length(), entry.getLengthBeforeParsing() );
+
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+    }
+
+
+    /**
+     * Test the ldif parser with a file without a version. It should default to 1
+     * @throws Exception
+     */
+    @Test
+    public void testLdifWithoutVersion() throws Exception
+    {
+        String ldif =
+            "#Comment 1\r" +
+                "#\r" +
+                " th\n" +
+                " is is still a comment\n" +
+                "\n" +
+                "# end";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 0, entries.size() );
+        assertEquals( 1, reader.getVersion() );
+    }
+
+
+    /**
+     * Spaces at the end of values should not be included into values.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserEndSpaces() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+    }
+
+
+    @Test
+    public void testLdifParserAddAttrCaseInsensitiveAttrId() throws Exception
+    {
+        // test that mixed case attr ids work at all
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: modify\n" +
+                "add: administrativeRole\n" +
+                "administrativeRole: accessControlSpecificArea\n" +
+                "-";
+
+        testReaderAttrIdCaseInsensitive( ldif );
+
+        // test that attr id comparisons are case insensitive and that the version in the add: line is used.
+        // See DIRSERVER-1029 for some discussion.
+        ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: modify\n" +
+                "add: administrativeRole\n" +
+                "administrativerole: accessControlSpecificArea\n" +
+                "-";
+
+        testReaderAttrIdCaseInsensitive( ldif );
+    }
+
+
+    private void testReaderAttrIdCaseInsensitive( String ldif ) throws Exception
+    {
+        LdifReader reader = new LdifReader();
+
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        assertNotNull( entries );
+        reader.close();
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertTrue( entry.isChangeModify() );
+
+        assertEquals( "dc=example,dc=com", entry.getDn().getName() );
+
+        List<Modification> mods = entry.getModifications();
+        assertTrue( mods.size() == 1 );
+        Attribute attr = mods.get( 0 ).getAttribute();
+        assertTrue( attr.getId().equals( "administrativerole" ) );
+        assertEquals( attr.getString(), "accessControlSpecificArea" );
+    }
+
+
+    /**
+     * Changes and entries should not be mixed
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserCombinedEntriesChanges() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:\n" +
+                "\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception ne )
+        {
+            assertTrue( true );
+        }
+        finally
+        {
+            reader.close();
+        }
+    }
+
+
+    /**
+     * Changes and entries should not be mixed
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserCombinedEntriesChanges2() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:\n" +
+                "\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception ne )
+        {
+            assertTrue( true );
+        }
+        finally
+        {
+            reader.close();
+        }
+    }
+
+
+    /**
+     * Changes and entries should not be mixed
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserCombinedChangesEntries() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: delete\n" +
+                "\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:\n";
+
+        LdifReader reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception ne )
+        {
+            assertTrue( true );
+        }
+        finally
+        {
+            reader.close();
+        }
+    }
+
+
+    /**
+     * Changes and entries should not be mixed
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserCombinedChangesEntries2() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "changetype: delete\n" +
+                "\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:\n";
+
+        LdifReader reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception ne )
+        {
+            assertTrue( true );
+        }
+        finally
+        {
+            reader.close();
+        }
+    }
+
+
+    @Test
+    public void testLdifParser() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName: app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserMuiltiLineComments() throws Exception
+    {
+        String ldif =
+            "#comment\n" +
+                " still a comment\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1#another comment\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName: app1\n" +
+                "serviceType: http\n" +
+                "dependencies:\n" +
+                "httpHeaders:\n" +
+                "startupOptions:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "app1#another comment" ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserMultiLineEntries() throws Exception
+    {
+        String ldif =
+            "#comment\n" +
+                "dn: cn=app1,ou=appli\n" +
+                " cations,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1#another comment\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName: app1\n" +
+                "serviceType: http\n" +
+                "dependencies:\n" +
+                "httpHeaders:\n" +
+                "startupOptions:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "app1#another comment" ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserBase64() throws Exception, UnsupportedEncodingException
+    {
+        String ldif =
+            "#comment\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn:: RW1tYW51ZWwgTMOpY2hhcm55\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName: app1\n" +
+                "serviceType: http\n" +
+                "dependencies:\n" +
+                "httpHeaders:\n" +
+                "startupOptions:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Emmanuel L\u00e9charny".getBytes( "UTF-8" ) ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserBase64MultiLine() throws Exception, UnsupportedEncodingException
+    {
+        String ldif =
+            "#comment\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn:: RW1tYW51ZWwg\n" +
+                " TMOpY2hhcm55ICA=\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName: app1\n" +
+                "serviceType: http\n" +
+                "dependencies:\n" +
+                "httpHeaders:\n" +
+                "startupOptions:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=app1,ou=applications,ou=conf,dc=apache,dc=org", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Emmanuel L\u00e9charny  ".getBytes( "UTF-8" ) ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample1() throws Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Barbara Jensen\n" +
+                "cn: Barbara J Jensen\n" +
+                "cn: Babs Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: bjensen\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "description: A big sailing fan.\n" +
+                "\n" +
+                "dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Bjorn Jensen\n" +
+                "sn: Jensen\n" +
+                "telephonenumber: +1 408 555 1212";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 2, entries.size() );
+
+        // Entry 1
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Barbara Jensen" ) );
+        assertTrue( attr.contains( "Barbara J Jensen" ) );
+        assertTrue( attr.contains( "Babs Jensen" ) );
+
+        attr = entry.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = entry.get( "uid" );
+        assertTrue( attr.contains( "bjensen" ) );
+
+        attr = entry.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = entry.get( "description" );
+        assertTrue( attr.contains( "A big sailing fan." ) );
+
+        // Entry 2
+        entry = entries.get( 1 );
+        assertTrue( entry.isLdifContent() );
+
+        attr = entry.get( "dn" );
+        assertEquals( "cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com", entry.getDn().getName() );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Bjorn Jensen" ) );
+
+        attr = entry.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = entry.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample2() throws Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Barbara Jensen\n" +
+                "cn: Barbara J Jensen\n" +
+                "cn: Babs Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: bjensen\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "description:Babs is a big sailing fan, and travels extensively in sea\n" +
+                " rch of perfect sailing conditions.\n" +
+                "title:Product Manager, Rod and Reel Division";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry 1
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Barbara Jensen" ) );
+        assertTrue( attr.contains( "Barbara J Jensen" ) );
+        assertTrue( attr.contains( "Babs Jensen" ) );
+
+        attr = entry.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = entry.get( "uid" );
+        assertTrue( attr.contains( "bjensen" ) );
+
+        attr = entry.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = entry.get( "description" );
+        assertTrue( attr
+            .contains( "Babs is a big sailing fan, and travels extensively in search of perfect sailing conditions." ) );
+
+        attr = entry.get( "title" );
+        assertTrue( attr.contains( "Product Manager, Rod and Reel Division" ) );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample3() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "dn: cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Gern Jensen\n" +
+                "cn: Gern O Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: gernj\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl\n" +
+                " IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG\n" +
+                " VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg\n" +
+                " b3V0IG1vcmUu";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry 1
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Gern Jensen" ) );
+        assertTrue( attr.contains( "Gern O Jensen" ) );
+
+        attr = entry.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = entry.get( "uid" );
+        assertTrue( attr.contains( "gernj" ) );
+
+        attr = entry.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = entry.get( "description" );
+        assertTrue( attr
+            .contains( "What a careful reader you are!  This value is base-64-encoded because it has a control character in it (a CR).\r  By the way, you should really get out more."
+                .getBytes( "UTF-8" ) ) );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample3VariousSpacing() throws Exception, Exception
+    {
+        String ldif =
+            "version:1\n" +
+                "dn:cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com  \n" +
+                "objectclass:top\n" +
+                "objectclass:   person   \n" +
+                "objectclass:organizationalPerson\n" +
+                "cn:Gern Jensen\n" +
+                "cn:Gern O Jensen\n" +
+                "sn:Jensen\n" +
+                "uid:gernj\n" +
+                "telephonenumber:+1 408 555 1212  \n" +
+                "description::  V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl\n" +
+                " IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG\n" +
+                " VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg\n" +
+                " b3V0IG1vcmUu  ";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry 1
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "person" ) );
+        assertTrue( attr.contains( "organizationalPerson" ) );
+
+        attr = entry.get( "cn" );
+        assertTrue( attr.contains( "Gern Jensen" ) );
+        assertTrue( attr.contains( "Gern O Jensen" ) );
+
+        attr = entry.get( "sn" );
+        assertTrue( attr.contains( "Jensen" ) );
+
+        attr = entry.get( "uid" );
+        assertTrue( attr.contains( "gernj" ) );
+
+        attr = entry.get( "telephonenumber" );
+        assertTrue( attr.contains( "+1 408 555 1212" ) );
+
+        attr = entry.get( "description" );
+        assertTrue( attr
+            .contains( "What a careful reader you are!  This value is base-64-encoded because it has a control character in it (a CR).\r  By the way, you should really get out more."
+                .getBytes( "UTF-8" ) ) );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample4() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n"
+                +
+                "dn:: b3U95Za25qWt6YOoLG89QWlyaXVz\n"
+                +
+                "# dn:: ou=���������,o=Airius\n"
+                +
+                "objectclass: top\n"
+                +
+                "objectclass: organizationalUnit\n"
+                +
+                "ou:: 5Za25qWt6YOo\n"
+                +
+                "# ou:: ���������\n"
+                +
+                "ou;lang-ja:: 5Za25qWt6YOo\n"
+                +
+                "# ou;lang-ja:: ���������\n"
+                +
+                "ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2\n"
+                +
+                "# ou;lang-ja:: ������������������\n"
+                +
+                "ou;lang-en: Sales\n"
+                +
+                "description: Japanese office\n"
+                +
+                "\n"
+                +
+                "dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz\n"
+                +
+                "# dn:: uid=rogasawara,ou=���������,o=Airius\n"
+                +
+                "userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=\n"
+                +
+                "objectclass: top\n"
+                +
+                "objectclass: person\n"
+                +
+                "objectclass: organizationalPerson\n"
+                +
+                "objectclass: inetOrgPerson\n"
+                +
+                "uid: rogasawara\n"
+                +
+                "mail: rogasawara@airius.co.jp\n"
+                +
+                "givenname;lang-ja:: 44Ot44OJ44OL44O8\n"
+                +
+                "# givenname;lang-ja:: ������������\n"
+                +
+                "sn;lang-ja:: 5bCP56yg5Y6f\n"
+                +
+                "# sn;lang-ja:: ���������\n"
+                +
+                "cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==\n"
+                +
+                "# cn;lang-ja:: ��������� ������������\n"
+                +
+                "title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==\n"
+                +
+                "# title;lang-ja:: ��������� ������\n"
+                +
+                "preferredlanguage: ja\n"
+                +
+                "givenname:: 44Ot44OJ44OL44O8\n"
+                +
+                "# givenname:: ������������\n"
+                +
+                "sn:: 5bCP56yg5Y6f\n"
+                +
+                "# sn:: ���������\n"
+                +
+                "cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==\n"
+                +
+                "# cn:: ��������� ������������\n"
+                +
+                "title:: 5Za25qWt6YOoIOmDqOmVtw==\n"
+                +
+                "# title:: ��������� ������\n"
+                +
+                "givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8\n"
+                +
+                "# givenname;lang-ja;phonetic:: ������������\n"
+                +
+                "sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ\n"
+                +
+                "# sn;lang-ja;phonetic:: ���������������\n"
+                +
+                "cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==\n"
+                +
+                "# cn;lang-ja;phonetic:: ��������������� ������������\n"
+                +
+                "title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==\n" +
+                "# title;lang-ja;phonetic::\n" +
+                "# ������������������ ������������\n" +
+                "givenname;lang-en: Rodney\n" +
+                "sn;lang-en: Ogasawara\n" +
+                "cn;lang-en: Rodney Ogasawara\n" +
+                "title;lang-en: Sales, Director\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        String[][][] values =
+            {
+                {
+                    { "dn", "ou=\u55b6\u696d\u90e8,o=Airius" }, // 55b6 = ���, 696d = ���, 90e8 = ���
+                        { "objectclass", "top" },
+                        { "objectclass", "organizationalUnit" },
+                        { "ou", "\u55b6\u696d\u90e8" },
+                        { "ou;lang-ja", "\u55b6\u696d\u90e8" },
+                        { "ou;lang-ja;phonetic", "\u3048\u3044\u304e\u3087\u3046\u3076" }, // 3048 = ���, 3044 = ���, 304e = ���
+                        // 3087 = ���, 3046 = ���, 3076 = ���
+                        { "ou;lang-en", "Sales" },
+                        { "description", "Japanese office" } },
+                {
+                    { "dn", "uid=rogasawara,ou=\u55b6\u696d\u90e8,o=Airius" },
+                    { "userpassword", "{SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=" },
+                    { "objectclass", "top" },
+                    { "objectclass", "person" },
+                    { "objectclass", "organizationalPerson" },
+                    { "objectclass", "inetOrgPerson" },
+                    { "uid", "rogasawara" },
+                    { "mail", "rogasawara@airius.co.jp" },
+                    { "givenname;lang-ja", "\u30ed\u30c9\u30cb\u30fc" }, // 30ed = ���, 30c9 = ���, 30cb = ���, 30fc = ���
+                        { "sn;lang-ja", "\u5c0f\u7b20\u539f" }, // 5c0f = ���, 7b20 = ���, 539f = ���
+                        { "cn;lang-ja", "\u5c0f\u7b20\u539f \u30ed\u30c9\u30cb\u30fc" },
+                        { "title;lang-ja", "\u55b6\u696d\u90e8 \u90e8\u9577" }, // 9577 = ���
+                        { "preferredlanguage", "ja" },
+                        { "givenname", "\u30ed\u30c9\u30cb\u30fc" },
+                        { "sn", "\u5c0f\u7b20\u539f" },
+                        { "cn", "\u5c0f\u7b20\u539f \u30ed\u30c9\u30cb\u30fc" },
+                        { "title", "\u55b6\u696d\u90e8 \u90e8\u9577" },
+                        { "givenname;lang-ja;phonetic", "\u308d\u3069\u306b\u30fc" }, // 308d = ���,3069 = ���, 306b = ���
+                        { "sn;lang-ja;phonetic", "\u304a\u304c\u3055\u308f\u3089" }, // 304a = ���, 304c = ���,3055 = ���,308f = ���, 3089 = ���
+                        { "cn;lang-ja;phonetic", "\u304a\u304c\u3055\u308f\u3089 \u308d\u3069\u306b\u30fc" },
+                        { "title;lang-ja;phonetic", "\u3048\u3044\u304e\u3087\u3046\u3076 \u3076\u3061\u3087\u3046" }, // 304E = ���, 3061 = ���
+                        { "givenname;lang-en", "Rodney" },
+                        { "sn;lang-en", "Ogasawara" },
+                        { "cn;lang-en", "Rodney Ogasawara" },
+                        { "title;lang-en", "Sales, Director" } } };
+
+        assertEquals( 2, entries.size() );
+
+        // Entry 1
+        for ( int i = 0; i < entries.size(); i++ )
+        {
+            LdifEntry entry = entries.get( i );
+            assertTrue( entry.isLdifContent() );
+
+            for ( int j = 0; j < values[i].length; j++ )
+            {
+                if ( "dn".equalsIgnoreCase( values[i][j][0] ) )
+                {
+                    assertEquals( values[i][j][1], entry.getDn().getName() );
+                }
+                else
+                {
+                    Attribute attr = entry.get( values[i][j][0] );
+
+                    if ( attr.contains( values[i][j][1] ) )
+                    {
+                        assertTrue( true );
+                    }
+                    else
+                    {
+                        assertTrue( attr.contains( values[i][j][1].getBytes( "UTF-8" ) ) );
+                    }
+                }
+            }
+        }
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample5() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Horatio Jensen\n" +
+                "cn: Horatio N Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: hjensen\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "jpegphoto:< file:" +
+                HJENSEN_JPEG_FILE.getAbsolutePath() +
+                "\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        String[][] values =
+            {
+                { "dn", "cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com" },
+                { "objectclass", "top" },
+                { "objectclass", "person" },
+                { "objectclass", "organizationalPerson" },
+                { "cn", "Horatio Jensen" },
+                { "cn", "Horatio N Jensen" },
+                { "sn", "Jensen" },
+                { "uid", "hjensen" },
+                { "telephonenumber", "+1 408 555 1212" },
+                { "jpegphoto", null } };
+
+        assertEquals( 1, entries.size() );
+
+        // Entry 1
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        for ( int i = 0; i < values.length; i++ )
+        {
+            if ( "dn".equalsIgnoreCase( values[i][0] ) )
+            {
+                assertEquals( values[i][1], entry.getDn().getName() );
+            }
+            else if ( "jpegphoto".equalsIgnoreCase( values[i][0] ) )
+            {
+                Attribute attr = entry.get( values[i][0] );
+                assertEquals( Strings.dumpBytes( data ), Strings.dumpBytes( attr.getBytes() ) );
+            }
+            else
+            {
+                Attribute attr = entry.get( values[i][0] );
+
+                if ( attr.contains( values[i][1] ) )
+                {
+                    assertTrue( true );
+                }
+                else
+                {
+                    assertTrue( attr.contains( values[i][1].getBytes( "UTF-8" ) ) );
+                }
+            }
+        }
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample5WithSizeLimit() throws Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Horatio Jensen\n" +
+                "cn: Horatio N Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: hjensen\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "jpegphoto:< file:" +
+                HJENSEN_JPEG_FILE.getAbsolutePath() +
+                "\n";
+
+        LdifReader reader = new LdifReader();
+        reader.setSizeLimit( 128 );
+        reader.close();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception ne )
+        {
+            assertTrue( I18n.err( I18n.ERR_12070 ), ne.getMessage().startsWith( I18n.ERR_12070.getErrorCode() ) );
+        }
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample6() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                // First entry modification : ADD
+                "# Add a new entry\n" +
+                "dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com\n" +
+                "changetype: add\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Fiona Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: fiona\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "jpegphoto:< file:" +
+                FIONA_JPEG_FILE.getAbsolutePath() +
+                "\n" +
+                "\n"
+                +
+                // Second entry modification : DELETE
+                "# Delete an existing entry\n" +
+                "dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com\n" +
+                "changetype: delete\n" +
+                "\n"
+                +
+                // Third entry modification : MODRDN
+                "# Modify an entry's relative distinguished name\n" +
+                "dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com\n" +
+                "changetype: modrdn\n" +
+                "newrdn: cn=Paula Jensen\n" +
+                "deleteoldrdn: 1\n" +
+                "\n"
+                +
+                // Forth entry modification : MODRDN
+                "# Rename an entry and move all of its children to a new location in\n" +
+                "# the directory tree (only implemented by LDAPv3 servers).\n" +
+                "dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com\n" +
+                "changetype: moddn\n" +
+                "newrdn: ou=Product Development Accountants\n" +
+                "deleteoldrdn: 0\n" +
+                "newsuperior: ou=Accounting, dc=airius, dc=com\n" +
+                "# Modify an entry: add an additional value to the postaladdress\n" +
+                "# attribute, completely delete the description attribute, replace\n" +
+                "# the telephonenumber attribute with two values, and delete a specific\n" +
+                "# value from the facsimiletelephonenumber attribute\n" +
+                "\n"
+                +
+                // Fitfh entry modification : MODIFY
+                "dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com\n" +
+                "changetype: modify\n" +
+                "add: postaladdress\n" +
+                "postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086\n" +
+                "-\n" +
+                "delete: description\n" +
+                "-\n" +
+                "replace: telephonenumber\n" +
+                "telephonenumber: +1 408 555 1234\n" +
+                "telephonenumber: +1 408 555 5678\n" +
+                "-\n" +
+                "delete: facsimiletelephonenumber\n" +
+                "facsimiletelephonenumber: +1 408 555 9876\n" +
+                "-\n" +
+                "\n"
+                +
+                // Sixth entry modification : MODIFY
+                "# Modify an entry: replace the postaladdress attribute with an empty\n" +
+                "# set of values (which will cause the attribute to be removed), and\n" +
+                "# delete the entire description attribute. Note that the first will\n" +
+                "# always succeed, while the second will only succeed if at least\n" +
+                "# one value for the description attribute is present.\n" +
+                "dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com\n" +
+                "changetype: modify\n" +
+                "replace: postaladdress\n" +
+                "-\n" +
+                "delete: description\n" +
+                "-\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        String[][][] values =
+            {
+                // First entry modification : ADD
+                {
+                    { "dn", "cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com" },
+                    { "objectclass", "top" },
+                    { "objectclass", "person" },
+                    { "objectclass", "organizationalPerson" },
+                    { "cn", "Fiona Jensen" },
+                    { "sn", "Jensen" },
+                    { "uid", "fiona" },
+                    { "telephonenumber", "+1 408 555 1212" },
+                    { "jpegphoto", "" } },
+                    // Second entry modification : DELETE
+                    {
+                        { "dn", "cn=Robert Jensen, ou=Marketing, dc=airius, dc=com" } },
+                    // Third entry modification : MODRDN
+                    {
+                        { "dn", "cn=Paul Jensen, ou=Product Development, dc=airius, dc=com" },
+                        { "cn=Paula Jensen" } },
+                    // Forth entry modification : MODRDN
+                    {
+                        { "dn", "ou=PD Accountants, ou=Product Development, dc=airius, dc=com" },
+                        { "ou=Product Development Accountants" },
+                        { "ou=Accounting, dc=airius, dc=com" } },
+                    // Fitfh entry modification : MODIFY
+                    {
+                        { "dn", "cn=Paula Jensen, ou=Product Development, dc=airius, dc=com" },
+                        // add
+                        { "postaladdress", "123 Anystreet $ Sunnyvale, CA $ 94086" },
+                            // delete
+                            { "description" },
+                            // replace
+                            { "telephonenumber", "+1 408 555 1234", "+1 408 555 5678" },
+                            // delete
+                            { "facsimiletelephonenumber", "+1 408 555 9876" }, },
+                    // Sixth entry modification : MODIFY
+                    {
+                        { "dn", "cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com" },
+                        // replace
+                        { "postaladdress" },
+                            // delete
+                            { "description" } } };
+
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isChangeAdd() );
+
+        for ( int i = 0; i < values.length; i++ )
+        {
+            if ( "dn".equalsIgnoreCase( values[0][i][0] ) )
+            {
+                assertEquals( values[0][i][1], entry.getDn().getName() );
+            }
+            else if ( "jpegphoto".equalsIgnoreCase( values[0][i][0] ) )
+            {
+                Attribute attr = entry.get( values[0][i][0] );
+                assertEquals( Strings.dumpBytes( data ), Strings.dumpBytes( attr.getBytes() ) );
+            }
+            else
+            {
+                Attribute attr = entry.get( values[0][i][0] );
+
+                if ( attr.contains( values[0][i][1] ) )
+                {
+                    assertTrue( true );
+                }
+                else
+                {
+                    assertTrue( attr.contains( values[0][i][1].getBytes( "UTF-8" ) ) );
+                }
+            }
+        }
+
+        // Second entry
+        entry = entries.get( 1 );
+        assertTrue( entry.isChangeDelete() );
+        assertEquals( values[1][0][1], entry.getDn().getName() );
+
+        // Third entry
+        entry = entries.get( 2 );
+        assertTrue( entry.isChangeModRdn() );
+        assertEquals( values[2][0][1], entry.getDn().getName() );
+        assertEquals( values[2][1][0], entry.getNewRdn() );
+        assertTrue( entry.isDeleteOldRdn() );
+
+        // Forth entry
+        entry = entries.get( 3 );
+        assertTrue( entry.isChangeModDn() );
+        assertEquals( values[3][0][1], entry.getDn().getName() );
+        assertEquals( values[3][1][0], entry.getNewRdn() );
+        assertFalse( entry.isDeleteOldRdn() );
+        assertEquals( values[3][2][0], entry.getNewSuperior() );
+
+        // Fifth entry
+        entry = entries.get( 4 );
+        List<Modification> modifs = entry.getModifications();
+
+        assertTrue( entry.isChangeModify() );
+        assertEquals( values[4][0][1], entry.getDn().getName() );
+
+        // "add: postaladdress"
+        // "postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086"
+        Modification item = modifs.get( 0 );
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, item.getOperation() );
+        assertEquals( values[4][1][0], item.getAttribute().getId() );
+        assertTrue( item.getAttribute().contains( values[4][1][1] ) );
+
+        // "delete: description\n" +
+        item = modifs.get( 1 );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, item.getOperation() );
+        assertEquals( values[4][2][0], item.getAttribute().getId() );
+
+        // "replace: telephonenumber"
+        // "telephonenumber: +1 408 555 1234"
+        // "telephonenumber: +1 408 555 5678"
+        item = modifs.get( 2 );
+        assertEquals( ModificationOperation.REPLACE_ATTRIBUTE, item.getOperation() );
+
+        assertEquals( values[4][3][0], item.getAttribute().getId() );
+        assertTrue( item.getAttribute().contains( values[4][3][1], values[4][3][2] ) );
+
+        // "delete: facsimiletelephonenumber"
+        // "facsimiletelephonenumber: +1 408 555 9876"
+        item = modifs.get( 3 );
+
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, item.getOperation() );
+
+        assertEquals( values[4][4][0], item.getAttribute().getId() );
+        assertTrue( item.getAttribute().contains( values[4][4][1] ) );
+
+        // Sixth entry
+        entry = entries.get( 5 );
+        modifs = entry.getModifications();
+
+        assertTrue( entry.isChangeModify() );
+        assertEquals( values[5][0][1], entry.getDn().getName() );
+
+        // "replace: postaladdress"
+        item = modifs.get( 0 );
+        assertEquals( ModificationOperation.REPLACE_ATTRIBUTE, item.getOperation() );
+        assertEquals( values[5][1][0], item.getAttribute().getId() );
+
+        // "delete: description"
+        item = modifs.get( 1 );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, item.getOperation() );
+        assertEquals( values[5][2][0], item.getAttribute().getId() );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample7() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "control: 1.2.840.113556.1.4.805 true\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "ou=Product Development, dc=airius, dc=com", entry.getDn().getName() );
+        assertTrue( entry.isChangeDelete() );
+
+        // Check the control
+        Control control = entry.getControl( "1.2.840.113556.1.4.805" );
+
+        assertEquals( "1.2.840.113556.1.4.805", control.getOid() );
+        assertTrue( control.isCritical() );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample7NoValueNoCritical() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "control: 1.2.840.113556.1.4.805\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "ou=Product Development, dc=airius, dc=com", entry.getDn().getName() );
+        assertTrue( entry.isChangeDelete() );
+
+        // Check the control
+        Control control = entry.getControl( "1.2.840.113556.1.4.805" );
+
+        assertEquals( "1.2.840.113556.1.4.805", control.getOid() );
+        assertFalse( control.isCritical() );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample7NoCritical() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "control: 1.2.840.113556.1.4.805:control-value\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "ou=Product Development, dc=airius, dc=com", entry.getDn().getName() );
+        assertTrue( entry.isChangeDelete() );
+
+        // Check the control
+        LdifControl control = entry.getControl( "1.2.840.113556.1.4.805" );
+
+        assertEquals( "1.2.840.113556.1.4.805", control.getOid() );
+        assertFalse( control.isCritical() );
+        assertEquals( "control-value", Strings.utf8ToString( control.getValue() ) );
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample7NoOid() throws Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "control: true\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception ne )
+        {
+            assertTrue( true );
+        }
+        finally
+        {
+            reader.close();
+        }
+    }
+
+
+    @Test
+    public void testLdifParserRFC2849Sample7BadOid() throws Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Delete an entry. The operation will attach the LDAPv3\n" +
+                "# Tree Delete Control defined in [9]. The criticality\n" +
+                "# field is \"true\" and the controlValue field is\n" +
+                "# absent, as required by [9].\n" +
+                "dn: ou=Product Development, dc=airius, dc=com\n" +
+                "control: 1.2.840.113A556.1.4.805 true\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception ne )
+        {
+            assertTrue( true );
+        }
+        finally
+        {
+            reader.close();
+        }
+    }
+
+
+    @Test
+    public void testLdifReaderDirServer() throws Exception, Exception
+    {
+        String ldif =
+            "# -------------------------------------------------------------------\n" +
+                "#\n" +
+                "#  Licensed to the Apache Software Foundation (ASF) under one\n" +
+                "#  or more contributor license agreements.  See the NOTICE file\n" +
+                "#  distributed with this work for additional information\n" +
+                "#  regarding copyright ownership.  The ASF licenses this file\n" +
+                "#  to you under the Apache License, Version 2.0 (the\n" +
+                "#  \"License\"); you may not use this file except in compliance\n" +
+                "#  with the License.  You may obtain a copy of the License at\n" +
+                "#  \n" +
+                "#    http://www.apache.org/licenses/LICENSE-2.0\n" +
+                "#  \n" +
+                "#  Unless required by applicable law or agreed to in writing,\n" +
+                "#  software distributed under the License is distributed on an\n" +
+                "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n" +
+                "#  KIND, either express or implied.  See the License for the\n" +
+                "#  specific language governing permissions and limitations\n" +
+                "#  under the License. \n" +
+                "#  \n" +
+                "#\n" +
+                "# EXAMPLE.COM is freely and reserved for testing according to this RFC:\n" +
+                "#\n" +
+                "# http://www.rfc-editor.org/rfc/rfc2606.txt\n" +
+                "#\n" +
+                "# -------------------------------------------------------------------\n" +
+                "\n" +
+                "dn: ou=Users, dc=example, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: organizationalunit\n" +
+                "ou: Users";
+
+        LdifReader reader = new LdifReader();
+
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "ou=Users, dc=example, dc=com", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "organizationalunit" ) );
+
+        attr = entry.get( "ou" );
+        assertTrue( attr.contains( "Users" ) );
+    }
+
+
+    @Test
+    public void testLdifParserCommentsEmptyLines() throws Exception, Exception
+    {
+        String ldif =
+            "#\n"
+                +
+                "#  Licensed to the Apache Software Foundation (ASF) under one\n"
+                +
+                "#  or more contributor license agreements.  See the NOTICE file\n"
+                +
+                "#  distributed with this work for additional information\n"
+                +
+                "#  regarding copyright ownership.  The ASF licenses this file\n"
+                +
+                "#  to you under the Apache License, Version 2.0 (the\n"
+                +
+                "#  \"License\"); you may not use this file except in compliance\n"
+                +
+                "#  with the License.  You may obtain a copy of the License at\n"
+                +
+                "#  \n"
+                +
+                "#    http://www.apache.org/licenses/LICENSE-2.0\n"
+                +
+                "#  \n"
+                +
+                "#  Unless required by applicable law or agreed to in writing,\n"
+                +
+                "#  software distributed under the License is distributed on an\n"
+                +
+                "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n"
+                +
+                "#  KIND, either express or implied.  See the License for the\n"
+                +
+                "#  specific language governing permissions and limitations\n"
+                +
+                "#  under the License. \n"
+                +
+                "#  \n"
+                +
+                "#\n"
+                +
+                "#\n"
+                +
+                "#   EXAMPLE.COM is freely and reserved for testing according to this RFC:\n"
+                +
+                "#\n"
+                +
+                "#   http://www.rfc-editor.org/rfc/rfc2606.txt\n"
+                +
+                "#\n"
+                +
+                "#\n"
+                +
+                "\n"
+                +
+                "#\n"
+                +
+                "# This ACI allows brouse access to the root suffix and one level below that to anyone.\n"
+                +
+                "# At this level there is nothing critical exposed.  Everything that matters is one or\n"
+                +
+                "# more levels below this.\n"
+                +
+                "#\n"
+                +
+                "\n"
+                +
+                "dn: cn=browseRootAci,dc=example,dc=com\n"
+                +
+                "objectClass: top\n"
+                +
+                "objectClass: subentry\n"
+                +
+                "objectClass: accessControlSubentry\n"
+                +
+                "subtreeSpecification: { maximum 1 }\n"
+                +
+                "prescriptiveACI: { identificationTag \"browseRoot\", precedence 100, authenticationLevel none, itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { protectedItems {entry}, grantsAndDenials { grantReturnDN, grantBrowse } } } } }\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "cn=browseRootAci,dc=example,dc=com", entry.getDn().getName() );
+        Attribute attr = entry.get( "objectClass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( SchemaConstants.SUBENTRY_OC ) );
+        assertTrue( attr.contains( "accessControlSubentry" ) );
+
+        attr = entry.get( "subtreeSpecification" );
+        assertTrue( attr.contains( "{ maximum 1 }" ) );
+
+        attr = entry.get( "prescriptiveACI" );
+        assertTrue( attr
+            .contains( "{ identificationTag \"browseRoot\", precedence 100, authenticationLevel none, itemOrUserFirst userFirst: { userClasses { allUsers }, userPermissions { { protectedItems {entry}, grantsAndDenials { grantReturnDN, grantBrowse } } } } }" ) );
+    }
+
+
+    @Test
+    public void testRemoveAttribute() throws Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Horatio Jensen\n" +
+                "cn: Horatio N Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: hjensen\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "jpegphoto:< file:" +
+                HJENSEN_JPEG_FILE.getAbsolutePath() +
+                "\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        LdifEntry entry = entries.get( 0 );
+
+        assertNotNull( entry.get( "uid" ) );
+        entry.removeAttribute( "uid" );
+        assertNull( entry.get( "uid" ) );
+    }
+
+
+    @Test
+    public void testChangeTypeAdd() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: add\n" +
+                "attr1: ATTR1\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "dc=example,dc=com", entry.getDn().getName() );
+
+        assertTrue( entry.isLdifChange() );
+        assertTrue( entry.isChangeAdd() );
+
+        assertEquals( 1, entry.getEntry().size() );
+
+        Attribute attr = entry.get( "attr1" );
+        assertTrue( attr.contains( "ATTR1" ) );
+    }
+
+
+    @Test
+    public void testChangeTypeAddAttrs2Values() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: add\n" +
+                "attr1: ATTR1\n" +
+                "attr1: ATTR2\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "dc=example,dc=com", entry.getDn().getName() );
+
+        assertTrue( entry.isLdifChange() );
+        assertTrue( entry.isChangeAdd() );
+
+        assertEquals( 1, entry.getEntry().size() );
+
+        Attribute attr = entry.get( "attr1" );
+        assertEquals( 2, attr.size() );
+        assertTrue( attr.contains( "ATTR1" ) );
+        assertTrue( attr.contains( "ATTR2" ) );
+    }
+
+
+    @Test
+    public void testChangeTypeAdd2Attrs2Values() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: add\n" +
+                "attr1: ATTR1\n" +
+                "attr1: ATTR2\n" +
+                "attr2: ATTR1\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "dc=example,dc=com", entry.getDn().getName() );
+
+        assertTrue( entry.isLdifChange() );
+        assertTrue( entry.isChangeAdd() );
+
+        assertEquals( 2, entry.getEntry().size() );
+
+        Attribute attr = entry.get( "attr1" );
+        assertEquals( 2, attr.size() );
+        assertTrue( attr.contains( "ATTR1" ) );
+        assertTrue( attr.contains( "ATTR2" ) );
+
+        Attribute attr2 = entry.get( "attr2" );
+        assertEquals( 1, attr2.size() );
+        assertTrue( attr2.contains( "ATTR1" ) );
+    }
+
+
+    @Test
+    public void testChangeTypeDelete() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "dc=example,dc=com", entry.getDn().getName() );
+
+        assertTrue( entry.isLdifChange() );
+        assertTrue( entry.isChangeDelete() );
+    }
+
+
+    @Test
+    public void testLdifChangeDeleteWithControl() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "control: 1.1.1\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "dc=example,dc=com", entry.getDn().getName() );
+
+        assertTrue( entry.isLdifChange() );
+        assertTrue( entry.isChangeDelete() );
+
+        assertTrue( entry.hasControls() );
+        assertEquals( 1, entry.getControls().size() );
+
+        LdifControl control = entry.getControl( "1.1.1" );
+
+        assertEquals( "1.1.1", control.getOid() );
+        assertFalse( control.isCritical() );
+        assertNull( control.getValue() );
+    }
+
+
+    @Test
+    public void testLdifChangeDeleteWithControls() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "control: 1.1.1\n" +
+                "control: 1.1.2 true\n" +
+                "control: 1.1.3:ABCDEF\n" +
+                "control: 1.1.4 true:ABCDEF\n" +
+                "control: 1.1.5::RW1tYW51ZWwgTMOpY2hhcm55\n" +
+                "control: 1.1.6 true::RW1tYW51ZWwgTMOpY2hhcm55\n" +
+                "changetype: delete\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertEquals( 1, entries.size() );
+
+        // Entry
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( "dc=example,dc=com", entry.getDn().getName() );
+
+        assertTrue( entry.isLdifChange() );
+        assertTrue( entry.isChangeDelete() );
+
+        assertTrue( entry.hasControls() );
+        assertEquals( 6, entry.getControls().size() );
+
+        // First control
+        LdifControl control = entry.getControl( "1.1.1" );
+
+        assertEquals( "1.1.1", control.getOid() );
+        assertFalse( control.isCritical() );
+        assertNull( control.getValue() );
+
+        // Second control
+        control = entry.getControl( "1.1.2" );
+
+        assertEquals( "1.1.2", control.getOid() );
+        assertTrue( control.isCritical() );
+        assertNull( control.getValue() );
+
+        // Third control
+        control = entry.getControl( "1.1.3" );
+
+        assertEquals( "1.1.3", control.getOid() );
+        assertFalse( control.isCritical() );
+        assertEquals( "ABCDEF", Strings.utf8ToString( control.getValue() ) );
+
+        // Forth control
+        control = entry.getControl( "1.1.4" );
+
+        assertEquals( "1.1.4", control.getOid() );
+        assertTrue( control.isCritical() );
+        assertEquals( "ABCDEF", Strings.utf8ToString( control.getValue() ) );
+
+        // Fifth control
+        control = entry.getControl( "1.1.5" );
+
+        assertEquals( "1.1.5", control.getOid() );
+        assertFalse( control.isCritical() );
+        assertEquals( "Emmanuel L\u00e9charny", Strings.utf8ToString( control.getValue() ) );
+
+        // Sixth control
+        control = entry.getControl( "1.1.6" );
+
+        assertEquals( "1.1.6", control.getOid() );
+        assertTrue( control.isCritical() );
+        assertEquals( "Emmanuel L\u00e9charny", Strings.utf8ToString( control.getValue() ) );
+    }
+
+
+    @Test(expected = LdapLdifException.class)
+    public void testChangeTypeDeleteBadEntry() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: delete\n" +
+                "attr1: test";
+
+        LdifReader reader = new LdifReader();
+
+        reader.parseLdif( ldif );
+    }
+
+
+    @Test(expected = LdapLdifException.class)
+    public void testLdifContentWithControl() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "control: 1.1.1\n" +
+                "attr1: test";
+
+        LdifReader reader = new LdifReader();
+
+        reader.parseLdif( ldif );
+    }
+
+
+    /**
+     * Test that we can parse a LDIF with a modify changeType and see if the
+     * empty attribute and the attribute deletion aren't producing the same Modify entry
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserChangeTypeModifyDeleteEmptyValue() throws Exception
+    {
+        // test that mixed case attr ids work at all
+        String ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: modify\n" +
+                "delete: userPassword\n" +
+                "-\n" +
+                "\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: modify\n" +
+                "delete: userPassword\n" +
+                "userPassword:\n" +
+                "-";
+
+        LdifReader reader = new LdifReader();
+
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+
+        LdifEntry entry1 = entries.get( 0 );
+        Modification modification = entry1.getModifications().get( 0 );
+        assertEquals( 0, modification.getAttribute().size() );
+        assertNull( modification.getAttribute().get() );
+
+        LdifEntry entry2 = entries.get( 1 );
+        modification = entry2.getModifications().get( 0 );
+        assertEquals( 1, modification.getAttribute().size() );
+        assertNotNull( modification.getAttribute().get() );
+        assertNull( modification.getAttribute().getBytes() );
+    }
+
+
+    /**
+     * Test lengths when multiple entries are present
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLdifParserLengthAndOffset() throws Exception
+    {
+        String ldif1 = "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+            "cn: app1\n" +
+            "objectClass: top\n" +
+            "objectClass: apApplication\n" +
+            "displayName:   app1   \n" +
+            "dependencies:\n" +
+            "envVars:\n";
+
+        String comment = "# This comment was copied. Delete an entry. The operation will attach the LDAPv3\n" +
+            "# Tree Delete Control defined in [9]. The criticality\n" +
+            "# field is \"true\" and the controlValue field is\n" +
+            "# absent, as required by [9].\n";
+
+        String version = "version:   1\n";
+
+        String ldif =
+            version +
+                ldif1 +
+                "\n" +
+                comment +
+                ldif1 + "\n";
+
+        LdifReader reader = new LdifReader();
+
+        List<LdifEntry> lstEntries = null;
+
+        try
+        {
+            lstEntries = reader.parseLdif( ldif );
+        }
+        catch ( Exception ne )
+        {
+            fail();
+        }
+        finally
+        {
+            reader.close();
+        }
+
+        LdifEntry entry1 = lstEntries.get( 0 );
+
+        assertEquals( version.length() + ldif1.length(), entry1.getLengthBeforeParsing() );
+
+        LdifEntry entry2 = lstEntries.get( 1 );
+
+        assertEquals( ldif1.length() + comment.length(), entry2.getLengthBeforeParsing() );
+
+        byte[] data = ldif.getBytes();
+
+        String ldif1Bytes = new String( data, ( int ) entry1.getOffset(), entry1.getLengthBeforeParsing() );
+        assertNotNull( reader.parseLdif( ldif1Bytes ).get( 0 ) );
+
+        String ldif2Bytes = new String( data, ( int ) entry2.getOffset(), entry2.getLengthBeforeParsing() );
+        assertNotNull( reader.parseLdif( ldif2Bytes ).get( 0 ) );
+
+        File file = File.createTempFile( "offsetTest", "ldif" );
+        file.deleteOnExit();
+        FileWriter fw = new FileWriter( file );
+        fw.write( ldif );
+        fw.close();
+
+        RandomAccessFile raf = new RandomAccessFile( file, "r" );
+
+        LdifReader fileReader = new LdifReader( file );
+
+        LdifEntry rafEntry1 = fileReader.next();
+
+        data = new byte[rafEntry1.getLengthBeforeParsing()];
+        raf.read( data, ( int ) rafEntry1.getOffset(), data.length );
+
+        reader = new LdifReader();
+        LdifEntry reReadeRafEntry1 = reader.parseLdif( new String( data ) ).get( 0 );
+        assertNotNull( reReadeRafEntry1 );
+        assertEquals( rafEntry1.getOffset(), reReadeRafEntry1.getOffset() );
+        assertEquals( rafEntry1.getLengthBeforeParsing(), reReadeRafEntry1.getLengthBeforeParsing() );
+        reader.close();
+
+        LdifEntry rafEntry2 = fileReader.next();
+
+        data = new byte[rafEntry2.getLengthBeforeParsing()];
+        raf.readFully( data, 0, data.length );
+
+        reader = new LdifReader();
+        LdifEntry reReadeRafEntry2 = reader.parseLdif( new String( data ) ).get( 0 );
+        assertNotNull( reReadeRafEntry2 );
+        assertEquals( rafEntry2.getLengthBeforeParsing(), reReadeRafEntry2.getLengthBeforeParsing() );
+        reader.close();
+    }
+
+
+    @Test
+    // for DIRAPI-174
+    public void testLineNumber() throws Exception
+    {
+        String ldif =
+            "versionN:   1\n" + // wrong tag name 'versionN'
+                "dn: dc=example,dc=com\n" +
+                "changetype: delete\n" +
+                "attr1: test";
+
+        LdifReader reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception e )
+        {
+        }
+
+        assertEquals( 1, reader.getLineNumber() );
+
+        ldif =
+            "version:   1\n" +
+                "d n: dc=example,dc=com\n" + // wrong name "d n"
+                "changetype: delete\n" +
+                "attr1: test";
+        reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception e )
+        {
+        }
+
+        assertEquals( 2, reader.getLineNumber() );
+
+        // wrong changetype
+        ldif =
+            "version:   1\n" +
+                "dn: dc=example,dc=com\n" +
+                "changetype: delete\n" +
+                "attr1: test";
+        reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail();
+        }
+        catch ( Exception e )
+        {
+        }
+
+        assertEquals( 4, reader.getLineNumber() );
+
+        ldif =
+            "version:   1\n" +
+                "dn: cn=app1,ou=applications,ou=conf,dc=apache,dc=org\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app1   \n" +
+                "dependencies:\n" +
+                "envVars:\n\n" + // watch out the extra newline while counting
+                "d n: cn=app2,ou=applications,ou=conf,dc=apache,dc=org\n" + // wrong start
+                "cn: app2\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName:   app2   \n" +
+                "dependencies:\n" +
+                "envVars:";
+        reader = new LdifReader();
+
+        try
+        {
+            reader.parseLdif( ldif );
+            fail( "shouldn't be parsed" );
+        }
+        catch ( Exception e )
+        {
+        }
+
+        assertEquals( 10, reader.getLineNumber() );
+    }
+
+
+    @Test
+    public void testLdifParserRootDSE() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn:\n" +
+                "cn: app1\n" +
+                "objectClass: top\n" +
+                "objectClass: apApplication\n" +
+                "displayName: app1   \n" +
+                "dependencies:\n" +
+                "envVars:";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+
+        assertEquals( "", entry.getDn().getName() );
+
+        Attribute attr = entry.get( "cn" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "objectclass" );
+        assertTrue( attr.contains( "top" ) );
+        assertTrue( attr.contains( "apApplication" ) );
+
+        attr = entry.get( "displayname" );
+        assertTrue( attr.contains( "app1" ) );
+
+        attr = entry.get( "dependencies" );
+        assertNull( attr.get().getValue() );
+
+        attr = entry.get( "envvars" );
+        assertNull( attr.get().getValue() );
+    }
+
+
+    /**
+     * Test a LDIF generated by a request with 1.1
+     */
+    @Test
+    public void testLdifParserNoAttribute() throws Exception
+    {
+        String ldif =
+            "version:   1\n" +
+                "dn: cn=test1\n" +
+                "\n" +
+                "dn: cn=test2\n" +
+                "\n" +
+                "dn: cn=test3";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        reader.close();
+
+        assertNotNull( entries );
+
+        // Check test 1
+        LdifEntry entry = entries.get( 0 );
+        assertTrue( entry.isLdifContent() );
+        assertEquals( "cn=test1", entry.getDn().getName() );
+        assertEquals( 0, entry.size() );
+
+        // Check test 2
+        entry = entries.get( 1 );
+        assertTrue( entry.isLdifContent() );
+        assertEquals( "cn=test2", entry.getDn().getName() );
+        assertEquals( 0, entry.size() );
+
+        // Check test 3
+        entry = entries.get( 2 );
+        assertTrue( entry.isLdifContent() );
+        assertEquals( "cn=test3", entry.getDn().getName() );
+        assertEquals( 0, entry.size() );
+    }
+
+
+    @Test
+    public void testLdifParserWithUnderscoresAT() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Add a new entry\n" +
+                "dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com\n" +
+                "changetype: add\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "objectclass: organizationalPerson\n" +
+                "cn: Fiona Jensen\n" +
+                "sn: Jensen\n" +
+                "uid: fiona\n" +
+                "telephonenumber: +1 408 555 1212\n" +
+                "An_idiot_Attribute: thanks M$ for that";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        LdifEntry entry = entries.get( 0 );
+        assertEquals( entry.get( "An_idiot_Attribute" ).getString(), "thanks M$ for that" );
+        reader.close();
+    }
+
+
+    @Test
+    public void testLdifParserWithMixedATHR() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Add a new entry\n" +
+                "dn: cn=DeviceTypes,cn=SDT,cn=prod_81,o=myconfiguration\n" +
+                "cn: DeviceTypes\n" +
+                "javaClassName: java.lang.String\n" +
+                "myconfigstringvalue: P:Phone (except BlackBerry)\n" +
+                "myconfigstringvalue:: WjpCbGFja0JlcnJ5w4LCrg==\n" +
+                "myconfigstringvalue: 3:Internet only device\n" +
+                "objectClass: top\n" +
+                "objectClass: javaobject\n" +
+                "objectClass: myconfigstringvaluedobject\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        LdifEntry entry = entries.get( 0 );
+
+        // Check that the myconfigstringvalue contains 3 values
+        assertEquals( 3, entry.get( "myconfigstringvalue" ).size() );
+        assertTrue( entry.get( "myconfigstringvalue" ).isHumanReadable() );
+
+        reader.close();
+    }
+
+
+    @Test
+    public void testLdifParserWithMixedATBinary() throws Exception, Exception
+    {
+        String ldif =
+            "version: 1\n" +
+                "# Add a new entry\n" +
+                "dn: cn=DeviceTypes,cn=SDT,cn=prod_81,o=myconfiguration\n" +
+                "cn: DeviceTypes\n" +
+                "javaClassName: java.lang.String\n" +
+                "myconfigstringvalue:: WjpCbGFja0JlcnJ5w4LCrg==\n" +
+                "myconfigstringvalue: P:Phone (except BlackBerry)\n" +
+                "myconfigstringvalue: 3:Internet only device\n" +
+                "objectClass: top\n" +
+                "objectClass: javaobject\n" +
+                "objectClass: myconfigstringvaluedobject\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        LdifEntry entry = entries.get( 0 );
+
+        // Check that the myconfigstringvalue contains 3 values
+        assertEquals( 3, entry.get( "myconfigstringvalue" ).size() );
+        assertFalse( entry.get( "myconfigstringvalue" ).isHumanReadable() );
+
+        reader.close();
+
+    }
+
+
+
+    @Test
+    public void testLdifParserWithReplaceEmptyValue() throws Exception, Exception
+    {
+        String ldif =
+            "dn: cn=Steven Nguyen,ou=SAP,dc=sap,dc=local\n" +
+            "changetype: modify\n" +
+            "replace: objectClass\n" +
+            "objectClass: top\n" +
+            "objectClass: user\n" +
+            "objectClass: person\n" +
+            "objectClass: organizationalPerson\n" +
+            "-\n" +
+            "replace: sn\n" +
+            "sn: Nguyen Linh\n" +
+            "-\n" +
+            "replace: url\n" +
+            "-\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( ldif );
+        LdifEntry entry = entries.get( 0 );
+
+        assertEquals( ldif, entry.toString() );
+        reader.close();
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifRevertorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifRevertorTest.java
new file mode 100644
index 0000000..f56e6b2
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifRevertorTest.java
@@ -0,0 +1,1953 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.entry.*;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.ldif.ChangeType;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.ldif.LdifRevertor;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the LdifReverter methods
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifRevertorTest
+{
+    /**
+     * Helper method to build a basic entry used by the Modify tests
+     */
+    private Entry buildEntry() throws LdapException
+    {
+        Entry entry = new DefaultEntry( "",
+            "objectclass: top",
+            "objectclass: person",
+            "cn: test",
+            "sn: joe doe",
+            "l: USA" );
+
+        return entry;
+    }
+
+
+    /**
+     * Test a AddRequest reverse
+     *
+     * @throws LdapInvalidDnException
+     */
+    @Test
+    public void testReverseAdd() throws LdapInvalidDnException
+    {
+        Dn dn = new Dn( "dc=apache, dc=com" );
+        LdifEntry reversed = LdifRevertor.reverseAdd( dn );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Delete, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+    }
+
+
+    /**
+     * Test a DelRequest reverse
+     * @throws LdapException
+     */
+    @Test
+    public void testReverseDel() throws LdapException
+    {
+        Dn dn = new Dn( "dc=apache, dc=com" );
+
+        Entry deletedEntry = new DefaultEntry( dn ,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: apache",
+            "dc: apache" );
+
+        LdifEntry reversed = LdifRevertor.reverseDel( dn, deletedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Add, reversed.getChangeType() );
+        assertNotNull( reversed.getEntry() );
+        assertEquals( deletedEntry, reversed.getEntry() );
+    }
+
+
+    /**
+     * Test a reversed Modify adding a existing value from an existing attribute
+     */
+    @Test
+    public void testReverseModifyDelExistingOuValue() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        modifiedEntry.put( "ou", "apache", "acme corp" );
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+
+        Modification mod = new DefaultModification(
+            ModificationOperation.REMOVE_ATTRIBUTE,
+            new DefaultAttribute( "ou", "acme corp" ) );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+
+        assertEquals( "ou", attr.getId() );
+        assertEquals( "acme corp", attr.getString() );
+    }
+
+
+    /**
+     * Test a reversed Modify deleting an existing attribute
+     */
+    @Test
+    public void testReverseModifyDeleteOU() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        modifiedEntry.put( "ou", "apache", "acme corp" );
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+
+        Modification mod = new DefaultModification(
+            ModificationOperation.REMOVE_ATTRIBUTE,
+            new DefaultAttribute( "ou" ) );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+        assertEquals( "ou", attr.getId() );
+
+        assertTrue( attr.contains( "apache", "acme corp" ) );
+    }
+
+
+    /**
+     * Test a reversed Modify deleting all values of an existing attribute
+     */
+    @Test
+    public void testReverseModifyDelExistingOuWithAllValues() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        Attribute ou = new DefaultAttribute( "ou", "apache", "acme corp" );
+        modifiedEntry.put( ou );
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+
+        Modification mod = new DefaultModification(
+            ModificationOperation.REMOVE_ATTRIBUTE, ou );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.ADD_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+        assertEquals( "ou", attr.getId() );
+
+        assertTrue( ou.contains( "apache", "acme corp" ) );
+    }
+
+
+    /**
+     * Test a reversed Modify replacing existing values with new values
+     */
+    @Test
+    public void testReverseModifyReplaceExistingOuValues() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        Attribute ou = new DefaultAttribute( "ou", "apache", "acme corp" );
+        modifiedEntry.put( ou );
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+
+        Attribute ouModified = new DefaultAttribute( "ou", "directory", "BigCompany inc." );
+
+        Modification mod = new DefaultModification(
+            ModificationOperation.REPLACE_ATTRIBUTE, ouModified );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.REPLACE_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+        assertEquals( ou, attr );
+    }
+
+
+    /**
+     * Test a reversed Modify replace by injecting a new attribute
+     */
+    @Test
+    public void testReverseModifyReplaceNewAttribute() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+
+        Attribute newOu = new DefaultAttribute( "ou", "apache", "acme corp" );
+
+        Modification mod = new DefaultModification(
+            ModificationOperation.REPLACE_ATTRIBUTE, newOu );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.REPLACE_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+        assertEquals( "ou", attr.getId() );
+
+        assertNull( attr.get() );
+    }
+
+
+    /**
+     * Test a reversed Modify replace by removing an attribute
+     */
+    @Test
+    public void testReverseModifyReplaceExistingOuWithNothing() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        modifiedEntry.put( "ou", "apache", "acme corp" );
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+
+        Modification mod = new DefaultModification(
+            ModificationOperation.REPLACE_ATTRIBUTE, new DefaultAttribute( "ou" ) );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.REPLACE_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+        assertEquals( "ou", attr.getId() );
+
+        assertTrue( attr.contains( "apache", "acme corp" ) );
+    }
+
+
+    /**
+     * Test a multiple modifications reverse.
+     * 
+     * On the following entry :
+     *  dn: cn=test, ou=system
+     *  objectclass: top
+     *  objectclass: person
+     *  cn: test
+     *  sn: joe doe
+     *  l: USA
+     *  ou: apache
+     *  ou: acme corp
+     * 
+     * We will :
+     *  - add an 'ou' value 'BigCompany inc.'
+     *  - delete the 'l' attribute
+     *  - add the 'l=FR' attribute
+     *  - replace the 'l=FR' by a 'l=USA' attribute
+     *  - replace the 'ou' attribute with 'apache' value.
+     * 
+     * The modify ldif will be :
+     * 
+     *  dn: cn=test, ou=system
+     *  changetype: modify
+     *  add: ou
+     *  ou: BigCompany inc.
+     *  -
+     *  delete: l
+     *  -
+     *  add: l
+     *  l: FR
+     *  -
+     *  replace: l
+     *  l: USA
+     *  -
+     *  replace: ou
+     *  ou: apache
+     *  -
+     * 
+     * At the end, the entry will looks like :
+     *  dn: cn=test, ou=system
+     *  objectclass: top
+     *  objectclass: person
+     *  cn: test
+     *  sn: joe doe
+     *  l: USA
+     *  ou: apache
+     * 
+     * and the reversed LDIF will be :
+     * 
+     *  dn: cn=test, ou=system
+     *  changetype: modify
+     *  replace: ou
+     *  ou: apache
+     *  ou: acme corp
+     *  -
+     *  replace: l
+     *  l: USA
+     *  -
+     *  delete: l
+     *  l: FR
+     *  -
+     *  add: l
+     *  l: USA
+     *  -
+     *  delete: ou
+     *  ou: BigCompany inc.
+     *  -
+     * 
+     */
+    @Test
+    public void testReverseMultipleModifications() throws Exception
+    {
+        String initialEntryLdif =
+            "dn: cn=test, ou=system\n" +
+                "objectclass: top\n" +
+                "objectclass: person\n" +
+                "cn: test\n" +
+                "sn: joe doe\n" +
+                "l: USA\n" +
+                "ou: apache\n" +
+                "ou: acme corp\n";
+
+        LdifReader reader = new LdifReader();
+        List<LdifEntry> entries = reader.parseLdif( initialEntryLdif );
+        reader.close();
+
+        LdifEntry initialEntry = entries.get( 0 );
+
+        // We will :
+        //   - add an 'ou' value 'BigCompany inc.'
+        //   - delete the 'l' attribute
+        //   - add the 'l=FR' attribute
+        //   - replace the 'l=FR' by a 'l=USA' attribute
+        //   - replace the 'ou' attribute with 'apache' value.
+        Dn dn = new Dn( "cn=test, ou=system" );
+
+        List<Modification> modifications = new ArrayList<Modification>();
+
+        // First, inject the 'ou'
+        Modification mod = new DefaultModification(
+            ModificationOperation.ADD_ATTRIBUTE, new DefaultAttribute( "ou", "BigCompany inc." ) );
+        modifications.add( mod );
+
+        // Remove the 'l'
+        mod = new DefaultModification(
+            ModificationOperation.REMOVE_ATTRIBUTE, new DefaultAttribute( "l" ) );
+        modifications.add( mod );
+
+        // Add 'l=FR'
+        mod = new DefaultModification(
+            ModificationOperation.ADD_ATTRIBUTE, new DefaultAttribute( "l", "FR" ) );
+        modifications.add( mod );
+
+        // Replace it with 'l=USA'
+        mod = new DefaultModification(
+            ModificationOperation.REPLACE_ATTRIBUTE, new DefaultAttribute( "l", "USA" ) );
+        modifications.add( mod );
+
+        // Replace the ou value
+        mod = new DefaultModification(
+            ModificationOperation.REPLACE_ATTRIBUTE, new DefaultAttribute( "ou", "apache" ) );
+        modifications.add( mod );
+
+        LdifEntry reversedEntry = LdifRevertor.reverseModify( dn, modifications, initialEntry.getEntry() );
+
+        String expectedEntryLdif =
+            "dn: cn=test, ou=system\n" +
+                "changetype: modify\n" +
+                "replace: ou\n" +
+                "ou: apache\n" +
+                "ou: acme corp\n" +
+                "ou: BigCompany inc.\n" +
+                "-\n" +
+                "replace: l\n" +
+                "l: FR\n" +
+                "-\n" +
+                "delete: l\n" +
+                "l: FR\n" +
+                "-\n" +
+                "add: l\n" +
+                "l: USA\n" +
+                "-\n" +
+                "delete: ou\n" +
+                "ou: BigCompany inc.\n" +
+                "-\n\n";
+
+        reader = new LdifReader();
+        entries = reader.parseLdif( expectedEntryLdif );
+        reader.close();
+
+        LdifEntry expectedEntry = entries.get( 0 );
+
+        assertEquals( expectedEntry, reversedEntry );
+    }
+
+
+    /**
+     * Test a reversed Modify adding a new attribute value
+     * in an exiting attribute
+     */
+    @Test
+    public void testReverseModifyAddNewOuValue() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        modifiedEntry.put( "ou", "apache", "acme corp" );
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+        Modification mod = new DefaultModification(
+            ModificationOperation.ADD_ATTRIBUTE,
+            new DefaultAttribute( "ou", "BigCompany inc." ) );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+        assertEquals( "ou", attr.getId() );
+        assertEquals( "BigCompany inc.", attr.getString() );
+    }
+
+
+    /**
+     * Test a reversed Modify adding a new attribute
+     */
+    @Test
+    public void testReverseModifyAddNewOu() throws LdapException
+    {
+        Entry modifiedEntry = buildEntry();
+
+        Dn dn = new Dn( "cn=test, ou=system" );
+        Modification mod = new DefaultModification(
+            ModificationOperation.ADD_ATTRIBUTE,
+            new DefaultAttribute( "ou", "BigCompany inc." ) );
+
+        LdifEntry reversed = LdifRevertor.reverseModify( dn,
+            Collections.<Modification> singletonList( mod ), modifiedEntry );
+
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+        List<Modification> mods = reversed.getModifications();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.size() );
+
+        Modification modif = mods.get( 0 );
+
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, modif.getOperation() );
+
+        Attribute attr = modif.getAttribute();
+
+        assertNotNull( attr );
+        assertEquals( "ou", attr.getId() );
+        assertEquals( "BigCompany inc.", attr.getString() );
+    }
+
+
+    /**
+     * Test a AddRequest reverse where the Dn is to be base64 encoded
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testReverseAddBase64DN() throws LdapException
+    {
+        Dn dn = new Dn( "dc=Emmanuel L\u00c9charny" );
+        LdifEntry reversed = LdifRevertor.reverseAdd( dn );
+        assertNotNull( reversed );
+        assertEquals( dn.getName(), reversed.getDn().getName() );
+        assertEquals( ChangeType.Delete, reversed.getChangeType() );
+        assertNull( reversed.getEntry() );
+    }
+
+
+    /**
+     * Test a reversed move ModifyDN
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void testReverseModifyDNMove() throws LdapException
+    {
+        Dn dn = new Dn( "cn=john doe, dc=example, dc=com" );
+        Dn newSuperior = new Dn( "ou=system" );
+        Rdn rdn = new Rdn( "cn=john doe" );
+
+        LdifEntry reversed = LdifRevertor.reverseMove( newSuperior, dn );
+
+        assertNotNull( reversed );
+
+        assertEquals( "cn=john doe,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModDn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( rdn.getName(), reversed.getNewRdn() );
+        assertEquals( "dc=example, dc=com", Strings.trim( reversed.getNewSuperior() ) );
+        assertNull( reversed.getEntry() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the Rdn are both simple, not overlapping,
+     * with deleteOldRdn = false, and the Ava not present in the initial entry?
+     * 
+     * Covers case 1.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test11ReverseRenameSimpleSimpleNotOverlappingKeepOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the Rdn are both simple, not overlapping,
+     * with deleteOldRdn = false, and with a Ava present in the initial entry.
+     * 
+     * Covers case 1.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=small
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test12ReverseRenameSimpleSimpleNotOverlappingKeepOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=small" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=small,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the Rdn are both simple, not overlapping,
+     * with deleteOldRdn = true, and the Ava not present in the initial entry
+     * 
+     * Covers case 2.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test21ReverseRenameSimpleSimpleNotOverlappingDeleteOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the Rdn are both simple, not overlapping,
+     * with deleteOldRdn = true, and with a Ava present in the initial entry.
+     * 
+     * Covers case 2.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=small
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test22ReverseRenameSimpleSimpleNotOverlappingDeleteOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=small" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=small,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is simple, not overlapping, with deleteOldRdn = false, and
+     * with a Ava not present in the initial entry.
+     * 
+     * Covers case 3 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test3ReverseRenameCompositeSimpleNotOverlappingKeepOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is simple, not overlapping, with deleteOldRdn = false, and
+     * with an Ava present in the initial entry.
+     * 
+     * Covers case 3 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=big
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test3ReverseRenameCompositeSimpleNotOverlappingKeepOldRdnExistsInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=big" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=big,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is simple, not overlapping, with deleteOldRdn = true, and
+     * with an Ava not present in the initial entry.
+     * 
+     * Covers case 4 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test4ReverseRenameCompositeSimpleNotOverlappingDeleteOldRdnDontExistsInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is simple, not overlapping, with deleteOldRdn = true, and
+     * with an Ava present in the initial entry.
+     * 
+     * Covers case 4 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=big
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test4ReverseRenameCompositeSimpleNotOverlappingDeleteOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=big" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=big,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is simple, they overlap, with deleteOldRdn = false.
+     * 
+     * Covers case 5 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test5ReverseRenameCompositeSimpleOverlappingKeepOldRdn() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is simple, they overlap, with deleteOldRdn = true.
+     * 
+     * Covers case 5 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test5ReverseRenameCompositeSimpleOverlappingDeleteOldRdn() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = false, and
+     * the new values don't exist in the entry.
+     * 
+     * Covers case 6.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+sn=plumber
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test61ReverseRenameSimpleCompositeNotOverlappingKeepOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe+sn=plumber" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe+sn=plumber,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = false, and
+     * the new values exists in the entry.
+     * 
+     * Covers case 6.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+sn=small
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test62ReverseRenameSimpleCompositeNotOverlappingKeepOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe+sn=small" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 2, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe+sn=small,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+
+        reversed = reverseds.get( 1 );
+
+        assertEquals( "cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        Modification[] mods = reversed.getModificationArray();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.length );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, mods[0].getOperation() );
+        assertNotNull( mods[0].getAttribute() );
+        assertEquals( "cn", mods[0].getAttribute().getId() );
+        assertEquals( "joe", mods[0].getAttribute().getString() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = true, and
+     * none of new values exists in the entry.
+     * 
+     * Covers case 7.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+sn=plumber
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test71ReverseRenameSimpleCompositeNotOverlappingDeleteOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe+sn=plumber" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe+sn=plumber,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = true, and
+     * some of new values exists in the entry.
+     * 
+     * Covers case 7.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+sn=small
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test72ReverseRenameSimpleCompositeNotOverlappingDeleteOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe+sn=small" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 2, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe+sn=small,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+
+        reversed = reverseds.get( 1 );
+
+        assertEquals( "cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        Modification[] mods = reversed.getModificationArray();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.length );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, mods[0].getOperation() );
+        assertNotNull( mods[0].getAttribute() );
+        assertEquals( "cn", mods[0].getAttribute().getId() );
+        assertEquals( "joe", mods[0].getAttribute().getString() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they overlap, with deleteOldRdn = false, and
+     * none of new values exists in the entry.
+     * 
+     * Covers case 8.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: This is a test
+     * 
+     * new Rdn : sn=small+cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test81ReverseRenameSimpleCompositeOverlappingKeepOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "sn=small+cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=small+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they overlap, with deleteOldRdn = false, and
+     * some of the new values exist in the entry.
+     * 
+     * Covers case 8.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: This is a test
+     * seeAlso: big
+     * 
+     * new Rdn : sn=small+cn=test+seeAlso=big
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test82ReverseRenameSimpleCompositeOverlappingKeepOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "sn=small+cn=test+seeAlso=big" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "seeAlso: big",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 2, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=small+cn=test+seeAlso=big,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+
+        reversed = reverseds.get( 1 );
+
+        assertEquals( "cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        Modification[] mods = reversed.getModificationArray();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.length );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, mods[0].getOperation() );
+        assertNotNull( mods[0].getAttribute() );
+        assertEquals( "sn", mods[0].getAttribute().getId() );
+        assertEquals( "small", mods[0].getAttribute().getString() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they overlap, with deleteOldRdn = true, and
+     * none of new values exists in the entry.
+     * 
+     * Covers case 9.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: This is a test
+     * 
+     * new Rdn : sn=small+cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test91ReverseRenameSimpleCompositeOverlappingDeleteOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "sn=small+cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=small+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is simple,
+     * the new Rdn is composite, they overlap, with deleteOldRdn = true, and
+     * some of the new values exists in the entry.
+     * 
+     * Covers case 9.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * seeAlso: big
+     * sn: This is a test
+     * 
+     * new Rdn : cn=small+cn=test+cn=big
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test92ReverseRenameSimpleCompositeOverlappingDeleteOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "cn=test" );
+        Rdn newRdn = new Rdn( "sn=small+cn=test+seeAlso=big" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "seeAlso: big",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 2, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=small+cn=test+seeAlso=big,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+
+        reversed = reverseds.get( 1 );
+
+        assertEquals( "cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        Modification[] mods = reversed.getModificationArray();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.length );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, mods[0].getOperation() );
+        assertNotNull( mods[0].getAttribute() );
+        assertEquals( "sn", mods[0].getAttribute().getId() );
+        assertEquals( "small", mods[0].getAttribute().getString() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = false, and
+     * none of new values exists in the entry.
+     * 
+     * Covers case 10.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+cn=plumber
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test101ReverseRenameCompositeCompositeNotOverlappingKeepOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe+sn=plumber" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe+sn=plumber,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = false, and
+     * some of the new values exists in the entry.
+     * 
+     * Covers case 10.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : sn=joe+cn=big
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test102ReverseRenameCompositeCompositeNotOverlappingKeepOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "sn=joe+cn=big" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 2, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=joe+cn=big,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+
+        reversed = reverseds.get( 1 );
+
+        assertEquals( "sn=small+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        Modification[] mods = reversed.getModificationArray();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.length );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, mods[0].getOperation() );
+        assertNotNull( mods[0].getAttribute() );
+        assertEquals( "sn", mods[0].getAttribute().getId() );
+        assertEquals( "joe", mods[0].getAttribute().getString() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = true, and
+     * none of new values exists in the entry.
+     * 
+     * Covers case 11.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+sn=plumber
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test111ReverseRenameCompositeCompositeNotOverlappingDeleteOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe+sn=plumber" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe+sn=plumber,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they don't overlap, with deleteOldRdn = true, and
+     * some of the new values exists in the entry.
+     * 
+     * Covers case 11.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+sn=big
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test112ReverseRenameCompositeCompositeNotOverlappingDeleteOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "cn=joe+sn=big" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 2, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "cn=joe+sn=big,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+
+        reversed = reverseds.get( 1 );
+
+        assertEquals( "sn=small+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.Modify, reversed.getChangeType() );
+        Modification[] mods = reversed.getModificationArray();
+
+        assertNotNull( mods );
+        assertEquals( 1, mods.length );
+        assertEquals( ModificationOperation.REMOVE_ATTRIBUTE, mods[0].getOperation() );
+        assertNotNull( mods[0].getAttribute() );
+        assertEquals( "cn", mods[0].getAttribute().getId() );
+        assertEquals( "joe", mods[0].getAttribute().getString() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they are overlapping, with deleteOldRdn = false, and
+     * none of new values exists in the entry.
+     * 
+     * Covers case 12.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : cn=joe+cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test121ReverseRenameCompositeCompositeOverlappingKeepOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "sn=joe+cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=joe+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they are overlapping, with deleteOldRdn = false, and
+     * some of the new values exists in the entry.
+     * 
+     * Covers case 12.2 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : sn=big+cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test122ReverseRenameCompositeCompositeOverlappingKeepOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "sn=big+cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.KEEP_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=big+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they are overlapping, with deleteOldRdn = true, and
+     * none of new values exists in the entry.
+     * 
+     * Covers case 13.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * cn: big
+     * sn: small
+     * sn: This is a test
+     * 
+     * new Rdn : sn=joe+cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test131ReverseRenameCompositeCompositeOverlappingDeleteOldRdnDontExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "sn=joe+cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "cn: big",
+            "sn: small",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=joe+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+
+
+    /**
+     * Test a reversed rename ModifyDN, where the initial Rdn is composite,
+     * the new Rdn is composite, they are overlapping, with deleteOldRdn = true, and
+     * some of the new values exists in the entry.
+     * 
+     * Covers case 13.1 of http://cwiki.apache.org/confluence/display/DIRxSRVx11/Reverse+LDIF
+     * 
+     * Initial entry
+     * dn: sn=small+cn=test,ou=system
+     * objectclass: top
+     * objectclass: person
+     * cn: test
+     * sn: small
+     * sn: big
+     * sn: This is a test
+     * 
+     * new Rdn : sn=big+cn=test
+     *
+     * @throws LdapException on error
+     */
+    @Test
+    public void test132ReverseRenameCompositeCompositeOverlappingDeleteOldRdnExistInEntry() throws LdapException
+    {
+        Dn dn = new Dn( "sn=small+cn=test,ou=system" );
+        Rdn oldRdn = new Rdn( "sn=small+cn=test" );
+        Rdn newRdn = new Rdn( "sn=big+cn=test" );
+
+        Entry entry = new DefaultEntry( dn,
+            "objectClass: top",
+            "objectClass: person",
+            "cn: test",
+            "sn: small",
+            "sn: big",
+            "sn: this is a test" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseRename( entry, newRdn, LdifRevertor.DELETE_OLD_RDN );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+        LdifEntry reversed = reverseds.get( 0 );
+
+        assertEquals( "sn=big+cn=test,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( oldRdn.getName(), reversed.getNewRdn() );
+        assertNull( reversed.getNewSuperior() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifUtilsTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifUtilsTest.java
new file mode 100644
index 0000000..20179a0
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/ldif/LdifUtilsTest.java
@@ -0,0 +1,578 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.ldif;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.ldif.ChangeType;
+import org.apache.directory.api.ldap.model.ldif.LdapLdifException;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.ldif.LdifRevertor;
+import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.ldap.model.message.controls.ManageDsaITImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the LdifUtils methods
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifUtilsTest
+{
+    private String testString = "this is a test";
+
+
+    /**
+     * Tests the method IsLdifSafe with a null String
+     */
+    @Test
+    public void testIsLdifNullString()
+    {
+        assertTrue( LdifUtils.isLDIFSafe( null ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with an empty String
+     */
+    @Test
+    public void testIsLdifEmptyString()
+    {
+        assertTrue( LdifUtils.isLDIFSafe( "" ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char NUL (ASCII code 0)
+     */
+    @Test
+    public void testIsLdifSafeStartingWithNUL()
+    {
+        char c = ( char ) 0;
+
+        assertFalse( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char LF (ASCII code 10)
+     */
+    @Test
+    public void testIsLdifSafeStartingWithLF()
+    {
+        char c = ( char ) 10;
+
+        assertFalse( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char CR (ASCII code 13)
+     */
+    @Test
+    public void testIsLdifSafeStartingWithCR()
+    {
+        char c = ( char ) 13;
+
+        assertFalse( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char SPACE (ASCII code 32)
+     */
+    @Test
+    public void testIsLdifSafeStartingWithSpace()
+    {
+        char c = ( char ) 32;
+
+        assertFalse( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char COLON (:) (ASCII code 58)
+     */
+    @Test
+    public void testIsLdifSafeStartingWithColon()
+    {
+        char c = ( char ) 58;
+
+        assertFalse( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char LESS_THAN (<) (ASCII code 60)
+     */
+    @Test
+    public void testIsLdifSafeStartingWithLessThan()
+    {
+        char c = ( char ) 60;
+
+        assertFalse( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char with ASCII code 127
+     */
+    @Test
+    public void testIsLdifSafeStartingWithCharGreaterThan127()
+    {
+        char c = ( char ) 127;
+
+        assertTrue( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String starting with the
+     * char with ASCII code greater than 127
+     */
+    @Test
+    public void testIsLdifSafeStartingWithCharGreaterThan127Bis()
+    {
+        char c = ( char ) 222;
+
+        assertFalse( LdifUtils.isLDIFSafe( c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String containing the
+     * char NUL (ASCII code 0)
+     */
+    @Test
+    public void testIsLdifSafeContainsNUL()
+    {
+        char c = ( char ) 0;
+
+        assertFalse( LdifUtils.isLDIFSafe( testString + c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String containing the
+     * char LF (ASCII code 10)
+     */
+    @Test
+    public void testIsLdifSafeContainsLF()
+    {
+        char c = ( char ) 10;
+
+        assertFalse( LdifUtils.isLDIFSafe( testString + c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String containing the
+     * char CR (ASCII code 13)
+     */
+    @Test
+    public void testIsLdifSafeContainsCR()
+    {
+        char c = ( char ) 13;
+
+        assertFalse( LdifUtils.isLDIFSafe( testString + c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String containing the
+     * char with ASCII code 127
+     */
+    @Test
+    public void testIsLdifSafeContainsCharGreaterThan127()
+    {
+        char c = ( char ) 127;
+
+        assertTrue( LdifUtils.isLDIFSafe( testString + c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String containing a
+     * char with ASCII code greater than 127
+     */
+    @Test
+    public void testIsLdifSafeContainsCharGreaterThan127Bis()
+    {
+        char c = ( char ) 328;
+
+        assertFalse( LdifUtils.isLDIFSafe( testString + c + testString ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a String ending with the
+     * char SPACE (ASCII code 32)
+     */
+    @Test
+    public void testIsLdifSafeEndingWithSpace()
+    {
+        char c = ( char ) 32;
+
+        assertFalse( LdifUtils.isLDIFSafe( testString + c ) );
+    }
+
+
+    /**
+     * Tests the method IsLdifSafe with a correct String
+     */
+    @Test
+    public void testIsLdifSafeCorrectString()
+    {
+        assertTrue( LdifUtils.isLDIFSafe( testString ) );
+    }
+
+
+    /**
+     * Test the way LDIF lines are stripped to a number of chars
+     */
+    @Test
+    public void testStripLineToNChars()
+    {
+        String line = "abc";
+
+        try
+        {
+            LdifUtils.stripLineToNChars( line, 1 );
+            fail();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // This is correct
+        }
+
+        String res = LdifUtils.stripLineToNChars( line, 2 );
+        assertEquals( "ab\n c", res );
+        assertEquals( "abc", LdifUtils.stripLineToNChars( line, 3 ) );
+    }
+
+
+    /**
+     * Test that the LDIF is stripped to 5 chars per line
+     *
+     */
+    @Test
+    public void testStripLineTo5Chars()
+    {
+        assertEquals( "a", LdifUtils.stripLineToNChars( "a", 5 ) );
+        assertEquals( "ab", LdifUtils.stripLineToNChars( "ab", 5 ) );
+        assertEquals( "abc", LdifUtils.stripLineToNChars( "abc", 5 ) );
+        assertEquals( "abcd", LdifUtils.stripLineToNChars( "abcd", 5 ) );
+        assertEquals( "abcde", LdifUtils.stripLineToNChars( "abcde", 5 ) );
+        assertEquals( "abcde\n f", LdifUtils.stripLineToNChars( "abcdef", 5 ) );
+        assertEquals( "abcde\n fg", LdifUtils.stripLineToNChars( "abcdefg", 5 ) );
+        assertEquals( "abcde\n fgh", LdifUtils.stripLineToNChars( "abcdefgh", 5 ) );
+        assertEquals( "abcde\n fghi", LdifUtils.stripLineToNChars( "abcdefghi", 5 ) );
+        assertEquals( "abcde\n fghi\n j", LdifUtils.stripLineToNChars( "abcdefghij", 5 ) );
+        assertEquals( "abcde\n fghi\n jk", LdifUtils.stripLineToNChars( "abcdefghijk", 5 ) );
+        assertEquals( "abcde\n fghi\n jkl", LdifUtils.stripLineToNChars( "abcdefghijkl", 5 ) );
+        assertEquals( "abcde\n fghi\n jklm", LdifUtils.stripLineToNChars( "abcdefghijklm", 5 ) );
+        assertEquals( "abcde\n fghi\n jklm\n n", LdifUtils.stripLineToNChars( "abcdefghijklmn", 5 ) );
+        assertEquals( "abcde\n fghi\n jklm\n no", LdifUtils.stripLineToNChars( "abcdefghijklmno", 5 ) );
+        assertEquals( "abcde\n fghi\n jklm\n nop", LdifUtils.stripLineToNChars( "abcdefghijklmnop", 5 ) );
+    }
+
+
+    /**
+     * Tests that unsafe characters are encoded using UTF-8 charset. 
+     * @throws LdapException 
+     * 
+     * @throws NamingException
+     */
+    @Test
+    public void testConvertToLdifEncoding() throws LdapException
+    {
+        Attributes attributes = new BasicAttributes( "cn", "Saarbr\u00FCcken" );
+        String ldif = LdifUtils.convertToLdif( attributes );
+        assertEquals( "cn:: U2FhcmJyw7xja2Vu\n", ldif );
+    }
+
+
+    /**
+     * Tests that null values are correctly encoded 
+     * 
+     * @throws NamingException
+     */
+    @Test
+    public void testConvertToLdifAttrWithNullValues() throws LdapException
+    {
+        Attributes attributes = new BasicAttributes( "cn", null );
+        String ldif = LdifUtils.convertToLdif( attributes );
+        assertEquals( "cn:\n", ldif );
+    }
+
+
+    /**
+     * Test a conversion of an entry from a LDIF file
+     */
+    @Test
+    public void testConvertToLdif() throws LdapException
+    {
+        LdifEntry entry = new LdifEntry();
+        entry.setDn( "cn=Saarbr\u00FCcken, dc=example, dc=com" );
+        entry.setChangeType( ChangeType.Add );
+
+        entry.addAttribute( "objectClass", "top", "person", "inetorgPerson" );
+        entry.addAttribute( "cn", "Saarbr\u00FCcken" );
+        entry.addAttribute( "sn", "test" );
+
+        LdifUtils.convertToLdif( entry, 15 );
+    }
+
+
+    /**
+     * Test a conversion of an attributes from a LDIF file
+     * @throws org.apache.directory.api.ldap.model.ldif.LdapLdifException
+     */
+    @Test
+    public void testConvertAttributesfromLdif() throws LdapException, LdapLdifException
+    {
+        Attributes attributes = new BasicAttributes( true );
+
+        Attribute oc = new BasicAttribute( "objectclass" );
+        oc.add( "top" );
+        oc.add( "person" );
+        oc.add( "inetorgPerson" );
+
+        attributes.put( oc );
+
+        attributes.put( "cn", "Saarbrucken" );
+        attributes.put( "sn", "test" );
+
+        String ldif = LdifUtils.convertToLdif( attributes, ( Dn ) null, 15 );
+        Attributes result = LdifUtils.getJndiAttributesFromLdif( ldif );
+        assertEquals( attributes, result );
+    }
+
+
+    /**
+     * Check that the correct reverse LDIF is produced for a modifyDn
+     * operation that moves and renames the entry while preserving the
+     * old rdn.
+     *
+     * @throws NamingException on error
+     */
+    @Test
+    public void testReverseModifyDNSuperior() throws LdapException
+    {
+        Dn dn = new Dn( "cn=john doe, dc=example, dc=com" );
+        Dn newSuperior = new Dn( "ou=system" );
+
+        Entry entry = new DefaultEntry( dn );
+        entry.add( "objectClass", "person", "uidObject" );
+        entry.add( "cn", "john doe", "jack doe" );
+        entry.add( "sn", "doe" );
+        entry.add( "uid", "jdoe" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseMoveAndRename( entry, newSuperior, new Rdn( "cn=jack doe" ),
+            false );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+
+        LdifEntry reversed = reverseds.get( 0 );
+        assertEquals( "cn=jack doe,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertFalse( reversed.isDeleteOldRdn() );
+        assertEquals( "cn=john doe", reversed.getNewRdn() );
+        assertEquals( "dc=example, dc=com", Strings.trim( reversed.getNewSuperior() ) );
+        assertNull( reversed.getEntry() );
+    }
+
+
+    /**
+     * Test a reversed ModifyDN with a deleteOldRdn, rdn change, and a superior
+     *
+     * @throws NamingException on error
+     */
+    @Test
+    public void testReverseModifyDNDeleteOldRdnSuperior() throws LdapException
+    {
+        Dn dn = new Dn( "cn=john doe, dc=example, dc=com" );
+        Dn newSuperior = new Dn( "ou=system" );
+
+        Entry entry = new DefaultEntry( dn );
+        entry.add( "objectClass", "person", "uidObject" );
+        entry.add( "cn", "john doe" );
+        entry.add( "sn", "doe" );
+        entry.add( "uid", "jdoe" );
+
+        List<LdifEntry> reverseds = LdifRevertor.reverseMoveAndRename( entry, newSuperior, new Rdn( "cn=jack doe" ),
+            false );
+
+        assertNotNull( reverseds );
+        assertEquals( 1, reverseds.size() );
+
+        LdifEntry reversed = reverseds.get( 0 );
+        assertEquals( "cn=jack doe,ou=system", reversed.getDn().getName() );
+        assertEquals( ChangeType.ModRdn, reversed.getChangeType() );
+        assertTrue( reversed.isDeleteOldRdn() );
+        assertEquals( "cn=john doe", reversed.getNewRdn() );
+        assertEquals( "dc=example, dc=com", Strings.trim( reversed.getNewSuperior() ) );
+        assertNull( reversed.getEntry() );
+    }
+
+
+    @Test
+    public void testCreateAttributesVarargs() throws LdapException, LdapLdifException, NamingException
+    {
+        String mOid = "m-oid: 1.2.3.4";
+        String description = "description";
+
+        Attributes attrs = LdifUtils.createJndiAttributes(
+            "objectClass: top",
+            "objectClass: metaTop",
+            "objectClass: metaSyntax",
+            mOid,
+            "m-description", description );
+
+        assertEquals( "top", attrs.get( "objectClass" ).get( 0 ) );
+        assertEquals( "metaTop", attrs.get( "objectClass" ).get( 1 ) );
+        assertEquals( "metaSyntax", attrs.get( "objectClass" ).get( 2 ) );
+        assertEquals( "1.2.3.4", attrs.get( "m-oid" ).get() );
+        assertEquals( "description", attrs.get( "m-description" ).get() );
+
+        try
+        {
+            LdifUtils.createJndiAttributes(
+                "objectClass", "top",
+                "objectClass" );
+            fail();
+        }
+        catch ( LdapInvalidAttributeValueException iave )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testConvertEntryNoControls() throws Exception
+    {
+        LdifReader reader = new LdifReader();
+
+        String expected =
+            "dn: ou=test\n" +
+                "ObjectClass: top\n" +
+                "ObjectClass: metaTop\n" +
+                "ObjectClass: metaSyntax\n" +
+                "m-oid: 1.2.3.4\n" +
+                "m-description: description\n\n";
+
+        List<LdifEntry> entries = reader.parseLdif( expected );
+        LdifEntry expectedEntry = entries.get( 0 );
+
+        LdifEntry entry = new LdifEntry();
+
+        entry.setDn( "ou=test" );
+        entry.addAttribute( "ObjectClass", "top", "metaTop", "metaSyntax" );
+        entry.addAttribute( "m-oid", "1.2.3.4" );
+        entry.addAttribute( "m-description", "description" );
+
+        String converted = LdifUtils.convertToLdif( entry );
+
+        assertNotNull( converted );
+
+        entries = reader.parseLdif( converted );
+        LdifEntry convertedEntry = entries.get( 0 );
+
+        assertEquals( expectedEntry, convertedEntry );
+    }
+
+
+    @Test
+    public void testConvertEntryOneControl() throws Exception
+    {
+        LdifReader reader = new LdifReader();
+
+        String expected =
+            "dn: ou=test\n" +
+                "control: 2.16.840.1.113730.3.4.2 false\n" +
+                "changetype: add\n" +
+                "ObjectClass: top\n" +
+                "ObjectClass: metaTop\n" +
+                "ObjectClass: metaSyntax\n" +
+                "m-oid: 1.2.3.4\n" +
+                "m-description: description\n\n";
+
+        List<LdifEntry> entries = reader.parseLdif( expected );
+        LdifEntry expectedEntry = entries.get( 0 );
+
+        LdifEntry entry = new LdifEntry();
+
+        entry.setDn( "ou=test" );
+        entry.addAttribute( "ObjectClass", "top", "metaTop", "metaSyntax" );
+        entry.addAttribute( "m-oid", "1.2.3.4" );
+        entry.addAttribute( "m-description", "description" );
+
+        ManageDsaITImpl control = new ManageDsaITImpl();
+
+        entry.addControl( control );
+
+        String converted = LdifUtils.convertToLdif( entry );
+
+        assertNotNull( converted );
+
+        entries = reader.parseLdif( converted );
+        LdifEntry convertedEntry = entries.get( 0 );
+
+        assertEquals( expectedEntry, convertedEntry );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AbstractMessageTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AbstractMessageTest.java
new file mode 100644
index 0000000..5abea12
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AbstractMessageTest.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test cases for the AbstractMessage class' methods.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ *         $Rev: 910150 $
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AbstractMessageTest
+{
+    /**
+     * Tests to see the same object returns true.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        AbstractMessage msg;
+        msg = new AbstractMessage( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        assertTrue( msg.equals( msg ) );
+    }
+
+
+    /**
+     * Tests to see the same exact copy returns true.
+     */
+    @Test
+    public void testEqualsExactCopy()
+    {
+        AbstractMessage msg0;
+        AbstractMessage msg1;
+        msg0 = new AbstractMessage( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        msg1 = new AbstractMessage( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        assertTrue( msg0.equals( msg1 ) );
+        assertTrue( msg1.equals( msg0 ) );
+    }
+
+
+    /**
+     * Tests to make sure changes in the id result in inequality.
+     */
+    @Test
+    public void testNotEqualsDiffId()
+    {
+        AbstractMessage msg0;
+        AbstractMessage msg1;
+        msg0 = new AbstractMessage( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        msg1 = new AbstractMessage( 6, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        assertFalse( msg0.equals( msg1 ) );
+        assertFalse( msg1.equals( msg0 ) );
+    }
+
+
+    /**
+     * Tests to make sure changes in the type result in inequality.
+     */
+    @Test
+    public void testNotEqualsDiffType()
+    {
+        AbstractMessage msg0;
+        AbstractMessage msg1;
+        msg0 = new AbstractMessage( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        msg1 = new AbstractMessage( 5, MessageTypeEnum.UNBIND_REQUEST )
+        {
+        };
+        assertFalse( msg0.equals( msg1 ) );
+        assertFalse( msg1.equals( msg0 ) );
+    }
+
+
+    /**
+     * Tests to make sure changes in the controls result in inequality.
+     */
+    @Test
+    public void testNotEqualsDiffControls()
+    {
+        AbstractMessage msg0;
+        AbstractMessage msg1;
+
+        msg0 = new AbstractMessage( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+
+        msg0.addControl( new Control()
+        {
+            public boolean isCritical()
+            {
+                return false;
+            }
+
+
+            public void setCritical( boolean isCritical )
+            {
+            }
+
+
+            public String getOid()
+            {
+                return "0.0";
+            }
+        } );
+
+        msg1 = new AbstractMessage( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+
+        assertFalse( msg0.equals( msg1 ) );
+        assertFalse( msg1.equals( msg0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AbstractResultResponseTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AbstractResultResponseTest.java
new file mode 100644
index 0000000..65300f5
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AbstractResultResponseTest.java
@@ -0,0 +1,208 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the methods of the AbstractResultResponse class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AbstractResultResponseTest
+{
+    /**
+     * Tests to see the same object returns true.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        AbstractResultResponse msg;
+        msg = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        assertTrue( msg.equals( msg ) );
+    }
+
+
+    /**
+     * Tests to see the same exact copy returns true.
+     */
+    @Test
+    public void testEqualsExactCopy() throws LdapException
+    {
+        AbstractResultResponse msg0 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        AbstractResultResponse msg1 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        LdapResult r0 = msg0.getLdapResult();
+        LdapResult r1 = msg1.getLdapResult();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertTrue( msg0.equals( msg1 ) );
+        assertTrue( msg1.equals( msg0 ) );
+    }
+
+
+    /**
+     * Tests to see the same exact copy returns true.
+     */
+    @Test
+    public void testNotEqualsDiffResult() throws LdapException
+    {
+        AbstractResultResponse msg0 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        AbstractResultResponse msg1 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        LdapResult r0 = msg0.getLdapResult();
+        LdapResult r1 = msg1.getLdapResult();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=apache,dc=org" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertFalse( msg0.equals( msg1 ) );
+        assertFalse( msg1.equals( msg0 ) );
+    }
+
+
+    /**
+     * Tests to make sure changes in the id result in inequality.
+     */
+    @Test
+    public void testNotEqualsDiffId()
+    {
+        AbstractResultResponse msg0;
+        AbstractResultResponse msg1;
+        msg0 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        msg1 = new AbstractResultResponse( 6, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        assertFalse( msg0.equals( msg1 ) );
+        assertFalse( msg1.equals( msg0 ) );
+    }
+
+
+    /**
+     * Tests to make sure changes in the type result in inequality.
+     */
+    @Test
+    public void testNotEqualsDiffType()
+    {
+        AbstractResultResponse msg0;
+        AbstractResultResponse msg1;
+        msg0 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        msg1 = new AbstractResultResponse( 5, MessageTypeEnum.UNBIND_REQUEST )
+        {
+        };
+        assertFalse( msg0.equals( msg1 ) );
+        assertFalse( msg1.equals( msg0 ) );
+    }
+
+
+    /**
+     * Tests to make sure changes in the controls result in inequality.
+     */
+    @Test
+    public void testNotEqualsDiffControls()
+    {
+        AbstractResultResponse msg0;
+        AbstractResultResponse msg1;
+
+        msg0 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+
+        msg0.addControl( new Control()
+        {
+            public boolean isCritical()
+            {
+                return false;
+            }
+
+
+            public void setCritical( boolean isCritical )
+            {
+            }
+
+
+            public String getOid()
+            {
+                return "0.0";
+            }
+        } );
+
+        msg1 = new AbstractResultResponse( 5, MessageTypeEnum.BIND_REQUEST )
+        {
+        };
+        assertFalse( msg0.equals( msg1 ) );
+        assertFalse( msg1.equals( msg0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AddRequestImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AddRequestImplTest.java
new file mode 100644
index 0000000..e3bd95a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/AddRequestImplTest.java
@@ -0,0 +1,305 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the AddRequestImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AddRequestImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Creates and populates a AttributeImpl with a specific id.
+     * 
+     * @param id
+     *            the id for the attribute
+     * @return the AttributeImpl assembled for testing
+     */
+    private Attribute getAttribute( String id ) throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( id );
+        attr.add( "value0" );
+        attr.add( "value1" );
+        attr.add( "value2" );
+        return attr;
+    }
+
+
+    /**
+     * Creates and populates a LockableAttributes object
+     * 
+     * @return
+     */
+    private Entry getEntry()
+    {
+        Entry entry = new DefaultEntry();
+
+        try
+        {
+            entry.put( getAttribute( "attr0" ) );
+            entry.put( getAttribute( "attr1" ) );
+            entry.put( getAttribute( "attr2" ) );
+        }
+        catch ( LdapException ne )
+        {
+            // Do nothing
+        }
+
+        return entry;
+    }
+
+
+    /**
+     * Tests the same object referrence for equality.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        AddRequestImpl req = new AddRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.equals( req ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy() throws LdapException
+    {
+        AddRequestImpl req0 = new AddRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setEntryDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setEntry( getEntry() );
+
+        AddRequestImpl req1 = new AddRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setEntryDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setEntry( getEntry() );
+
+        assertTrue( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the IDs are different.
+     */
+    @Test
+    public void testNotEqualDiffId() throws LdapException
+    {
+        AddRequestImpl req0 = new AddRequestImpl();
+        req0.setMessageId( 7 );
+        req0.setEntryDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setEntry( getEntry() );
+
+        AddRequestImpl req1 = new AddRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setEntryDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setEntry( getEntry() );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the Dn names are different.
+     */
+    @Test
+    public void testNotEqualDiffName() throws LdapException
+    {
+        AddRequestImpl req0 = new AddRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setEntry( getEntry() );
+        req0.setEntryDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        AddRequestImpl req1 = new AddRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setEntry( getEntry() );
+        req1.setEntryDn( new Dn( "cn=admin,dc=apache,dc=org" ) );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Tests for equality even when another BindRequest implementation is used.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        AddRequest req0 = new AddRequest()
+        {
+            public Entry getEntry()
+            {
+                return AddRequestImplTest.this.getEntry();
+            }
+
+
+            public AddRequest setEntry( Entry entry )
+            {
+                return this;
+            }
+
+
+            public Dn getEntryDn()
+            {
+                return null;
+            }
+
+
+            public AddRequest setEntryDn( Dn entryDn )
+            {
+                return this;
+            }
+
+
+            public MessageTypeEnum getResponseType()
+            {
+                return MessageTypeEnum.ADD_RESPONSE;
+            }
+
+
+            public boolean hasResponse()
+            {
+                return true;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.ADD_REQUEST;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public AddRequest addControl( Control control )
+            {
+                return this;
+            }
+
+
+            public AddRequest removeControl( Control control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 5;
+            }
+
+
+            public Object get( Object key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object key, Object value )
+            {
+                return null;
+            }
+
+
+            public void abandon()
+            {
+            }
+
+
+            public boolean isAbandoned()
+            {
+                return false;
+            }
+
+
+            public AddRequest addAbandonListener( AbandonListener listener )
+            {
+                return this;
+            }
+
+
+            public AddResponse getResultResponse()
+            {
+                return null;
+            }
+
+
+            public AddRequest addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public AddRequest setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        AddRequestImpl req1 = new AddRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setEntry( getEntry() );
+        assertTrue( req1.equals( req0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/BindRequestImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/BindRequestImplTest.java
new file mode 100644
index 0000000..ec970fd
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/BindRequestImplTest.java
@@ -0,0 +1,410 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCases for the methods of the BindRequestImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ *         $Rev: 923524 $
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BindRequestImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Tests the same object referrence for equality.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        BindRequestImpl req = new BindRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.equals( req ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy() throws LdapException
+    {
+        BindRequestImpl req0 = new BindRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setCredentials( "password".getBytes() );
+        req0.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setSimple( true );
+        req0.setVersion3( true );
+
+        BindRequestImpl req1 = new BindRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setCredentials( "password".getBytes() );
+        req1.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setSimple( true );
+        req1.setVersion3( true );
+
+        assertTrue( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the IDs are different.
+     */
+    @Test
+    public void testNotEqualDiffId() throws LdapException
+    {
+        BindRequestImpl req0 = new BindRequestImpl();
+        req0.setMessageId( 7 );
+        req0.setCredentials( "password".getBytes() );
+        req0.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setSimple( true );
+        req0.setVersion3( true );
+
+        BindRequestImpl req1 = new BindRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setCredentials( "password".getBytes() );
+        req1.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setSimple( true );
+        req1.setVersion3( true );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the credentials are different.
+     */
+    @Test
+    public void testNotEqualDiffCreds() throws LdapException
+    {
+        BindRequestImpl req0 = new BindRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setCredentials( "abcdefg".getBytes() );
+        req0.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setSimple( true );
+        req0.setVersion3( true );
+
+        BindRequestImpl req1 = new BindRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setCredentials( "password".getBytes() );
+        req1.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setSimple( true );
+        req1.setVersion3( true );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the Dn names are different.
+     */
+    @Test
+    public void testNotEqualDiffName() throws LdapException
+    {
+        BindRequestImpl req0 = new BindRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setCredentials( "password".getBytes() );
+        req0.setDn( new Dn( "uid=akarasulu,dc=example,dc=com" ) );
+        req0.setSimple( true );
+        req0.setVersion3( true );
+
+        BindRequestImpl req1 = new BindRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setCredentials( "password".getBytes() );
+        req1.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setSimple( true );
+        req1.setVersion3( true );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the auth mechanisms are different.
+     */
+    @Test
+    public void testNotEqualDiffSimple() throws LdapException
+    {
+        BindRequestImpl req0 = new BindRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setCredentials( "password".getBytes() );
+        req0.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setSimple( false );
+        req0.setVersion3( true );
+
+        BindRequestImpl req1 = new BindRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setCredentials( "password".getBytes() );
+        req1.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setSimple( true );
+        req1.setVersion3( true );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the bind LDAP versions are different.
+     */
+    @Test
+    public void testNotEqualDiffVersion() throws LdapException
+    {
+        BindRequestImpl req0 = new BindRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setCredentials( "password".getBytes() );
+        req0.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setSimple( true );
+        req0.setVersion3( false );
+
+        BindRequestImpl req1 = new BindRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setCredentials( "password".getBytes() );
+        req1.setDn( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setSimple( true );
+        req1.setVersion3( true );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Tests for equality even when another BindRequest implementation is used.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        BindRequest req0 = new BindRequest()
+        {
+            public boolean isSimple()
+            {
+                return true;
+            }
+
+
+            public boolean getSimple()
+            {
+                return true;
+            }
+
+
+            public BindRequest setSimple( boolean a_isSimple )
+            {
+                return this;
+            }
+
+
+            public byte[] getCredentials()
+            {
+                return null;
+            }
+
+
+            public BindRequest setCredentials( String credentials )
+            {
+                return this;
+            }
+
+
+            public BindRequest setCredentials( byte[] credentials )
+            {
+                return this;
+            }
+
+
+            public String getName()
+            {
+                return null;
+            }
+
+
+            public BindRequest setName( String name )
+            {
+                return this;
+            }
+
+
+            public Dn getDn()
+            {
+                return null;
+            }
+
+
+            public BindRequest setDn( Dn dn )
+            {
+                return this;
+            }
+
+
+            public boolean isVersion3()
+            {
+                return true;
+            }
+
+
+            public boolean getVersion3()
+            {
+                return true;
+            }
+
+
+            public BindRequest setVersion3( boolean isVersion3 )
+            {
+                return this;
+            }
+
+
+            public MessageTypeEnum getResponseType()
+            {
+                return MessageTypeEnum.BIND_RESPONSE;
+            }
+
+
+            public boolean hasResponse()
+            {
+                return true;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.BIND_REQUEST;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public BindRequest addControl( Control control )
+            {
+                return this;
+            }
+
+
+            public BindRequest removeControl( Control control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 5;
+            }
+
+
+            public Object get( Object a_key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object a_key, Object a_value )
+            {
+                return null;
+            }
+
+
+            public String getSaslMechanism()
+            {
+                return null;
+            }
+
+
+            public BindRequest setSaslMechanism( String saslMechanism )
+            {
+                return this;
+            }
+
+
+            public BindResponse getResultResponse()
+            {
+                return null;
+            }
+
+
+            public BindRequest addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public void abandon()
+            {
+            }
+
+
+            public BindRequest addAbandonListener( AbandonListener listener )
+            {
+                return this;
+            }
+
+
+            public boolean isAbandoned()
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public BindRequest setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        BindRequest req1 = new BindRequestImpl();
+        req1.setMessageId( 5 );
+        assertTrue( req1.equals( req0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/BindResponseImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/BindResponseImplTest.java
new file mode 100644
index 0000000..0a4ef50
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/BindResponseImplTest.java
@@ -0,0 +1,199 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.BindResponseImpl;
+import org.apache.directory.api.ldap.model.message.LdapResultImpl;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the methods of the BindResponseImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ *         $Rev: 946353 $
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BindResponseImplTest
+
+{
+    /**
+     * Tests to make sure the same object returns true with equals().
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        BindResponseImpl resp = new BindResponseImpl( 1 );
+        assertTrue( "same object should be equal", resp.equals( resp ) );
+    }
+
+
+    /**
+     * Tests to make sure newly created objects with same id are equal.
+     */
+    @Test
+    public void testEqualsNewWithSameId()
+    {
+        BindResponseImpl resp0 = new BindResponseImpl( 1 );
+        BindResponseImpl resp1 = new BindResponseImpl( 1 );
+        assertTrue( "default copy with same id should be equal", resp0.equals( resp1 ) );
+        assertTrue( "default copy with same id should be equal", resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests to make sure the same object has the same hashCode.
+     */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        BindResponseImpl resp = new BindResponseImpl( 1 );
+        assertTrue( resp.hashCode() == resp.hashCode() );
+    }
+
+
+    /**
+     * Tests to make sure newly created objects with same id have the same hashCode.
+     */
+    @Test
+    public void testHashCodeNewWithSameId()
+    {
+        BindResponseImpl resp0 = new BindResponseImpl( 1 );
+        BindResponseImpl resp1 = new BindResponseImpl( 1 );
+        assertTrue( resp1.hashCode() == resp0.hashCode() );
+    }
+
+
+    /**
+     * Tests to make sure newly created objects with same different id are not
+     * equal.
+     */
+    @Test
+    public void testNotEqualsNewWithDiffId()
+    {
+        BindResponseImpl resp0 = new BindResponseImpl( 1 );
+        BindResponseImpl resp1 = new BindResponseImpl( 2 );
+        assertFalse( "different id objects should not be equal", resp0.equals( resp1 ) );
+        assertFalse( "different id objects should not be equal", resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests to make sure newly created objects with same different saslCreds
+     * are not equal.
+     */
+    @Test
+    public void testNotEqualsNewWithDiffSaslCreds()
+    {
+        BindResponseImpl resp0 = new BindResponseImpl( 1 );
+        resp0.setServerSaslCreds( new byte[2] );
+        BindResponseImpl resp1 = new BindResponseImpl( 1 );
+        resp1.setServerSaslCreds( new byte[3] );
+        assertFalse( "different serverSaslCreds objects should not be equal", resp0.equals( resp1 ) );
+        assertFalse( "different serverSaslCreds objects should not be equal", resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equality of two fully loaded identical BindResponse PDUs.
+     */
+    @Test
+    public void testEqualsWithTheWorks() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        BindResponseImpl resp0 = new BindResponseImpl( 1 );
+        BindResponseImpl resp1 = new BindResponseImpl( 1 );
+
+        resp0.setServerSaslCreds( "password".getBytes() );
+        resp1.setServerSaslCreds( "password".getBytes() );
+
+        assertTrue( "loaded carbon copies should be equal", resp0.equals( resp1 ) );
+        assertTrue( "loaded carbon copies should be equal", resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equal hashCode of two fully loaded identical BindResponse PDUs.
+     */
+    @Test
+    public void testHashCodeWithTheWorks() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        BindResponseImpl resp0 = new BindResponseImpl( 1 );
+        BindResponseImpl resp1 = new BindResponseImpl( 1 );
+
+        resp0.setServerSaslCreds( "password".getBytes() );
+        resp1.setServerSaslCreds( "password".getBytes() );
+
+        assertTrue( resp0.hashCode() == resp1.hashCode() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/CompareRequestImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/CompareRequestImplTest.java
new file mode 100644
index 0000000..ba46314
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/CompareRequestImplTest.java
@@ -0,0 +1,342 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the CompareRequestImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CompareRequestImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Tests the same object reference for equality.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        CompareRequestImpl req = new CompareRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.equals( req ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy() throws LdapException
+    {
+        CompareRequestImpl req0 = new CompareRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setAttributeId( "objectClass" );
+        req0.setAssertionValue( "top" );
+
+        CompareRequestImpl req1 = new CompareRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setAttributeId( "objectClass" );
+        req1.setAssertionValue( "top" );
+
+        assertTrue( req0.equals( req1 ) );
+        assertTrue( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Tests the same object reference for equal hashCode.
+     */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        CompareRequestImpl req = new CompareRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.hashCode() == req.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using exact copies.
+     */
+    @Test
+    public void testHashCodeExactCopy() throws LdapException
+    {
+        CompareRequestImpl req0 = new CompareRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req0.setAttributeId( "objectClass" );
+        req0.setAssertionValue( "top" );
+
+        CompareRequestImpl req1 = new CompareRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+        req1.setAttributeId( "objectClass" );
+        req1.setAssertionValue( "top" );
+
+        assertTrue( req0.hashCode() == req1.hashCode() );
+    }
+
+
+    /**
+     * Test for inequality when only the IDs are different.
+     */
+    @Test
+    public void testNotEqualDiffId() throws LdapException
+    {
+        CompareRequestImpl req0 = new CompareRequestImpl();
+        req0.setMessageId( 7 );
+        req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        CompareRequestImpl req1 = new CompareRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the attributeIds are different.
+     */
+    @Test
+    public void testNotEqualDiffAttributeIds() throws LdapException
+    {
+        CompareRequestImpl req0 = new CompareRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setName( new Dn( "cn=admin,dc=apache,dc=org" ) );
+        req0.setAttributeId( "dc" );
+        req0.setAssertionValue( "apache.org" );
+
+        CompareRequestImpl req1 = new CompareRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=apache,dc=org" ) );
+        req1.setAttributeId( "nisDomain" );
+        req1.setAssertionValue( "apache.org" );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the Assertion values are different.
+     */
+    @Test
+    public void testNotEqualDiffValue() throws LdapException
+    {
+        CompareRequestImpl req0 = new CompareRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setName( new Dn( "cn=admin,dc=apache,dc=org" ) );
+        req0.setAttributeId( "dc" );
+        req0.setAssertionValue( "apache.org" );
+
+        CompareRequestImpl req1 = new CompareRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=apache,dc=org" ) );
+        req1.setAttributeId( "dc" );
+        req1.setAssertionValue( "nagoya.apache.org" );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Tests for equality even when another CompareRequest implementation is
+     * used.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        CompareRequest req0 = new CompareRequest()
+        {
+            public Value<?> getAssertionValue()
+            {
+                return null;
+            }
+
+
+            public CompareRequest setAssertionValue( String value )
+            {
+                return this;
+            }
+
+
+            public CompareRequest setAssertionValue( byte[] value )
+            {
+                return this;
+            }
+
+
+            public String getAttributeId()
+            {
+                return null;
+            }
+
+
+            public CompareRequest setAttributeId( String attrId )
+            {
+                return this;
+            }
+
+
+            public Dn getName()
+            {
+                return null;
+            }
+
+
+            public CompareRequest setName( Dn name )
+            {
+                return this;
+            }
+
+
+            public MessageTypeEnum getResponseType()
+            {
+                return MessageTypeEnum.COMPARE_RESPONSE;
+            }
+
+
+            public boolean hasResponse()
+            {
+                return true;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.COMPARE_REQUEST;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public CompareRequest addControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public CompareRequest removeControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 5;
+            }
+
+
+            public Object get( Object a_key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object a_key, Object a_value )
+            {
+                return null;
+            }
+
+
+            public void abandon()
+            {
+            }
+
+
+            public boolean isAbandoned()
+            {
+                return false;
+            }
+
+
+            public CompareRequest addAbandonListener( AbandonListener listener )
+            {
+                return this;
+            }
+
+
+            public CompareResponse getResultResponse()
+            {
+                return null;
+            }
+
+
+            public CompareRequest addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public CompareRequest setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        CompareRequestImpl req1 = new CompareRequestImpl();
+        req1.setMessageId( 5 );
+        assertTrue( req1.equals( req0 ) );
+        assertFalse( req0.equals( req1 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/DeleteRequestImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/DeleteRequestImplTest.java
new file mode 100644
index 0000000..895843a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/DeleteRequestImplTest.java
@@ -0,0 +1,272 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the methods of the DeleteRequestImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DeleteRequestImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Tests the same object reference for equality.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        DeleteRequestImpl req = new DeleteRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.equals( req ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy() throws LdapException
+    {
+        DeleteRequestImpl req0 = new DeleteRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        DeleteRequestImpl req1 = new DeleteRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        assertTrue( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Tests the same object reference for equal hashCode.
+     */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        DeleteRequestImpl req = new DeleteRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.hashCode() == req.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using exact copies.
+     */
+    @Test
+    public void testHashCodeExactCopy() throws LdapException
+    {
+        DeleteRequestImpl req0 = new DeleteRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        DeleteRequestImpl req1 = new DeleteRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        assertTrue( req0.hashCode() == req1.hashCode() );
+    }
+
+
+    /**
+     * Test for inequality when only the IDs are different.
+     */
+    @Test
+    public void testNotEqualDiffId() throws LdapException
+    {
+        DeleteRequestImpl req0 = new DeleteRequestImpl();
+        req0.setMessageId( 7 );
+        req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        DeleteRequestImpl req1 = new DeleteRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the Dn names are different.
+     */
+    @Test
+    public void testNotEqualDiffName() throws LdapException
+    {
+        DeleteRequestImpl req0 = new DeleteRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setName( new Dn( "uid=akarasulu,dc=example,dc=com" ) );
+
+        DeleteRequestImpl req1 = new DeleteRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Tests for equality even when another DeleteRequest implementation is
+     * used.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        DeleteRequest req0 = new DeleteRequest()
+        {
+            public Dn getName()
+            {
+                return null;
+            }
+
+
+            public DeleteRequest setName( Dn name )
+            {
+                return this;
+            }
+
+
+            public MessageTypeEnum getResponseType()
+            {
+                return MessageTypeEnum.DEL_RESPONSE;
+            }
+
+
+            public boolean hasResponse()
+            {
+                return true;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.DEL_REQUEST;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public DeleteRequest addControl( Control control )
+            {
+                return this;
+            }
+
+
+            public DeleteRequest removeControl( Control control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 5;
+            }
+
+
+            public Object get( Object key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object key, Object value )
+            {
+                return null;
+            }
+
+
+            public void abandon()
+            {
+            }
+
+
+            public boolean isAbandoned()
+            {
+                return false;
+            }
+
+
+            public DeleteRequest addAbandonListener( AbandonListener listener )
+            {
+                return this;
+            }
+
+
+            public DeleteResponse getResultResponse()
+            {
+                return null;
+            }
+
+
+            public DeleteRequest addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public DeleteRequest setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        DeleteRequestImpl req1 = new DeleteRequestImpl();
+        req1.setMessageId( 5 );
+        assertTrue( req1.equals( req0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ExtendedRequestImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ExtendedRequestImplTest.java
new file mode 100644
index 0000000..8b66041
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ExtendedRequestImplTest.java
@@ -0,0 +1,273 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the ExtendedRequestImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ExtendedRequestImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Tests the same object reference for equality.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        ExtendedRequestImpl req = new ExtendedRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.equals( req ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy()
+    {
+        ExtendedRequestImpl req0 = new ExtendedRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setRequestName( "1.1.1.1" );
+
+        ExtendedRequestImpl req1 = new ExtendedRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setRequestName( "1.1.1.1" );
+
+        assertTrue( req0.equals( req1 ) );
+        assertTrue( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Tests the same object reference for equal hashCode.
+     */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        ExtendedRequestImpl req = new ExtendedRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.hashCode() == req.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using exact copies.
+     */
+    @Test
+    public void testHashCodeExactCopy()
+    {
+        ExtendedRequestImpl req0 = new ExtendedRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setRequestName( "1.1.1.1" );
+
+        ExtendedRequestImpl req1 = new ExtendedRequestImpl();
+        req1.setMessageId( 5 );
+        req1.setRequestName( "1.1.1.1" );
+
+        assertTrue( req0.hashCode() == req1.hashCode() );
+    }
+
+
+    /**
+     * Test for inequality when only the IDs are different.
+     */
+    @Test
+    public void testNotEqualDiffId()
+    {
+        ExtendedRequestImpl req0 = new ExtendedRequestImpl();
+        req0.setMessageId( 7 );
+        ExtendedRequestImpl req1 = new ExtendedRequestImpl();
+        req1.setMessageId( 5 );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the OID is different.
+     */
+    @Test
+    public void testNotEqualDiffOID()
+    {
+        ExtendedRequestImpl req0 = new ExtendedRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setRequestName( "1.1.1.1" );
+
+        ExtendedRequestImpl req1 = new ExtendedRequestImpl();
+        req1.setMessageId( 5 );
+        req0.setRequestName( "1.2.2.1" );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the Assertion values are different.
+     */
+    @Test
+    public void testNotEqualDiffValue()
+    {
+        ExtendedRequestImpl req0 = new ExtendedRequestImpl();
+        req0.setMessageId( 5 );
+        req0.setRequestName( "1.1.1.1" );
+
+        ExtendedRequestImpl req1 = new ExtendedRequestImpl();
+        req1.setMessageId( 5 );
+        req0.setRequestName( "1.1.1.1" );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Tests for equality even when another ExtendedRequest implementation is
+     * used.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        ExtendedRequest req0 = new ExtendedRequest()
+        {
+            public ExtendedRequest setRequestName( String oid )
+            {
+                return this;
+            }
+
+
+            public MessageTypeEnum getResponseType()
+            {
+                return MessageTypeEnum.EXTENDED_RESPONSE;
+            }
+
+
+            public boolean hasResponse()
+            {
+                return true;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.EXTENDED_REQUEST;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public ExtendedRequest addControl( Control control )
+            {
+                return this;
+            }
+
+
+            public ExtendedRequest removeControl( Control control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 5;
+            }
+
+
+            public Object get( Object key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object key, Object value )
+            {
+                return null;
+            }
+
+
+            public ExtendedResponse getResultResponse()
+            {
+                return null;
+            }
+
+
+            public String getRequestName()
+            {
+                return null;
+            }
+
+
+            public ExtendedRequest addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public ExtendedRequest setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        ExtendedRequestImpl req1 = new ExtendedRequestImpl();
+        req1.setMessageId( 5 );
+        assertTrue( req1.equals( req0 ) );
+        assertFalse( req0.equals( req1 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ExtendedResponseImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ExtendedResponseImplTest.java
new file mode 100644
index 0000000..531b154
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ExtendedResponseImplTest.java
@@ -0,0 +1,271 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the ExtendedResponseImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ExtendedResponseImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Creates and populates a ExtendedResponseImpl stub for testing purposes.
+     * 
+     * @return a populated ExtendedResponseImpl stub
+     */
+    private ExtendedResponseImpl createStub()
+    {
+        // Construct the Search response to test with results and referrals
+        ExtendedResponseImpl response = new ExtendedResponseImpl( 45 );
+        response.setResponseName( "1.1.1.1" );
+        LdapResult result = response.getLdapResult();
+
+        try
+        {
+            result.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        }
+        catch ( LdapException ine )
+        {
+            // Do nothing
+        }
+
+        result.setResultCode( ResultCodeEnum.SUCCESS );
+        ReferralImpl refs = new ReferralImpl();
+        refs.addLdapUrl( "ldap://someserver.com" );
+        refs.addLdapUrl( "ldap://apache.org" );
+        refs.addLdapUrl( "ldap://another.net" );
+        result.setReferral( refs );
+        return response;
+    }
+
+
+    /**
+     * Tests for equality using the same object.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        ExtendedResponseImpl resp = createStub();
+        assertTrue( resp.equals( resp ) );
+    }
+
+
+    /**
+     * Tests for equality using an exact copy.
+     */
+    @Test
+    public void testEqualsExactCopy()
+    {
+        ExtendedResponseImpl resp0 = createStub();
+        ExtendedResponseImpl resp1 = createStub();
+        assertTrue( resp0.equals( resp1 ) );
+        assertTrue( resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equality using different stub implementations.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        ExtendedResponseImpl resp0 = createStub();
+        ExtendedResponse resp1 = new ExtendedResponse()
+        {
+            public String getResponseName()
+            {
+                return "1.1.1.1";
+            }
+
+
+            public void setResponseName( String oid )
+            {
+            }
+
+
+            public LdapResult getLdapResult()
+            {
+                LdapResultImpl result = new LdapResultImpl();
+
+                try
+                {
+                    result.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+                }
+                catch ( LdapException ine )
+                {
+                    // do nothing
+                }
+
+                result.setResultCode( ResultCodeEnum.SUCCESS );
+                ReferralImpl refs = new ReferralImpl();
+                refs.addLdapUrl( "ldap://someserver.com" );
+                refs.addLdapUrl( "ldap://apache.org" );
+                refs.addLdapUrl( "ldap://another.net" );
+                result.setReferral( refs );
+
+                return result;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.EXTENDED_RESPONSE;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public ExtendedResponse addControl( Control control )
+            {
+                return this;
+            }
+
+
+            public ExtendedResponse removeControl( Control control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 45;
+            }
+
+
+            public Object get( Object a_key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object a_key, Object a_value )
+            {
+                return null;
+            }
+
+
+            public ExtendedResponse addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public ExtendedResponse setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        assertTrue( resp0.equals( resp1 ) );
+        assertFalse( resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equal hashCode using the same object.
+     */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        ExtendedResponseImpl resp = createStub();
+        assertTrue( resp.hashCode() == resp.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using an exact copy.
+     */
+    @Test
+    public void testHashCodeExactCopy()
+    {
+        ExtendedResponseImpl resp0 = createStub();
+        ExtendedResponseImpl resp1 = createStub();
+        assertTrue( resp0.hashCode() == resp1.hashCode() );
+    }
+
+
+    /**
+     * Tests inequality when messageIds are different.
+     */
+    @Test
+    public void testNotEqualsDiffIds()
+    {
+        ExtendedResponseImpl resp0 = new ExtendedResponseImpl( 3 );
+        ExtendedResponseImpl resp1 = new ExtendedResponseImpl( 4 );
+
+        assertFalse( resp0.equals( resp1 ) );
+        assertFalse( resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests inequality when responseNames are different.
+     */
+    @Test
+    public void testNotEqualsDiffNames()
+    {
+        ExtendedResponseImpl resp0 = createStub();
+        resp0.setResponseName( "1.2.3.4" );
+        ExtendedResponseImpl resp1 = createStub();
+        resp1.setResponseName( "1.2.3.4.5" );
+
+        assertFalse( resp0.equals( resp1 ) );
+        assertFalse( resp1.equals( resp0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/LdapResultImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/LdapResultImplTest.java
new file mode 100644
index 0000000..2dc8d0b
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/LdapResultImplTest.java
@@ -0,0 +1,384 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.LdapResult;
+import org.apache.directory.api.ldap.model.message.LdapResultImpl;
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the methods of the LdapResultImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *         $Rev: 946251 $
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapResultImplTest
+{
+    /**
+     * Tests to make sure the two same objects are seen as equal.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        assertTrue( "same object should be equal", r0.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests to make sure a default LdapResultImpl equals another one just
+     * created.
+     */
+    @Test
+    public void testEqualsDefaultCopy()
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        assertTrue( "default copy should be equal", r0.equals( r1 ) );
+        assertTrue( "default copy should be equal", r1.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests for equality when the lockable parent is not the same.
+     */
+    @Test
+    public void testEqualsDiffLockableParent()
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        assertTrue( "default copy with different lockable parents " + "should be equal", r0.equals( r1 ) );
+        assertTrue( "default copy with different lockable parents " + "should be equal", r1.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests for equality when the lockable parent is the same.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+
+        LdapResult r1 = new LdapResult()
+        {
+            public ResultCodeEnum getResultCode()
+            {
+                return ResultCodeEnum.SUCCESS;
+            }
+
+
+            public void setResultCode( ResultCodeEnum a_resultCode )
+            {
+            }
+
+
+            public Dn getMatchedDn()
+            {
+                return null;
+            }
+
+
+            public void setMatchedDn( Dn dn )
+            {
+            }
+
+
+            public String getDiagnosticMessage()
+            {
+                return null;
+            }
+
+
+            public void setDiagnosticMessage( String diagnosticMessage )
+            {
+            }
+
+
+            public boolean isReferral()
+            {
+                return false;
+            }
+
+
+            public Referral getReferral()
+            {
+                return null;
+            }
+
+
+            public void setReferral( Referral referral )
+            {
+            }
+
+
+            public boolean isDefaultSuccess()
+            {
+                return false;
+            }
+        };
+
+        assertTrue( "r0 equals should see other impl r1 as equal", r0.equals( r1 ) );
+        assertFalse( "r1 impl uses Object.equals() so it should not see " + "r0 as the same object", r1.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests two non default carbon copies for equality.
+     */
+    @Test
+    public void testEqualsCarbonCopy() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertTrue( "exact copy should be equal", r0.equals( r1 ) );
+        assertTrue( "exact copy should be equal", r1.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests to make sure the two same objects have equal HashCode.
+     */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        assertTrue( r0.hashCode() == r0.hashCode() );
+    }
+
+
+    /**
+     * Tests to make sure a default LdapResultImpl has equal hashCode another one just
+     * created.
+     */
+    @Test
+    public void testHashCodeDefaultCopy()
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        assertTrue( r0.hashCode() == r1.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode when the lockable parent is not the same.
+     */
+    @Test
+    public void testHashCodeDiffLockableParent()
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        assertTrue( r0.hashCode() == r1.hashCode() );
+    }
+
+
+    /**
+     * Tests two non default carbon copies for equal hashCode.
+     */
+    @Test
+    public void testHashCodeCarbonCopy() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertTrue( r0.hashCode() == r1.hashCode() );
+    }
+
+
+    /**
+     * Tests for inequality when the error message is different.
+     */
+    @Test
+    public void testNotEqualsDiffErrorMessage() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertFalse( "results with different error messages should " + "not be equal", r0.equals( r1 ) );
+        assertFalse( "results with different error messages should " + "not be equal", r1.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests for inequality when the matchedDn properties are not the same.
+     */
+    @Test
+    public void testNotEqualsDiffMatchedDn() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=apache,dc=org" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertFalse( "results with different matchedDn properties " + "should not be equal", r0.equals( r1 ) );
+        assertFalse( "results with different matchedDn properties " + "should not be equal", r1.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests for inequality when the resultCode properties are not the same.
+     */
+    @Test
+    public void testNotEqualsDiffResultCode() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.SIZE_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://someserver.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertFalse( "results with different result codes should not be equal", r0.equals( r1 ) );
+        assertFalse( "results with different result codes should not be equal", r1.equals( r0 ) );
+    }
+
+
+    /**
+     * Tests for inequality when the referrals are not the same.
+     */
+    @Test
+    public void testNotEqualsDiffReferrals() throws LdapException
+    {
+        LdapResultImpl r0 = new LdapResultImpl();
+        LdapResultImpl r1 = new LdapResultImpl();
+
+        r0.setDiagnosticMessage( "blah blah blah" );
+        r1.setDiagnosticMessage( "blah blah blah" );
+
+        r0.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        r1.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+
+        r0.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+        r1.setResultCode( ResultCodeEnum.TIME_LIMIT_EXCEEDED );
+
+        Referral refs0 = new ReferralImpl();
+        r0.setReferral( refs0 );
+        refs0.addLdapUrl( "ldap://someserver.com" );
+        refs0.addLdapUrl( "ldap://anotherserver.org" );
+
+        Referral refs1 = new ReferralImpl();
+        r1.setReferral( refs1 );
+        refs1.addLdapUrl( "ldap://abc.com" );
+        refs1.addLdapUrl( "ldap://anotherserver.org" );
+
+        assertFalse( "results with different referrals should not be equal", r0.equals( r1 ) );
+        assertFalse( "results with different referrals should not be equal", r1.equals( r0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyDnRequestImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyDnRequestImplTest.java
new file mode 100644
index 0000000..87ed6a6
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyDnRequestImplTest.java
@@ -0,0 +1,428 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the ModifyDnRequestImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyDnRequestImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Constructs a ModifyDnrequest to test.
+     * 
+     * @return the request
+     */
+    private ModifyDnRequestImpl getRequest()
+    {
+        // Construct the ModifyDn request to test
+        ModifyDnRequestImpl request = new ModifyDnRequestImpl();
+        request.setMessageId( 45 );
+        request.setDeleteOldRdn( true );
+
+        try
+        {
+            request.setName( new Dn( "dc=admins,dc=apache,dc=org" ) );
+            request.setNewRdn( new Rdn( "dc=administrators" ) );
+            request.setNewSuperior( new Dn( "dc=groups,dc=apache,dc=org" ) );
+        }
+        catch ( LdapException ine )
+        {
+            // do nothing
+        }
+
+        return request;
+    }
+
+
+    /**
+     * Tests the same object reference for equality.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        ModifyDnRequestImpl req = new ModifyDnRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.equals( req ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy0()
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        ModifyDnRequestImpl req1 = getRequest();
+
+        assertTrue( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy1()
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        req0.setNewSuperior( null );
+        ModifyDnRequestImpl req1 = getRequest();
+        req1.setNewSuperior( null );
+
+        assertTrue( req0.equals( req1 ) );
+    }
+
+
+    /**
+    * Tests the same object reference for equal hashCode
+    */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        ModifyDnRequestImpl req = new ModifyDnRequestImpl();
+        req.setMessageId( 5 );
+        assertTrue( req.hashCode() == req.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using exact copies.
+     */
+    @Test
+    public void testHashCodeExactCopy0()
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        ModifyDnRequestImpl req1 = getRequest();
+
+        assertTrue( req0.hashCode() == req1.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using exact copies.
+     */
+    @Test
+    public void testHashCodeExactCopy1()
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        req0.setNewSuperior( null );
+        ModifyDnRequestImpl req1 = getRequest();
+        req1.setNewSuperior( null );
+
+        assertTrue( req0.hashCode() == req1.hashCode() );
+    }
+
+
+    /**
+     * Test for inequality when only the IDs are different.
+     */
+    @Test
+    public void testNotEqualDiffId()
+    {
+        ModifyDnRequestImpl req0 = new ModifyDnRequestImpl();
+        req0.setMessageId( 4 );
+        ModifyDnRequestImpl req1 = new ModifyDnRequestImpl();
+        req1.setMessageId( 5 );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the Dn names are different.
+     */
+    @Test
+    public void testNotEqualDiffName() throws LdapException
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        ModifyDnRequestImpl req1 = getRequest();
+        req1.setName( new Dn( "cn=admin,dc=apache,dc=org" ) );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the newSuperior DNs are different.
+     */
+    @Test
+    public void testNotEqualDiffNewSuperior() throws LdapException
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        req0.setNewSuperior( new Dn( "cn=admin,dc=example,dc=com" ) );
+
+        ModifyDnRequestImpl req1 = getRequest();
+        req1.setNewSuperior( new Dn( "cn=admin,dc=apache,dc=org" ) );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the delete old Rdn properties is different.
+     */
+    @Test
+    public void testNotEqualDiffDeleteOldRdn()
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        req0.setDeleteOldRdn( true );
+
+        ModifyDnRequestImpl req1 = getRequest();
+        req1.setDeleteOldRdn( false );
+
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the new Rdn properties are different.
+     */
+    @Test
+    public void testNotEqualDiffNewRdn() throws LdapException
+    {
+        ModifyDnRequestImpl req0 = getRequest();
+        req0.setNewRdn( new Rdn( "cn=admin0" ) );
+
+        ModifyDnRequestImpl req1 = getRequest();
+        req1.setNewRdn( new Rdn( "cn=admin1" ) );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Tests for equality even when another BindRequest implementation is used.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        ModifyDnRequest req0 = new ModifyDnRequest()
+        {
+            public Dn getName()
+            {
+                try
+                {
+                    return new Dn( "dc=admins,dc=apache,dc=org" );
+                }
+                catch ( LdapException ine )
+                {
+                    // do nothing
+                    return null;
+                }
+            }
+
+
+            public ModifyDnRequest setName( Dn name )
+            {
+                return this;
+            }
+
+
+            public Rdn getNewRdn()
+            {
+                try
+                {
+                    return new Rdn( "dc=administrators" );
+                }
+                catch ( LdapException ine )
+                {
+                    // do nothing
+                    return null;
+                }
+            }
+
+
+            public ModifyDnRequest setNewRdn( Rdn newRdn )
+            {
+                return this;
+            }
+
+
+            public boolean getDeleteOldRdn()
+            {
+                return true;
+            }
+
+
+            public ModifyDnRequest setDeleteOldRdn( boolean deleteOldRdn )
+            {
+                return this;
+            }
+
+
+            public Dn getNewSuperior()
+            {
+                try
+                {
+                    return new Dn( "dc=groups,dc=apache,dc=org" );
+                }
+                catch ( LdapException ine )
+                {
+                    // do nothing
+                    return null;
+                }
+            }
+
+
+            public ModifyDnRequest setNewSuperior( Dn newSuperior )
+            {
+                return this;
+            }
+
+
+            public boolean isMove()
+            {
+                return false;
+            }
+
+
+            public MessageTypeEnum getResponseType()
+            {
+                return MessageTypeEnum.MODIFYDN_RESPONSE;
+            }
+
+
+            public boolean hasResponse()
+            {
+                return true;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.MODIFYDN_REQUEST;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public ModifyDnRequest addControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public ModifyDnRequest removeControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 45;
+            }
+
+
+            public Object get( Object a_key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object a_key, Object a_value )
+            {
+                return null;
+            }
+
+
+            public void abandon()
+            {
+            }
+
+
+            public boolean isAbandoned()
+            {
+                return false;
+            }
+
+
+            public ModifyDnRequest addAbandonListener( AbandonListener listener )
+            {
+                return this;
+            }
+
+
+            public ModifyDnResponse getResultResponse()
+            {
+                return null;
+            }
+
+
+            public ModifyDnRequest addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public ModifyDnRequest setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        ModifyDnRequestImpl req1 = getRequest();
+        assertTrue( req1.equals( req0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyRequestImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyRequestImplTest.java
new file mode 100644
index 0000000..3a4446f
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ModifyRequestImplTest.java
@@ -0,0 +1,535 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test case for the ModifyRequestImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ModifyRequestImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Builds a ModifyRequest for testing purposes.
+     * 
+     * @return the ModifyRequest to use for tests
+     */
+    private ModifyRequestImpl getRequest() throws LdapException
+    {
+        // Construct the Modify request to test
+        ModifyRequestImpl req = new ModifyRequestImpl();
+        req.setMessageId( 45 );
+
+        try
+        {
+            req.setName( new Dn( "cn=admin,dc=apache,dc=org" ) );
+        }
+        catch ( LdapException ne )
+        {
+            // do nothing
+        }
+
+        Attribute attr = new DefaultAttribute( "attr0" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        Modification item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        req.addModification( item );
+
+        attr = new DefaultAttribute( "attr1" );
+        attr.add( "val3" );
+        item = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
+        req.addModification( item );
+
+        attr = new DefaultAttribute( "attr2" );
+        attr.add( "val4" );
+        attr.add( "val5" );
+        item = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attr );
+        req.addModification( item );
+
+        return req;
+    }
+
+
+    /**
+     * Tests the same object reference for equality.
+     */
+    @Test
+    public void testEqualsSameObj() throws LdapException
+    {
+        ModifyRequestImpl req = getRequest();
+        assertTrue( req.equals( req ) );
+    }
+
+
+    /**
+     * Tests for equality using exact copies.
+     */
+    @Test
+    public void testEqualsExactCopy() throws LdapException
+    {
+        ModifyRequestImpl req0 = getRequest();
+        ModifyRequestImpl req1 = getRequest();
+        assertTrue( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Tests the same object reference for equal hashCode.
+     */
+    @Test
+    public void testHashCodeSameObj() throws LdapException
+    {
+        ModifyRequestImpl req = getRequest();
+        assertTrue( req.hashCode() == req.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using exact copies.
+     */
+    @Test
+    public void testHashCodeExactCopy() throws LdapException
+    {
+        ModifyRequestImpl req0 = getRequest();
+        ModifyRequestImpl req1 = getRequest();
+        assertTrue( req0.hashCode() == req1.hashCode() );
+    }
+
+
+    /**
+     * Test for inequality when only the IDs are different.
+     */
+    @Test
+    public void testNotEqualDiffId()
+    {
+        ModifyRequestImpl req0 = new ModifyRequestImpl();
+        req0.setMessageId( 7 );
+        ModifyRequestImpl req1 = new ModifyRequestImpl();
+        req1.setMessageId( 5 );
+        assertFalse( req0.equals( req1 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the Dn names are different.
+     */
+    @Test
+    public void testNotEqualDiffName()
+    {
+        try
+        {
+            ModifyRequestImpl req0 = getRequest();
+            req0.setName( new Dn( "cn=admin,dc=example,dc=com" ) );
+            ModifyRequestImpl req1 = getRequest();
+            req1.setName( new Dn( "cn=admin,dc=apache,dc=org" ) );
+
+            assertFalse( req0.equals( req1 ) );
+        }
+        catch ( LdapException ine )
+        {
+            // do nothing
+        }
+    }
+
+
+    /**
+     * Test for inequality when only the mods ops are different.
+     */
+    @Test
+    public void testNotEqualDiffModOps() throws LdapException
+    {
+        ModifyRequestImpl req0 = getRequest();
+        Attribute attr = new DefaultAttribute( "attr3" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        Modification item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        req0.addModification( item );
+
+        ModifyRequestImpl req1 = getRequest();
+        attr = new DefaultAttribute( "attr3" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        item = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
+        req0.addModification( item );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the number of mods are different.
+     */
+    @Test
+    public void testNotEqualDiffModCount() throws LdapException
+    {
+        ModifyRequestImpl req0 = getRequest();
+        Attribute attr = new DefaultAttribute( "attr3" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        Modification item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        req0.addModification( item );
+
+        ModifyRequestImpl req1 = getRequest();
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the mods attribute Id's are different.
+     */
+    @Test
+    public void testNotEqualDiffModIds() throws LdapException
+    {
+        ModifyRequestImpl req0 = getRequest();
+        Attribute attr = new DefaultAttribute( "attr3" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        Modification item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        req0.addModification( item );
+
+        ModifyRequestImpl req1 = getRequest();
+        attr = new DefaultAttribute( "attr4" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        req0.addModification( item );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Test for inequality when only the mods attribute values are different.
+     */
+    @Test
+    public void testNotEqualDiffModValues() throws LdapException
+    {
+        ModifyRequestImpl req0 = getRequest();
+        Attribute attr = new DefaultAttribute( "attr3" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        Modification item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        req0.addModification( item );
+
+        ModifyRequestImpl req1 = getRequest();
+        attr = new DefaultAttribute( "attr3" );
+        attr.add( "val0" );
+        attr.add( "val1" );
+        attr.add( "val2" );
+        attr.add( "val3" );
+        item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+        req0.addModification( item );
+
+        assertFalse( req0.equals( req1 ) );
+        assertFalse( req1.equals( req0 ) );
+    }
+
+
+    /**
+     * Tests for equality even when another BindRequest implementation is used.
+     */
+    @Test
+    public void testEqualsDiffImpl() throws LdapException
+    {
+        ModifyRequest req0 = new ModifyRequest()
+        {
+            public Collection<Modification> getModifications()
+            {
+                List<Modification> list = new ArrayList<Modification>();
+
+                try
+                {
+                    Attribute attr = new DefaultAttribute( "attr0" );
+                    attr.add( "val0" );
+                    attr.add( "val1" );
+                    attr.add( "val2" );
+                    Modification item = new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, attr );
+                    list.add( item );
+
+                    attr = new DefaultAttribute( "attr1" );
+                    attr.add( "val3" );
+                    item = new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
+                    list.add( item );
+
+                    attr = new DefaultAttribute( "attr2" );
+                    attr.add( "val4" );
+                    attr.add( "val5" );
+                    item = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attr );
+                    list.add( item );
+                }
+                catch ( LdapInvalidAttributeValueException liave )
+                {
+                    // Can't happen
+                }
+
+                return list;
+            }
+
+
+            public ModifyRequest addModification( Modification mod )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest removeModification( Modification mod )
+            {
+                return this;
+            }
+
+
+            public Dn getName()
+            {
+                try
+                {
+                    return new Dn( "cn=admin,dc=apache,dc=org" );
+                }
+                catch ( Exception e )
+                {
+                    //do nothing
+                    return null;
+                }
+            }
+
+
+            public ModifyRequest setName( Dn name )
+            {
+                return this;
+            }
+
+
+            public MessageTypeEnum getResponseType()
+            {
+                return MessageTypeEnum.MODIFY_RESPONSE;
+            }
+
+
+            public boolean hasResponse()
+            {
+                return true;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.MODIFY_REQUEST;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public ModifyRequest addControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest removeControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 45;
+            }
+
+
+            public Object get( Object a_key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object a_key, Object a_value )
+            {
+                return null;
+            }
+
+
+            public void abandon()
+            {
+            }
+
+
+            public boolean isAbandoned()
+            {
+                return false;
+            }
+
+
+            public ModifyRequest addAbandonListener( AbandonListener listener )
+            {
+                return this;
+            }
+
+
+            public ModifyResponse getResultResponse()
+            {
+                return null;
+            }
+
+
+            public ModifyRequest addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public ModifyRequest setMessageId( int messageId )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest addModification( Attribute attr, ModificationOperation modOp )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest replace( String attributeName )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest replace( String attributeName, String... attributeValue )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest replace( String attributeName, byte[]... attributeValue )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest replace( Attribute attr )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest add( String attributeName, String... attributeValue )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest add( String attributeName, byte[]... attributeValue )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest add( Attribute attr )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest remove( String attributeName, String... attributeValue )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest remove( String attributeName, byte[]... attributeValue )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest remove( Attribute attr )
+            {
+                return this;
+            }
+
+
+            public ModifyRequest remove( String attributerName )
+            {
+                return this;
+            }
+        };
+
+        ModifyRequestImpl req1 = getRequest();
+        assertTrue( req1.equals( req0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ReferralImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ReferralImplTest.java
new file mode 100644
index 0000000..a426d82
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/ReferralImplTest.java
@@ -0,0 +1,245 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.message.Referral;
+import org.apache.directory.api.ldap.model.message.ReferralImpl;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the ReferralImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ *         $Rev: 946251 $
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ReferralImplTest
+{
+    /**
+     * Tests to make sure the equals method works for the same exact object.
+     */
+    @Test
+    public void testEqualsSameObject()
+    {
+        ReferralImpl refs = new ReferralImpl();
+        assertTrue( "equals method should work for the same object", refs.equals( refs ) );
+    }
+
+
+    /**
+     * Tests to make sure the equals method works for two objects that are the
+     * same exact copy of one another.
+     */
+    @Test
+    public void testEqualsExactCopy()
+    {
+        ReferralImpl refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://blah0" );
+        refs0.addLdapUrl( "ldap://blah1" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        ReferralImpl refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://blah0" );
+        refs1.addLdapUrl( "ldap://blah1" );
+        refs1.addLdapUrl( "ldap://blah2" );
+        assertTrue( "exact copies of Referrals should be equal", refs0.equals( refs1 ) );
+        assertTrue( "exact copies of Referrals should be equal", refs1.equals( refs0 ) );
+    }
+
+
+    /**
+     * Tests to make sure the equals method works for two objects that are the
+     * same exact copy of one another but there are redundant entries.
+     */
+    @Test
+    public void testEqualsExactCopyWithRedundancy()
+    {
+        ReferralImpl refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://blah0" );
+        refs0.addLdapUrl( "ldap://blah1" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        ReferralImpl refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://blah0" );
+        refs1.addLdapUrl( "ldap://blah1" );
+        refs1.addLdapUrl( "ldap://blah2" );
+        refs1.addLdapUrl( "ldap://blah2" );
+        assertTrue( "exact copies of Referrals should be equal", refs0.equals( refs1 ) );
+        assertTrue( "exact copies of Referrals should be equal", refs1.equals( refs0 ) );
+    }
+
+
+    /**
+     * Tests to make sure to get equal hashCode for the same exact object.
+     */
+    @Test
+    public void testHashCodeSameObject()
+    {
+        ReferralImpl refs = new ReferralImpl();
+        assertTrue( refs.hashCode() == refs.hashCode() );
+    }
+
+
+    /**
+     * Tests to make sure to get equal hashCode for two objects that are the
+     * same exact copy of one another.
+     */
+    @Test
+    public void testHashCodeExactCopy()
+    {
+        ReferralImpl refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://blah0" );
+        refs0.addLdapUrl( "ldap://blah1" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        ReferralImpl refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://blah0" );
+        refs1.addLdapUrl( "ldap://blah1" );
+        refs1.addLdapUrl( "ldap://blah2" );
+        assertTrue( refs0.hashCode() == refs1.hashCode() );
+    }
+
+
+    /**
+     * Tests to make sure to get equal hashCode for two objects that are the
+     * same exact copy of one another but there are redundant entries.
+     */
+    @Test
+    public void testHashCodeExactCopyWithRedundancy()
+    {
+        ReferralImpl refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://blah0" );
+        refs0.addLdapUrl( "ldap://blah1" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        ReferralImpl refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://blah0" );
+        refs1.addLdapUrl( "ldap://blah1" );
+        refs1.addLdapUrl( "ldap://blah2" );
+        refs1.addLdapUrl( "ldap://blah2" );
+        assertTrue( refs0.hashCode() == refs1.hashCode() );
+    }
+
+
+    /**
+     * Tests to make sure the equals method works for two objects that are the
+     * not exact copies of one another but have the same number of URLs.
+     */
+    @Test
+    public void testEqualsSameNumberButDifferentUrls()
+    {
+        ReferralImpl refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://blah0" );
+        refs0.addLdapUrl( "ldap://blah1" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        refs0.addLdapUrl( "ldap://blah3" );
+        ReferralImpl refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://blah0" );
+        refs1.addLdapUrl( "ldap://blah1" );
+        refs1.addLdapUrl( "ldap://blah2" );
+        refs1.addLdapUrl( "ldap://blah4" );
+        assertFalse( "Referrals should not be equal", refs0.equals( refs1 ) );
+        assertFalse( "Referrals should not be equal", refs1.equals( refs0 ) );
+    }
+
+
+    /**
+     * Tests to make sure the equals method works for two objects that are the
+     * not exact copies of one another and one has a subset of the urls of the
+     * other.
+     */
+    @Test
+    public void testEqualsSubset()
+    {
+        ReferralImpl refs0 = new ReferralImpl();
+        refs0.addLdapUrl( "ldap://blah0" );
+        refs0.addLdapUrl( "ldap://blah1" );
+        refs0.addLdapUrl( "ldap://blah2" );
+        refs0.addLdapUrl( "ldap://blah3" );
+        ReferralImpl refs1 = new ReferralImpl();
+        refs1.addLdapUrl( "ldap://blah0" );
+        refs1.addLdapUrl( "ldap://blah1" );
+        assertFalse( "Referrals should not be equal", refs0.equals( refs1 ) );
+        assertFalse( "Referrals should not be equal", refs1.equals( refs0 ) );
+    }
+
+
+    @Test
+    public void testEqualsDifferentImpls()
+    {
+        Referral refs0 = new Referral()
+        {
+            public Collection<String> getLdapUrls()
+            {
+                return Collections.emptyList();
+            }
+
+
+            public void addLdapUrl( String url )
+            {
+            }
+
+
+            public void removeLdapUrl( String url )
+            {
+            }
+
+
+            public void addLdapUrlBytes( byte[] urlBytes )
+            {
+            }
+
+
+            public Collection<byte[]> getLdapUrlsBytes()
+            {
+                return null;
+            }
+
+
+            public int getReferralLength()
+            {
+                return 0;
+            }
+
+
+            public void setReferralLength( int referralLength )
+            {
+            }
+        };
+
+        ReferralImpl refs1 = new ReferralImpl();
+
+        assertFalse( "Object.equals() in effect because we did not redefine " + " equals for the new impl above", refs0
+            .equals( refs1 ) );
+        assertTrue( "Empty Referrals should be equal even if they are different" + " implementation classes", refs1
+            .equals( refs0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResponseDoneImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResponseDoneImplTest.java
new file mode 100644
index 0000000..fc7af45
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResponseDoneImplTest.java
@@ -0,0 +1,243 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCases for the SearchResponseImpl class methods.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ *         $Rev: 946251 $
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResponseDoneImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Creates and populates a SearchResponseDoneImpl stub for testing purposes.
+     * 
+     * @return a populated SearchResponseDoneImpl stub
+     */
+    private SearchResultDoneImpl createStub()
+    {
+        // Construct the Search response to test with results and referrals
+        SearchResultDoneImpl response = new SearchResultDoneImpl( 45 );
+        LdapResult result = response.getLdapResult();
+
+        try
+        {
+            result.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+        }
+        catch ( LdapException ine )
+        {
+            // do nothing
+        }
+
+        result.setResultCode( ResultCodeEnum.SUCCESS );
+        ReferralImpl refs = new ReferralImpl();
+        refs.addLdapUrl( "ldap://someserver.com" );
+        refs.addLdapUrl( "ldap://apache.org" );
+        refs.addLdapUrl( "ldap://another.net" );
+        result.setReferral( refs );
+        return response;
+    }
+
+
+    /**
+     * Tests for equality using the same object.
+     */
+    @Test
+    public void testEqualsSameObj()
+    {
+        SearchResultDoneImpl resp = createStub();
+        assertTrue( resp.equals( resp ) );
+    }
+
+
+    /**
+     * Tests for equality using an exact copy.
+     */
+    @Test
+    public void testEqualsExactCopy()
+    {
+        SearchResultDoneImpl resp0 = createStub();
+        SearchResultDoneImpl resp1 = createStub();
+        assertTrue( resp0.equals( resp1 ) );
+        assertTrue( resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equality using different stub implementations.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        SearchResultDoneImpl resp0 = createStub();
+        SearchResultDone resp1 = new SearchResultDone()
+        {
+            public LdapResult getLdapResult()
+            {
+                LdapResultImpl result = new LdapResultImpl();
+
+                try
+                {
+                    result.setMatchedDn( new Dn( "dc=example,dc=com" ) );
+                }
+                catch ( Exception e )
+                {
+                    // Do nothing
+                }
+                result.setResultCode( ResultCodeEnum.SUCCESS );
+                ReferralImpl refs = new ReferralImpl();
+                refs.addLdapUrl( "ldap://someserver.com" );
+                refs.addLdapUrl( "ldap://apache.org" );
+                refs.addLdapUrl( "ldap://another.net" );
+                result.setReferral( refs );
+
+                return result;
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.SEARCH_RESULT_DONE;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public SearchResultDone addControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public SearchResultDone removeControl( Control a_control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 45;
+            }
+
+
+            public Object get( Object a_key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object a_key, Object a_value )
+            {
+                return null;
+            }
+
+
+            public SearchResultDone addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public SearchResultDone setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        assertTrue( resp0.equals( resp1 ) );
+        assertFalse( resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equal hashCode using the same object.
+     */
+    @Test
+    public void testHashCodeSameObj()
+    {
+        SearchResultDoneImpl resp = createStub();
+        assertTrue( resp.hashCode() == resp.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode using an exact copy.
+     */
+    @Test
+    public void testHashCodeExactCopy()
+    {
+        SearchResultDoneImpl resp0 = createStub();
+        SearchResultDoneImpl resp1 = createStub();
+        assertTrue( resp0.hashCode() == resp1.hashCode() );
+    }
+
+
+    /**
+     * Tests inequality when messageIds are different.
+     */
+    @Test
+    public void testNotEqualsDiffIds()
+    {
+        SearchResultDoneImpl resp0 = new SearchResultDoneImpl( 3 );
+        SearchResultDoneImpl resp1 = new SearchResultDoneImpl( 4 );
+
+        assertFalse( resp0.equals( resp1 ) );
+        assertFalse( resp1.equals( resp0 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResponseReferenceImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResponseReferenceImplTest.java
new file mode 100644
index 0000000..5c2021f
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResponseReferenceImplTest.java
@@ -0,0 +1,231 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * TestCase for the SearchResponseReferenceImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResponseReferenceImplTest
+{
+    private static final Map<String, Control> EMPTY_CONTROL_MAP = new HashMap<String, Control>();
+
+
+    /**
+     * Creates a baseline referral to test with and adds it to the supplied
+     * response object.
+     * 
+     * @param resp
+     *            the parent lockable
+     * @return the newly created referral for testing
+     */
+    private Referral getReferral( SearchResultReference resp )
+    {
+        ReferralImpl ref = new ReferralImpl();
+        resp.setReferral( ref );
+        ref.addLdapUrl( "http://apache.org???" );
+        ref.addLdapUrl( "http://mit.edu???" );
+        ref.addLdapUrl( "http://abc.com???" );
+        return ref;
+    }
+
+
+    /**
+     * Tests for equality when the same object reference is used.
+     */
+    @Test
+    public void testEqualsSameObject()
+    {
+        SearchResultReferenceImpl resp = new SearchResultReferenceImpl( 5 );
+        getReferral( resp );
+        assertTrue( "the same object should be equal", resp.equals( resp ) );
+    }
+
+
+    /**
+     * Tests for equality when an exact copy is compared.
+     */
+    @Test
+    public void testEqualsExactCopy()
+    {
+        SearchResultReferenceImpl resp0 = new SearchResultReferenceImpl( 5 );
+        getReferral( resp0 );
+        SearchResultReferenceImpl resp1 = new SearchResultReferenceImpl( 5 );
+        getReferral( resp1 );
+
+        assertTrue( "exact copies should be equal", resp0.equals( resp1 ) );
+        assertTrue( "exact copies should be equal", resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equality when a different implementation is used.
+     */
+    @Test
+    public void testEqualsDiffImpl()
+    {
+        SearchResultReference resp0 = new SearchResultReference()
+        {
+            public Referral getReferral()
+            {
+                return SearchResponseReferenceImplTest.this.getReferral( this );
+            }
+
+
+            public void setReferral( Referral referral )
+            {
+            }
+
+
+            public MessageTypeEnum getType()
+            {
+                return MessageTypeEnum.SEARCH_RESULT_REFERENCE;
+            }
+
+
+            public Map<String, Control> getControls()
+            {
+                return EMPTY_CONTROL_MAP;
+            }
+
+
+            public SearchResultReference addControl( Control control )
+            {
+                return this;
+            }
+
+
+            public SearchResultReference removeControl( Control control )
+            {
+                return this;
+            }
+
+
+            public int getMessageId()
+            {
+                return 5;
+            }
+
+
+            public Object get( Object key )
+            {
+                return null;
+            }
+
+
+            public Object put( Object key, Object value )
+            {
+                return null;
+            }
+
+
+            public SearchResultReference addAllControls( Control[] controls )
+            {
+                return this;
+            }
+
+
+            public boolean hasControl( String oid )
+            {
+                return false;
+            }
+
+
+            public Control getControl( String oid )
+            {
+                return null;
+            }
+
+
+            public SearchResultReference setMessageId( int messageId )
+            {
+                return this;
+            }
+        };
+
+        SearchResultReferenceImpl resp1 = new SearchResultReferenceImpl( 5 );
+        getReferral( resp1 );
+
+        assertFalse( "using Object.equal() should NOT be equal", resp0.equals( resp1 ) );
+        assertTrue( "same but different implementations should be equal", resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equal hashCode when the same object reference is used.
+     */
+    @Test
+    public void testHashCodeSameObject()
+    {
+        SearchResultReferenceImpl resp = new SearchResultReferenceImpl( 5 );
+        getReferral( resp );
+        assertTrue( resp.hashCode() == resp.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode when an exact copy is compared.
+     */
+    @Test
+    public void testHashCodeExactCopy()
+    {
+        SearchResultReferenceImpl resp0 = new SearchResultReferenceImpl( 5 );
+        getReferral( resp0 );
+        SearchResultReferenceImpl resp1 = new SearchResultReferenceImpl( 5 );
+        getReferral( resp1 );
+
+        assertTrue( resp0.hashCode() == resp1.hashCode() );
+    }
+
+
+    /**
+     * Tests for inequality when the urls are not the same.
+     */
+    @Test
+    public void testNotEqualDiffUrls()
+    {
+        SearchResultReferenceImpl resp0 = new SearchResultReferenceImpl( 5 );
+        getReferral( resp0 );
+        SearchResultReferenceImpl resp1 = new SearchResultReferenceImpl( 5 );
+        getReferral( resp1 );
+        resp1.getReferral().addLdapUrl( "ldap://asdf.com???" );
+
+        assertFalse( "different urls should not be equal", resp1.equals( resp0 ) );
+        assertFalse( "different urls should not be equal", resp0.equals( resp1 ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResultEntryImplTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResultEntryImplTest.java
new file mode 100644
index 0000000..c3ac841
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/SearchResultEntryImplTest.java
@@ -0,0 +1,157 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.message;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.SearchResultEntryImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test cases for the methods of the SearchResponseEntryImpl class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
+ *         $Rev: 946251 $
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SearchResultEntryImplTest
+{
+    /**
+     * Creates and populates an EntryAttribute with a specific id.
+     * 
+     * @param id the id for the attribute
+     * @return the EntryAttribute assembled for testing
+     */
+    private Attribute getEntry( String id ) throws LdapException
+    {
+        Attribute attr = new DefaultAttribute( id );
+        attr.add( "value0" );
+        attr.add( "value1" );
+        attr.add( "value2" );
+        return attr;
+    }
+
+
+    /**
+     * Creates and populates an Entry object
+     * 
+     * @return The populated Entry object
+     */
+    private Entry getEntry() throws LdapException
+    {
+        Entry attrs = new DefaultEntry();
+        attrs.put( getEntry( "attr0" ) );
+        attrs.put( getEntry( "attr1" ) );
+        attrs.put( getEntry( "attr2" ) );
+        return attrs;
+    }
+
+
+    /**
+     * Tests for equality when the same object reference is used.
+     */
+    @Test
+    public void testEqualsSameObject()
+    {
+        SearchResultEntryImpl resp = new SearchResultEntryImpl( 5 );
+        assertTrue( "the same object should be equal", resp.equals( resp ) );
+    }
+
+
+    /**
+     * Tests for equality when an exact copy is compared.
+     */
+    @Test
+    public void testEqualsExactCopy() throws LdapException
+    {
+        SearchResultEntryImpl resp0 = new SearchResultEntryImpl( 5 );
+        resp0.setEntry( getEntry() );
+        resp0.setObjectName( new Dn( "dc=example,dc=com" ) );
+
+        SearchResultEntryImpl resp1 = new SearchResultEntryImpl( 5 );
+        resp1.setEntry( getEntry() );
+        resp1.setObjectName( new Dn( "dc=example,dc=com" ) );
+
+        assertTrue( "exact copies should be equal", resp0.equals( resp1 ) );
+        assertTrue( "exact copies should be equal", resp1.equals( resp0 ) );
+    }
+
+
+    /**
+     * Tests for equal hashCode when the same object reference is used.
+     */
+    @Test
+    public void testHashCodeSameObject()
+    {
+        SearchResultEntryImpl resp = new SearchResultEntryImpl( 5 );
+        assertTrue( resp.hashCode() == resp.hashCode() );
+    }
+
+
+    /**
+     * Tests for equal hashCode when an exact copy is compared.
+     */
+    @Test
+    public void testHashCodeExactCopy() throws LdapException
+    {
+        SearchResultEntryImpl resp0 = new SearchResultEntryImpl( 5 );
+        resp0.setEntry( getEntry() );
+        resp0.setObjectName( new Dn( "dc=example,dc=com" ) );
+
+        SearchResultEntryImpl resp1 = new SearchResultEntryImpl( 5 );
+        resp1.setEntry( getEntry() );
+        resp1.setObjectName( new Dn( "dc=example,dc=com" ) );
+
+        assertTrue( resp0.hashCode() == resp1.hashCode() );
+    }
+
+
+    /**
+     * Tests for inequality when the objectName dn is not the same.
+     */
+    @Test
+    public void testNotEqualDiffObjectName() throws LdapException
+    {
+        SearchResultEntryImpl resp0 = new SearchResultEntryImpl( 5 );
+        resp0.setEntry( getEntry() );
+        resp0.setObjectName( new Dn( "dc=apache,dc=org" ) );
+
+        SearchResultEntryImpl resp1 = new SearchResultEntryImpl( 5 );
+        resp1.setEntry( getEntry() );
+        resp1.setObjectName( new Dn( "dc=example,dc=com" ) );
+
+        assertFalse( "different object names should not be equal", resp1.equals( resp0 ) );
+        assertFalse( "different object names should not be equal", resp0.equals( resp1 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/controls/OpaqueControlTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/controls/OpaqueControlTest.java
new file mode 100644
index 0000000..a2ff581
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/message/controls/OpaqueControlTest.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.message.controls;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.api.util.StringConstants;
+import org.junit.Test;
+
+
+/**
+ * Test the OpaqueControl class
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OpaqueControlTest
+{
+    @Test
+    public void testEmptyValue()
+    {
+        OpaqueControl control = new OpaqueControl( "1.1" );
+
+        assertFalse( control.hasEncodedValue() );
+
+        control.setEncodedValue( StringConstants.EMPTY_BYTES );
+
+        assertTrue( control.hasEncodedValue() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/AvaSerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/AvaSerializationTest.java
new file mode 100644
index 0000000..ae2074c
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/AvaSerializationTest.java
@@ -0,0 +1,358 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Ava;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the AttributeTypeAndValue class serialization
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AvaSerializationTest
+{
+    /** A null schemaManager used in tests */
+    SchemaManager schemaManager = null;
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testStringAtavSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+
+        atav.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testBinaryAtavSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] upValue = Strings.getBytesUtf8( "  Test  " );
+
+        Ava atav = new Ava( schemaManager, "CN", upValue );
+
+        atav.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testNullAtavSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testNullNormValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", ( String ) null );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            String message = ioe.getMessage();
+            assertEquals( "Cannot serialize a wrong ATAV, the value should not be null", message );
+        }
+    }
+
+
+    @Test
+    public void testNullUpValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", ( String ) null );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            String message = ioe.getMessage();
+            assertEquals( "Cannot serialize a wrong ATAV, the value should not be null", message );
+        }
+    }
+
+
+    @Test
+    public void testEmptyNormValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "test" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testEmptyUpValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test serialization of a simple ATAV
+     */
+    @Test
+    public void testStringAtavStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "Test" );
+
+        atav.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testBinaryAtavStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        byte[] upValue = Strings.getBytesUtf8( "  Test  " );
+
+        Ava atav = new Ava( schemaManager, "CN", upValue );
+
+        atav.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    /**
+     * Test static serialization of a simple ATAV
+     */
+    @Test
+    public void testNullAtavStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testNullUpValueStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", ( String ) null );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        try
+        {
+            atav.writeExternal( out );
+            fail();
+        }
+        catch ( IOException ioe )
+        {
+            String message = ioe.getMessage();
+            assertEquals( "Cannot serialize a wrong ATAV, the value should not be null", message );
+        }
+    }
+
+
+    @Test
+    public void testEmptyNormValueStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+
+
+    @Test
+    public void testEmptyUpValueStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Ava atav = new Ava( schemaManager, "CN", "" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        atav.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Ava atav2 = new Ava( schemaManager );
+        atav2.readExternal( in );
+
+        assertEquals( atav, atav2 );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/AvaTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/AvaTest.java
new file mode 100644
index 0000000..309aec4
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/AvaTest.java
@@ -0,0 +1,260 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Ava;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the class AttributeTypeAndValue
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AvaTest
+{
+    /** A null schemaManager used in tests */
+    SchemaManager schemaManager = null;
+
+
+    /**
+     * Test a null AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueNull()
+    {
+        Ava atav = new Ava();
+        assertEquals( "", atav.toString() );
+        assertEquals( "", atav.getName() );
+    }
+
+
+    /**
+     * Test a null type for an AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueNullType() throws LdapException
+    {
+        try
+        {
+            new Ava( schemaManager, null, ( String ) null );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+
+    }
+
+
+    /**
+     * Test an invalid type for an AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueInvalidType() throws LdapException
+    {
+        try
+        {
+            new Ava( schemaManager, "  ", ( String ) null );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * Test a valid type for an AttributeTypeAndValue
+     */
+    @Test
+    public void testAttributeTypeAndValueValidType() throws LdapException
+    {
+        Ava atav = new Ava( schemaManager, "A", ( String ) null );
+        assertEquals( "A=", atav.toString() );
+        assertEquals( "a=", atav.getNormName() );
+        assertEquals( "A=", atav.getName() );
+
+        atav = new Ava( schemaManager, "  A  ", ( String ) null );
+        assertEquals( "a=", atav.getNormName() );
+        assertEquals( "  A  =", atav.toString() );
+        assertEquals( "  A  =", atav.getName() );
+
+        try
+        {
+            atav = new Ava( schemaManager, null, ( String ) null );
+            fail();
+        }
+        catch ( LdapInvalidDnException lide )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test an empty AttributeTypeAndValue
+     */
+    @Test
+    public void testLdapRDNEmpty()
+    {
+        try
+        {
+            new Ava( schemaManager, "", "" );
+            fail( "Should not occurs ... " );
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a simple AttributeTypeAndValue : a = b
+     */
+    @Test
+    public void testLdapRDNSimple() throws LdapException
+    {
+        Ava atav = new Ava( schemaManager, "a", "b" );
+        assertEquals( "a=b", atav.toString() );
+        assertEquals( "a=b", atav.getName() );
+    }
+
+
+    /**
+     * Compares two equals atavs
+     */
+    @Test
+    public void testEqualsAttributeEquals() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "a", "b" );
+        Ava atav2 = new Ava( schemaManager, "a", "b" );
+
+        assertTrue( atav1.equals( atav2 ) );
+    }
+
+
+    /**
+     * Compares two equals atavs but with a type in different case
+     */
+    @Test
+    public void testEqualsAttributeIdSameCase() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "a", "b" );
+        Ava atav2 = new Ava( schemaManager, "A", "b" );
+
+        assertTrue( atav1.equals( atav2 ) );
+    }
+
+
+    /**
+     * Compare two atavs : the first one is superior because its type is
+     * superior
+     */
+    @Test
+    public void testEqualsAtav1TypeSuperior() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "b", "b" );
+
+        Ava atav2 = new Ava( schemaManager, "a", "b" );
+
+        assertFalse( atav1.equals( atav2 ) );
+    }
+
+
+    /**
+     * Compare two atavs : the second one is superior because its type is
+     * superior
+     */
+    @Test
+    public void testEqualsAtav2TypeSuperior() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "a", "b" );
+        Ava atav2 = new Ava( schemaManager, "b", "b" );
+
+        assertFalse( atav1.equals( atav2 ) );
+    }
+
+
+    /**
+     * Compare two atavs : the first one is superior because its type is
+     * superior
+     */
+    @Test
+    public void testEqualsAtav1ValueSuperior() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "a", "b" );
+        Ava atav2 = new Ava( schemaManager, "a", "a" );
+
+        assertFalse( atav1.equals( atav2 ) );
+    }
+
+
+    /**
+     * Compare two atavs : the second one is superior because its type is
+     * superior
+     */
+    @Test
+    public void testEqualsAtav2ValueSuperior() throws LdapException
+    {
+        Ava atav1 = new Ava( schemaManager, "a", "a" );
+        Ava atav2 = new Ava( schemaManager, "a", "b" );
+
+        assertFalse( atav1.equals( atav2 ) );
+    }
+
+
+    @Test
+    public void testNormalize() throws LdapException
+    {
+        Ava atav = new Ava( schemaManager, " A ", "a" );
+
+        assertEquals( "a=a", atav.normalize() );
+
+    }
+
+
+    @Test
+    public void testAvaSimpleNorm() throws LdapException
+    {
+        Ava atav = new Ava( schemaManager, " CommonName ", " This is    a TEST " );
+        assertEquals( " CommonName =\\ This is    a TEST\\ ", atav.toString() );
+        assertEquals( "commonname=\\ This is    a TEST\\ ", atav.getNormName() );
+        assertEquals( " CommonName =\\ This is    a TEST\\ ", atav.getName() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnParserDIRSERVER_584_Test.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnParserDIRSERVER_584_Test.java
new file mode 100644
index 0000000..0f424d3
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnParserDIRSERVER_584_Test.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Testcase devised specifically for DIRSERVER-584.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @see <a href="https://issues.apache.org/jira/browse/DIRSERVER-584">DIRSERVER-584</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DnParserDIRSERVER_584_Test
+{
+    /**
+     * Need this testa() to run first to mess up the state of the static parser.
+     */
+    @Test(expected = LdapException.class)
+    public void testa() throws Exception
+    {
+        new Dn( "ou=test+testing" );
+    }
+
+
+    /**
+     * Need this testb() to run second to use the mess up static parser.  This
+     * test should succeed but fails.
+     */
+    @Test
+    public void testb() throws Exception
+    {
+        new Dn( "ou=system" );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnParserTest.java
new file mode 100644
index 0000000..13276ed
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnParserTest.java
@@ -0,0 +1,690 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the class Dn
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DnParserTest
+{
+    /**
+     * test an empty Dn
+     */
+    @Test
+    public void testLdapDNEmpty() throws LdapException
+    {
+        Dn dn = new Dn( "" );
+
+        assertEquals( "", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn : a = b
+     */
+    @Test
+    public void testLdapDNSimple() throws LdapException
+    {
+        Dn dn = new Dn( "a = b" );
+
+        assertEquals( "a = b", dn.getName() );
+        assertEquals( "a=b", dn.getNormName() );
+    }
+
+
+    /**
+     * test a composite Dn : a = b, d = e
+     */
+    @Test
+    public void testLdapDNComposite() throws LdapException
+    {
+        Dn dn = new Dn( "a = b, c = d" );
+
+        assertEquals( "a=b,c=d", dn.getNormName() );
+        assertEquals( "a = b, c = d", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with or without spaces: a=b, a =b, a= b, a = b, a = b
+     */
+    @Test
+    public void testLdapDNCompositeWithSpace() throws LdapException
+    {
+        Dn dn = new Dn( "a=b, a =b, a= b, a = b, a  =  b" );
+        assertEquals( "a=b,a=b,a=b,a=b,a=b", dn.getNormName() );
+        assertEquals( "a=b, a =b, a= b, a = b, a  =  b", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with differents separators : a=b;c=d,e=f It should
+     * return a=b,c=d,e=f (the ';' is replaced by a ',')
+     */
+    @Test
+    public void testLdapDNCompositeSepators() throws LdapException
+    {
+        Dn dn = new Dn( "a=b;c=d,e=f" );
+        assertEquals( "a=b,c=d,e=f", dn.getNormName() );
+        assertEquals( "a=b;c=d,e=f", dn.getName() );
+    }
+
+
+    /**
+     * Test an attributeType with '_' (some vendors allow that)
+     */
+    @Test
+    public void testAttributeTypeWithUnderscore() throws LdapException
+    {
+        Dn dn = new Dn( "a_a = b + c_c = d" );
+        assertEquals( "a_a=b+c_c=d", dn.getNormName() );
+        assertEquals( "a_a = b + c_c = d", dn.getName() );
+    }
+
+
+    /**
+     * Test DN with '_' in value, because of special handling in Antlr grammar.
+     */
+    @Test
+    public void testAttributeValueWithUnderscore() throws LdapException
+    {
+        Dn dn = new Dn( "cn=\\#ACL_AD-Projects_Author,ou=Notes_Group,o=Contacts,c=DE" );
+        assertEquals( "cn=\\#ACL_AD-Projects_Author,ou=Notes_Group,o=Contacts,c=DE", dn.getNormName() );
+        assertEquals( "cn=\\#ACL_AD-Projects_Author,ou=Notes_Group,o=Contacts,c=DE", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with multiple NameComponents : a = b + c = d
+     */
+    @Test
+    public void testLdapDNSimpleMultivaluedAttribute() throws LdapException
+    {
+        Dn dn = new Dn( "a = b + c = d" );
+        assertEquals( "a=b+c=d", dn.getNormName() );
+        assertEquals( "a = b + c = d", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with multiple NC and separators : a=b+c=d, e=f + g=h +
+     * i=j
+     */
+    @Test
+    public void testLdapDNCompositeMultivaluedAttribute() throws LdapException
+    {
+        Dn dn = new Dn( "a=b+c=d, e=f + g=h + i=j" );
+        assertEquals( "a=b+c=d,e=f+g=h+i=j", dn.getNormName() );
+        assertEquals( "a=b+c=d, e=f + g=h + i=j", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with an oid prefix (uppercase) : OID.12.34.56 = azerty
+     */
+    @Test
+    public void testLdapDNOidUpper() throws LdapException
+    {
+        Dn dn = new Dn( "OID.12.34.56 = azerty" );
+        assertEquals( "oid.12.34.56=azerty", dn.getNormName() );
+        assertEquals( "OID.12.34.56 = azerty", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with an oid prefix (lowercase) : oid.12.34.56 = azerty
+     */
+    @Test
+    public void testLdapDNOidLower() throws LdapException
+    {
+        Dn dn = new Dn( "oid.12.34.56 = azerty" );
+        assertEquals( "oid.12.34.56=azerty", dn.getNormName() );
+        assertEquals( "oid.12.34.56 = azerty", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with an oid attribut without oid prefix : 12.34.56 =
+     * azerty
+     */
+    @Test
+    public void testLdapDNOidWithoutPrefix() throws LdapException
+    {
+        Dn dn = new Dn( "12.34.56 = azerty" );
+        assertEquals( "12.34.56=azerty", dn.getNormName() );
+        assertEquals( "12.34.56 = azerty", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with an oid attribut wiithout oid prefix : 12.34.56 =
+     * azerty; 7.8 = test
+     */
+    @Test
+    public void testLdapDNCompositeOidWithoutPrefix() throws LdapException
+    {
+        Dn dn = new Dn( "12.34.56 = azerty; 7.8 = test" );
+        assertEquals( "12.34.56=azerty,7.8=test", dn.getNormName() );
+        assertEquals( "12.34.56 = azerty; 7.8 = test", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with pair char attribute value : a = \,\=\+\<\>\#\;\\\"\C3\A9"
+     */
+    @Test
+    public void testLdapDNPairCharAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\\C3\\A9" );
+        assertEquals( "a=\\,\\=\\+\\<\\>#\\;\\\\\\\"\u00e9", dn.getNormName() );
+        assertEquals( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\\C3\\A9", dn.getName() );
+
+        dn = new Dn( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\u00e9" );
+        assertEquals( "a=\\,\\=\\+\\<\\>#\\;\\\\\\\"\u00e9", dn.getNormName() );
+        assertEquals( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\u00e9", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with hexString attribute value : a = #0010A0AAFF
+     */
+    @Test
+    public void testLdapDNHexStringAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = #0010A0AAFF" );
+        assertEquals( "a=#0010A0AAFF", dn.getNormName() );
+        assertEquals( "a = #0010A0AAFF", dn.getName() );
+    }
+
+
+    /**
+     * test exception from illegal hexString attribute value : a=#zz.
+     */
+    @Test
+    public void testBadLdapDNHexStringAttributeValue() throws LdapException
+    {
+        try
+        {
+            new Dn( "a=#zz" );
+            fail();
+        }
+        catch ( LdapInvalidDnException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a simple Dn with quoted attribute value : a = "quoted \"value"
+     */
+    @Test
+    public void testLdapDNQuotedAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = quoted \\\"value" );
+        assertEquals( "a=quoted \\\"value", dn.getNormName() );
+        assertEquals( "a = quoted \\\"value", dn.getName() );
+
+        dn = new Dn( "cn=Mackie \\\"The Knife\\\" Messer" );
+        assertEquals( "cn=Mackie \\\"The Knife\\\" Messer", dn.getNormName() );
+        assertEquals( "cn=Mackie \\\"The Knife\\\" Messer", dn.getName() );
+    }
+
+
+    /**
+     * Tests a corner case of the parser because the sequence "\DC" is also a valid hex pair
+     */
+    @Test
+    public void testLdapDNBackslashInAttributeValue() throws LdapException
+    {
+        Dn dn = new Dn( "a = AC\\\\DC" );
+        assertEquals( "a=AC\\\\DC", dn.getNormName() );
+        assertEquals( "a = AC\\\\DC", dn.getName() );
+    }
+
+
+    /**
+     * Test the encoding of a LdanDN
+     */
+    @Test
+    public void testNameToBytes() throws LdapException
+    {
+        Dn dn = new Dn( "cn = John, ou = People, OU = Marketing" );
+
+        byte[] bytes = Dn.getBytes( dn );
+
+        assertEquals( 30, bytes.length );
+        assertEquals( "cn=John,ou=People,ou=Marketing", Strings.utf8ToString( bytes ) );
+    }
+
+
+    @Test
+    public void testStringParser() throws LdapException
+    {
+        String dn = Strings.utf8ToString( new byte[]
+            { 'C', 'N', ' ', '=', ' ', 'E', 'm', 'm', 'a', 'n', 'u', 'e', 'l', ' ', ' ', 'L', ( byte ) 0xc3,
+                ( byte ) 0xa9, 'c', 'h', 'a', 'r', 'n', 'y' } );
+
+        Dn name = new Dn( dn );
+
+        assertEquals( "CN = Emmanuel  L\u00e9charny", name.getName() );
+        assertEquals( "cn=Emmanuel  L\u00e9charny", name.getNormName() );
+    }
+
+
+    @Test
+    public void testStringParserShort() throws LdapException
+    {
+        String dn = Strings.utf8ToString( new byte[]
+            { 'C', '=', ' ', 'E', ( byte ) 0xc3, ( byte ) 0xa9, 'c' } );
+
+        Dn name = new Dn( dn );
+
+        assertEquals( "C= E\u00e9c", name.getName() );
+        assertEquals( "c=E\u00e9c", name.getNormName() );
+    }
+
+
+    @Test
+    public void testVsldapExtras() throws LdapException
+    {
+        Dn name = new Dn(
+            "cn=Billy Bakers, OID.2.5.4.11=Corporate Tax, ou=Fin-Accounting, ou=Americas, ou=Search, o=IMC, c=US" );
+
+        assertEquals(
+            "cn=Billy Bakers, OID.2.5.4.11=Corporate Tax, ou=Fin-Accounting, ou=Americas, ou=Search, o=IMC, c=US", name
+                .getName() );
+        assertEquals(
+            "cn=Billy Bakers,oid.2.5.4.11=Corporate Tax,ou=Fin-Accounting,ou=Americas,ou=Search,o=IMC,c=US", name
+                .getNormName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringEmpty() throws LdapException
+    {
+
+        Dn nameEmpty = new Dn( "" );
+
+        assertNotNull( nameEmpty );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringNull() throws LdapException
+    {
+        Dn nameNull = new Dn( ( String ) null );
+
+        assertEquals( "Null Dn are legal : ", "", nameNull.toString() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringRFC1779_1() throws LdapException
+    {
+        Dn nameRFC1779_1 = new Dn( "CN=Marshall T. Rose, O=Dover Beach Consulting, L=Santa Clara, ST=California, C=US" );
+
+        assertEquals( "RFC1779_1 : ",
+            "CN=Marshall T. Rose, O=Dover Beach Consulting, L=Santa Clara, ST=California, C=US",
+            nameRFC1779_1.getName() );
+        assertEquals( "RFC1779_1 : ", "cn=Marshall T. Rose,o=Dover Beach Consulting,l=Santa Clara,st=California,c=US",
+            nameRFC1779_1.getNormName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringRFC2253_1() throws LdapException
+    {
+        Dn nameRFC2253_1 = new Dn( "CN=Steve Kille,O=Isode limited,C=GB" );
+
+        assertEquals( "RFC2253_1 : ", "CN=Steve Kille,O=Isode limited,C=GB", nameRFC2253_1.getName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringRFC2253_2() throws LdapException
+    {
+        Dn nameRFC2253_2 = new Dn( "OU = Sales + CN =   J. Smith , O = Widget Inc. , C = US" );
+
+        assertEquals( "RFC2253_2 : ", "OU = Sales + CN =   J. Smith , O = Widget Inc. , C = US",
+            nameRFC2253_2.getName() );
+        assertEquals( "RFC2253_2 : ", "ou=Sales+cn=J. Smith,o=Widget Inc.,c=US", nameRFC2253_2.getNormName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringRFC2253_3() throws LdapException
+    {
+        Dn nameRFC2253_3 = new Dn( "CN=L. Eagle,   O=Sue\\, Grabbit and Runn, C=GB" );
+
+        assertEquals( "RFC2253_3 : ", "CN=L. Eagle,   O=Sue\\, Grabbit and Runn, C=GB", nameRFC2253_3
+            .getName() );
+        assertEquals( "RFC2253_3 : ", "cn=L. Eagle,o=Sue\\, Grabbit and Runn,c=GB", nameRFC2253_3.getNormName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringRFC2253_4() throws LdapException
+    {
+        Dn nameRFC2253_4 = new Dn( "CN=Before\\0DAfter,O=Test,C=GB" );
+        assertEquals( "RFC2253_4 : ", "CN=Before\\0DAfter,O=Test,C=GB", nameRFC2253_4.getName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringRFC2253_5() throws LdapException
+    {
+        Dn nameRFC2253_5 = new Dn( "1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB" );
+
+        assertEquals( "RFC2253_5 : ", "1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB", nameRFC2253_5
+            .getName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseStringRFC2253_6() throws LdapException
+    {
+        Dn nameRFC2253_6 = new Dn( "SN=Lu\\C4\\8Di\\C4\\87" );
+
+        assertEquals( "RFC2253_6 : ", "SN=Lu\\C4\\8Di\\C4\\87", nameRFC2253_6.getName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     *
+     * @throws LdapException
+     *             if anything goes wrong
+     */
+    @Test
+    public final void testParseInvalidString()
+    {
+        try
+        {
+            new Dn( "&#347;=&#347;rasulu,dc=example,dc=com" );
+            fail( "the invalid name should never succeed in a parse" );
+        }
+        catch ( Exception e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    /**
+     * Tests to see if inner whitespace is preserved after an escaped ',' in a
+     * value of a name component. This test was added to try to reproduce the
+     * bug encountered in DIREVE-179 <a
+     * href="http://issues.apache.org/jira/browse/DIREVE-179"> here</a>.
+     *
+     * @throws LdapException
+     *             if anything goes wrong on parse()
+     */
+    @Test
+    public final void testPreserveSpaceAfterEscape() throws LdapException
+    {
+        String input = "ou=some test\\,  something else";
+        String result = new Dn( input ).toString();
+        assertEquals( "ou=some test\\,  something else", result );
+    }
+
+
+    @Test
+    public void testWindowsFilePath() throws Exception
+    {
+        // '\' should be escaped as stated in RFC 2253
+        String path = "windowsFilePath=C:\\\\cygwin";
+        Dn result = new Dn( path );
+        assertEquals( path, result.getName() );
+        assertEquals( "windowsfilepath=C:\\\\cygwin", result.getNormName() );
+    }
+
+
+    @Test
+    public void testNameFrenchChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', 0x4A, ( byte ) 0xC3, ( byte ) 0xA9, 0x72, ( byte ) 0xC3, ( byte ) 0xB4, 0x6D, 0x65 },
+            "UTF-8" );
+
+        String result = new Dn( cn ).toString();
+
+        assertEquals( "cn=J\u00e9r\u00f4me", result.toString() );
+    }
+
+
+    @Test
+    public void testNameGermanChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC3, ( byte ) 0x84, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3, ( byte ) 0x9C,
+                ( byte ) 0xC3, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0xA4, ( byte ) 0xC3, ( byte ) 0xB6,
+                ( byte ) 0xC3, ( byte ) 0xBC }, "UTF-8" );
+
+        String result = new Dn( cn ).toString();
+
+        assertEquals( "cn=\u00C4\u00D6\u00DC\u00DF\u00E4\u00F6\u00FC", result.toString() );
+    }
+
+
+    @Test
+    public void testNameTurkishChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC4, ( byte ) 0xB0, ( byte ) 0xC4, ( byte ) 0xB1, ( byte ) 0xC5, ( byte ) 0x9E,
+                ( byte ) 0xC5, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3, ( byte ) 0xB6,
+                ( byte ) 0xC3, ( byte ) 0x9C, ( byte ) 0xC3, ( byte ) 0xBC, ( byte ) 0xC4, ( byte ) 0x9E,
+                ( byte ) 0xC4, ( byte ) 0x9F }, "UTF-8" );
+
+        String result = new Dn( cn ).toString();
+
+        assertEquals( "cn=\u0130\u0131\u015E\u015F\u00D6\u00F6\u00DC\u00FC\u011E\u011F", result );
+    }
+
+
+    @Test
+    public void testAUmlautPlusBytes() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC3, ( byte ) 0x84, '\\', '2', 'B' }, "UTF-8" );
+
+        Dn dn = new Dn( cn );
+
+        assertEquals( "cn=\u00c4\\2B", dn.getName() );
+        assertEquals( "cn=\u00c4\\+", dn.getNormName() );
+    }
+
+
+    @Test
+    public void testAUmlautPlusChar() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC3, ( byte ) 0xA4, '\\', '+' }, "UTF-8" );
+
+        Dn dn = new Dn( cn );
+
+        assertEquals( "cn=\u00E4\\+", dn.getName() );
+        assertEquals( "cn=\u00E4\\+", dn.getNormName() );
+    }
+
+
+    /**
+     * Test to check that even with a non escaped char, the Dn is parsed ok
+     * or at least an error is generated.
+     *
+     * @throws LdapException
+     *             if anything goes wrong on parse()
+     */
+    @Test
+    public final void testNonEscapedChars()
+    {
+        String input = "ou=ou+test";
+
+        try
+        {
+            new Dn( input ).toString();
+            fail( "Should never reach this point" );
+        }
+        catch ( LdapException ne )
+        {
+            assertTrue( true );
+            return;
+        }
+    }
+
+
+    /**
+     * Test the Dn.get( int ) method
+     */
+    @Test
+    public void testGetRdnN() throws Exception
+    {
+        Dn dn = new Dn( "cn=test,dc=example,dc=org" );
+
+        assertEquals( "cn=test", dn.getRdn( 0 ).getName() );
+        assertEquals( "dc=example", dn.getRdn( 1 ).getName() );
+        assertEquals( "dc=org", dn.getRdn( 2 ).getName() );
+    }
+
+
+    /**
+     * Test case for DIRAPI-88 (RDN parsing fails with values containing a # character followed by other characters)
+     */
+    @Test
+    public final void testDIRAPI88()
+    {
+        String[] values = new String[]
+            {
+                "200511230101#38SA",
+                "2#28",
+                "2#2Z",
+                "2#2",
+                "2#ZZ"
+            };
+        
+        for ( String value : values )
+        {
+            try
+            {
+                String dnStr = "workforceID=" + value;
+                assertTrue( Dn.isValid( dnStr ) );
+                
+                Dn dn = new Dn( dnStr );
+                Rdn rdn = dn.getRdn();
+                assertEquals( value, rdn.getValue() );
+            }
+            catch ( Exception e )
+            {
+                fail();
+            }
+        }
+        
+        try
+        {
+            String dnStr = "workforceID=2# + a=b";
+            assertTrue( Dn.isValid( dnStr ) );
+            
+            Dn dn = new Dn( dnStr );
+            Rdn rdn = dn.getRdn();
+            assertEquals( "2#", rdn.getValue() );
+        }
+        catch ( Exception e )
+        {
+            fail();
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnSerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnSerializationTest.java
new file mode 100644
index 0000000..0abaf5b
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/DnSerializationTest.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Dn Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DnSerializationTest
+{
+    @Test
+    public void testDnFullSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Dn dn1 = new Dn( "gn=john + cn=doe, dc=example, dc=com" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn();
+        dn2.readExternal( in );
+
+        assertEquals( dn1, dn2 );
+    }
+
+
+    @Test
+    public void testDnEmptySerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Dn dn1 = new Dn();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn();
+        dn2.readExternal( in );
+
+        assertEquals( dn1, dn2 );
+    }
+
+
+    @Test
+    public void testDnSimpleSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Dn dn1 = new Dn( "Cn = Doe" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        dn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Dn dn2 = new Dn();
+        dn2.readExternal( in );
+
+        assertEquals( dn1, dn2 );
+        assertEquals( "Cn = Doe", dn2.getName() );
+        assertEquals( "cn=Doe", dn2.getNormName() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/FastDnParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/FastDnParserTest.java
new file mode 100644
index 0000000..4e22267
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/FastDnParserTest.java
@@ -0,0 +1,637 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.FastDnParser;
+import org.apache.directory.api.ldap.model.name.TooComplexDnException;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the fast Dn parser.
+ * 
+ * The test cases are copied from DnParserTest and adjusted when an
+ * TooComplexDnException is expected.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class FastDnParserTest
+{
+
+    /**
+     * test an empty Dn
+     */
+    @Test
+    public void testLdapDNEmpty() throws LdapException
+    {
+        assertEquals( "", FastDnParser.parse( "" ).getName() );
+    }
+
+
+    /**
+     * Tests incomplete DNs, used to check that the parser does not
+     * run into infinite loops.
+     */
+    @Test
+    public void testLdapDNIncomplete() throws LdapException
+    {
+        // empty Dn is ok
+        FastDnParser.parse( " " );
+
+        // test DNs starting with an descr
+        try
+        {
+            FastDnParser.parse( " a" );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+        try
+        {
+            FastDnParser.parse( " a " );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+        try
+        {
+            FastDnParser.parse( " a- " );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+        FastDnParser.parse( " a =" );
+        FastDnParser.parse( " a = " );
+        FastDnParser.parse( " a = b" );
+
+        // test DNs starting with an OID
+        try
+        {
+            FastDnParser.parse( " 1 = b " );
+            fail( "OID must contain at least on dot." );
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+        try
+        {
+            FastDnParser.parse( " 0" );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+        try
+        {
+            FastDnParser.parse( " 0." );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+        try
+        {
+            FastDnParser.parse( " 0.5" );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+        try
+        {
+            FastDnParser.parse( " 0.5 " );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            // expected
+        }
+
+        FastDnParser.parse( " 0.5=" );
+        FastDnParser.parse( " 0.5 = " );
+        FastDnParser.parse( " 0.5 = b" );
+    }
+
+
+    /**
+     * test a simple Dn : a = b
+     */
+    @Test
+    public void testLdapDNSimple() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "a = b" );
+
+        assertEquals( "a = b", dn.getName() );
+        assertEquals( "a=b", dn.getNormName() );
+        assertEquals( "a = b", dn.toString() );
+
+        assertEquals( "a = b", dn.getRdn().getName() );
+        assertEquals( "a=b", dn.getRdn().getNormName() );
+
+        assertEquals( "a = b", dn.getRdn().getAva().getName() );
+        assertEquals( "a=b", dn.getRdn().getAva().getNormName() );
+
+        assertEquals( "a", dn.getRdn().getAva().getType() );
+        assertEquals( "a", dn.getRdn().getAva().getNormType() );
+        assertEquals( "b", dn.getRdn().getAva().getValue().getValue() );
+        assertEquals( "b", dn.getRdn().getAva().getValue().getNormValue() );
+    }
+
+
+    /**
+     * test a composite Dn : a = b, d = e
+     */
+    @Test
+    public void testLdapDNComposite() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "a = b, c = d" );
+        assertEquals( "a=b,c=d", dn.getNormName() );
+        assertEquals( "a = b, c = d", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with or without spaces: a=b, a =b, a= b, a = b, a = b
+     */
+    @Test
+    public void testLdapDNCompositeWithSpace() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "a=b, a =b, a= b, a = b, a  =  b" );
+        assertEquals( "a=b,a=b,a=b,a=b,a=b", dn.getNormName() );
+        assertEquals( "a=b, a =b, a= b, a = b, a  =  b", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with differents separators : a=b;c=d,e=f It should
+     * return a=b,c=d,e=f (the ';' is replaced by a ',')
+     */
+    @Test
+    public void testLdapDNCompositeSepators() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "a=b;c=d,e=f" );
+        assertEquals( "a=b,c=d,e=f", dn.getNormName() );
+        assertEquals( "a=b;c=d,e=f", dn.getName() );
+    }
+
+    /**
+     * Test an attributeType with '_' (Microsoft morons support...)
+     */
+    @Test
+    public void testAttributeTypeWithUnderscore() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "microsoft_developpers=morons" );
+        assertEquals( "microsoft_developpers=morons", dn.getNormName() );
+    }
+
+    
+    /**
+     * test a simple Dn with multiple NameComponents : a = b + c = d
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testLdapDNSimpleMultivaluedAttribute() throws LdapException
+    {
+        FastDnParser.parse( "a = b + c = d" );
+        fail( "Multivalued Rdn not supported by fast parser" );
+    }
+
+
+    /**
+     * test a composite Dn with multiple NC and separators : a=b+c=d, e=f + g=h +
+     * i=j
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testLdapDNCompositeMultivaluedAttribute() throws LdapException
+    {
+        FastDnParser.parse( "a=b+c=d, e=f + g=h + i=j" );
+        fail( "Multivalued Rdn not supported by fast parser" );
+    }
+
+
+    /**
+     * test a simple Dn with an oid prefix (uppercase) : OID.12.34.56 = azerty
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testLdapDNOidUpper() throws LdapException
+    {
+        FastDnParser.parse( "OID.12.34.56 = azerty" );
+        fail( "OID prefix not supported by fast parser" );
+    }
+
+
+    /**
+     * test a simple Dn with an oid prefix (lowercase) : oid.12.34.56 = azerty
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testLdapDNOidLower() throws LdapException
+    {
+        FastDnParser.parse( "oid.12.34.56 = azerty" );
+        fail( "OID prefix not supported by fast parser" );
+    }
+
+
+    /**
+     * test a simple Dn with an oid attribut without oid prefix : 12.34.56 =
+     * azerty
+     */
+    @Test
+    public void testLdapDNOidWithoutPrefix() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "12.34.56 = azerty" );
+        assertEquals( "12.34.56=azerty", dn.getNormName() );
+        assertEquals( "12.34.56 = azerty", dn.getName() );
+    }
+
+
+    /**
+     * test a composite Dn with an oid attribut wiithout oid prefix : 12.34.56 =
+     * azerty; 7.8 = test
+     */
+    @Test
+    public void testLdapDNCompositeOidWithoutPrefix() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "12.34.56 = azerty; 7.8 = test" );
+        assertEquals( "12.34.56=azerty,7.8=test", dn.getNormName() );
+        assertEquals( "12.34.56 = azerty; 7.8 = test", dn.getName() );
+    }
+
+
+    /**
+     * test a simple Dn with pair char attribute value : a = \,\=\+\<\>\#\;\\\"\C3\A9"
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testLdapDNPairCharAttributeValue() throws LdapException
+    {
+        FastDnParser.parse( "a = \\,\\=\\+\\<\\>\\#\\;\\\\\\\"\\C3\\A9" );
+        fail( "Complex DNs not supported by fast parser" );
+    }
+
+
+    /**
+     * test a simple Dn with hexString attribute value : a = #0010A0AAFF
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testLdapDNHexStringAttributeValue() throws LdapException
+    {
+        FastDnParser.parse( "a = #0010A0AAFF" );
+        fail( "Hex DNs not supported by fast parser" );
+    }
+
+
+    /**
+     * test exception from illegal hexString attribute value : a=#zz.
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testBadLdapDNHexStringAttributeValue() throws LdapException
+    {
+        FastDnParser.parse( "a=#zz" );
+        fail( "Hex DNs not supported by fast parser" );
+    }
+
+
+    /**
+     * test a simple Dn with quoted attribute value : a = "quoted \"value"
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testLdapDNQuotedAttributeValue() throws LdapException
+    {
+        FastDnParser.parse( "a = quoted \\\"value" );
+        fail( "Quotes not supported by fast parser" );
+    }
+
+
+    /**
+     * Test the encoding of a LdanDN
+     */
+    @Test
+    public void testNameToBytes() throws LdapException
+    {
+        Dn dn = FastDnParser.parse( "cn = John, ou = People, OU = Marketing" );
+
+        byte[] bytes = Dn.getBytes( dn );
+
+        assertEquals( 30, bytes.length );
+        assertEquals( "cn=John,ou=People,ou=Marketing", Strings.utf8ToString( bytes ) );
+    }
+
+
+    @Test
+    public void testStringParser() throws LdapException
+    {
+        String dn = Strings.utf8ToString( new byte[]
+            { 'C', 'N', ' ', '=', ' ', 'E', 'm', 'm', 'a', 'n', 'u', 'e', 'l', ' ', ' ', 'L', ( byte ) 0xc3,
+                ( byte ) 0xa9, 'c', 'h', 'a', 'r', 'n', 'y' } );
+
+        Dn name = FastDnParser.parse( dn );
+
+        assertEquals( "CN = Emmanuel  L\u00e9charny", name.getName() );
+        assertEquals( "cn=Emmanuel  L\u00e9charny", name.getNormName() );
+    }
+
+
+    @Test
+    public void testStringParserShort() throws LdapException
+    {
+        String dn = Strings.utf8ToString( new byte[]
+            { 'C', '=', ' ', 'E', ( byte ) 0xc3, ( byte ) 0xa9, 'c' } );
+
+        Dn name = FastDnParser.parse( dn );
+
+        assertEquals( "C= E\u00e9c", name.getName() );
+        assertEquals( "c=E\u00e9c", name.getNormName() );
+    }
+
+
+    @Test(expected=TooComplexDnException.class)
+    public void testVsldapExtras() throws LdapException
+    {
+        FastDnParser
+            .parse( "cn=Billy Bakers, OID.2.5.4.11=Corporate Tax, ou=Fin-Accounting, ou=Americas, ou=Search, o=IMC, c=US" );
+        fail( "OID prefix not supported by fast parser" );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test
+    public final void testParseStringEmpty() throws LdapException
+    {
+        Dn nameEmpty = FastDnParser.parse( "" );
+
+        assertNotNull( nameEmpty );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test
+    public final void testParseStringNull() throws LdapException
+    {
+        Dn nameNull = FastDnParser.parse( null );
+
+        assertEquals( "Null Dn are legal : ", "", nameNull.toString() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test
+    public final void testParseStringRFC1779_1() throws LdapException
+    {
+        Dn nameRFC1779_1 = FastDnParser
+            .parse( "CN=Marshall T. Rose, O=Dover Beach Consulting, L=Santa Clara, ST=California, C=US" );
+
+        assertEquals( "RFC1779_1 : ",
+            "CN=Marshall T. Rose, O=Dover Beach Consulting, L=Santa Clara, ST=California, C=US",
+            nameRFC1779_1.getName() );
+        assertEquals( "RFC1779_1 : ", "cn=Marshall T. Rose,o=Dover Beach Consulting,l=Santa Clara,st=California,c=US",
+            nameRFC1779_1.getNormName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test
+    public final void testParseStringRFC2253_1() throws LdapException
+    {
+        Dn nameRFC2253_1 = FastDnParser.parse( "CN=Steve Kille,O=Isode limited,C=GB" );
+
+        assertEquals( "RFC2253_1 : ", "CN=Steve Kille,O=Isode limited,C=GB", nameRFC2253_1.getName() );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test(expected=TooComplexDnException.class)
+    public final void testParseStringRFC2253_2() throws LdapException
+    {
+        FastDnParser.parse( "CN = Sales + CN =   J. Smith , O = Widget Inc. , C = US" );
+        fail( "Multivalued Rdn not supported by fast parser" );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test(expected=TooComplexDnException.class)
+    public final void testParseStringRFC2253_3() throws LdapException
+    {
+        FastDnParser.parse( "CN=L. Eagle,   O=Sue\\, Grabbit and Runn, C=GB" );
+        fail( "Complex DNs not supported by fast parser" );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test(expected=TooComplexDnException.class)
+    public final void testParseStringRFC2253_4() throws LdapException
+    {
+        FastDnParser.parse( "CN=Before\\0DAfter,O=Test,C=GB" );
+        fail( "Complex DNs not supported by fast parser" );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test(expected=TooComplexDnException.class)
+    public final void testParseStringRFC2253_5() throws LdapException
+    {
+        FastDnParser.parse( "1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB" );
+        fail( "Hex DNs not supported by fast parser" );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test(expected=TooComplexDnException.class)
+    public final void testParseStringRFC2253_6() throws LdapException
+    {
+        FastDnParser.parse( "SN=Lu\\C4\\8Di\\C4\\87" );
+        fail( "Complex DNs not supported by fast parser" );
+    }
+
+
+    /**
+     * Class under test for Name parse(String)
+     */
+    @Test
+    public final void testParseInvalidString()
+    {
+        try
+        {
+            FastDnParser.parse( "&#347;=&#347;rasulu,dc=example,dc=com" );
+            fail( "the invalid name should never succeed in a parse" );
+        }
+        catch ( LdapException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    /**
+     * Tests to see if inner whitespace is preserved after an escaped ',' in a
+     * value of a name component. This test was added to try to reproduce the
+     * bug encountered in DIREVE-179 <a
+     * href="http://issues.apache.org/jira/browse/DIREVE-179"> here</a>.
+     */
+    @Test(expected=TooComplexDnException.class)
+    public final void testPreserveSpaceAfterEscape() throws LdapException
+    {
+        String input = "ou=some test\\,  something else";
+
+        FastDnParser.parse( input ).toString();
+        fail( "Complex DNs not supported by fast parser" );
+    }
+
+
+    @Test(expected=TooComplexDnException.class)
+    public void testWindowsFilePath() throws Exception
+    {
+        // '\' should be escaped as stated in RFC 2253
+        String path = "windowsFilePath=C:\\\\cygwin";
+
+        FastDnParser.parse( path );
+        fail( "Complex DNs not supported by fast parser" );
+    }
+
+
+    @Test
+    public void testNameFrenchChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', 0x4A, ( byte ) 0xC3, ( byte ) 0xA9, 0x72, ( byte ) 0xC3, ( byte ) 0xB4, 0x6D, 0x65 },
+            "UTF-8" );
+
+        String result = FastDnParser.parse( cn ).toString();
+
+        assertEquals( "cn=J\u00e9r\u00f4me", result );
+    }
+
+
+    @Test
+    public void testNameGermanChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC3, ( byte ) 0x84, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3, ( byte ) 0x9C,
+                ( byte ) 0xC3, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0xA4, ( byte ) 0xC3, ( byte ) 0xB6,
+                ( byte ) 0xC3, ( byte ) 0xBC }, "UTF-8" );
+
+        String result = FastDnParser.parse( cn ).toString();
+
+        assertEquals( "cn=\u00C4\u00D6\u00DC\u00DF\u00E4\u00F6\u00FC", result );
+    }
+
+
+    /**
+     * Test that we can have non-ascii characters in a DN when we use the 
+     * fast DN parser
+     */
+    @Test
+    public void testNameTurkishChars() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC4, ( byte ) 0xB0, ( byte ) 0xC4, ( byte ) 0xB1, ( byte ) 0xC5, ( byte ) 0x9E,
+                ( byte ) 0xC5, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3, ( byte ) 0xB6,
+                ( byte ) 0xC3, ( byte ) 0x9C, ( byte ) 0xC3, ( byte ) 0xBC, ( byte ) 0xC4, ( byte ) 0x9E,
+                ( byte ) 0xC4, ( byte ) 0x9F }, "UTF-8" );
+
+        String result = FastDnParser.parse( cn ).toString();
+
+        assertEquals( "cn=\u0130\u0131\u015E\u015F\u00D6\u00F6\u00DC\u00FC\u011E\u011F", result );
+
+    }
+
+
+    /**
+     * Test that we can have non-ascii characters in a DN when we use the 
+     * fast DN parser, but not followded by bytes
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testAUmlautPlusBytes() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC3, ( byte ) 0x84, 0x5C, 0x32, 0x42 }, "UTF-8" );
+
+        FastDnParser.parse( cn ).toString();
+        fail( "DNs with special characters not supported by fast parser" );
+    }
+
+
+    /**
+     * Test that we can't have escaped characters in a DN when we use the 
+     * fast DN parser
+     */
+    @Test(expected=TooComplexDnException.class)
+    public void testAUmlautPlusChar() throws Exception
+    {
+        String cn = new String( new byte[]
+            { 'c', 'n', '=', ( byte ) 0xC3, ( byte ) 0x84, '\\', '+' }, "UTF-8" );
+
+        FastDnParser.parse( cn ).toString();
+        fail( "DNs with special characters not supported by fast parser" );
+    }
+
+
+    /**
+     * Test to check that even with a non escaped char, the Dn is parsed ok
+     * or at least an error is generated.
+     */
+    @Test(expected=TooComplexDnException.class)
+    public final void testNonEscapedChars() throws LdapException
+    {
+        String input = "ou=ou+test";
+
+        FastDnParser.parse( input ).toString();
+        fail( "Should never reach this point" );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/RdnSerializationTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/RdnSerializationTest.java
new file mode 100644
index 0000000..45f31ba
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/RdnSerializationTest.java
@@ -0,0 +1,323 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Rdn Serialization
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class RdnSerializationTest
+{
+    @Test
+    public void testRdnFullSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn( "gn=john + cn=doe" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn1, rdn2 );
+    }
+
+
+    @Test
+    public void testRdnEmptySerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn1, rdn2 );
+    }
+
+
+    @Test
+    public void testRdnSimpleSerialization() throws IOException, LdapException, ClassNotFoundException
+    {
+        Rdn rdn1 = new Rdn( "cn=doe" );
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn1.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn1, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of an empty Rdn
+     */
+    @Test
+    public void testEmptyRDNStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( "" );
+
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    @Test
+    public void testNullRdnStaticSerialization() throws IOException, ClassNotFoundException, LdapInvalidDnException
+    {
+        Rdn rdn = new Rdn();
+
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn
+     */
+    @Test
+    public void testSimpleRdnStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( "a=b" );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn
+     */
+    @Test
+    public void testSimpleRdn2StaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " ABC  = DEF " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with no value
+     */
+    @Test
+    public void testSimpleRdnNoValueStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " ABC  =" );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with one value
+     */
+    @Test
+    public void testSimpleRdnOneValueStaticSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " ABC  = def " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with three values
+     */
+    @Test
+    public void testSimpleRdnThreeValuesStaticSerialization() throws LdapException, IOException,
+        ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " A = a + B = b + C = c " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with three unordered values
+     */
+    @Test
+    public void testSimpleRdnThreeValuesUnorderedStaticSerialization() throws LdapException, IOException,
+        ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " B = b + A = a + C = c " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        rdn.writeExternal( out );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = new Rdn();
+        rdn2.readExternal( in );
+
+        assertEquals( rdn, rdn2 );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/RdnTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/RdnTest.java
new file mode 100644
index 0000000..72babca
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/name/RdnTest.java
@@ -0,0 +1,1273 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.name;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Iterator;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Ava;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the class Rdn
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class RdnTest
+{
+    /** A null schemaManager used in tests */
+    SchemaManager schemaManager = null;
+
+
+    /**
+     * Test a null Rdn
+     */
+    @Test
+    public void testRdnNull()
+    {
+        assertEquals( "", new Rdn().toString() );
+    }
+
+
+    /**
+     * test an empty Rdn
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnEmpty() throws LdapException
+    {
+        assertEquals( "", new Rdn( "" ).toString() );
+    }
+
+
+    /**
+     * test a simple Rdn : a = b
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnSimple() throws LdapException
+    {
+        assertEquals( "a=b", new Rdn( "a = b" ).getNormName() );
+    }
+
+
+    /**
+     * test a composite Rdn : a = b, d = e
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnComposite() throws LdapException
+    {
+        assertEquals( "a=b+c=d", new Rdn( "a = b + c = d" ).getNormName() );
+    }
+
+
+    /**
+     * test a composite Rdn with or without spaces: a=b, a =b, a= b, a = b, a =
+     * b
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnCompositeWithSpace() throws LdapException
+    {
+        assertEquals( "a=b", new Rdn( "a=b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a=b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( "a =b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( "a= b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( "a=b " ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a =b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a= b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a=b " ).getNormName() );
+        assertEquals( "a=b", new Rdn( "a = b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( "a =b " ).getNormName() );
+        assertEquals( "a=b", new Rdn( "a= b " ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a = b" ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a =b " ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a= b " ).getNormName() );
+        assertEquals( "a=b", new Rdn( "a = b " ).getNormName() );
+        assertEquals( "a=b", new Rdn( " a = b " ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with differents separators : a = b + c = d
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnSimpleMultivaluedAttribute() throws LdapException
+    {
+        String result = new Rdn( "a = b + c = d" ).getNormName();
+        assertEquals( "a=b+c=d", result );
+    }
+
+
+    /**
+     * test a composite Rdn with differents separators : a=b+c=d, e=f + g=h +
+     * i=j
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnCompositeMultivaluedAttribute() throws LdapException
+    {
+        Rdn rdn = new Rdn( "a =b+c=d + e=f + g  =h + i =j " );
+
+        // NameComponent are not ordered
+        assertEquals( "b", rdn.getValue( "a" ) );
+        assertEquals( "d", rdn.getValue( "c" ) );
+        assertEquals( "f", rdn.getValue( "  E  " ) );
+        assertEquals( "h", rdn.getValue( "g" ) );
+        assertEquals( "j", rdn.getValue( "i" ) );
+    }
+
+
+    /**
+     * test a simple Rdn with an oid prefix (uppercase) : OID.12.34.56 = azerty
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnOidUpper() throws LdapException
+    {
+        assertEquals( "oid.12.34.56=azerty", new Rdn( "OID.12.34.56 =  azerty" ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with an oid prefix (lowercase) : oid.12.34.56 = azerty
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnOidLower() throws LdapException
+    {
+        assertEquals( "oid.12.34.56=azerty", new Rdn( "oid.12.34.56 = azerty" ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with an oid attribut wiithout oid prefix : 12.34.56 =
+     * azerty
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnOidWithoutPrefix() throws LdapException
+    {
+        assertEquals( "12.34.56=azerty", new Rdn( "12.34.56 = azerty" ).getNormName() );
+    }
+
+
+    /**
+     * test a composite Rdn with an oid attribut wiithout oid prefix : 12.34.56 =
+     * azerty; 7.8 = test
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnCompositeOidWithoutPrefix() throws LdapException
+    {
+        String result = new Rdn( "12.34.56 = azerty + 7.8 = test" ).getNormName();
+        assertEquals( "12.34.56=azerty+7.8=test", result );
+    }
+
+
+    /**
+     * test a simple Rdn with pair char attribute value : a = \,\=\+\<\>\#\;\\\"\C3\A9"
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnPairCharAttributeValue() throws LdapException
+    {
+        String rdn = Strings.utf8ToString( new byte[]
+            { 'a', '=', '\\', ',', '\\', '=', '\\', '+', '\\', '<', '\\', '>', '#', '\\', ';', '\\', '\\', '\\', '"', '\\',
+                'C', '3', '\\', 'A', '9' } );
+        assertEquals( "a=\\,\\=\\+\\<\\>#\\;\\\\\\\"\u00e9", new Rdn( rdn ).getNormName() );
+    }
+
+
+    /**
+     * test a simple Rdn with hexString attribute value : a = #0010A0AAFF
+     */
+    @Test
+    public void testRdnHexStringAttributeValue() throws LdapException
+    {
+        assertEquals( "a=#0010A0AAFF", new Rdn( "a = #0010A0AAFF" ).getNormName() );
+    }
+
+
+    /**
+     * test exception from illegal hexString attribute value : a=#zz.
+     */
+    @Test
+    public void testBadRdnHexStringAttributeValue() throws LdapException
+    {
+        try
+        {
+            new Rdn( "a=#zz" );
+            fail();
+        }
+        catch ( LdapException ine )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a simple Rdn with quoted attribute value : a = "quoted \"value"
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRdnQuotedAttributeValue() throws LdapException
+    {
+        Rdn rdn = new Rdn( "a = quoted \\\"value" );
+        assertEquals( "a=quoted \\\"value", rdn.getNormName() );
+        assertEquals( "quoted \\\"value", rdn.getValue( "a" ) );
+        assertEquals( "quoted \"value", rdn.getNormValue( "a" ) );
+    }
+
+
+    /**
+     * Test the clone method for a Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCloningOneNameComponent() throws LdapException
+    {
+        Rdn rdn = new Rdn( "a", "b" );
+
+        Rdn rdnClone = rdn.clone();
+
+        rdn = new Rdn( "c=d" );
+
+        assertEquals( "b", rdnClone.getValue( "a" ) );
+    }
+
+
+    /**
+     * Test teh creation of a new Rdn
+     * 
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException
+     */
+    @Test
+    public void testRDNCreation() throws LdapException
+    {
+        Rdn rdn = new Rdn( "A", "  b  " );
+        assertEquals( "a=\\  b \\ ", rdn.getNormName() );
+        assertEquals( "A=  b  ", rdn.getName() );
+    }
+
+
+    /**
+     * Test the clone method for a Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCloningTwoNameComponent() throws LdapException
+    {
+        Rdn rdn = new Rdn( "a = b + aa = bb" );
+
+        Rdn rdnClone = rdn.clone();
+
+        rdn.clear();
+        rdn = new Rdn( "c=d" );
+
+        assertEquals( "b", rdnClone.getValue( "a" ) );
+        assertEquals( "bb", rdnClone.getValue( "aa" ) );
+        assertEquals( "", rdnClone.getValue( "c" ) );
+    }
+
+
+    /**
+     * Test the equals method for a Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNull() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b + c = d + e = f + g = h " );
+        Rdn rdn2 = null;
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NC to a single NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NC() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b + c = d + e = f + g = h " );
+        Rdn rdn2 = new Rdn( " a = b " );
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a single NC to a composite NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NCS() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b " );
+        Rdn rdn2 = new Rdn( " a = b + c = d + e = f + g = h " );
+
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NCS to a composite NCS in the same order.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NCSOrdered() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b + c = d + e = f + g = h " );
+        Rdn rdn2 = new Rdn( " a = b + c = d + e = f + g = h " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NCS to a composite NCS in a different order.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NCSUnordered() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b + b = f + g = h + c = d " );
+        Rdn rdn2 = new Rdn( " a = b + c = d + b = f + g = h " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a composite NCS to a different composite NCS.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNCS2NCSNotEquals() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = f + g = h + c = d " );
+        Rdn rdn2 = new Rdn( " c = d + a = h + g = h " );
+
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-2.
+     * The first ATAV is equal, the second or following ATAV differs.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareSecondAtav() throws LdapException
+    {
+        // the second ATAV differs
+        Rdn rdn1 = new Rdn( " a = b + c = d " );
+        Rdn rdn2 = new Rdn( " a = b + c = y " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+
+        // the third ATAV differs
+        Rdn rdn3 = new Rdn( " a = b + c = d + e = f " );
+        Rdn rdn4 = new Rdn( " a = b + c = d + e = y " );
+        assertFalse( rdn3.equals( rdn4 ) );
+        assertFalse( rdn4.equals( rdn3 ) );
+
+        // the second ATAV differs in value only
+        Rdn rdn5 = new Rdn( " a = b + b = c " );
+        Rdn rdn6 = new Rdn( " a = b + b = y " );
+        assertFalse( rdn5.equals( rdn6 ) );
+        assertFalse( rdn6.equals( rdn5 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-2.
+     * The compare operation should return a correct value (1 or -1)
+     * depending on the ATAVs, not on their position.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareIndependentFromOrder() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b + c = d " );
+        Rdn rdn2 = new Rdn( " c = d + a = b " );
+        assertTrue( rdn1.equals( rdn2 ) );
+
+        rdn1 = new Rdn( " a = b + c = e " );
+        rdn2 = new Rdn( " c = d + a = b " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+
+        rdn1 = new Rdn( " a = b + c = d " );
+        rdn2 = new Rdn( " e = f + g = h " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for single-valued RDNs.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareInvertableNC2NC() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b " );
+        Rdn rdn2 = new Rdn( " a = c " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for multi-valued RDNs with different values.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareInvertableNCS2NCSDifferentValues() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b + b = c " );
+        Rdn rdn2 = new Rdn( " a = b + b = y " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for multi-valued RDNs with different types.
+     * 
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException
+     */
+    @Test
+    public void testCompareInvertableNCS2NCSDifferentTypes() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b + c = d  " );
+        Rdn rdn2 = new Rdn( " e = f + g = h " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Test for DIRSHARED-3.
+     * Tests that equals() is invertable for multi-valued RDNs with different order.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testCompareInvertableNCS2NCSUnordered() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " c = d + a = b " );
+        Rdn rdn2 = new Rdn( " a = b + e = f " );
+        assertFalse( rdn1.equals( rdn2 ) );
+        assertFalse( rdn2.equals( rdn1 ) );
+    }
+
+
+    /**
+     * Compares with a null Rdn.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNullRdn() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b " );
+
+        assertFalse( rdn1.equals( null ) );
+    }
+
+
+    /**
+     * Compares a simple NC to a simple NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NC() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b " );
+        Rdn rdn2 = new Rdn( " a = b " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a simple NC to a simple NC in UperCase.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NCUperCase() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b " );
+        Rdn rdn2 = new Rdn( " A = b " );
+
+        assertTrue( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * Compares a simple NC to a different simple NC.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testRDNCompareToNC2NCNotEquals() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( " a = b " );
+        Rdn rdn2 = new Rdn( " A = d " );
+
+        assertFalse( rdn1.equals( rdn2 ) );
+    }
+
+
+    /**
+     * 
+     * Test the getValue method.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testGetValue() throws LdapException
+    {
+        Rdn rdn = new Rdn( " a = b + b = f + g = h + c = d " );
+
+        assertEquals( "b", rdn.getNormValue() );
+    }
+
+
+    /**
+     * 
+     * Test the getType method.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testGetType() throws LdapException
+    {
+        Rdn rdn = new Rdn( " a = b + b = f + g = h + c = d " );
+
+        assertEquals( "a", rdn.getNormType() );
+    }
+
+
+    /**
+     * Test the getSize method.
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testGetSize() throws LdapException
+    {
+        Rdn rdn = new Rdn( " a = b + b = f + g = h + c = d " );
+
+        assertEquals( 4, rdn.size() );
+    }
+
+
+    /**
+     * Test the getSize method.
+     *
+     */
+    @Test
+    public void testGetSize0()
+    {
+        Rdn rdn = new Rdn();
+
+        assertEquals( 0, rdn.size() );
+    }
+
+
+    /**
+     * Test the equals method
+     *
+     * @throws LdapException
+     */
+    @Test
+    public void testEquals() throws LdapException
+    {
+        Rdn rdn = new Rdn( "a=b + c=d + e=f" );
+
+        assertFalse( rdn.equals( null ) );
+        assertFalse( rdn.equals( "test" ) );
+        assertFalse( rdn.equals( new Rdn( "a=c + c=d + e=f" ) ) );
+        assertFalse( rdn.equals( new Rdn( "a=b" ) ) );
+        assertTrue( rdn.equals( new Rdn( "a=b + c=d + e=f" ) ) );
+        assertTrue( rdn.equals( new Rdn( "a=b + C=d + E=f" ) ) );
+        assertTrue( rdn.equals( new Rdn( "c=d + e=f + a=b" ) ) );
+    }
+
+
+    @Test
+    public void testUnescapeValueHexa()
+    {
+        byte[] res = ( byte[] ) Rdn.unescapeValue( "#fF" );
+
+        assertEquals( "0xFF ", Strings.dumpBytes( res ) );
+
+        res = ( byte[] ) Rdn.unescapeValue( "#0123456789aBCDEF" );
+        assertEquals( "0x01 0x23 0x45 0x67 0x89 0xAB 0xCD 0xEF ", Strings.dumpBytes( res ) );
+    }
+
+
+    @Test
+    public void testUnescapeValueHexaWrong()
+    {
+        try
+        {
+            Rdn.unescapeValue( "#fF1" );
+            fail(); // Should not happen
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testUnescapeValueString()
+    {
+        String res = ( String ) Rdn.unescapeValue( "azerty" );
+
+        assertEquals( "azerty", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringSpecial()
+    {
+        String res = ( String ) Rdn.unescapeValue( "\\\\\\#\\,\\+\\;\\<\\>\\=\\\"\\ " );
+
+        assertEquals( "\\#,+;<>=\" ", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithSpaceInTheMiddle()
+    {
+        String res = ( String ) Rdn.unescapeValue( "a b" );
+
+        assertEquals( "a b", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithSpaceInAtTheBeginning()
+    {
+        String res = ( String ) Rdn.unescapeValue( "\\ a b" );
+
+        assertEquals( " a b", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithSpaceInAtTheEnd()
+    {
+        String res = ( String ) Rdn.unescapeValue( "a b\\ " );
+
+        assertEquals( "a b ", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithPoundInTheMiddle()
+    {
+        String res = ( String ) Rdn.unescapeValue( "a#b" );
+
+        assertEquals( "a#b", res );
+    }
+
+
+    @Test
+    public void testUnescapeValueStringWithPoundAtTheEnd()
+    {
+        String res = ( String ) Rdn.unescapeValue( "ab#" );
+
+        assertEquals( "ab#", res );
+    }
+
+
+    @Test
+    public void testEscapeValueString()
+    {
+        String res = Rdn.escapeValue( Strings.getBytesUtf8( "azerty" ) );
+
+        assertEquals( "azerty", res );
+    }
+
+
+    @Test
+    public void testEscapeValueStringSpecial()
+    {
+        String res = Rdn.escapeValue( Strings.getBytesUtf8( "\\#,+;<>=\" " ) );
+
+        assertEquals( "\\\\#\\,\\+\\;\\<\\>\\=\\\"\\ ", res );
+    }
+
+
+    @Test
+    public void testEscapeValueNumeric()
+    {
+        String res = Rdn.escapeValue( new byte[]
+            { '-', 0x00, '-', 0x1F, '-', 0x7F, '-' } );
+
+        assertEquals( "-\\00-\\1F-\\7F-", res );
+    }
+
+
+    @Test
+    public void testEscapeValueMix()
+    {
+        String res = Rdn.escapeValue( new byte[]
+            { '\\', 0x00, '-', '+', '#', 0x7F, '-' } );
+
+        assertEquals( "\\\\\\00-\\+#\\7F-", res );
+    }
+
+
+    @Test
+    public void testDIRSERVER_703() throws LdapException
+    {
+        Rdn rdn = new Rdn( "cn=Kate Bush+sn=Bush" );
+        assertEquals( "cn=Kate Bush+sn=Bush", rdn.getName() );
+    }
+
+
+    @Test
+    public void testMultiValuedIterator() throws LdapException
+    {
+        Rdn rdn = new Rdn( "cn=Kate Bush+sn=Bush" );
+        Iterator<Ava> iterator = rdn.iterator();
+        assertNotNull( iterator );
+        assertTrue( iterator.hasNext() );
+        assertNotNull( iterator.next() );
+        assertTrue( iterator.hasNext() );
+        assertNotNull( iterator.next() );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    @Test
+    public void testSingleValuedIterator() throws LdapException
+    {
+        Rdn rdn = new Rdn( "cn=Kate Bush" );
+        Iterator<Ava> iterator = rdn.iterator();
+        assertNotNull( iterator );
+        assertTrue( iterator.hasNext() );
+        assertNotNull( iterator.next() );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    @Test
+    public void testEmptyIterator()
+    {
+        Rdn rdn = new Rdn();
+        Iterator<Ava> iterator = rdn.iterator();
+        assertNotNull( iterator );
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    @Test
+    public void testRdnWithSpaces() throws LdapException
+    {
+        Rdn rdn = new Rdn( "cn=a\\ b\\ c" );
+        assertEquals( "cn=a b c", rdn.getNormName() );
+    }
+
+
+    @Test
+    public void testEscapedSpaceInValue() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( "cn=a b c" );
+        Rdn rdn2 = new Rdn( "cn=a\\ b\\ c" );
+        assertEquals( "cn=a b c", rdn1.getNormName() );
+        assertEquals( "cn=a b c", rdn2.getNormName() );
+        assertTrue( rdn1.equals( rdn2 ) );
+
+        Rdn rdn3 = new Rdn( "cn= \\ a b c\\  " );
+        Rdn rdn4 = new Rdn( "cn=\\ a\\ b\\ c\\ " );
+        assertEquals( "cn=\\ a b c\\ ", rdn3.getNormName() );
+        assertEquals( "cn=\\ a b c\\ ", rdn4.getNormName() );
+        assertTrue( rdn3.equals( rdn4 ) );
+    }
+
+
+    @Test
+    public void testEscapedHashInValue() throws LdapException
+    {
+        Rdn rdn1 = new Rdn( "cn=a#b#c" );
+        Rdn rdn2 = new Rdn( "cn=a\\#b\\#c" );
+        assertEquals( "cn=a#b#c", rdn1.getNormName() );
+        assertEquals( "cn=a#b#c", rdn2.getNormName() );
+        assertTrue( rdn1.equals( rdn2 ) );
+
+        Rdn rdn3 = new Rdn( "cn=\\#a#b#c\\#" );
+        Rdn rdn4 = new Rdn( "cn=\\#a\\#b\\#c\\#" );
+        assertEquals( "cn=\\#a#b#c#", rdn3.getNormName() );
+        assertEquals( "cn=\\#a#b#c#", rdn4.getNormName() );
+        assertTrue( rdn3.equals( rdn4 ) );
+    }
+
+
+    @Test
+    public void testEscapedAttributeValue()
+    {
+        // space doesn't need to be escaped in the middle of a string
+        assertEquals( "a b", Rdn.escapeValue( "a b" ) );
+        assertEquals( "a b c", Rdn.escapeValue( "a b c" ) );
+        assertEquals( "a b c d", Rdn.escapeValue( "a b c d" ) );
+
+        // space must be escaped at the beginning and the end of a string
+        assertEquals( "\\ a b", Rdn.escapeValue( " a b" ) );
+        assertEquals( "a b\\ ", Rdn.escapeValue( "a b " ) );
+        assertEquals( "\\ a b\\ ", Rdn.escapeValue( " a b " ) );
+        assertEquals( "\\  a  b \\ ", Rdn.escapeValue( "  a  b  " ) );
+
+        // hash doesn't need to be escaped in the middle and the end of a string
+        assertEquals( "a#b", Rdn.escapeValue( "a#b" ) );
+        assertEquals( "a#b#", Rdn.escapeValue( "a#b#" ) );
+        assertEquals( "a#b#c", Rdn.escapeValue( "a#b#c" ) );
+        assertEquals( "a#b#c#", Rdn.escapeValue( "a#b#c#" ) );
+        assertEquals( "a#b#c#d", Rdn.escapeValue( "a#b#c#d" ) );
+        assertEquals( "a#b#c#d#", Rdn.escapeValue( "a#b#c#d#" ) );
+
+        // hash must be escaped at the beginning of a string
+        assertEquals( "\\#a#b", Rdn.escapeValue( "#a#b" ) );
+        assertEquals( "\\##a#b", Rdn.escapeValue( "##a#b" ) );
+
+        // other characters that need to be escaped
+        // '"', '+', ',', ';', '<', '>', '\', the null (U+0000) character
+        assertEquals( "\\\"\\+\\,\\;\\<\\>\\\\\\00", Rdn.escapeValue( "\"+,;<>\\\u0000" ) );
+
+        // unicode characters don't need to be escaped
+        // \u00e9 - e with acute - 2 bytes in UTF-8
+        // \u20ac - Euro character - 3 bytes in UTF-8
+        // \uD83D\uDE08 - Smiley - 4 bytes in UTF-8
+        assertEquals( "\u00e9\u20AC\uD83D\uDE08", Rdn.escapeValue( "\u00e9\u20AC\uD83D\uDE08" ) );
+    }
+
+
+    /** Serialization tests ------------------------------------------------- */
+
+    /**
+     * Test serialization of an empty Rdn
+     */
+    @Test
+    public void testEmptyRDNSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( "" );
+
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    @Test
+    public void testNullRdnSerialization() throws IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn();
+
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn
+     */
+    @Test
+    public void testSimpleRdnSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( "a=b" );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn
+     */
+    @Test
+    public void testSimpleRdn2Serialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " ABC  = DEF " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with no value
+     */
+    @Test
+    public void testSimpleRdnNoValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " ABC  =" );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with one value
+     */
+    @Test
+    public void testSimpleRdnOneValueSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " ABC  = def " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with three values
+     */
+    @Test
+    public void testSimpleRdnThreeValuesSerialization() throws LdapException, IOException, ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " A = a + B = b + C = c " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * Test serialization of a simple Rdn with three unordered values
+     */
+    @Test
+    public void testSimpleRdnThreeValuesUnorderedSerialization() throws LdapException, IOException,
+        ClassNotFoundException
+    {
+        Rdn rdn = new Rdn( " B = b + A = a + C = c " );
+        rdn.normalize();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+
+        out.writeObject( rdn );
+
+        ObjectInputStream in = null;
+
+        byte[] data = baos.toByteArray();
+        in = new ObjectInputStream( new ByteArrayInputStream( data ) );
+
+        Rdn rdn2 = ( Rdn ) in.readObject();
+
+        assertEquals( rdn, rdn2 );
+    }
+
+
+    /**
+     * test an Rdn with empty value
+     */
+    @Test
+    public void testRdnWithEmptyValue() throws LdapException
+    {
+        assertTrue( Rdn.isValid( "a=" ) );
+        assertTrue( Rdn.isValid( "a=\"\"" ) );
+        assertEquals( "a=", new Rdn( "a=\"\"" ).getNormName() );
+        assertEquals( "a=", new Rdn( "a=" ).getNormName() );
+    }
+
+
+    /**
+     * test an Rdn with escaped comma
+     */
+    @Test
+    public void testRdnWithEscapedComa() throws LdapException
+    {
+        assertTrue( Rdn.isValid( "a=b\\,c" ) );
+        assertEquals( "a=b\\,c", new Rdn( "a=b\\,c" ).getNormName() );
+
+        assertTrue( Rdn.isValid( "a=\"b,c\"" ) );
+        assertEquals( "a=b\\,c", new Rdn( "a=\"b,c\"" ).getNormName() );
+        assertEquals( "a=\"b,c\"", new Rdn( "a=\"b,c\"" ).getName() );
+
+        assertTrue( Rdn.isValid( "a=\"b\\,c\"" ) );
+        Rdn rdn = new Rdn( "a=\"b\\,c\"" );
+        assertEquals( "a=\"b\\,c\"", rdn.getName() );
+        assertEquals( "a=b\\\\\\,c", rdn.getNormName() );
+    }
+
+
+    /**
+     * Tests the equals and equals results of cloned multi-valued RDNs.
+     * Test for DIRSHARED-9.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testComparingOfClonedMultiValuedRDNs() throws LdapException
+    {
+        // Use upper case attribute types to test if normalized types are used
+        // for comparison
+        Rdn rdn = new Rdn( " A = b + C = d" );
+        Rdn clonedRdn = rdn.clone();
+
+        assertTrue( rdn.equals( clonedRdn ) );
+    }
+
+
+    /**
+     * Tests the equals and equals results of copy constructed multi-valued RDNs.
+     * Test for DIRSHARED-9.
+     * 
+     * @throws LdapException
+     */
+    @Test
+    public void testComparingOfCopyConstructedMultiValuedRDNs() throws LdapException
+    {
+        // Use upper case attribute types to test if normalized types are used
+        // for comparison
+        Rdn rdn = new Rdn( " A = b + C = d" );
+        Rdn copiedRdn = new Rdn( rdn );
+
+        assertTrue( rdn.equals( copiedRdn ) );
+    }
+
+
+    /**
+     * test the UpName method on a Rdn with more than one atav
+     */
+    @Test
+    public void testGetUpNameMultipleAtav() throws LdapException
+    {
+        Rdn rdn = new Rdn( " A = b + C = d " );
+
+        assertEquals( " A = b + C = d ", rdn.getName() );
+    }
+
+
+    /**
+     * test the iterator over a RDN
+     */
+    @Test
+    public void testIterator() throws LdapException
+    {
+        Rdn rdn = new Rdn( "cn=John + sn=Doe" );
+
+        String[] expected = new String[]
+            { "cn=John ", " sn=Doe" };
+        int i = 0;
+
+        for ( Ava ava : rdn )
+        {
+            assertEquals( expected[i], ava.toString() );
+            i++;
+        }
+    }
+
+
+    /**
+     * test that a RDN with two AVAs throws an exception
+     */
+    @Test( expected=LdapInvalidDnException.class )
+    public void testWrongRdn() throws LdapException
+    {
+        new Rdn( " A = b, C = d " );
+    }
+
+
+    /**
+     * test that a RDN with an attributeType used twice throws an exception
+     */
+    @Test( expected=LdapInvalidDnException.class )
+    public void testWrongRdnAtUsedTwice() throws LdapException
+    {
+        new Rdn( " A = b + A = d " );
+    }
+
+
+    @Test
+    public void testAvaConstructor() throws LdapInvalidDnException
+    {
+        Rdn rdn = new Rdn( new Ava( "CN", "\u00E4" ), new Ava( "A", "d" ) );
+        assertEquals( "CN=\u00E4+A=d", rdn.getName() );
+        assertEquals( "cn=\u00E4+a=d", rdn.getNormName() );
+        assertEquals( "\u00E4", rdn.getValue( "CN" ) );
+        assertEquals( "\u00E4", rdn.getValue() );
+        assertEquals( "\u00E4", rdn.getValue() );
+        assertEquals( "CN", rdn.getType() );
+        assertEquals( "cn", rdn.getNormType() );
+    }
+
+
+    /**
+     * test that a RDN with an attributeType used twice throws an exception
+     */
+    @Test(expected = LdapInvalidDnException.class)
+    public void testAvaConstructorWrongRdnAtUsedTwice() throws LdapException
+    {
+        new Rdn( new Ava( "A", "b" ), new Ava( "A", "d" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/password/PasswordUtilTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/password/PasswordUtilTest.java
new file mode 100644
index 0000000..0d986d4
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/password/PasswordUtilTest.java
@@ -0,0 +1,59 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.model.password;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+
+/**
+ * A test for the PasswordUtil class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordUtilTest
+{
+
+    @Test
+    public void compareCredentialTest()
+    {
+        // Simple cases
+        assertTrue( PasswordUtil.compareCredentials( null, null ) );
+        assertTrue( PasswordUtil.compareCredentials( new byte[]{}, new byte[]{} ) );
+        assertTrue( PasswordUtil.compareCredentials( new byte[]{ 0x01 }, new byte[]{ 0x01 } ) );
+        
+        // Simple failures
+        assertFalse( PasswordUtil.compareCredentials( null, new byte[]{ 0x01 } ) );
+        assertFalse( PasswordUtil.compareCredentials( new byte[]{ 0x01 }, null ) );
+        assertFalse( PasswordUtil.compareCredentials( new byte[]{ 0x01 }, new byte[]{ 0x02 } ) );
+        
+        // With some different lengths
+        assertFalse( PasswordUtil.compareCredentials( Strings.getBytesUtf8( "Password1" ), Strings.getBytesUtf8( "Password1 " ) ) );
+
+        // With different passwords
+        assertFalse( PasswordUtil.compareCredentials( Strings.getBytesUtf8( "Password1" ), Strings.getBytesUtf8( "password1" ) ) );
+
+        // With same passwords
+        assertTrue( PasswordUtil.compareCredentials( Strings.getBytesUtf8( "Password1" ), Strings.getBytesUtf8( "Password1" ) ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/AttributeTypeTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/AttributeTypeTest.java
new file mode 100644
index 0000000..6a53107
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/AttributeTypeTest.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class AttributeType.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeTypeTest
+{
+    private MutableAttributeType attributeType;
+
+
+    /**
+     * Initialize attribute type instances
+     */
+    @Before
+    public void initAttributeTypes() throws Exception
+    {
+        attributeType = new MutableAttributeType( "1.2.3.4" );
+        attributeType.setNames( "name1", "name2" );
+        attributeType.setDescription( "description" );
+        attributeType.setObsolete( false );
+        attributeType.setEqualityOid( "caseIgnoreMatch" );
+        attributeType.setSuperiorOid( "2.3.4.5" );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = attributeType.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "attributetype (" ) );
+        assertTrue( string.contains( " NAME " ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tSUP " ) );
+        assertTrue( string.contains( "\n\tUSAGE" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/DitContentRuleTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/DitContentRuleTest.java
new file mode 100644
index 0000000..dac7a7e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/DitContentRuleTest.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class DitContentRule.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DitContentRuleTest
+{
+    private DitContentRule ditContentRule;
+
+
+    /**
+     * Initialize attribute type instances
+     */
+    @Before
+    public void initDitContentRules() throws Exception
+    {
+        ditContentRule = new DitContentRule( "1.2.3.4" );
+        ditContentRule.setNames( "name1", "name2" );
+        ditContentRule.setDescription( "description" );
+        ditContentRule.setObsolete( false );
+        ditContentRule.setAuxObjectClassOids( Arrays.asList( "oc1", "oc2" ) );
+        ditContentRule.setMustAttributeTypeOids( Arrays.asList( "must1", "must2" ) );
+        ditContentRule.setMayAttributeTypeOids( Arrays.asList( "may1", "may2" ) );
+        ditContentRule.setNotAttributeTypeOids( Arrays.asList( "not1", "not2" ) );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = ditContentRule.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "ditcontentrule (" ) );
+        assertTrue( string.contains( " NAME " ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tAUX " ) );
+        assertTrue( string.contains( "\n\tMUST" ) );
+        assertTrue( string.contains( "\n\tMAY" ) );
+        assertTrue( string.contains( "\n\tNOT" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/DitStructureRuleTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/DitStructureRuleTest.java
new file mode 100644
index 0000000..2a6b7e2
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/DitStructureRuleTest.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class DitStructureRule.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DitStructureRuleTest
+{
+    private DitStructureRule ditStructureRule;
+
+
+    /**
+     * Initialize attribute type instances
+     */
+    @Before
+    public void initDitStructureRules() throws Exception
+    {
+        ditStructureRule = new DitStructureRule( 1234 );
+        ditStructureRule.setNames( "name1", "name2" );
+        ditStructureRule.setDescription( "description" );
+        ditStructureRule.setObsolete( false );
+        ditStructureRule.setForm( "form1" );
+        ditStructureRule.setSuperRules( Arrays.asList( 111, 222, 333 ) );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = ditStructureRule.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "ditstructurerule (" ) );
+        assertTrue( string.contains( " NAME " ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tFORM " ) );
+        assertTrue( string.contains( "\n\tSUP" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/LdapSyntaxTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/LdapSyntaxTest.java
new file mode 100644
index 0000000..e933b05
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/LdapSyntaxTest.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class LdapSyntax.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapSyntaxTest
+{
+    private LdapSyntax ldapSyntax;
+
+
+    /**
+     * Initialize ldap syntax use instances
+     */
+    @Before
+    public void initMatchingRuleUses() throws Exception
+    {
+        ldapSyntax = new LdapSyntax( "1.2.3.4" );
+        ldapSyntax.setDescription( "description" );
+        ldapSyntax.setHumanReadable( true );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = ldapSyntax.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "ldapsyntax (" ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tX-NOT-HUMAN-READABLE " ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/MatchingRuleTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/MatchingRuleTest.java
new file mode 100644
index 0000000..14877a2
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/MatchingRuleTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class MatchingRule.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MatchingRuleTest
+{
+    private MutableMatchingRule matchingRule;
+
+
+    /**
+     * Initialize matching rule instances
+     */
+    @Before
+    public void initMatchingRules() throws Exception
+    {
+        matchingRule = new MutableMatchingRule( "1.2.3.4" );
+        matchingRule.setNames( "name1", "name2" );
+        matchingRule.setDescription( "description" );
+        matchingRule.setObsolete( false );
+        matchingRule.setSyntaxOid( "2.3.4.5" );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = matchingRule.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "matchingrule (" ) );
+        assertTrue( string.contains( " NAME " ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tSYNTAX " ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/MatchingRuleUseTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/MatchingRuleUseTest.java
new file mode 100644
index 0000000..f60247a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/MatchingRuleUseTest.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class MatchingRuleUse.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MatchingRuleUseTest
+{
+    private MatchingRuleUse matchingRuleUse;
+
+
+    /**
+     * Initialize matching rule use instances
+     */
+    @Before
+    public void initMatchingRuleUses() throws Exception
+    {
+        matchingRuleUse = new MatchingRuleUse( "1.2.3.4" );
+        matchingRuleUse.setNames( "name1", "name2" );
+        matchingRuleUse.setDescription( "description" );
+        matchingRuleUse.setObsolete( false );
+        matchingRuleUse.setApplicableAttributeOids( Arrays.asList( "2.3.4.5" ) );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = matchingRuleUse.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "matchingruleuse (" ) );
+        assertTrue( string.contains( " NAME " ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tAPPLIES " ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/NameFormTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/NameFormTest.java
new file mode 100644
index 0000000..20f803e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/NameFormTest.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class NameForm.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NameFormTest
+{
+    private NameForm nameForm;
+
+
+    /**
+     * Initialize attribute type instances
+     */
+    @Before
+    public void initNameForms() throws Exception
+    {
+        nameForm = new NameForm( "1.2.3.4" );
+        nameForm.setNames( "name1", "name2" );
+        nameForm.setDescription( "description" );
+        nameForm.setObsolete( false );
+        nameForm.setStructuralObjectClassOid( "2.3.4.5" );
+        nameForm.setMustAttributeTypeOids( Arrays.asList( "must1", "must2" ) );
+        nameForm.setMayAttributeTypeOids( Arrays.asList( "may0" ) );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = nameForm.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "nameform (" ) );
+        assertTrue( string.contains( " NAME " ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tOC" ) );
+        assertTrue( string.contains( "\n\tMUST" ) );
+        assertTrue( string.contains( "\n\tMAY" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/ObjectClassTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/ObjectClassTest.java
new file mode 100644
index 0000000..d1a7340
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/ObjectClassTest.java
@@ -0,0 +1,156 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Unit tests class ObjectClass.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ObjectClassTest
+{
+    private ObjectClass objectClassA;
+    private ObjectClass objectClassACopy;
+    private ObjectClass objectClassB;
+    private ObjectClass objectClassC;
+    private MutableObjectClass objectClass;
+
+
+    /**
+     * Initialize object class instances
+     */
+    @Before
+    public void initObjectClasses() throws Exception
+    {
+        // TODO Create ObjectClasses with more meaningful constructor arguments
+        objectClassA = new ObjectClass( "aa" );
+        objectClassACopy = new ObjectClass( "aa" );
+        objectClassB = new ObjectClass( "aa" );
+        objectClassC = new ObjectClass( "cc" );
+
+        objectClass = new MutableObjectClass( "1.2.3.4" );
+        objectClass.setNames( "name1", "name2" );
+        objectClass.setDescription( "description" );
+        objectClass.setObsolete( false );
+        objectClass.setSuperiorOids( Collections.singletonList( "1.3.5.7" ) );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.setMustAttributeTypeOids( Arrays.asList( "att1", "att2" ) );
+        objectClass.setMayAttributeTypeOids( Arrays.asList( "att3", "att4" ) );
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( objectClassA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( objectClassA, objectClassA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( objectClassA.hashCode(), objectClassA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( objectClassA, objectClassACopy );
+        assertEquals( objectClassACopy, objectClassA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( objectClassA.hashCode(), objectClassACopy.hashCode() );
+        assertEquals( objectClassACopy.hashCode(), objectClassA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( objectClassA, objectClassACopy );
+        assertEquals( objectClassACopy, objectClassB );
+        assertEquals( objectClassA, objectClassB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( objectClassA.hashCode(), objectClassACopy.hashCode() );
+        assertEquals( objectClassACopy.hashCode(), objectClassB.hashCode() );
+        assertEquals( objectClassA.hashCode(), objectClassB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( objectClassA.equals( objectClassC ) );
+        assertFalse( objectClassC.equals( objectClassA ) );
+    }
+
+
+    @Test
+    public void testToString() throws Exception
+    {
+        String string = objectClass.toString();
+
+        assertNotNull( string );
+        assertTrue( string.startsWith( "objectclass (" ) );
+        assertTrue( string.contains( " NAME " ) );
+        assertTrue( string.contains( "\n\tDESC " ) );
+        assertTrue( string.contains( "\n\tSUP " ) );
+        assertTrue( string.contains( "\n\tSTRUCTURAL" ) );
+        assertTrue( string.contains( "\n\tMUST" ) );
+        assertTrue( string.contains( "\n\tMAY" ) );
+        assertTrue( string.endsWith( " )" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaObjectRendererTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaObjectRendererTest.java
new file mode 100644
index 0000000..1554460
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaObjectRendererTest.java
@@ -0,0 +1,571 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.directory.api.ldap.model.schema.parsers.AttributeTypeDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.DitContentRuleDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.DitStructureRuleDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapSyntaxDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleUseDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.NameFormDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.ObjectClassDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.OpenLdapSchemaParser;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaObjectRendererTest
+{
+
+    private MutableObjectClass objectClassSimple;
+    private MutableObjectClass objectClassComplex;
+
+    private MutableAttributeType attributeTypeSimple;
+    private MutableAttributeType attributeTypeComplex;
+
+    private MutableMatchingRule matchingRule;
+    private MatchingRuleUse matchingRuleUse;
+    private LdapSyntax ldapSyntax;
+    private DitContentRule ditContentRule;
+    private DitStructureRule ditStructureRule;
+    private NameForm nameForm;
+
+
+    @Before
+    public void setUp()
+    {
+        objectClassSimple = new MutableObjectClass( "1.2.3.4" );
+        objectClassSimple.setNames( "name0" );
+        objectClassSimple.setMustAttributeTypeOids( Arrays.asList( "att0" ) );
+        objectClassSimple.setSchemaName( "dummy" );
+
+        objectClassComplex = new MutableObjectClass( "1.2.3.4" );
+        objectClassComplex.setNames( "name1", "name2" );
+        objectClassComplex.setDescription( "description with 'quotes'" );
+        objectClassComplex.setObsolete( true );
+        objectClassComplex.setSuperiorOids( Collections.singletonList( "1.3.5.7" ) );
+        objectClassComplex.setType( ObjectClassTypeEnum.AUXILIARY );
+        objectClassComplex.setMustAttributeTypeOids( Arrays.asList( "att1", "att2" ) );
+        objectClassComplex.setMayAttributeTypeOids( Arrays.asList( "att3", "att4" ) );
+        objectClassComplex.setSchemaName( "dummy" );
+
+        attributeTypeSimple = new MutableAttributeType( "1.2.3.4" );
+        attributeTypeSimple.setNames( "name0" );
+        attributeTypeSimple.setEqualityOid( "matchingRule0" );
+        attributeTypeSimple.setSyntaxOid( "2.3.4.5" );
+        attributeTypeSimple.setSyntaxLength( 512 );
+        attributeTypeSimple.setCollective( true );
+        attributeTypeSimple.setSchemaName( "dummy" );
+
+        attributeTypeComplex = new MutableAttributeType( "1.2.3.4" );
+        attributeTypeComplex.setNames( "name1", "name2" );
+        attributeTypeComplex.setDescription( "description with 'quotes'" );
+        attributeTypeComplex.setObsolete( true );
+        attributeTypeComplex.setSuperiorOid( "superAttr" );
+        attributeTypeComplex.setEqualityOid( "matchingRule1" );
+        attributeTypeComplex.setOrderingOid( "matchingRule2" );
+        attributeTypeComplex.setSubstringOid( "matchingRule3" );
+        attributeTypeComplex.setSingleValued( true );
+        attributeTypeComplex.setUserModifiable( false );
+        attributeTypeComplex.setUsage( UsageEnum.DIRECTORY_OPERATION );
+        attributeTypeComplex.setSchemaName( "dummy" );
+
+        matchingRule = new MutableMatchingRule( "1.2.3.4" );
+        matchingRule.setNames( "name0" );
+        matchingRule.setDescription( "description with 'quotes'" );
+        matchingRule.setObsolete( true );
+        matchingRule.setSyntaxOid( "2.3.4.5" );
+        matchingRule.setSchemaName( "dummy" );
+
+        matchingRuleUse = new MatchingRuleUse( "1.2.3.4" );
+        matchingRuleUse.setNames( "name0" );
+        matchingRuleUse.setDescription( "description with 'quotes'" );
+        matchingRuleUse.setObsolete( true );
+        matchingRuleUse.setApplicableAttributeOids( Arrays.asList( "2.3.4.5", "3.4.5.6" ) );
+        matchingRuleUse.setSchemaName( "dummy" );
+
+        ldapSyntax = new LdapSyntax( "1.2.3.4" );
+        ldapSyntax.setDescription( "description with 'quotes'" );
+        ldapSyntax.setHumanReadable( false );
+        ldapSyntax.setSchemaName( "dummy" );
+
+        ditContentRule = new DitContentRule( "1.2.3.4" );
+        ditContentRule.setNames( "name1", "name2" );
+        ditContentRule.setDescription( "description with 'quotes'" );
+        ditContentRule.setObsolete( true );
+        ditContentRule.setAuxObjectClassOids( Arrays.asList( "oc1", "oc2" ) );
+        ditContentRule.setMustAttributeTypeOids( Arrays.asList( "must1", "must2" ) );
+        ditContentRule.setMayAttributeTypeOids( Arrays.asList( "may1", "may2" ) );
+        ditContentRule.setNotAttributeTypeOids( Arrays.asList( "not1", "not2" ) );
+        ditContentRule.setSchemaName( "dummy" );
+
+        ditStructureRule = new DitStructureRule( 1234 );
+        ditStructureRule.setNames( "name1", "name2" );
+        ditStructureRule.setDescription( "description with 'quotes'" );
+        ditStructureRule.setObsolete( true );
+        ditStructureRule.setForm( "form1" );
+        ditStructureRule.setSuperRules( Arrays.asList( 111, 222, 333 ) );
+        ditStructureRule.setSchemaName( "dummy" );
+
+        nameForm = new NameForm( "1.2.3.4" );
+        nameForm.setNames( "name1", "name2" );
+        nameForm.setDescription( "description with 'quotes'" );
+        nameForm.setObsolete( true );
+        nameForm.setStructuralObjectClassOid( "oc1" );
+        nameForm.setMustAttributeTypeOids( Arrays.asList( "must1", "must2" ) );
+        nameForm.setMayAttributeTypeOids( Arrays.asList( "may0" ) );
+        nameForm.setSchemaName( "dummy" );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererObjectClassMinimal()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( new ObjectClass( "1.2.3" ) );
+        String expected = "objectclass ( 1.2.3\n\tSTRUCTURAL )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererObjectClassSimple()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( objectClassSimple );
+        String expected = "objectclass ( 1.2.3.4 NAME 'name0'\n\tSTRUCTURAL\n\tMUST att0 )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererObjectClassComplex()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( objectClassComplex );
+        String expected = "objectclass ( 1.2.3.4 NAME ( 'name1' 'name2' )\n\tDESC 'description with \\27quotes\\27'\n\tOBSOLETE\n\tSUP 1.3.5.7\n\tAUXILIARY\n\tMUST ( att1 $ att2 )\n\tMAY ( att3 $ att4 ) )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererAndParserRoundtripObjectClassSimple() throws Exception
+    {
+        testOpenLdapSchemaRendererAndParserRountrip( objectClassSimple );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererAndParserRoundtripObjectClassComplex() throws Exception
+    {
+        testOpenLdapSchemaRendererAndParserRountrip( objectClassComplex );
+    }
+
+
+    private void testOpenLdapSchemaRendererAndParserRountrip( ObjectClass original ) throws Exception
+    {
+        // must unset schema name because OpenLdapSchemaParser doesn't know about schema name
+        original.setSchemaName( null );
+
+        String renderedOriginal = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( original );
+        ObjectClass parsed = ( ObjectClass ) new OpenLdapSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererObjectClassMinimal()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( new ObjectClass( "1.2.3" ) );
+        String expected = "( 1.2.3 STRUCTURAL X-SCHEMA 'null' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererObjectClassSimple()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( objectClassSimple );
+        String expected = "( 1.2.3.4 NAME 'name0' STRUCTURAL MUST att0 X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererObjectClassComplex()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( objectClassComplex );
+        String expected = "( 1.2.3.4 NAME ( 'name1' 'name2' ) DESC 'description with \\27quotes\\27' OBSOLETE SUP 1.3.5.7 AUXILIARY MUST ( att1 $ att2 ) MAY ( att3 $ att4 ) X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripObjectClassSimple() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( objectClassSimple );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripObjectClassComplex() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( objectClassComplex );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( ObjectClass original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        ObjectClass parsed = new ObjectClassDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererAttributeTypeSimple()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( attributeTypeSimple );
+        String expected = "attributetype ( 1.2.3.4 NAME 'name0'\n\tEQUALITY matchingRule0\n\tSYNTAX 2.3.4.5{512}\n\tCOLLECTIVE\n\tUSAGE userApplications )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererAttributeTypeComplex()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( attributeTypeComplex );
+        String expected = "attributetype ( 1.2.3.4 NAME ( 'name1' 'name2' )\n\tDESC 'description with \\27quotes\\27'\n\tOBSOLETE\n\tSUP superAttr\n\tEQUALITY matchingRule1\n\tORDERING matchingRule2\n\tSUBSTR matchingRule3\n\tSINGLE-VALUE\n\tNO-USER-MODIFICATION\n\tUSAGE directoryOperation )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererAndParserRoundtripAttributeTypeSimple() throws Exception
+    {
+        testOpenLdapSchemaRendererAndParserRountrip( attributeTypeSimple );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererAndParserRoundtripAttributeTypeComplex() throws Exception
+    {
+        testOpenLdapSchemaRendererAndParserRountrip( attributeTypeComplex );
+    }
+
+
+    private void testOpenLdapSchemaRendererAndParserRountrip( AttributeType original ) throws Exception
+    {
+        // must unset schema name because OpenLdapSchemaParser doesn't know about schema name
+        original.setSchemaName( null );
+
+        String renderedOriginal = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( original );
+        AttributeType parsed = ( AttributeType ) new OpenLdapSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAttributeTypeSimple()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( attributeTypeSimple );
+        String expected = "( 1.2.3.4 NAME 'name0' EQUALITY matchingRule0 SYNTAX 2.3.4.5{512} COLLECTIVE USAGE userApplications X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAttributeTypeComplex()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( attributeTypeComplex );
+        String expected = "( 1.2.3.4 NAME ( 'name1' 'name2' ) DESC 'description with \\27quotes\\27' OBSOLETE SUP superAttr EQUALITY matchingRule1 ORDERING matchingRule2 SUBSTR matchingRule3 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripAttributeTypeSimple() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( attributeTypeSimple );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripAttributeTypeComplex() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( attributeTypeComplex );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( AttributeType original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        AttributeType parsed = new AttributeTypeDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererMatchingRule()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( matchingRule );
+        String expected = "matchingrule ( 1.2.3.4 NAME 'name0'\n\tDESC 'description with \\27quotes\\27'\n\tOBSOLETE\n\tSYNTAX 2.3.4.5 )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererMatchingRule()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( matchingRule );
+        String expected = "( 1.2.3.4 NAME 'name0' DESC 'description with \\27quotes\\27' OBSOLETE SYNTAX 2.3.4.5 X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripMatchingRule() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( matchingRule );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( MatchingRule original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        MatchingRule parsed = new MatchingRuleDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererLdapSyntax()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( ldapSyntax );
+        String expected = "ldapsyntax ( 1.2.3.4\n\tDESC 'description with \\27quotes\\27'\n\tX-NOT-HUMAN-READABLE 'true' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererLdapSyntax()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( ldapSyntax );
+        String expected = "( 1.2.3.4 DESC 'description with \\27quotes\\27' X-SCHEMA 'dummy' X-NOT-HUMAN-READABLE 'true' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripLdapSyntax() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( ldapSyntax );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( LdapSyntax original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        LdapSyntax parsed = new LdapSyntaxDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererMatchingRuleUse()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( matchingRuleUse );
+        String expected = "matchingruleuse ( 1.2.3.4 NAME 'name0'\n\tDESC 'description with \\27quotes\\27'\n\tOBSOLETE\n\tAPPLIES ( 2.3.4.5 $ 3.4.5.6 ) )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererMatchingRuleUse()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( matchingRuleUse );
+        String expected = "( 1.2.3.4 NAME 'name0' DESC 'description with \\27quotes\\27' OBSOLETE APPLIES ( 2.3.4.5 $ 3.4.5.6 ) X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripMatchingRuleUse() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( matchingRuleUse );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( MatchingRuleUse original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        MatchingRuleUse parsed = new MatchingRuleUseDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererDitContentRule()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( ditContentRule );
+        String expected = "ditcontentrule ( 1.2.3.4 NAME ( 'name1' 'name2' )\n\tDESC 'description with \\27quotes\\27'\n\tOBSOLETE\n\tAUX ( oc1 $ oc2 )\n\tMUST ( must1 $ must2 )\n\tMAY ( may1 $ may2 )\n\tNOT ( not1 $ not2 ) )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererDitContentRule()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( ditContentRule );
+        String expected = "( 1.2.3.4 NAME ( 'name1' 'name2' ) DESC 'description with \\27quotes\\27' OBSOLETE AUX ( oc1 $ oc2 ) MUST ( must1 $ must2 ) MAY ( may1 $ may2 ) NOT ( not1 $ not2 ) X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripDitContentRule() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( ditContentRule );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( DitContentRule original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        DitContentRule parsed = new DitContentRuleDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererDitStructureRule()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( ditStructureRule );
+        String expected = "ditstructurerule ( 1234 NAME ( 'name1' 'name2' )\n\tDESC 'description with \\27quotes\\27'\n\tOBSOLETE\n\tFORM form1\n\tSUP ( 111 222 333 ) )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererDitStructureRule()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( ditStructureRule );
+        String expected = "( 1234 NAME ( 'name1' 'name2' ) DESC 'description with \\27quotes\\27' OBSOLETE FORM form1 SUP ( 111 222 333 ) X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+
+        ditStructureRule.setSuperRules( null );
+        String actual2 = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( ditStructureRule );
+        String expected2 = "( 1234 NAME ( 'name1' 'name2' ) DESC 'description with \\27quotes\\27' OBSOLETE FORM form1 X-SCHEMA 'dummy' )";
+        assertEquals( expected2, actual2 );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripDitStructureRule() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( ditStructureRule );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( DitStructureRule original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        DitStructureRule parsed = new DitStructureRuleDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+
+
+    @Test
+    public void testOpenLdapSchemaRendererNameForm()
+    {
+        String actual = SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( nameForm );
+        String expected = "nameform ( 1.2.3.4 NAME ( 'name1' 'name2' )\n\tDESC 'description with \\27quotes\\27'\n\tOBSOLETE\n\tOC oc1\n\tMUST ( must1 $ must2 )\n\tMAY may0 )";
+        assertEquals( expected, actual );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererNameForm()
+    {
+        String actual = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( nameForm );
+        String expected = "( 1.2.3.4 NAME ( 'name1' 'name2' ) DESC 'description with \\27quotes\\27' OBSOLETE OC oc1 MUST ( must1 $ must2 ) MAY may0 X-SCHEMA 'dummy' )";
+        assertEquals( expected, actual );
+
+        nameForm.setMayAttributeTypeOids( new ArrayList<String>() );
+        String actual2 = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( nameForm );
+        String expected2 = "( 1.2.3.4 NAME ( 'name1' 'name2' ) DESC 'description with \\27quotes\\27' OBSOLETE OC oc1 MUST ( must1 $ must2 ) X-SCHEMA 'dummy' )";
+        assertEquals( expected2, actual2 );
+    }
+
+
+    @Test
+    public void testSubschemSubentryRendererAndParserRoundtripNameForm() throws ParseException
+    {
+        testSubschemSubentryRendererAndParserRoundtrip( nameForm );
+    }
+
+
+    private void testSubschemSubentryRendererAndParserRoundtrip( NameForm original ) throws ParseException
+    {
+        String renderedOriginal = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( original );
+        NameForm parsed = new NameFormDescriptionSchemaParser().parse( renderedOriginal );
+        String renderedParsed = SchemaObjectRenderer.SUBSCHEMA_SUBENTRY_RENDERER.render( parsed );
+
+        assertTrue( original.equals( parsed ) );
+        assertTrue( renderedOriginal.equals( renderedParsed ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaObjectSorterTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaObjectSorterTest.java
new file mode 100644
index 0000000..2ab61e1
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaObjectSorterTest.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Test;
+
+
+/**
+ * Tests for SchemaObjectSorter.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaObjectSorterTest
+{
+
+    private void addAttributeType( List<AttributeType> attributeTypes, String oid, String name, String superiorOid )
+    {
+        MutableAttributeType at = new MutableAttributeType( oid );
+        at.setNames( name );
+        at.setSuperiorOid( superiorOid );
+        attributeTypes.add( at );
+    }
+
+
+    @Test
+    public void testSortAttributeTypesAlreadySorted()
+    {
+        List<AttributeType> attributeTypes = new ArrayList<AttributeType>();
+        addAttributeType( attributeTypes, "1.1.1", "att1", null );
+        addAttributeType( attributeTypes, "1.1.2", "att2", "att1" );
+        addAttributeType( attributeTypes, "1.1.3", "att3", "att2" );
+        addAttributeType( attributeTypes, "1.1.4", "att4", "att3" );
+        addAttributeType( attributeTypes, "1.1.5", "att5", "att1" );
+        addAttributeType( attributeTypes, "1.1.6", "att6", null );
+        addAttributeType( attributeTypes, "1.1.7", "att7", "other" );
+
+        Iterable<AttributeType> sorted = SchemaObjectSorter.hierarchicalOrdered( attributeTypes );
+        assertHierarchicalOrderAT( sorted );
+    }
+
+
+    @Test
+    public void testSortAttributeTypesShuffled()
+    {
+        List<String> oids = Arrays.asList( "1.1.1", "1.1.2", "1.1.3", "1.1.4", "1.1.5", "1.1.6", "1.1.7" );
+        for ( int i = 0; i < 1000; i++ )
+        {
+            Collections.shuffle( oids );
+            Iterator<String> oidIterator = oids.iterator();
+
+            List<AttributeType> attributeTypes = new ArrayList<AttributeType>();
+            addAttributeType( attributeTypes, oidIterator.next(), "att1", null );
+            addAttributeType( attributeTypes, oidIterator.next(), "aTT2", "att1" );
+            addAttributeType( attributeTypes, oidIterator.next(), "att3", "att2" );
+            addAttributeType( attributeTypes, oidIterator.next(), "att4", "atT3" );
+            addAttributeType( attributeTypes, oidIterator.next(), "att5", "aTt1" );
+            addAttributeType( attributeTypes, oidIterator.next(), "att6", null );
+            addAttributeType( attributeTypes, oidIterator.next(), "att7", "other" );
+
+            Iterable<AttributeType> sorted = SchemaObjectSorter.hierarchicalOrdered( attributeTypes );
+            assertHierarchicalOrderAT( sorted );
+        }
+    }
+
+
+    private void assertHierarchicalOrderAT( Iterable<AttributeType> ordered )
+    {
+        Iterator<AttributeType> iterator = ordered.iterator();
+
+        String name1 = assertNextSuperiorAT( iterator, null, "other" );
+        String name2 = assertNextSuperiorAT( iterator, null, "other", name1 );
+        String name3 = assertNextSuperiorAT( iterator, null, "other", name1, name2 );
+        String name4 = assertNextSuperiorAT( iterator, null, "other", name1, name2, name3 );
+        String name5 = assertNextSuperiorAT( iterator, null, "other", name1, name2, name3, name4 );
+        String name6 = assertNextSuperiorAT( iterator, null, "other", name1, name2, name3, name4, name5 );
+        assertNextSuperiorAT( iterator, null, "other", name1, name2, name3, name4, name5, name6 );
+
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    private String assertNextSuperiorAT( Iterator<AttributeType> iterator, String... expected )
+    {
+        assertTrue( iterator.hasNext() );
+
+        AttributeType next = iterator.next();
+        String superiorOid = next.getSuperiorOid();
+        if(superiorOid != null) {
+            superiorOid = superiorOid.toLowerCase();
+        }
+
+        if ( !Arrays.asList( expected ).contains( superiorOid ) )
+        {
+            fail( "Expected that " + Arrays.asList( expected ) + " contains " + superiorOid );
+        }
+
+        return next.getName().toLowerCase();
+    }
+
+
+    @Test(expected = IllegalStateException.class)
+    public void testSortAttributeTypesLoop()
+    {
+        List<AttributeType> attributeTypes = new ArrayList<AttributeType>();
+        addAttributeType( attributeTypes, "1.1.1", "att1", "att4" );
+        addAttributeType( attributeTypes, "1.1.2", "att2", "att1" );
+        addAttributeType( attributeTypes, "1.1.3", "att3", "att2" );
+        addAttributeType( attributeTypes, "1.1.4", "att4", "att3" );
+
+        Iterable<AttributeType> sorted = SchemaObjectSorter.hierarchicalOrdered( attributeTypes );
+        sorted.iterator().next();
+    }
+
+
+    private void addObjectClass( List<ObjectClass> objectClasses, String oid, String name, String... superiorOid )
+    {
+        MutableObjectClass oc = new MutableObjectClass( oid );
+        oc.setNames( name );
+        if ( superiorOid != null )
+        {
+            oc.setSuperiorOids( Arrays.asList( superiorOid ) );
+        }
+        objectClasses.add( oc );
+    }
+
+
+    @Test
+    public void testSortObjectClassesAlreadySorted()
+    {
+        List<ObjectClass> objectClasses = new ArrayList<ObjectClass>();
+        addObjectClass( objectClasses, "1.2.1", "oc1" );
+        addObjectClass( objectClasses, "1.2.2", "OC2", "oc1" );
+        addObjectClass( objectClasses, "1.2.3", "oc3", "oC2" );
+        addObjectClass( objectClasses, "1.2.4", "oc4" );
+        addObjectClass( objectClasses, "1.2.5", "oc5", "Oc2", "oC4" );
+        addObjectClass( objectClasses, "1.2.6", "oc6", "other" );
+
+        Iterable<ObjectClass> sorted = SchemaObjectSorter.sortObjectClasses( objectClasses );
+        assertHierarchicalOrderOC( sorted );
+    }
+
+
+    @Test
+    public void testSortObjectClassesShuffled()
+    {
+        List<String> oids = Arrays.asList( "1.1.1", "1.1.2", "1.1.3", "1.1.4", "1.1.5", "1.1.6" );
+        for ( int i = 0; i < 1000; i++ )
+        {
+            Collections.shuffle( oids );
+            Iterator<String> oidIterator = oids.iterator();
+
+            List<ObjectClass> objectClasses = new ArrayList<ObjectClass>();
+            addObjectClass( objectClasses, oidIterator.next(), "oc1" );
+            addObjectClass( objectClasses, oidIterator.next(), "OC2", "oc1" );
+            addObjectClass( objectClasses, oidIterator.next(), "oc3", "Oc2" );
+            addObjectClass( objectClasses, oidIterator.next(), "oc4" );
+            addObjectClass( objectClasses, oidIterator.next(), "oc5", "oC2", "OC4" );
+            addObjectClass( objectClasses, oidIterator.next(), "oc6", "other" );
+
+            Iterable<ObjectClass> sorted = SchemaObjectSorter.sortObjectClasses( objectClasses );
+            assertHierarchicalOrderOC( sorted );
+        }
+    }
+
+
+    private void assertHierarchicalOrderOC( Iterable<ObjectClass> ordered )
+    {
+        Iterator<ObjectClass> iterator = ordered.iterator();
+
+        String name1 = assertNextSuperiorOC( iterator, null, "other" );
+        String name2 = assertNextSuperiorOC( iterator, null, "other", name1 );
+        String name3 = assertNextSuperiorOC( iterator, null, "other", name1, name2 );
+        String name4 = assertNextSuperiorOC( iterator, null, "other", name1, name2, name3 );
+        String name5 = assertNextSuperiorOC( iterator, null, "other", name1, name2, name3, name4 );
+        assertNextSuperiorOC( iterator, null, "other", name1, name2, name3, name4, name5 );
+
+        assertFalse( iterator.hasNext() );
+    }
+
+
+    private String assertNextSuperiorOC( Iterator<ObjectClass> iterator, String... expected )
+    {
+        assertTrue( iterator.hasNext() );
+
+        ObjectClass next = iterator.next();
+        List<String> superiorOids = next.getSuperiorOids();
+        for ( int i = 0; i < superiorOids.size(); i++ )
+        {
+            superiorOids.set( i, superiorOids.get( i ).toLowerCase() );
+        }
+
+        if ( !Arrays.asList( expected ).containsAll( superiorOids ) )
+        {
+            fail( "Expected that " + Arrays.asList( expected ) + " contains all " + superiorOids );
+        }
+
+        return next.getName().toLowerCase();
+    }
+
+
+    @Test(expected = IllegalStateException.class)
+    public void testSortObjectClassesLoop()
+    {
+        List<ObjectClass> objectClasses = new ArrayList<ObjectClass>();
+        addObjectClass( objectClasses, "1.2.1", "oc1", "oc3" );
+        addObjectClass( objectClasses, "1.2.2", "oc2", "oc1" );
+        addObjectClass( objectClasses, "1.2.3", "oc3", "oc2" );
+
+        Iterable<ObjectClass> sorted = SchemaObjectSorter.sortObjectClasses( objectClasses );
+        sorted.iterator().next();
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaUtilsTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaUtilsTest.java
new file mode 100644
index 0000000..d20adaf
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SchemaUtilsTest.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * The unit tests for methods on SchemaUtils.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaUtilsTest
+{
+    public static LdapSyntax[] getSyntaxes()
+    {
+        LdapSyntax[] syntaxes = new LdapSyntax[3];
+        syntaxes[0] = new LdapSyntax( "1.3.6.1.4.1.1466.115.121.1.12", "Dn syntax", true );
+        syntaxes[1] = new LdapSyntax( "1.3.6.1.4.1.1466.115.121.1.15", "Directory String syntax", true );
+        syntaxes[2] = new LdapSyntax( "1.3.6.1.4.1.1466.115.121.1.58", "Substring assertion syntax", true );
+
+        return syntaxes;
+    }
+
+
+    public static MatchingRule[] getMatchingRules()
+    {
+        MutableMatchingRule[] mrs = new MutableMatchingRule[3];
+
+        mrs[0] = new MutableMatchingRule( "2.5.13.2" );
+        mrs[0].setSyntax( getSyntaxes()[1] );
+        mrs[0].addName( "caseIgnoreMatch" );
+        mrs[0].setDescription( "Ignores case in strings" );
+
+        mrs[1] = new MutableMatchingRule( "2.5.13.4" );
+        mrs[0].setSyntax( getSyntaxes()[2] );
+        mrs[1].addName( "caseIgnoreSubstringsMatch" );
+        mrs[1].setDescription( "Ignores case in substrings" );
+
+        mrs[2] = new MutableMatchingRule( "2.5.13.1" );
+        mrs[0].setSyntax( getSyntaxes()[0] );
+        mrs[2].addName( "distinguishedNameMatch" );
+        mrs[2].setDescription( "distinguishedNameMatch" );
+
+        return mrs;
+    }
+
+
+    public AttributeType[] getAttributeTypes()
+    {
+        MutableAttributeType[] ats = new MutableAttributeType[5];
+
+        ats[0] = new MutableAttributeType( "2.5.4.41" );
+        ats[0].addName( "name" );
+        ats[0].setSyntax( getSyntaxes()[1] );
+        ats[0].setSyntaxLength( 32768 );
+        ats[0].setEquality( getMatchingRules()[0] );
+        ats[0].setSubstring( getMatchingRules()[1] );
+
+        // ( 2.5.4.3 NAME 'cn' SUP name )
+        ats[1] = new MutableAttributeType( "2.5.4.3" );
+        ats[1].addName( "cn", "commonName" );
+
+        ats[2] = new MutableAttributeType( "2.5.4.41" );
+        ats[2].addName( "name" );
+        ats[2].setSyntax( getSyntaxes()[1] );
+        ats[2].setSyntaxLength( 32768 );
+        ats[2].setEquality( getMatchingRules()[0] );
+        ats[2].setSubstring( getMatchingRules()[1] );
+
+        ats[3] = new MutableAttributeType( "2.5.4.41" );
+        ats[3].addName( "name" );
+        ats[3].setSyntax( getSyntaxes()[1] );
+        ats[3].setSyntaxLength( 32768 );
+        ats[3].setEquality( getMatchingRules()[0] );
+        ats[3].setSubstring( getMatchingRules()[1] );
+
+        ats[4] = new MutableAttributeType( "2.5.4.41" );
+        ats[4].addName( "name" );
+        ats[4].setSyntax( getSyntaxes()[1] );
+        ats[4].setSyntaxLength( 32768 );
+        ats[4].setEquality( getMatchingRules()[0] );
+        ats[4].setSubstring( getMatchingRules()[1] );
+
+        return ats;
+    }
+
+
+    /**
+     * Tests rendering operations on qdescrs render method. Both overloaded
+     * operations {@link org.apache.directory.api.ldap.model.schema.SchemaUtils#render(StringBuffer, String[])} and
+     * {@link org.apache.directory.api.ldap.model.schema.SchemaUtils#render(String[])} are tested here.
+     */
+    @Test
+    public void testRenderQdescrs()
+    {
+        assertEquals( "", SchemaUtils.renderQDescrs( new StringBuffer(), ( List<String> ) null ).toString() );
+        assertEquals( "", SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+            {} ) ).toString() );
+        assertEquals( "'name1'", SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+            { "name1" } ) ).toString() );
+        assertEquals( "( 'name1' 'name2' )", SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+            { "name1", "name2" } ) ).toString() );
+        assertEquals( "( 'name1' 'name2' 'name3' )",
+            SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+                { "name1", "name2", "name3" } ) ).toString() );
+
+        assertEquals( "", SchemaUtils.renderQDescrs( new StringBuffer(), ( List<String> ) null ).toString() );
+
+        assertEquals( "", SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+            {} ) ).toString() );
+
+        assertEquals( "'name1'", SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+            { "name1" } ) ).toString() );
+
+        assertEquals( "( 'name1' 'name2' )", SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+            { "name1", "name2" } ) ).toString() );
+
+        assertEquals( "( 'name1' 'name2' 'name3' )",
+            SchemaUtils.renderQDescrs( new StringBuffer(), Arrays.asList( new String[]
+                { "name1", "name2", "name3" } ) ).toString() );
+    }
+    
+    
+    /**
+     * Test the isAttributeNameValid method
+     */
+    @Test
+    public void testIsAttributeNameValid()
+    {
+        assertFalse( SchemaUtils.isAttributeNameValid( null ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "" ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "    " ) );
+        
+        // Descr
+        assertTrue( SchemaUtils.isAttributeNameValid( "a" ) );
+        assertTrue( SchemaUtils.isAttributeNameValid( "ObjectClass-text_test123" ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "-text_test123" ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "text_te&st123" ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "text_te st123" ) );
+        
+        // Numericoid
+        assertTrue( SchemaUtils.isAttributeNameValid( "0" ) );
+        assertTrue( SchemaUtils.isAttributeNameValid( "0" ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "00.1.2.3" ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "0.1.2..3" ) );
+        assertFalse( SchemaUtils.isAttributeNameValid( "0.01.2.3" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SyntaxCheckerTest.java
new file mode 100644
index 0000000..01aad6c
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/SyntaxCheckerTest.java
@@ -0,0 +1,126 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.AccessPointSyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.CountrySyntaxChecker;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Unit tests class SyntaxChecker.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SyntaxCheckerTest
+{
+    SyntaxChecker objectClassA;
+    SyntaxChecker objectClassACopy;
+    SyntaxChecker objectClassB;
+    SyntaxChecker objectClassC;
+
+
+    /**
+     * Initialize name instances
+     */
+    @Before
+    public void initNames() throws Exception
+    {
+        objectClassA = new AccessPointSyntaxChecker();
+        objectClassACopy = new AccessPointSyntaxChecker();
+        objectClassB = new AccessPointSyntaxChecker();
+        objectClassC = new CountrySyntaxChecker();
+    }
+
+
+    @Test
+    public void testEqualsNull() throws Exception
+    {
+        assertFalse( objectClassA.equals( null ) );
+    }
+
+
+    @Test
+    public void testEqualsReflexive() throws Exception
+    {
+        assertEquals( objectClassA, objectClassA );
+    }
+
+
+    @Test
+    public void testHashCodeReflexive() throws Exception
+    {
+        assertEquals( objectClassA.hashCode(), objectClassA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsSymmetric() throws Exception
+    {
+        assertEquals( objectClassA, objectClassACopy );
+        assertEquals( objectClassACopy, objectClassA );
+    }
+
+
+    @Test
+    public void testHashCodeSymmetric() throws Exception
+    {
+        assertEquals( objectClassA.hashCode(), objectClassACopy.hashCode() );
+        assertEquals( objectClassACopy.hashCode(), objectClassA.hashCode() );
+    }
+
+
+    @Test
+    public void testEqualsTransitive() throws Exception
+    {
+        assertEquals( objectClassA, objectClassACopy );
+        assertEquals( objectClassACopy, objectClassB );
+        assertEquals( objectClassA, objectClassB );
+    }
+
+
+    @Test
+    public void testHashCodeTransitive() throws Exception
+    {
+        assertEquals( objectClassA.hashCode(), objectClassACopy.hashCode() );
+        assertEquals( objectClassACopy.hashCode(), objectClassB.hashCode() );
+        assertEquals( objectClassA.hashCode(), objectClassB.hashCode() );
+    }
+
+
+    @Test
+    public void testNotEqualDiffValue() throws Exception
+    {
+        assertFalse( objectClassA.equals( objectClassC ) );
+        assertFalse( objectClassC.equals( objectClassA ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/UsageEnumTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/UsageEnumTest.java
new file mode 100644
index 0000000..d1d858f
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/UsageEnumTest.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema;
+
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * The unit tests for methods on UsageEnum.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UsageEnumTest
+{
+    @Test
+    public void testGetValue()
+    {
+        assertEquals( 0, UsageEnum.USER_APPLICATIONS.getValue() );
+        assertEquals( 1, UsageEnum.DIRECTORY_OPERATION.getValue() );
+        assertEquals( 2, UsageEnum.DISTRIBUTED_OPERATION.getValue() );
+        assertEquals( 3, UsageEnum.DSA_OPERATION.getValue() );
+    }
+
+
+    @Test
+    public void testGetUsage()
+    {
+        assertEquals( UsageEnum.DIRECTORY_OPERATION, UsageEnum.getUsage( "directoryOperation" ) );
+        assertEquals( UsageEnum.USER_APPLICATIONS, UsageEnum.getUsage( "userApplications" ) );
+        assertEquals( UsageEnum.DISTRIBUTED_OPERATION, UsageEnum.getUsage( "distributedOperation" ) );
+        assertEquals( UsageEnum.DSA_OPERATION, UsageEnum.getUsage( "dSAOperation" ) );
+        assertEquals( null, UsageEnum.getUsage( "azerty" ) );
+    }
+
+
+    @Test
+    public void testRenderer()
+    {
+        assertEquals( "directoryOperation", UsageEnum.render( UsageEnum.DIRECTORY_OPERATION ) );
+        assertEquals( "userApplications", UsageEnum.render( UsageEnum.USER_APPLICATIONS ) );
+        assertEquals( "distributedOperation", UsageEnum.render( UsageEnum.DISTRIBUTED_OPERATION ) );
+        assertEquals( "dSAOperation", UsageEnum.render( UsageEnum.DSA_OPERATION ) );
+        assertEquals( "userApplications", UsageEnum.render( null ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/BitStringComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/BitStringComparatorTest.java
new file mode 100644
index 0000000..63d544b
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/BitStringComparatorTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.comparators.BitStringComparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the BitString comparator
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BitStringComparatorTest
+{
+    private BitStringComparator comparator;
+
+
+    @Before
+    public void init()
+    {
+        comparator = new BitStringComparator( null );
+    }
+
+
+    @Test
+    public void testNullBitString()
+    {
+        assertEquals( 0, comparator.compare( null, null ) );
+        assertEquals( -1, comparator.compare( null, "0101B" ) );
+        assertEquals( -1, comparator.compare( null, "000B" ) );
+        assertEquals( 1, comparator.compare( "0101B", null ) );
+        assertEquals( 1, comparator.compare( "111B", null ) );
+    }
+
+
+    @Test
+    public void testBitStringsEquals()
+    {
+        assertEquals( 0, comparator.compare( "0B", "0B" ) );
+        assertEquals( 0, comparator.compare( "1B", "1B" ) );
+        assertEquals( 0, comparator.compare( "101010B", "101010B" ) );
+        assertEquals( 0, comparator.compare( "00000101010B", "00101010B" ) );
+    }
+
+
+    @Test
+    public void testBitStringsNotEquals()
+    {
+        assertEquals( -1, comparator.compare( "0B", "1B" ) );
+        assertEquals( 1, comparator.compare( "1B", "0B" ) );
+        assertEquals( 1, comparator.compare( "101110B", "101010B" ) );
+        assertEquals( -1, comparator.compare( "00000101010B", "00111010B" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/BooleanComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/BooleanComparatorTest.java
new file mode 100644
index 0000000..0339b42
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/BooleanComparatorTest.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.directory.api.ldap.model.schema.comparators.BooleanComparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the Boolean comparator
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BooleanComparatorTest
+{
+    private BooleanComparator comparator;
+
+
+    @Before
+    public void init()
+    {
+        comparator = new BooleanComparator( null );
+    }
+
+
+    @Test
+    public void testNullBooleans()
+    {
+        assertEquals( 0, comparator.compare( null, null ) );
+        assertEquals( -1, comparator.compare( null, "TRUE" ) );
+        assertEquals( -1, comparator.compare( null, "FALSE" ) );
+        assertEquals( 1, comparator.compare( "TRUE", null ) );
+        assertEquals( 1, comparator.compare( "FALSE", null ) );
+    }
+
+
+    @Test
+    public void testBooleans()
+    {
+        assertEquals( 0, comparator.compare( "TRUE", "TRUE" ) );
+        assertEquals( 0, comparator.compare( "FALSE", "FALSE" ) );
+        assertEquals( -1, comparator.compare( "FALSE", "TRUE" ) );
+        assertEquals( 1, comparator.compare( "TRUE", "FALSE" ) );
+
+        // tested with two different strings
+        String b1 = "TRUE";
+        String b2 = "true";
+
+        assertEquals( 0, comparator.compare( b1, b2.toUpperCase() ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/ByteArrayComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/ByteArrayComparatorTest.java
new file mode 100644
index 0000000..302829c
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/ByteArrayComparatorTest.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Testcase to test the ByteArrayComparator.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ByteArrayComparatorTest
+{
+    @Test
+    public void testBothNull()
+    {
+        assertEquals( 0, new ByteArrayComparator( null ).compare( null, null ) );
+    }
+
+
+    @Test
+    public void testB2Null()
+    {
+        assertEquals( 1, new ByteArrayComparator( null ).compare( new byte[0], null ) );
+    }
+
+
+    @Test
+    public void testB1Null()
+    {
+        assertEquals( -1, new ByteArrayComparator( null ).compare( null, new byte[0] ) );
+    }
+
+
+    @Test
+    public void testBothEmpty()
+    {
+        assertEquals( 0, new ByteArrayComparator( null ).compare( new byte[0], new byte[0] ) );
+    }
+
+
+    @Test
+    public void testBothEqualLengthOne()
+    {
+        assertEquals( 0, new ByteArrayComparator( null ).compare( new byte[1], new byte[1] ) );
+    }
+
+
+    @Test
+    public void testBothEqualLengthTen()
+    {
+        assertEquals( 0, new ByteArrayComparator( null ).compare( new byte[10], new byte[10] ) );
+    }
+
+
+    @Test
+    public void testB1PrefixOfB2()
+    {
+        byte[] b1 = new byte[]
+            { 0, 1, 2 };
+        byte[] b2 = new byte[]
+            { 0, 1, 2, 3 };
+
+        assertEquals( -1, new ByteArrayComparator( null ).compare( b1, b2 ) );
+    }
+
+
+    @Test
+    public void testB2PrefixOfB1()
+    {
+        byte[] b1 = new byte[]
+            { 0, 1, 2, 3 };
+        byte[] b2 = new byte[]
+            { 0, 1, 2 };
+
+        assertEquals( 1, new ByteArrayComparator( null ).compare( b1, b2 ) );
+    }
+
+
+    @Test
+    public void testB1GreaterThanB2()
+    {
+        byte[] b1 = new byte[]
+            { 0, 5 };
+        byte[] b2 = new byte[]
+            { 0, 1, 2 };
+
+        assertEquals( 1, new ByteArrayComparator( null ).compare( b1, b2 ) );
+    }
+
+
+    @Test
+    public void testB1GreaterThanB2SameLength()
+    {
+        byte[] b1 = new byte[]
+            { 0, 5 };
+        byte[] b2 = new byte[]
+            { 0, 1 };
+
+        assertEquals( 1, new ByteArrayComparator( null ).compare( b1, b2 ) );
+    }
+
+
+    @Test
+    public void testB2GreaterThanB1()
+    {
+        byte[] b1 = new byte[]
+            { 0, 1, 2 };
+        byte[] b2 = new byte[]
+            { 0, 5 };
+
+        assertEquals( -1, new ByteArrayComparator( null ).compare( b1, b2 ) );
+    }
+
+
+    @Test
+    public void testB2GreaterThanB1SameLength()
+    {
+        byte[] b1 = new byte[]
+            { 0, 1 };
+        byte[] b2 = new byte[]
+            { 0, 5 };
+
+        assertEquals( -1, new ByteArrayComparator( null ).compare( b1, b2 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/CsnComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/CsnComparatorTest.java
new file mode 100644
index 0000000..3ff101d
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/CsnComparatorTest.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.csn.Csn;
+import org.apache.directory.api.ldap.model.schema.comparators.CsnComparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the CSN comparator
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CsnComparatorTest
+{
+    private CsnComparator comparator;
+
+
+    @Before
+    public void init()
+    {
+        comparator = new CsnComparator( null );
+    }
+
+
+    @Test
+    public void testNullCSNs()
+    {
+        assertEquals( 0, comparator.compare( null, null ) );
+
+        Csn csn2 = new Csn( System.currentTimeMillis(), 1, 1, 1 );
+        assertEquals( -1, comparator.compare( null, csn2.toString() ) );
+
+        assertEquals( 1, comparator.compare( csn2.toString(), null ) );
+    }
+
+
+    @Test
+    public void testEqualsCSNs()
+    {
+        long t0 = System.currentTimeMillis();
+        Csn csn1 = new Csn( t0, 0, 0, 0 );
+        Csn csn2 = new Csn( t0, 0, 0, 0 );
+
+        assertEquals( 0, comparator.compare( csn1.toString(), csn2.toString() ) );
+    }
+
+
+    @Test
+    public void testDifferentTimeStampCSNs()
+    {
+        long t0 = System.currentTimeMillis();
+        long t1 = System.currentTimeMillis() + 1000;
+        Csn csn1 = new Csn( t0, 0, 0, 0 );
+        Csn csn2 = new Csn( t1, 0, 0, 0 );
+
+        assertEquals( -1, comparator.compare( csn1.toString(), csn2.toString() ) );
+        assertEquals( 1, comparator.compare( csn2.toString(), csn1.toString() ) );
+    }
+
+
+    @Test
+    public void testDifferentChangeCountCSNs()
+    {
+        long t0 = System.currentTimeMillis();
+        Csn csn1 = new Csn( t0, 0, 0, 0 );
+        Csn csn2 = new Csn( t0, 1, 0, 0 );
+
+        assertEquals( -1, comparator.compare( csn1.toString(), csn2.toString() ) );
+        assertEquals( 1, comparator.compare( csn2.toString(), csn1.toString() ) );
+    }
+
+
+    @Test
+    public void testDifferentReplicaIdCSNs()
+    {
+        long t0 = System.currentTimeMillis();
+        Csn csn1 = new Csn( t0, 0, 0, 0 );
+        Csn csn2 = new Csn( t0, 0, 1, 0 );
+
+        assertEquals( -1, comparator.compare( csn1.toString(), csn2.toString() ) );
+        assertEquals( 1, comparator.compare( csn2.toString(), csn1.toString() ) );
+    }
+
+
+    @Test
+    public void testDifferentOperationNumberCSNs()
+    {
+        long t0 = System.currentTimeMillis();
+        Csn csn1 = new Csn( t0, 0, 0, 0 );
+        Csn csn2 = new Csn( t0, 0, 0, 1 );
+
+        assertEquals( -1, comparator.compare( csn1.toString(), csn2.toString() ) );
+        assertEquals( 1, comparator.compare( csn2.toString(), csn1.toString() ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/CsnSidComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/CsnSidComparatorTest.java
new file mode 100644
index 0000000..6592c15
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/CsnSidComparatorTest.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.comparators.CsnSidComparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the CSN comparator
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CsnSidComparatorTest
+{
+    private CsnSidComparator comparator;
+
+
+    @Before
+    public void init()
+    {
+        comparator = new CsnSidComparator( null );
+    }
+
+
+    @Test
+    public void testNullSids()
+    {
+        assertEquals( 0, comparator.compare( null, null ) );
+
+        assertEquals( -1, comparator.compare( null, "000" ) );
+
+        assertEquals( 1, comparator.compare( "000", null ) );
+    }
+
+
+    @Test
+    public void testEqualsSids()
+    {
+        assertEquals( 0, comparator.compare( "000", "000" ) );
+        assertEquals( 0, comparator.compare( "000", "0" ) );
+        assertEquals( 0, comparator.compare( "fff", "fff" ) );
+    }
+
+
+    @Test
+    public void testDifferentSids()
+    {
+        assertEquals( -1, comparator.compare( "123", "456" ) );
+        assertEquals( 1, comparator.compare( "FFF", "000" ) );
+        assertEquals( 1, comparator.compare( "FFF", "GGG" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/DummyComparator.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/DummyComparator.java
new file mode 100644
index 0000000..47e174a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/DummyComparator.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import java.io.Serializable;
+
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+
+
+/**
+ * A Dummy comparator used for tests
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DummyComparator extends LdapComparator<String> implements Serializable
+{
+    /** The serial version UID */
+    private static final long serialVersionUID = 2L;
+
+
+    /**
+     * The DummyComparator constructor. Its OID is the StringOrderingMatch matching
+     * rule OID.
+     */
+    public DummyComparator( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * Compare two objects.
+     * 
+     * @param obj1 First object
+     * @param obj2 Second object
+     * @return 1 if obj1 > obj2, 0 if obj1 == obj2, -1 if obj1 < obj2
+     */
+    public int compare( String obj1, String obj2 )
+    {
+        if ( obj1 == obj2 )
+        {
+            return 0;
+        }
+
+        return obj1.compareTo( obj2 );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierFirstComponentComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierFirstComponentComparatorTest.java
new file mode 100644
index 0000000..cad64a2
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/ObjectIdentifierFirstComponentComparatorTest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.comparators.ObjectIdentifierFirstComponentComparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the ObjectIdentifierFirstComponent comparator
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ObjectIdentifierFirstComponentComparatorTest
+{
+    private ObjectIdentifierFirstComponentComparator comparator;
+
+
+    @Before
+    public void init()
+    {
+        comparator = new ObjectIdentifierFirstComponentComparator( null );
+    }
+
+
+    @Test
+    public void testNullObjectIdentifiers()
+    {
+        assertEquals( 0, comparator.compare( null, null ) );
+
+        String c2 = "( 1.1 FQCN org.apache.directory.SimpleComparator BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+
+        assertEquals( -1, comparator.compare( null, c2 ) );
+
+        assertEquals( -1, comparator.compare( c2, null ) );
+    }
+
+
+    @Test
+    public void testEqualsObjectIdentifiers()
+    {
+        String c1 = "( 1.1 FQCN org.apache.directory.SimpleComparator BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        String c2 = "( 1.1 fqcn org.apache.directory.SimpleComparator bytecode ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        assertEquals( 0, comparator.compare( c1, c2 ) );
+
+        String c3 = "( 1.1 FQCN org.apache.directory.SimpleComparator BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== X-SCHEMA 'system' )";
+        String c4 = "( 1.1 fqcn org.apache.directory.SimpleComparator bytecode ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        assertEquals( 0, comparator.compare( c3, c4 ) );
+    }
+
+
+    @Test
+    public void testDifferentObjectIdentifiers()
+    {
+        String c1 = "( 1.1 FQCN org.apache.directory.SimpleComparator BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        String c2 = "( 1.2 fqcn org.apache.directory.SimpleComparator bytecode ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        assertEquals( -1, comparator.compare( c1, c2 ) );
+
+        String c3 = "( 1.1 FQCN org.apache.directory.SimpleComparator BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== X-SCHEMA 'system' )";
+        String c4 = "( 1.1.1 fqcn org.apache.directory.SimpleComparator bytecode ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        assertNotSame( 0, comparator.compare( c3, c4 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/TelephoneNumberComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/TelephoneNumberComparatorTest.java
new file mode 100644
index 0000000..e89a189
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/TelephoneNumberComparatorTest.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.comparators.TelephoneNumberComparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the TelephoneNumber comparator
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TelephoneNumberComparatorTest
+{
+    private TelephoneNumberComparator comparator;
+
+
+    @Before
+    public void init()
+    {
+        comparator = new TelephoneNumberComparator( null );
+    }
+
+
+    @Test
+    public void testNullTelephoneNumbers()
+    {
+        String tel1 = null;
+        String tel2 = null;
+
+        assertEquals( 0, comparator.compare( tel1, tel2 ) );
+
+        tel2 = "abc";
+        assertEquals( -1, comparator.compare( tel1, tel2 ) );
+
+        String tel3 = null;
+        assertEquals( 1, comparator.compare( tel2, tel3 ) );
+    }
+
+
+    @Test
+    public void testEmptyTelephoneNumbers()
+    {
+        String tel1 = "";
+        String tel2 = "";
+
+        assertEquals( 0, comparator.compare( tel1, tel2 ) );
+
+        tel2 = "abc";
+        assertTrue( comparator.compare( tel1, tel2 ) < 0 );
+
+        String tel3 = "";
+        assertTrue( comparator.compare( tel2, tel3 ) > 0 );
+    }
+
+
+    @Test
+    public void testSimpleTelephoneNumbers()
+    {
+        String tel1 = "01 02 03 04 05";
+        String tel2 = "01 02 03 04 05";
+
+        assertEquals( 0, comparator.compare( tel1, tel2 ) );
+
+        tel2 = "0102030405";
+        assertEquals( 0, comparator.compare( tel1, tel2 ) );
+    }
+
+
+    @Test
+    public void testComplexTelephoneNumbers()
+    {
+        String tel1 = "  + 33 1 01-02-03-04-05  ";
+        String tel2 = "+3310102030405";
+
+        assertEquals( 0, comparator.compare( tel1, tel2 ) );
+
+        tel1 = "1-801-555-1212";
+        tel2 = "18015551212";
+
+        assertEquals( 0, comparator.compare( tel1, tel2 ) );
+        assertEquals( 0, comparator.compare( "1 801 555 1212", tel1 ) );
+        assertEquals( 0, comparator.compare( "1 801 555 1212", tel2 ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/WordComparatorTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/WordComparatorTest.java
new file mode 100644
index 0000000..fbb8f60
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/comparators/WordComparatorTest.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.comparators;
+
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.comparators.WordComparator;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the Word/Keyword comparator
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class WordComparatorTest
+{
+    private WordComparator comparator;
+
+
+    @Before
+    public void init()
+    {
+        comparator = new WordComparator( null );
+    }
+
+
+    @Test
+    public void testNullWordss()
+    {
+        assertEquals( 0, comparator.compare( null, null ) );
+        assertEquals( -1, comparator.compare( null, "  abc  " ) );
+        assertEquals( 1, comparator.compare( " abc def ghi ", null ) );
+    }
+
+
+    @Test
+    public void testEqualsWords()
+    {
+        assertEquals( 0, comparator.compare( "abc", "abc" ) );
+        assertEquals( 0, comparator.compare( "abc", "  abc  " ) );
+        assertEquals( 0, comparator.compare( "abc  def  ghi", "def" ) );
+        assertEquals( 0, comparator.compare( "abc  def  ghi", "  def  " ) );
+        assertEquals( 0, comparator.compare( "abc  def  ghi", "abc" ) );
+        assertEquals( 0, comparator.compare( "abc  def  ghi", "ghi" ) );
+    }
+
+
+    @Test
+    public void testNotEqualsWords()
+    {
+        assertEquals( -1, comparator.compare( "abc", "" ) );
+        assertEquals( -1, comparator.compare( "abc", "ab" ) );
+        assertEquals( -1, comparator.compare( "abc", "  ab  " ) );
+        assertEquals( -1, comparator.compare( "abc  def  ghi", "dkf" ) );
+        assertEquals( -1, comparator.compare( "abc  def  ghi", "  dkf  " ) );
+        assertEquals( -1, comparator.compare( "abc  def  ghi", "hi" ) );
+        assertEquals( -1, comparator.compare( "abc  def  ghi", "e" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/BooleanNormalizerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/BooleanNormalizerTest.java
new file mode 100644
index 0000000..2a2c3fe
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/BooleanNormalizerTest.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.schema.normalizers.BooleanNormalizer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+
+/**
+ * 
+ * BooleanNormalizerTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BooleanNormalizerTest
+{
+    BooleanNormalizer normalizer = new BooleanNormalizer();
+
+
+    @Test
+    public void testNormalizeNullValue() throws Exception
+    {
+        assertNull( normalizer.normalize( ( Value<?> ) null ) );
+    }
+
+
+    @Test
+    public void testNormalizeNonNullValue() throws Exception
+    {
+        assertEquals( "TRUE", normalizer.normalize( "true" ) );
+        assertEquals( "ABC", normalizer.normalize( "aBc" ) );
+        assertEquals( "FALSE", normalizer.normalize( "falsE" ) );
+    }
+
+
+    @Test
+    public void testNormalizeValueWithSpaces() throws Exception
+    {
+        assertEquals( "TRUE", normalizer.normalize( " tRuE " ) );
+    }
+
+
+    @Test
+    public void testNormalizeByteValue() throws Exception
+    {
+        assertEquals( "TRUE", normalizer.normalize( new BinaryValue( "tRuE".getBytes() ) ).getString() );
+        assertEquals( "TRUE", normalizer.normalize( new BinaryValue( "true".getBytes() ) ).getString() );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimNormalizerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimNormalizerTest.java
new file mode 100644
index 0000000..4bcc5a5
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/DeepTrimNormalizerTest.java
@@ -0,0 +1,260 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import static org.junit.Assert.assertEquals;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimNormalizer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the normalizer class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DeepTrimNormalizerTest
+{
+    @Test
+    public void testDeepTrimNormalizerNull() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( "", normalizer.normalize( ( String ) null ) );
+    }
+
+
+    @Test
+    public void testDeepTrimNormalizerEmpty() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( "", normalizer.normalize( "" ) );
+    }
+
+
+    @Test
+    public void testDeepTrimNormalizerOneSpace() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( " ", normalizer.normalize( " " ) );
+    }
+
+
+    @Test
+    public void testDeepTrimNormalizerTwoSpaces() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( " ", normalizer.normalize( "  " ) );
+    }
+
+
+    @Test
+    public void testDeepTrimNormalizerNSpaces() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( " ", normalizer.normalize( "      " ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringOneChar() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( "a", normalizer.normalize( "a" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringTwoChars() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( "aa", normalizer.normalize( "aa" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringNChars() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( "aaaaa", normalizer.normalize( "aaaaa" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringOneCombining() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        char[] chars = new char[]
+            { ' ', 0x0310 };
+        char[] expected = new char[]
+            { ' ', 0x0310 };
+        //assertEquals( new String( expected ), normalizer.normalize( new String( chars ) ) );
+        
+        String expectedStr = new String( expected );
+        String charsStr = new String( chars );
+        assertEquals( expectedStr, normalizer.normalize( charsStr ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringNCombining() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        char[] chars = new char[]
+            { ' ', 0x0310, ' ', 0x0311, ' ', 0x0312 };
+        char[] expected = new char[]
+            { ' ', 0x0310, ' ', 0x0311, ' ', 0x0312 };
+        assertEquals( new String( expected ), normalizer.normalize( new String( chars ) ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringCharsSpaces() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( "a", normalizer.normalize( " a" ) );
+        assertEquals( "a", normalizer.normalize( "a " ) );
+        assertEquals( "a", normalizer.normalize( " a " ) );
+        assertEquals( "a a", normalizer.normalize( "a a" ) );
+        assertEquals( "a a", normalizer.normalize( " a a" ) );
+        assertEquals( "a a", normalizer.normalize( "a a " ) );
+        assertEquals( "a a", normalizer.normalize( "a  a" ) );
+        assertEquals( "a a", normalizer.normalize( " a   a " ) );
+        assertEquals( "aaa aaa aaa", normalizer.normalize( "  aaa   aaa   aaa  " ) );
+    }
+
+
+    @Test
+    public void testNormalizeCharsCombiningSpaces() throws LdapException
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        char[] chars = new char[]
+            { ' ', 0x0310, 'a', 'a', ' ', ' ', 0x0311, ' ', ' ', 'a', 0x0311, 0x0312 };
+        char[] expected = new char[]
+            { ' ', 0x0310, 'a', 'a', ' ', 0x0311, ' ', 'a', 0x0311, 0x0312 };
+        String expectedStr = new String( expected );
+        String charsStr = new String( chars );
+        assertEquals( expectedStr, normalizer.normalize( charsStr ) );
+    }
+
+
+    @Test
+    public void testNormalizeString() throws Exception
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        assertEquals( "abcd", normalizer.normalize( "abcd" ) );
+    }
+
+
+    @Test
+    public void testMapToSpace() throws Exception
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        char[] chars = new char[]
+            { 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0085, 0x00A0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005,
+                0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x2028, 0x2029, 0x202F, 0x205F };
+        assertEquals( " ", normalizer.normalize( new String( chars ) ) );
+    }
+
+
+    @Test
+    public void testNormalizeIgnore() throws Exception
+    {
+        Normalizer normalizer = new DeepTrimNormalizer( "1.1.1" );
+        char[] chars = new char[58];
+
+        int pos = 0;
+
+        for ( char c = 0x0000; c < 0x0008; c++ )
+        {
+            chars[pos++] = c;
+        }
+
+        for ( char c = 0x000E; c < 0x001F; c++ )
+        {
+            chars[pos++] = c;
+        }
+
+        for ( char c = 0x007F; c < 0x0084; c++ )
+        {
+            chars[pos++] = c;
+        }
+
+        for ( char c = 0x0086; c < 0x009F; c++ )
+        {
+            chars[pos++] = c;
+        }
+
+        chars[pos++] = 0x00AD;
+
+        assertEquals( " ", normalizer.normalize( new String( chars ) ) );
+    }
+
+    /*
+     @Test
+     public void testSpeed() throws Exception
+    {
+        Normalizer normalizer = new DeepTrimNormalizer();
+        char[] chars = new char[]{ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0085, 0x00A0, 0x1680,
+            0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A,
+            0x2028, 0x2029, 0x202F, 0x205F };
+        String s = new String( chars );
+        assertEquals( "", normalizer.normalize( s ) );
+        
+        String t = "xs crvtbynU  Jikl7897790";
+        
+        Normalizer normalizer2 = new DeepTrimToLowerNormalizer();
+        
+        String s1 = (String)normalizer2.normalize( t );
+
+        long t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 100000; i++ )
+        {
+            normalizer2.normalize( t );
+        }
+        
+        long t1 = System.currentTimeMillis();
+        
+        System.out.println( t1 - t0 );
+
+        String s2 = StringTools.deepTrimToLower( t );
+
+        t0 = System.currentTimeMillis();
+
+        for ( int i = 0; i < 100000; i++ )
+        {
+            StringTools.deepTrimToLower( t );
+        }
+        
+        t1 = System.currentTimeMillis();
+        
+        System.out.println( t1 - t0 );
+    }
+    */
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/DummyNormalizer.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/DummyNormalizer.java
new file mode 100644
index 0000000..491f837
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/DummyNormalizer.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.StringValue;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.util.Strings;
+
+
+/**
+ * A Dummy normalizer used for tests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DummyNormalizer extends Normalizer
+{
+    /** A Dummy normalizer */
+    private static final DummyNormalizer NORMALIZER = new DummyNormalizer();
+
+
+    public DummyNormalizer()
+    {
+        super( SchemaConstants.CASE_IGNORE_MATCH_MR_OID );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Value<?> normalize( Value<?> value ) throws LdapException
+    {
+        String str = value.getString();
+
+        if ( Strings.isEmpty( str ) )
+        {
+            return new StringValue( str );
+        }
+
+        return new StringValue( str );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String normalize( String value ) throws LdapException
+    {
+        if ( Strings.isEmpty( value ) )
+        {
+            return value;
+        }
+
+        return value;
+    }
+
+
+    /**
+     * Normalize the given String
+     *
+     * @param string The string to normalize
+     * @return The normalized object
+     * @throws LdapException If the normalization throws an error
+     */
+    public static String normalizeString( String string ) throws LdapException
+    {
+        return NORMALIZER.normalize( string );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/NumericNormalizerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/NumericNormalizerTest.java
new file mode 100644
index 0000000..574f37c
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/NumericNormalizerTest.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.NumericNormalizer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+
+/**
+ * Test the numeric normalizer class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NumericNormalizerTest
+{
+    @Test
+    public void testNumericNormalizerNull() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "", normalizer.normalize( ( String ) null ) );
+    }
+
+
+    @Test
+    public void testNumericNormalizerEmpty() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "", normalizer.normalize( "" ) );
+    }
+
+
+    @Test
+    public void testNumericNormalizerOneSpace() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "", normalizer.normalize( " " ) );
+    }
+
+
+    @Test
+    public void testNumericNormalizerTwoSpaces() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "", normalizer.normalize( "  " ) );
+    }
+
+
+    @Test
+    public void testNumericNormalizerNSpaces() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "", normalizer.normalize( "      " ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringOneChar() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "1", normalizer.normalize( "1" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringTwoChars() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "11", normalizer.normalize( "11" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringNChars() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "123456", normalizer.normalize( "123456" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantNumericCharsSpaces() throws LdapException
+    {
+        Normalizer normalizer = new NumericNormalizer();
+        assertEquals( "1", normalizer.normalize( " 1" ) );
+        assertEquals( "1", normalizer.normalize( "1 " ) );
+        assertEquals( "1", normalizer.normalize( " 1 " ) );
+        assertEquals( "11", normalizer.normalize( "1 1" ) );
+        assertEquals( "11", normalizer.normalize( " 1 1" ) );
+        assertEquals( "11", normalizer.normalize( "1 1 " ) );
+        assertEquals( "11", normalizer.normalize( "1  1" ) );
+        assertEquals( "11", normalizer.normalize( " 1   1 " ) );
+        assertEquals( "123456789", normalizer.normalize( "  123   456   789  " ) );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/TelephoneNumberNormalizerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/TelephoneNumberNormalizerTest.java
new file mode 100644
index 0000000..f268df3
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/normalizers/TelephoneNumberNormalizerTest.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.schema.normalizers;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.TelephoneNumberNormalizer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+
+/**
+ * Test the Telephone Number normalizer class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TelephoneNumberNormalizerTest
+{
+    @Test
+    public void testTelephoneNumberNormalizerNull() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( ( String ) null ) );
+    }
+
+
+    @Test
+    public void testTelephoneNumberNormalizerEmpty() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( "" ) );
+    }
+
+
+    @Test
+    public void testTelephoneNumberNormalizerOneSpace() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( " " ) );
+    }
+
+
+    @Test
+    public void testTelephoneNumberNormalizerTwoSpaces() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( "  " ) );
+    }
+
+
+    @Test
+    public void testTelephoneNumberNormalizerNSpaces() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( "      " ) );
+    }
+
+
+    @Test
+    public void testTelephoneNumberNormalizerOneHyphen() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( "-" ) );
+    }
+
+
+    @Test
+    public void testTelephoneNumberNormalizerTwoHyphen() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( "--" ) );
+    }
+
+
+    @Test
+    public void testTelephoneNumberNormalizerHyphensSpaces() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "", normalizer.normalize( " -- - -- " ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringOneChar() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "1", normalizer.normalize( "1" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringTwoChars() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "11", normalizer.normalize( "11" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantSpacesStringNChars() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "123456", normalizer.normalize( "123456" ) );
+    }
+
+
+    @Test
+    public void testInsignifiantTelephoneNumberCharsSpaces() throws LdapException
+    {
+        Normalizer normalizer = new TelephoneNumberNormalizer();
+        assertEquals( "1", normalizer.normalize( " 1" ) );
+        assertEquals( "1", normalizer.normalize( "1 " ) );
+        assertEquals( "1", normalizer.normalize( " 1 " ) );
+        assertEquals( "11", normalizer.normalize( "1 1" ) );
+        assertEquals( "11", normalizer.normalize( " 1 1" ) );
+        assertEquals( "11", normalizer.normalize( "1 1 " ) );
+        assertEquals( "11", normalizer.normalize( "1  1" ) );
+        assertEquals( "11", normalizer.normalize( " 1   1 " ) );
+        assertEquals( "123456789", normalizer.normalize( "  123   456   789  " ) );
+        assertEquals( "1", normalizer.normalize( "-1" ) );
+        assertEquals( "1", normalizer.normalize( "1-" ) );
+        assertEquals( "1", normalizer.normalize( "-1-" ) );
+        assertEquals( "11", normalizer.normalize( "1-1" ) );
+        assertEquals( "11", normalizer.normalize( "-1-1" ) );
+        assertEquals( "11", normalizer.normalize( "1-1-" ) );
+        assertEquals( "11", normalizer.normalize( "1--1" ) );
+        assertEquals( "11", normalizer.normalize( "-1---1-" ) );
+        assertEquals( "1(2)+3456789", normalizer.normalize( "---1(2)+3   456-  789 --" ) );
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/parsers/OpenLdapSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/parsers/OpenLdapSchemaParserTest.java
new file mode 100644
index 0000000..0dcfbfb
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/parsers/OpenLdapSchemaParserTest.java
@@ -0,0 +1,459 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.parsers;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OpenLdapObjectIdentifierMacro;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the OpenLDAP schema parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class OpenLdapSchemaParserTest
+{
+    private OpenLdapSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new OpenLdapSchemaParser();
+        parser.setParserMonitor( new ConsoleParserMonitor() );
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    @Test
+    public void testSimpleAttributeTypeNoLength() throws Exception
+    {
+        String attributeTypeData = "attributetype ( 2.5.4.14 NAME 'searchGuide'\n"
+            + "        DESC 'RFC2256: search guide, obsoleted by enhancedSearchGuide'\n"
+            + "        SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )";
+
+        parser.parse( attributeTypeData );
+        List<MutableAttributeType> attributeTypes = parser.getAttributeTypes();
+        Map<String, AttributeType> mapAttributeTypes = mapAttributeTypes( attributeTypes );
+        AttributeType attributeType = mapAttributeTypes.get( "2.5.4.14" );
+
+        assertNotNull( attributeType );
+        assertEquals( "2.5.4.14", attributeType.getOid() );
+        assertEquals( "searchGuide", attributeType.getName() );
+        assertEquals( "RFC2256: search guide, obsoleted by enhancedSearchGuide", attributeType.getDescription() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.25", attributeType.getSyntaxOid() );
+    }
+
+
+    private Map<String, AttributeType> mapAttributeTypes( List<MutableAttributeType> attributeTypes )
+    {
+        Map<String, AttributeType> m = new HashMap<String, AttributeType>();
+
+        for ( AttributeType attributeType : attributeTypes )
+        {
+            m.put( attributeType.getOid(), attributeType );
+        }
+
+        return m;
+    }
+
+
+    @Test
+    public void testSimpleAttributeTypeParse() throws Exception
+    {
+        String attributeTypeData = "# adding a comment  \n"
+            + "attributetype ( 2.5.4.2 NAME 'knowledgeInformation'\n"
+            + "        DESC 'RFC2256: knowledge information'\n"
+            + "        EQUALITY caseIgnoreMatch\n"
+            + "        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )";
+        parser.parse( attributeTypeData );
+        List<MutableAttributeType> attributeTypeList = parser.getAttributeTypes();
+        Map<String, AttributeType> attributeTypes = mapAttributeTypes( attributeTypeList );
+        AttributeType type = attributeTypes.get( "2.5.4.2" );
+
+        assertNotNull( type );
+        assertEquals( "2.5.4.2", type.getOid() );
+        assertEquals( "knowledgeInformation", type.getName() );
+        assertEquals( "RFC2256: knowledge information", type.getDescription() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", type.getSyntaxOid() );
+        assertEquals( 32768, type.getSyntaxLength() );
+    }
+
+
+    @Test
+    public void testAttributeTypeParseWithDescQuotes() throws Exception
+    {
+        String attributeTypeData = "# adding a comment  \n"
+            + "attributetype ( 2.5.4.2 NAME 'knowledgeInformation'\n"
+            + "        DESC 'RFC2256: \"knowledge\" information'\n"
+            + "        EQUALITY caseIgnoreMatch\n"
+            + "        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )";
+        parser.parse( attributeTypeData );
+        List<MutableAttributeType> attributeTypeList = parser.getAttributeTypes();
+        Map<String, AttributeType> attributeTypes = mapAttributeTypes( attributeTypeList );
+        AttributeType type = attributeTypes.get( "2.5.4.2" );
+
+        assertNotNull( type );
+        assertEquals( "2.5.4.2", type.getOid() );
+        assertEquals( "knowledgeInformation", type.getName() );
+        assertEquals( "RFC2256: \"knowledge\" information", type.getDescription() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", type.getSyntaxOid() );
+        assertEquals( 32768, type.getSyntaxLength() );
+    }
+
+
+    /**
+     * Test that we can handle a DESC which contains only spaces
+     */
+    @Test
+    public void testAttributeTypeParseWithSpaceDesc() throws Exception
+    {
+        String attributeTypeData = "# adding a comment  \n"
+            + "attributetype ( 2.5.4.2 NAME 'knowledgeInformation'\n"
+            + "        DESC '  '\n"
+            + "        EQUALITY caseIgnoreMatch\n"
+            + "        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )";
+
+        parser.parse( attributeTypeData );
+        List<MutableAttributeType> attributeTypeList = parser.getAttributeTypes();
+        Map<String, AttributeType> attributeTypes = mapAttributeTypes( attributeTypeList );
+        AttributeType type = attributeTypes.get( "2.5.4.2" );
+
+        assertNotNull( type );
+        assertEquals( "2.5.4.2", type.getOid() );
+        assertEquals( "knowledgeInformation", type.getName() );
+        assertEquals( "  ", type.getDescription() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", type.getSyntaxOid() );
+        assertEquals( 32768, type.getSyntaxLength() );
+    }
+
+
+    @Test
+    public void testComplexAttributeTypeParse() throws Exception
+    {
+        String attributeTypeData = "# adding a comment  \n"
+            + "attributetype ( 2.5.4.2 NAME ( 'knowledgeInformation' 'asdf' ) \n"
+            + "        DESC 'RFC2256: knowledge information'\n"
+            + "        EQUALITY caseIgnoreMatch\n"
+            + "        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )";
+        parser.parse( attributeTypeData );
+        List<MutableAttributeType> attributeTypeList = parser.getAttributeTypes();
+        Map<String, AttributeType> attributeTypes = mapAttributeTypes( attributeTypeList );
+        AttributeType type = attributeTypes.get( "2.5.4.2" );
+
+        assertNotNull( type );
+        assertEquals( "2.5.4.2", type.getOid() );
+        assertEquals( "knowledgeInformation", type.getName() );
+        assertEquals( "RFC2256: knowledge information", type.getDescription() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", type.getSyntaxOid() );
+        assertEquals( 32768, type.getSyntaxLength() );
+    }
+
+
+    private Map<String, ObjectClass> mapObjectClasses( List<ObjectClass> objectClassList )
+    {
+        Map<String, ObjectClass> m = new HashMap<String, ObjectClass>();
+
+        for ( ObjectClass objectClass : objectClassList )
+        {
+            m.put( objectClass.getOid(), objectClass );
+        }
+
+        return m;
+    }
+
+
+    @Test
+    public void testObjectClassParse() throws Exception
+    {
+        String objectClassData = "objectclass ( 2.5.6.6 NAME 'person'\n"
+            + "        DESC 'RFC2256: a person'\n"
+            + "        SUP top STRUCTURAL\n"
+            + "        MUST ( sn $ cn )\n"
+            + "        MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )";
+        parser.parse( objectClassData );
+        List<ObjectClass> objectClassesList = parser.getObjectClassTypes();
+        Map<String, ObjectClass> objectClasses = mapObjectClasses( objectClassesList );
+        ObjectClass objectClass = objectClasses.get( "2.5.6.6" );
+
+        assertNotNull( objectClass );
+        assertEquals( "2.5.6.6", objectClass.getOid() );
+        assertEquals( "person", objectClass.getName() );
+        assertEquals( "RFC2256: a person", objectClass.getDescription() );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( "sn", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "cn", objectClass.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( "userPassword", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "telephoneNumber", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "seeAlso", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "description", objectClass.getMayAttributeTypeOids().get( 3 ) );
+    }
+
+
+    @Test
+    public void testObjectClassWithExtensionsParse() throws Exception
+    {
+        String objectClassData = "objectclass ( 2.5.6.6 NAME 'person'\n"
+            + "        DESC 'RFC2256: a person'\n"
+            + "        SUP top STRUCTURAL\n"
+            + "        MUST ( sn $ cn )\n"
+            + "        MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) \n"
+            + "        X-extension 'test' X-otherExtension ( 'test1' 'test2' ) )";
+        parser.parse( objectClassData );
+        List<ObjectClass> objectClassesList = parser.getObjectClassTypes();
+        Map<String, ObjectClass> objectClasses = mapObjectClasses( objectClassesList );
+        ObjectClass objectClass = objectClasses.get( "2.5.6.6" );
+
+        assertNotNull( objectClass );
+        assertEquals( "2.5.6.6", objectClass.getOid() );
+        assertEquals( "person", objectClass.getName() );
+        assertEquals( "RFC2256: a person", objectClass.getDescription() );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( "sn", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "cn", objectClass.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( "userPassword", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "telephoneNumber", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "seeAlso", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "description", objectClass.getMayAttributeTypeOids().get( 3 ) );
+        Map<String, List<String>> extensions = objectClass.getExtensions();
+
+        assertNotNull( extensions );
+
+        List<String> ext1 = objectClass.getExtension( "X-extension" );
+        assertNotNull( ext1 );
+        assertEquals( 1, ext1.size() );
+        assertTrue( ext1.contains( "test" ) );
+
+        List<String> ext2 = objectClass.getExtension( "X-otherExtension" );
+        assertNotNull( ext2 );
+        assertEquals( 2, ext2.size() );
+        assertTrue( ext2.contains( "test1" ) );
+        assertTrue( ext2.contains( "test2" ) );
+
+    }
+
+
+    @Test
+    public void testObjectClassMultipleNames() throws Exception
+    {
+        String objectClassData = "objectclass ( 0.9.2342.19200300.100.4.4\n"
+            + "\tNAME ( 'pilotPerson' 'newPilotPerson' )\n" + "\tSUP person STRUCTURAL\n"
+            + "\tMAY ( userid $ textEncodedORAddress $ rfc822Mailbox $\n"
+            + "\t\tfavouriteDrink $ roomNumber $ userClass $\n"
+            + "\t\thomeTelephoneNumber $ homePostalAddress $ secretary $\n"
+            + "\t\tpersonalTitle $ preferredDeliveryMethod $ businessCategory $\n"
+            + "\t\tjanetMailbox $ otherMailbox $ mobileTelephoneNumber $\n"
+            + "\t\tpagerTelephoneNumber $ organizationalStatus $\n"
+            + "\t\tmailPreferenceOption $ personalSignature )\n" + "\t)";
+        parser.parse( objectClassData );
+        List<ObjectClass> objectClassesList = parser.getObjectClassTypes();
+        Map<String, ObjectClass> objectClasses = mapObjectClasses( objectClassesList );
+        ObjectClass objectClass = objectClasses.get( "0.9.2342.19200300.100.4.4" );
+
+        assertNotNull( objectClass );
+        assertEquals( "0.9.2342.19200300.100.4.4", objectClass.getOid() );
+        assertEquals( "pilotPerson", objectClass.getName() );
+        assertEquals( "newPilotPerson", objectClass.getNames().get( 1 ) );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( "person", objectClass.getSuperiorOids().get( 0 ) );
+
+        assertEquals( "userid", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "textEncodedORAddress", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "rfc822Mailbox", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "favouriteDrink", objectClass.getMayAttributeTypeOids().get( 3 ) );
+        assertEquals( "roomNumber", objectClass.getMayAttributeTypeOids().get( 4 ) );
+        assertEquals( "userClass", objectClass.getMayAttributeTypeOids().get( 5 ) );
+        assertEquals( "homeTelephoneNumber", objectClass.getMayAttributeTypeOids().get( 6 ) );
+        assertEquals( "homePostalAddress", objectClass.getMayAttributeTypeOids().get( 7 ) );
+        assertEquals( "secretary", objectClass.getMayAttributeTypeOids().get( 8 ) );
+        assertEquals( "personalTitle", objectClass.getMayAttributeTypeOids().get( 9 ) );
+        assertEquals( "preferredDeliveryMethod", objectClass.getMayAttributeTypeOids().get( 10 ) );
+        assertEquals( "businessCategory", objectClass.getMayAttributeTypeOids().get( 11 ) );
+        assertEquals( "janetMailbox", objectClass.getMayAttributeTypeOids().get( 12 ) );
+        assertEquals( "otherMailbox", objectClass.getMayAttributeTypeOids().get( 13 ) );
+        assertEquals( "mobileTelephoneNumber", objectClass.getMayAttributeTypeOids().get( 14 ) );
+        assertEquals( "pagerTelephoneNumber", objectClass.getMayAttributeTypeOids().get( 15 ) );
+        assertEquals( "organizationalStatus", objectClass.getMayAttributeTypeOids().get( 16 ) );
+        assertEquals( "mailPreferenceOption", objectClass.getMayAttributeTypeOids().get( 17 ) );
+        assertEquals( "personalSignature", objectClass.getMayAttributeTypeOids().get( 18 ) );
+    }
+
+
+    @Test
+    public void testParseOpenLdapCoreSchema() throws Exception
+    {
+        InputStream input = getClass().getResourceAsStream( "core.schema" );
+        parser.parse( input );
+
+        List<MutableAttributeType> attributeTypes = parser.getAttributeTypes();
+        List<ObjectClass> objectClassTypes = parser.getObjectClassTypes();
+        Map<String, OpenLdapObjectIdentifierMacro> objectIdentifierMacros = parser.getObjectIdentifierMacros();
+
+        assertEquals( 52, attributeTypes.size() );
+        assertEquals( 27, objectClassTypes.size() );
+        assertEquals( 0, objectIdentifierMacros.size() );
+    }
+
+
+    @Test
+    public void testParseOpenLdapInetOrgPersonSchema() throws Exception
+    {
+        InputStream input = getClass().getResourceAsStream( "inetorgperson.schema" );
+        parser.parse( input );
+
+        List<MutableAttributeType> attributeTypes = parser.getAttributeTypes();
+        List<ObjectClass> objectClassTypes = parser.getObjectClassTypes();
+        Map<String, OpenLdapObjectIdentifierMacro> objectIdentifierMacros = parser.getObjectIdentifierMacros();
+
+        assertEquals( 9, attributeTypes.size() );
+        assertEquals( 1, objectClassTypes.size() );
+        assertEquals( 0, objectIdentifierMacros.size() );
+    }
+
+
+    @Test
+    public void testParseOpenLdapCollectiveSchema() throws Exception
+    {
+        InputStream input = getClass().getResourceAsStream( "collective.schema" );
+        parser.parse( input );
+
+        List<MutableAttributeType> attributeTypes = parser.getAttributeTypes();
+        List<ObjectClass> objectClassTypes = parser.getObjectClassTypes();
+        Map<String, OpenLdapObjectIdentifierMacro> objectIdentifierMacros = parser.getObjectIdentifierMacros();
+
+        assertEquals( 13, attributeTypes.size() );
+        assertEquals( 0, objectClassTypes.size() );
+        assertEquals( 0, objectIdentifierMacros.size() );
+        for ( AttributeType attributeTypeLiteral : attributeTypes )
+        {
+            assertTrue( attributeTypeLiteral.isCollective() );
+        }
+    }
+
+
+    @Test
+    public void testOpenLdapObjectIdentifiereMacros() throws Exception
+    {
+        InputStream input = getClass().getResourceAsStream( "dyngroup.schema" );
+        parser.parse( input );
+
+        List<MutableAttributeType> attributeTypes = parser.getAttributeTypes();
+        List<ObjectClass> objectClassTypes = parser.getObjectClassTypes();
+        Map<String, OpenLdapObjectIdentifierMacro> objectIdentifierMacros = parser.getObjectIdentifierMacros();
+
+        assertEquals( 2, attributeTypes.size() );
+        assertEquals( 2, objectClassTypes.size() );
+        assertEquals( 8, objectIdentifierMacros.size() );
+
+        // check that all macros are resolved
+        for ( OpenLdapObjectIdentifierMacro macro : objectIdentifierMacros.values() )
+        {
+            assertTrue( macro.isResolved() );
+            assertNotNull( macro.getResolvedOid() );
+            assertTrue( macro.getResolvedOid().matches( "[0-9]+(\\.[0-9]+)+" ) );
+        }
+
+        // check that OIDs in attribute types and object classes are resolved
+        for ( ObjectClass objectClass : objectClassTypes )
+        {
+            List<String> asList = objectClass.getNames();
+            if ( asList.contains( "groupOfURLs" ) )
+            {
+                assertEquals( "2.16.840.1.113730.3.2.33", objectClass.getOid() );
+            }
+            else if ( asList.contains( "dgIdentityAux" ) )
+            {
+                assertEquals( "1.3.6.1.4.1.4203.666.11.8.2.1", objectClass.getOid() );
+            }
+            else
+            {
+                fail( "object class 'groupOfURLs' or 'dgIdentityAux' expected" );
+            }
+        }
+
+        for ( AttributeType attributeType : attributeTypes )
+        {
+            List<String> asList = attributeType.getNames();
+
+            if ( asList.contains( "memberURL" ) )
+            {
+                assertEquals( "2.16.840.1.113730.3.1.198", attributeType.getOid() );
+            }
+            else if ( asList.contains( "dgIdentity" ) )
+            {
+                assertEquals( "1.3.6.1.4.1.4203.666.11.8.1.1", attributeType.getOid() );
+            }
+            else
+            {
+                fail( "attribute type 'memberURL' or 'dgIdentity' expected" );
+            }
+        }
+    }
+
+
+    @Test
+    public void testDescWithSpaces() throws Exception
+    {
+        String attributeTypeData = "attributetype ( 1.3.6.1.4.1.8104.1.1.37 NAME 'versionNumber'\n"
+            + "        DESC 'versionNumber ' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch\n"
+            + "        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)";
+
+        parser.parse( attributeTypeData );
+        List<MutableAttributeType> attributeTypes = parser.getAttributeTypes();
+        Map<String, AttributeType> mapAttributeTypes = mapAttributeTypes( attributeTypes );
+        AttributeType attributeType = mapAttributeTypes.get( "1.3.6.1.4.1.8104.1.1.37" );
+
+        assertNotNull( attributeType );
+        assertEquals( "1.3.6.1.4.1.8104.1.1.37", attributeType.getOid() );
+        assertEquals( "versionNumber", attributeType.getName() );
+        assertEquals( "versionNumber ", attributeType.getDescription() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", attributeType.getSyntaxOid() );
+        assertTrue( attributeType.isSingleValued() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/AttributeTypeRegistryTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/AttributeTypeRegistryTest.java
new file mode 100644
index 0000000..93d6593
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/AttributeTypeRegistryTest.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.DefaultAttributeTypeRegistry;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the AttributeTypeRegistry
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeTypeRegistryTest
+{
+    AttributeTypeRegistry atRegistry;
+
+
+    @Before
+    public void setup()
+    {
+        atRegistry = new DefaultAttributeTypeRegistry();
+    }
+
+
+    @Test
+    public void testUnregister() throws LdapException
+    {
+        MutableAttributeType at0 = new MutableAttributeType( "1.1" );
+        at0.addName( "t", "test", "Test", "T" );
+        atRegistry.register( at0 );
+
+        atRegistry.unregister( "1.1" );
+        assertFalse( atRegistry.contains( "1.1" ) );
+        assertFalse( atRegistry.contains( "t" ) );
+        assertFalse( atRegistry.contains( "T" ) );
+        assertFalse( atRegistry.contains( "tEsT" ) );
+
+        try
+        {
+            atRegistry.getOidByName( "T" );
+            fail();
+        }
+        catch ( LdapException ne )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    @Test
+    public void testRegister() throws LdapException
+    {
+        MutableAttributeType at0 = new MutableAttributeType( "1.1" );
+        at0.addName( "t", "test", "Test", "T" );
+        atRegistry.register( at0 );
+
+        assertTrue( atRegistry.contains( "1.1" ) );
+        assertTrue( atRegistry.contains( "t" ) );
+        assertTrue( atRegistry.contains( "T" ) );
+        assertTrue( atRegistry.contains( "tEsT" ) );
+        assertEquals( "1.1", atRegistry.getOidByName( "T" ) );
+
+        try
+        {
+            atRegistry.register( at0 );
+            fail();
+        }
+        catch ( LdapException ne )
+        {
+            assertTrue( true );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/OidRegistryTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/OidRegistryTest.java
new file mode 100644
index 0000000..e4ec84d
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/OidRegistryTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the OidRegistry class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class OidRegistryTest
+{
+
+    @Test
+    public void testCopy() throws Exception
+    {
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/RegistriesTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/RegistriesTest.java
new file mode 100644
index 0000000..6b77f68
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/registries/RegistriesTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.registries;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test the registries class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class RegistriesTest
+{
+    @Test
+    public void testClone()
+    {
+
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DummySyntaxChecker.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DummySyntaxChecker.java
new file mode 100644
index 0000000..ed23e24
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxCheckers/DummySyntaxChecker.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+
+
+/**
+ * A Dummy SyntaxChecker used for tests
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("serial")
+public class DummySyntaxChecker extends SyntaxChecker
+{
+    /**
+     * Creates a new instance of DummySyntaxChecker.
+     */
+    public DummySyntaxChecker()
+    {
+        super( SchemaConstants.OCTET_STRING_SYNTAX );
+    }
+
+
+    /**
+     * Creates a new instance of DummySyntaxChecker, with a specific OID
+     * 
+     * @param oid The Syntax's OID 
+     */
+    public DummySyntaxChecker( String oid )
+    {
+        super( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isValidSyntax( Object value )
+    {
+        // Always true.
+        return true;
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AccessPointSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AccessPointSyntaxCheckerTest.java
new file mode 100644
index 0000000..0c053ed
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AccessPointSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.AccessPointSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for AccessPointSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AccessPointSyntaxCheckerTest
+{
+    AccessPointSyntaxChecker checker = new AccessPointSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.2", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AttributeTypeDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AttributeTypeDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..ab06bc1
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AttributeTypeDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,132 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.AttributeTypeDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for AttributeTypeDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserAttributeTypeDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeTypeDescriptionSyntaxCheckerTest
+{
+    private AttributeTypeDescriptionSyntaxChecker checker = new AttributeTypeDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15  )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name  )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name EQUALITY caseIgnoreMatch  )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch  )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.4.3 NAME cn SUP name )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.4.3 name ( 'cn' 'commonName' )  sup name )" ) );
+
+        // spaces
+        assertTrue( checker.isValidSyntax( "(2.5.4.3 SUP name)" ) );
+        assertTrue( checker
+            .isValidSyntax( "(      2.5.4.3      NAME ('cn'   'commonName')     SYNTAX       1.3.6.1.4.1.1466.115.121.1.15   )" ) );
+
+        // COLLECTIVE requires usage userApplications
+        assertTrue( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name COLLECTIVE )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name COLLECTIVE USAGE userApplications )" ) );
+
+        // NO-USER-MODIFICATION requires an operational usage.
+        assertTrue( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name NO-USER-MODIFICATION USAGE dSAOperation )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name NO-USER-MODIFICATION USAGE directoryOperation )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name NO-USER-MODIFICATION USAGE distributedOperation )" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid OID
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name" ) );
+
+        // SYNTAX or SUP must be contained
+        assertFalse( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by' )" ) );
+
+        // COLLECTIVE requires usage userApplications
+        assertFalse( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name COLLECTIVE USAGE dSAOperation)" ) );
+        assertFalse( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name COLLECTIVE USAGE directoryOperation )" ) );
+        assertFalse( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name COLLECTIVE USAGE distributedOperation )" ) );
+
+        // NO-USER-MODIFICATION requires an operational usage.
+        assertFalse( checker.isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name NO-USER-MODIFICATION )" ) );
+        assertFalse( checker
+            .isValidSyntax( "( 2.5.4.3 NAME 'cn' SUP name NO-USER-MODIFICATION USAGE userApplications )" ) );
+
+        // invalid characters
+        assertFalse( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn#' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )" ) );
+        assertFalse( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'common_name' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )" ) );
+        assertFalse( checker
+            .isValidSyntax( "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP na=me EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )" ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AudioSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AudioSyntaxCheckerTest.java
new file mode 100644
index 0000000..aeb8d5d
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/AudioSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.AudioSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for AudioSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AudioSyntaxCheckerTest
+{
+    AudioSyntaxChecker checker = new AudioSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.4", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BinarySyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BinarySyntaxCheckerTest.java
new file mode 100644
index 0000000..6ef3868
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BinarySyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.BinarySyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for BinarySyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BinarySyntaxCheckerTest
+{
+    BinarySyntaxChecker checker = new BinarySyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.5", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BitStringSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BitStringSyntaxCheckerTest.java
new file mode 100644
index 0000000..163071b
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BitStringSyntaxCheckerTest.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.BitStringSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for BitStringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BitStringSyntaxCheckerTest
+{
+    BitStringSyntaxChecker checker = new BitStringSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "'" ) );
+        assertFalse( checker.isValidSyntax( "1" ) );
+        assertFalse( checker.isValidSyntax( "B" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "'0101B" ) );
+        assertFalse( checker.isValidSyntax( "0101B" ) );
+        assertFalse( checker.isValidSyntax( "0101'B" ) );
+        assertFalse( checker.isValidSyntax( "''B" ) );
+        assertFalse( checker.isValidSyntax( "'0101'" ) );
+        assertFalse( checker.isValidSyntax( "'11200'B" ) );
+        assertFalse( checker.isValidSyntax( "'1100'b" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "'0'B" ) );
+        assertTrue( checker.isValidSyntax( "'1'B" ) );
+        assertTrue( checker.isValidSyntax( "'0000'B" ) );
+        assertTrue( checker.isValidSyntax( "'11111'B" ) );
+        assertTrue( checker.isValidSyntax( "'01010101011100'B" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BooleanSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BooleanSyntaxCheckerTest.java
new file mode 100644
index 0000000..202da2c
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/BooleanSyntaxCheckerTest.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.BooleanSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for BooleanSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class BooleanSyntaxCheckerTest
+{
+    BooleanSyntaxChecker checker = new BooleanSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "F" ) );
+        assertFalse( checker.isValidSyntax( "t" ) );
+        assertFalse( checker.isValidSyntax( "T" ) );
+    }
+
+
+    @Test
+    public void testWrongValue()
+    {
+        assertFalse( checker.isValidSyntax( "abc" ) );
+        assertFalse( checker.isValidSyntax( "123" ) );
+    }
+
+
+    @Test
+    public void testMixedCase()
+    {
+        assertTrue( checker.isValidSyntax( "fAlSe" ) );
+        assertTrue( checker.isValidSyntax( "tRue" ) );
+        assertTrue( checker.isValidSyntax( "false" ) );
+        assertTrue( checker.isValidSyntax( "true" ) );
+    }
+
+
+    @Test
+    public void testUpperCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( "TRUE" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificateListSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificateListSyntaxCheckerTest.java
new file mode 100644
index 0000000..1b35852
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificateListSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.CertificateListSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for CertificateListSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CertificateListSyntaxCheckerTest
+{
+    CertificateListSyntaxChecker checker = new CertificateListSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.9", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificatePairSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificatePairSyntaxCheckerTest.java
new file mode 100644
index 0000000..d9e14c0
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificatePairSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.CertificatePairSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for CertificatePairSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CertificatePairSyntaxCheckerTest
+{
+    CertificatePairSyntaxChecker checker = new CertificatePairSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.10", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificateSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificateSyntaxCheckerTest.java
new file mode 100644
index 0000000..41a2a07
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CertificateSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.CertificateSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for CertificateSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CertificateSyntaxCheckerTest
+{
+    CertificateSyntaxChecker checker = new CertificateSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.8", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CountrySyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CountrySyntaxCheckerTest.java
new file mode 100644
index 0000000..8386609
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CountrySyntaxCheckerTest.java
@@ -0,0 +1,318 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.CountrySyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for BitStringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CountrySyntaxCheckerTest
+{
+    CountrySyntaxChecker checker = new CountrySyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "'" ) );
+        assertFalse( checker.isValidSyntax( "1" ) );
+        assertFalse( checker.isValidSyntax( "B" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "AF" ) );
+        assertTrue( checker.isValidSyntax( "AX" ) );
+        assertTrue( checker.isValidSyntax( "AL" ) );
+        assertTrue( checker.isValidSyntax( "DZ" ) );
+        assertTrue( checker.isValidSyntax( "AS" ) );
+        assertTrue( checker.isValidSyntax( "AD" ) );
+        assertTrue( checker.isValidSyntax( "AO" ) );
+        assertTrue( checker.isValidSyntax( "AI" ) );
+        assertTrue( checker.isValidSyntax( "AQ" ) );
+        assertTrue( checker.isValidSyntax( "AG" ) );
+        assertTrue( checker.isValidSyntax( "AR" ) );
+        assertTrue( checker.isValidSyntax( "AM" ) );
+        assertTrue( checker.isValidSyntax( "AW" ) );
+        assertTrue( checker.isValidSyntax( "AU" ) );
+        assertTrue( checker.isValidSyntax( "AT" ) );
+        assertTrue( checker.isValidSyntax( "AZ" ) );
+        assertTrue( checker.isValidSyntax( "BS" ) );
+        assertTrue( checker.isValidSyntax( "BH" ) );
+        assertTrue( checker.isValidSyntax( "BD" ) );
+        assertTrue( checker.isValidSyntax( "BB" ) );
+        assertTrue( checker.isValidSyntax( "BY" ) );
+        assertTrue( checker.isValidSyntax( "BE" ) );
+        assertTrue( checker.isValidSyntax( "BZ" ) );
+        assertTrue( checker.isValidSyntax( "BJ" ) );
+        assertTrue( checker.isValidSyntax( "BM" ) );
+        assertTrue( checker.isValidSyntax( "BT" ) );
+        assertTrue( checker.isValidSyntax( "BO" ) );
+        assertTrue( checker.isValidSyntax( "BA" ) );
+        assertTrue( checker.isValidSyntax( "BW" ) );
+        assertTrue( checker.isValidSyntax( "BV" ) );
+        assertTrue( checker.isValidSyntax( "BR" ) );
+        assertTrue( checker.isValidSyntax( "IO" ) );
+        assertTrue( checker.isValidSyntax( "BN" ) );
+        assertTrue( checker.isValidSyntax( "BG" ) );
+        assertTrue( checker.isValidSyntax( "BF" ) );
+        assertTrue( checker.isValidSyntax( "BI" ) );
+        assertTrue( checker.isValidSyntax( "KH" ) );
+        assertTrue( checker.isValidSyntax( "CM" ) );
+        assertTrue( checker.isValidSyntax( "CA" ) );
+        assertTrue( checker.isValidSyntax( "CV" ) );
+        assertTrue( checker.isValidSyntax( "KY" ) );
+        assertTrue( checker.isValidSyntax( "CF" ) );
+        assertTrue( checker.isValidSyntax( "TD" ) );
+        assertTrue( checker.isValidSyntax( "CL" ) );
+        assertTrue( checker.isValidSyntax( "CN" ) );
+        assertTrue( checker.isValidSyntax( "CX" ) );
+        assertTrue( checker.isValidSyntax( "CC" ) );
+        assertTrue( checker.isValidSyntax( "CO" ) );
+        assertTrue( checker.isValidSyntax( "KM" ) );
+        assertTrue( checker.isValidSyntax( "CG" ) );
+        assertTrue( checker.isValidSyntax( "CD" ) );
+        assertTrue( checker.isValidSyntax( "CK" ) );
+        assertTrue( checker.isValidSyntax( "CR" ) );
+        assertTrue( checker.isValidSyntax( "CI" ) );
+        assertTrue( checker.isValidSyntax( "HR" ) );
+        assertTrue( checker.isValidSyntax( "CU" ) );
+        assertTrue( checker.isValidSyntax( "CY" ) );
+        assertTrue( checker.isValidSyntax( "CZ" ) );
+        assertTrue( checker.isValidSyntax( "DK" ) );
+        assertTrue( checker.isValidSyntax( "DJ" ) );
+        assertTrue( checker.isValidSyntax( "DM" ) );
+        assertTrue( checker.isValidSyntax( "DO" ) );
+        assertTrue( checker.isValidSyntax( "EC" ) );
+        assertTrue( checker.isValidSyntax( "EG" ) );
+        assertTrue( checker.isValidSyntax( "SV" ) );
+        assertTrue( checker.isValidSyntax( "GQ" ) );
+        assertTrue( checker.isValidSyntax( "ER" ) );
+        assertTrue( checker.isValidSyntax( "EE" ) );
+        assertTrue( checker.isValidSyntax( "ET" ) );
+        assertTrue( checker.isValidSyntax( "FK" ) );
+        assertTrue( checker.isValidSyntax( "FO" ) );
+        assertTrue( checker.isValidSyntax( "FJ" ) );
+        assertTrue( checker.isValidSyntax( "FI" ) );
+        assertTrue( checker.isValidSyntax( "FR" ) );
+        assertTrue( checker.isValidSyntax( "GF" ) );
+        assertTrue( checker.isValidSyntax( "PF" ) );
+        assertTrue( checker.isValidSyntax( "TF" ) );
+        assertTrue( checker.isValidSyntax( "GA" ) );
+        assertTrue( checker.isValidSyntax( "GM" ) );
+        assertTrue( checker.isValidSyntax( "GE" ) );
+        assertTrue( checker.isValidSyntax( "DE" ) );
+        assertTrue( checker.isValidSyntax( "GH" ) );
+        assertTrue( checker.isValidSyntax( "GI" ) );
+        assertTrue( checker.isValidSyntax( "GR" ) );
+        assertTrue( checker.isValidSyntax( "GL" ) );
+        assertTrue( checker.isValidSyntax( "GD" ) );
+        assertTrue( checker.isValidSyntax( "GP" ) );
+        assertTrue( checker.isValidSyntax( "GU" ) );
+        assertTrue( checker.isValidSyntax( "GT" ) );
+        assertTrue( checker.isValidSyntax( "GG" ) );
+        assertTrue( checker.isValidSyntax( "GN" ) );
+        assertTrue( checker.isValidSyntax( "GW" ) );
+        assertTrue( checker.isValidSyntax( "GY" ) );
+        assertTrue( checker.isValidSyntax( "HT" ) );
+        assertTrue( checker.isValidSyntax( "HM" ) );
+        assertTrue( checker.isValidSyntax( "VA" ) );
+        assertTrue( checker.isValidSyntax( "HN" ) );
+        assertTrue( checker.isValidSyntax( "HK" ) );
+        assertTrue( checker.isValidSyntax( "HU" ) );
+        assertTrue( checker.isValidSyntax( "IS" ) );
+        assertTrue( checker.isValidSyntax( "IN" ) );
+        assertTrue( checker.isValidSyntax( "ID" ) );
+        assertTrue( checker.isValidSyntax( "IR" ) );
+        assertTrue( checker.isValidSyntax( "IQ" ) );
+        assertTrue( checker.isValidSyntax( "IE" ) );
+        assertTrue( checker.isValidSyntax( "IM" ) );
+        assertTrue( checker.isValidSyntax( "IL" ) );
+        assertTrue( checker.isValidSyntax( "IT" ) );
+        assertTrue( checker.isValidSyntax( "JM" ) );
+        assertTrue( checker.isValidSyntax( "JP" ) );
+        assertTrue( checker.isValidSyntax( "JE" ) );
+        assertTrue( checker.isValidSyntax( "JO" ) );
+        assertTrue( checker.isValidSyntax( "KZ" ) );
+        assertTrue( checker.isValidSyntax( "KE" ) );
+        assertTrue( checker.isValidSyntax( "KI" ) );
+        assertTrue( checker.isValidSyntax( "KP" ) );
+        assertTrue( checker.isValidSyntax( "KR" ) );
+        assertTrue( checker.isValidSyntax( "KW" ) );
+        assertTrue( checker.isValidSyntax( "KG" ) );
+        assertTrue( checker.isValidSyntax( "LA" ) );
+        assertTrue( checker.isValidSyntax( "LV" ) );
+        assertTrue( checker.isValidSyntax( "LB" ) );
+        assertTrue( checker.isValidSyntax( "LS" ) );
+        assertTrue( checker.isValidSyntax( "LR" ) );
+        assertTrue( checker.isValidSyntax( "LY" ) );
+        assertTrue( checker.isValidSyntax( "LI" ) );
+        assertTrue( checker.isValidSyntax( "LT" ) );
+        assertTrue( checker.isValidSyntax( "LU" ) );
+        assertTrue( checker.isValidSyntax( "MO" ) );
+        assertTrue( checker.isValidSyntax( "MK" ) );
+        assertTrue( checker.isValidSyntax( "MG" ) );
+        assertTrue( checker.isValidSyntax( "MW" ) );
+        assertTrue( checker.isValidSyntax( "MY" ) );
+        assertTrue( checker.isValidSyntax( "MV" ) );
+        assertTrue( checker.isValidSyntax( "ML" ) );
+        assertTrue( checker.isValidSyntax( "MT" ) );
+        assertTrue( checker.isValidSyntax( "MH" ) );
+        assertTrue( checker.isValidSyntax( "MQ" ) );
+        assertTrue( checker.isValidSyntax( "MR" ) );
+        assertTrue( checker.isValidSyntax( "MU" ) );
+        assertTrue( checker.isValidSyntax( "YT" ) );
+        assertTrue( checker.isValidSyntax( "MX" ) );
+        assertTrue( checker.isValidSyntax( "FM" ) );
+        assertTrue( checker.isValidSyntax( "MD" ) );
+        assertTrue( checker.isValidSyntax( "MC" ) );
+        assertTrue( checker.isValidSyntax( "MN" ) );
+        assertTrue( checker.isValidSyntax( "ME" ) );
+        assertTrue( checker.isValidSyntax( "MS" ) );
+        assertTrue( checker.isValidSyntax( "MA" ) );
+        assertTrue( checker.isValidSyntax( "MZ" ) );
+        assertTrue( checker.isValidSyntax( "MM" ) );
+        assertTrue( checker.isValidSyntax( "NA" ) );
+        assertTrue( checker.isValidSyntax( "NR" ) );
+        assertTrue( checker.isValidSyntax( "NP" ) );
+        assertTrue( checker.isValidSyntax( "NL" ) );
+        assertTrue( checker.isValidSyntax( "AN" ) );
+        assertTrue( checker.isValidSyntax( "NC" ) );
+        assertTrue( checker.isValidSyntax( "NZ" ) );
+        assertTrue( checker.isValidSyntax( "NI" ) );
+        assertTrue( checker.isValidSyntax( "NE" ) );
+        assertTrue( checker.isValidSyntax( "NG" ) );
+        assertTrue( checker.isValidSyntax( "NU" ) );
+        assertTrue( checker.isValidSyntax( "NF" ) );
+        assertTrue( checker.isValidSyntax( "MP" ) );
+        assertTrue( checker.isValidSyntax( "NO" ) );
+        assertTrue( checker.isValidSyntax( "OM" ) );
+        assertTrue( checker.isValidSyntax( "PK" ) );
+        assertTrue( checker.isValidSyntax( "PW" ) );
+        assertTrue( checker.isValidSyntax( "PS" ) );
+        assertTrue( checker.isValidSyntax( "PA" ) );
+        assertTrue( checker.isValidSyntax( "PG" ) );
+        assertTrue( checker.isValidSyntax( "PY" ) );
+        assertTrue( checker.isValidSyntax( "PE" ) );
+        assertTrue( checker.isValidSyntax( "PH" ) );
+        assertTrue( checker.isValidSyntax( "PN" ) );
+        assertTrue( checker.isValidSyntax( "PL" ) );
+        assertTrue( checker.isValidSyntax( "PT" ) );
+        assertTrue( checker.isValidSyntax( "PR" ) );
+        assertTrue( checker.isValidSyntax( "QA" ) );
+        assertTrue( checker.isValidSyntax( "RE" ) );
+        assertTrue( checker.isValidSyntax( "RO" ) );
+        assertTrue( checker.isValidSyntax( "RU" ) );
+        assertTrue( checker.isValidSyntax( "RW" ) );
+        assertTrue( checker.isValidSyntax( "SH" ) );
+        assertTrue( checker.isValidSyntax( "KN" ) );
+        assertTrue( checker.isValidSyntax( "LC" ) );
+        assertTrue( checker.isValidSyntax( "PM" ) );
+        assertTrue( checker.isValidSyntax( "VC" ) );
+        assertTrue( checker.isValidSyntax( "WS" ) );
+        assertTrue( checker.isValidSyntax( "SM" ) );
+        assertTrue( checker.isValidSyntax( "ST" ) );
+        assertTrue( checker.isValidSyntax( "SA" ) );
+        assertTrue( checker.isValidSyntax( "SN" ) );
+        assertTrue( checker.isValidSyntax( "RS" ) );
+        assertTrue( checker.isValidSyntax( "SC" ) );
+        assertTrue( checker.isValidSyntax( "SL" ) );
+        assertTrue( checker.isValidSyntax( "SG" ) );
+        assertTrue( checker.isValidSyntax( "SK" ) );
+        assertTrue( checker.isValidSyntax( "SI" ) );
+        assertTrue( checker.isValidSyntax( "SB" ) );
+        assertTrue( checker.isValidSyntax( "SO" ) );
+        assertTrue( checker.isValidSyntax( "ZA" ) );
+        assertTrue( checker.isValidSyntax( "GS" ) );
+        assertTrue( checker.isValidSyntax( "ES" ) );
+        assertTrue( checker.isValidSyntax( "LK" ) );
+        assertTrue( checker.isValidSyntax( "SD" ) );
+        assertTrue( checker.isValidSyntax( "SR" ) );
+        assertTrue( checker.isValidSyntax( "SJ" ) );
+        assertTrue( checker.isValidSyntax( "SZ" ) );
+        assertTrue( checker.isValidSyntax( "SE" ) );
+        assertTrue( checker.isValidSyntax( "CH" ) );
+        assertTrue( checker.isValidSyntax( "SY" ) );
+        assertTrue( checker.isValidSyntax( "TW" ) );
+        assertTrue( checker.isValidSyntax( "TJ" ) );
+        assertTrue( checker.isValidSyntax( "TZ" ) );
+        assertTrue( checker.isValidSyntax( "TH" ) );
+        assertTrue( checker.isValidSyntax( "TL" ) );
+        assertTrue( checker.isValidSyntax( "TG" ) );
+        assertTrue( checker.isValidSyntax( "TK" ) );
+        assertTrue( checker.isValidSyntax( "TO" ) );
+        assertTrue( checker.isValidSyntax( "TT" ) );
+        assertTrue( checker.isValidSyntax( "TN" ) );
+        assertTrue( checker.isValidSyntax( "TR" ) );
+        assertTrue( checker.isValidSyntax( "TM" ) );
+        assertTrue( checker.isValidSyntax( "TC" ) );
+        assertTrue( checker.isValidSyntax( "TV" ) );
+        assertTrue( checker.isValidSyntax( "UG" ) );
+        assertTrue( checker.isValidSyntax( "UA" ) );
+        assertTrue( checker.isValidSyntax( "AE" ) );
+        assertTrue( checker.isValidSyntax( "GB" ) );
+        assertTrue( checker.isValidSyntax( "US" ) );
+        assertTrue( checker.isValidSyntax( "UM" ) );
+        assertTrue( checker.isValidSyntax( "UY" ) );
+        assertTrue( checker.isValidSyntax( "UZ" ) );
+        assertTrue( checker.isValidSyntax( "VU" ) );
+        assertTrue( checker.isValidSyntax( "VE" ) );
+        assertTrue( checker.isValidSyntax( "VN" ) );
+        assertTrue( checker.isValidSyntax( "VG" ) );
+        assertTrue( checker.isValidSyntax( "VI" ) );
+        assertTrue( checker.isValidSyntax( "WF" ) );
+        assertTrue( checker.isValidSyntax( "EH" ) );
+        assertTrue( checker.isValidSyntax( "YE" ) );
+        assertTrue( checker.isValidSyntax( "ZM" ) );
+        assertTrue( checker.isValidSyntax( "ZW" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CsnSidSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CsnSidSyntaxCheckerTest.java
new file mode 100644
index 0000000..30217a3
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CsnSidSyntaxCheckerTest.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.CsnSidSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for CsnSidSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CsnSidSyntaxCheckerTest
+{
+    CsnSidSyntaxChecker checker = new CsnSidSyntaxChecker();
+
+
+    @Test
+    public void testNullCsnSid()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyCsnSid()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testValidCsnSid()
+    {
+        assertTrue( checker.isValidSyntax( "000" ) );
+        assertTrue( checker.isValidSyntax( "0" ) );
+        assertTrue( checker.isValidSyntax( "123" ) );
+        assertTrue( checker.isValidSyntax( "fff" ) );
+        assertTrue( checker.isValidSyntax( "FFF" ) );
+    }
+
+
+    @Test
+    public void testInvalidCsnSid()
+    {
+        assertFalse( checker.isValidSyntax( "Ggg" ) );
+        assertFalse( checker.isValidSyntax( "0-0" ) );
+        assertFalse( checker.isValidSyntax( "-1" ) );
+        assertFalse( checker.isValidSyntax( "0000" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CsnSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CsnSyntaxCheckerTest.java
new file mode 100644
index 0000000..f994646
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/CsnSyntaxCheckerTest.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.CsnSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for CsnSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class CsnSyntaxCheckerTest
+{
+    CsnSyntaxChecker checker = new CsnSyntaxChecker();
+
+
+    @Test
+    public void testNullCsn()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyCsn()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    /**
+     * Test that a replicaId not being an integer between 000 and fff
+     * is seen as invalid
+     */
+    @Test
+    public void testBadReplicaId()
+    {
+        assertFalse( checker.isValidSyntax( "20090602120000.100000Z#000000##000000" ) );
+        assertFalse( checker.isValidSyntax( "20090602120000.100000Z#000000#00P#000000" ) );
+        assertFalse( checker.isValidSyntax( "20090602120000.100000Z#000000#-1#000000" ) );
+        assertFalse( checker.isValidSyntax( "20090602120000.100000Z#000000#-01#000000" ) );
+        assertFalse( checker.isValidSyntax( "20090602120000.100000Z#000000#0#000000" ) );
+        assertFalse( checker.isValidSyntax( "20090602120000.100000Z#000000#0 0#000000" ) );
+        assertFalse( checker.isValidSyntax( "20090602120000.100000Z#000000#   #000000" ) );
+    }
+
+
+    /**
+     * Test that a replicaId is a valid number between 000 and fff
+     */
+    @Test
+    public void testValidReplicaId()
+    {
+        assertTrue( checker.isValidSyntax( "20090602120000.100000Z#000000#000#000000" ) );
+        assertTrue( checker.isValidSyntax( "20090602120000.100000Z#000000#00f#000000" ) );
+        assertTrue( checker.isValidSyntax( "20090602120000.100000Z#000000#fff#000000" ) );
+        assertTrue( checker.isValidSyntax( "20090602120000.100000Z#000000#123#000000" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DataQualitySyntaxSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DataQualitySyntaxSyntaxCheckerTest.java
new file mode 100644
index 0000000..70af81e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DataQualitySyntaxSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DataQualitySyntaxSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DataQualitySyntaxSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DataQualitySyntaxSyntaxCheckerTest
+{
+    DataQualitySyntaxSyntaxChecker checker = new DataQualitySyntaxSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.13", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DeliveryMethodSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DeliveryMethodSyntaxCheckerTest.java
new file mode 100644
index 0000000..fed5d1b
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DeliveryMethodSyntaxCheckerTest.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DeliveryMethodSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DeliveryMethodSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DeliveryMethodSyntaxCheckerTest
+{
+    DeliveryMethodSyntaxChecker checker = new DeliveryMethodSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "'" ) );
+        assertFalse( checker.isValidSyntax( "1" ) );
+        assertFalse( checker.isValidSyntax( "B" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "fAlSe" ) );
+        assertFalse( checker.isValidSyntax( "ANY" ) );
+        assertFalse( checker.isValidSyntax( "any  " ) );
+        assertFalse( checker.isValidSyntax( "any $" ) );
+        assertFalse( checker.isValidSyntax( "any $ any" ) );
+        assertFalse( checker.isValidSyntax( "any $$ mhs" ) );
+        assertFalse( checker.isValidSyntax( "$" ) );
+        assertFalse( checker.isValidSyntax( "$ any" ) );
+        assertFalse( checker.isValidSyntax( " any any" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "any" ) );
+        assertTrue( checker.isValidSyntax( "mhs" ) );
+        assertTrue( checker.isValidSyntax( "physical" ) );
+        assertTrue( checker.isValidSyntax( "telex" ) );
+        assertTrue( checker.isValidSyntax( "teletex" ) );
+        assertTrue( checker.isValidSyntax( "g3fax" ) );
+        assertTrue( checker.isValidSyntax( "g4fax" ) );
+        assertTrue( checker.isValidSyntax( "ia5" ) );
+        assertTrue( checker.isValidSyntax( "videotex" ) );
+        assertTrue( checker.isValidSyntax( "telephone" ) );
+        assertTrue( checker.isValidSyntax( "any$mhs" ) );
+        assertTrue( checker.isValidSyntax( "videotex   $   any" ) );
+        assertTrue( checker.isValidSyntax( "any $ mhs  $  physical $telex" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DirectoryStringSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DirectoryStringSyntaxCheckerTest.java
new file mode 100644
index 0000000..d03b8b2
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DirectoryStringSyntaxCheckerTest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DirectoryStringSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DirectoryStringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DirectoryStringSyntaxCheckerTest
+{
+    DirectoryStringSyntaxChecker checker = new DirectoryStringSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        byte[] bytes = new byte[2];
+
+        bytes[0] = ( byte ) 0x80;
+        bytes[1] = ( byte ) 0x00;
+
+        assertFalse( checker.isValidSyntax( bytes ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "0123456789" ) );
+        assertTrue( checker.isValidSyntax( "abcdefghijklmnopqrstuvwxyz" ) );
+        assertTrue( checker.isValidSyntax( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) );
+        assertTrue( checker.isValidSyntax( "'()+,-.=/:? " ) );
+
+        byte[] bytes = new byte[128];
+
+        for ( int i = 0; i < 128; i++ )
+        {
+            bytes[i] = ( byte ) i;
+        }
+
+        assertTrue( checker.isValidSyntax( new String( bytes ) ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DitContentRuleDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DitContentRuleDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..3cd5b9f
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DitContentRuleDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DitContentRuleDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DITContentRuleDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserDITContentRuleDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DitContentRuleDescriptionSyntaxCheckerTest
+{
+    private DitContentRuleDescriptionSyntaxChecker checker = new DitContentRuleDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( "( 2.5.6.4 )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.6.4 NAME 'organization' )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.6.4 NAME 'organization' DESC 'content rule for organization' )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.4 NAME 'organization' DESC 'content rule for organization' OBSOLETE )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.4 NAME 'organization' DESC 'content rule for organization' OBSOLETE AUX ( pilotOrganization $  2.5.6.5 ) )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.4 NAME 'organization' DESC 'content rule for organization' OBSOLETE AUX ( pilotOrganization $  2.5.6.5 ) MUST ( objectClass $ o ) )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.4 NAME 'organization' DESC 'content rule for organization' OBSOLETE AUX ( pilotOrganization $  2.5.6.5 ) MUST ( objectClass $ o ) MAY ( l $ st )  )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.4 NAME 'organization' DESC 'content rule for organization' OBSOLETE AUX ( pilotOrganization $  2.5.6.5 ) MUST ( objectClass $ o ) MAY ( l $ st ) NOT ( 1.2.3.4.5.6.7.8.9.0 $ ou ) )" ) );
+
+        assertTrue( checker.isValidSyntax( "(2.5.6.4)" ) );
+        assertTrue( checker.isValidSyntax( "(2.5.6.4 NAME organization)" ) );
+        assertTrue( checker
+            .isValidSyntax( "(   2.5.6.4     NAME   'organization'   DESC   'content rule for organization' OBSOLETE AUX ( pilotOrganization $  2.5.6.5 ) MUST ( objectClass $ o )     MAY    (    l   $   st   ) NOT (1.2.3.4.5.6.7.8.9.0 $ ou))" ) );
+
+        // lowercase NAME, DESC, AUX
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.4 name 'organization' desc 'content rule for organization' aux ( pilotOrganization $  2.5.6.5 ) )" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid OID
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 2.5.6.4 NAME 'organization'" ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DitStructureRuleDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DitStructureRuleDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..bb8bda0
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DitStructureRuleDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DitStructureRuleDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DITStructureRuleDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserDITStructureRuleDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DitStructureRuleDescriptionSyntaxCheckerTest
+{
+    private DitStructureRuleDescriptionSyntaxChecker checker = new DitStructureRuleDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( "( 2 FORM 2.5.15.3 )" ) );
+        assertTrue( checker.isValidSyntax( "( 2 NAME 'organization' FORM 2.5.15.3 )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2 NAME 'organization' DESC 'organization structure rule' FORM 2.5.15.3 )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2 NAME 'organization' DESC 'organization structure rule' OBSOLETE FORM 2.5.15.3 )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2 NAME 'organization' DESC 'organization structure rule' OBSOLETE FORM 2.5.15.3 SUP 1 )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2 NAME 'organization' DESC 'organization structure rule' OBSOLETE FORM 2.5.15.3 SUP ( 1 ) )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2 NAME 'organization' DESC 'organization structure rule' OBSOLETE FORM 2.5.15.3 SUP ( 1 1234567890 5 ) )" ) );
+
+        assertTrue( checker.isValidSyntax( "(2 FORM 2.5.15.3)" ) );
+        assertTrue( checker.isValidSyntax( "(2 NAME organization FORM 2.5.15.3)" ) );
+        assertTrue( checker
+            .isValidSyntax( "(   2   NAME    'organization'    DESC    'organization structure rule'    OBSOLETE   FORM   2.5.15.3    SUP   (1 1234567890        5   ))" ) );
+
+        // lowercase NAME, DESC, FORM
+        assertTrue( checker
+            .isValidSyntax( "( 2 name 'organization' desc 'organization structure rule' form 2.5.15.3 )" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid ruleid
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2 )" ) );
+        assertFalse( checker.isValidSyntax( "( A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 2 FORM 2.5.15.3" ) );
+
+        // missing FORM
+        assertFalse( checker.isValidSyntax( "( 2 NAME 'organization' DESC 'organization structure rule' )" ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DlSubmitPermissionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DlSubmitPermissionSyntaxCheckerTest.java
new file mode 100644
index 0000000..b77e6cd
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DlSubmitPermissionSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DlSubmitPermissionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DLSubmitPermissionSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DlSubmitPermissionSyntaxCheckerTest
+{
+    DlSubmitPermissionSyntaxChecker checker = new DlSubmitPermissionSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.18", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DnSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DnSyntaxCheckerTest.java
new file mode 100644
index 0000000..09a2a63
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DnSyntaxCheckerTest.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DnSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DNSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DnSyntaxCheckerTest
+{
+    DnSyntaxChecker checker = new DnSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "'" ) );
+        assertFalse( checker.isValidSyntax( "1" ) );
+        assertFalse( checker.isValidSyntax( "B" ) );
+    }
+
+
+    @Test
+    public void testWrongDN()
+    {
+        assertFalse( checker.isValidSyntax( "a=b," ) );
+        assertFalse( checker.isValidSyntax( "a=#0101'B" ) );
+        assertFalse( checker.isValidSyntax( "a=b+" ) );
+        assertFalse( checker.isValidSyntax( "a=b,c=d," ) );
+    }
+
+
+    @Test
+    public void testCorrectDN()
+    {
+        assertTrue( checker.isValidSyntax( "a=b" ) );
+        assertTrue( checker.isValidSyntax( "a = b" ) );
+        assertTrue( checker.isValidSyntax( "a=b + c=d" ) );
+        assertTrue( checker.isValidSyntax( "a=b,c=d" ) );
+        assertTrue( checker.isValidSyntax( "a=b\\,c \\= d, e=f" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DsaQualitySyntaxSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DsaQualitySyntaxSyntaxCheckerTest.java
new file mode 100644
index 0000000..d881c7e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DsaQualitySyntaxSyntaxCheckerTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DsaQualitySyntaxSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DSAQualitySyntaxSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DsaQualitySyntaxSyntaxCheckerTest
+{
+    DsaQualitySyntaxSyntaxChecker checker = new DsaQualitySyntaxSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "Bad" ) );
+        assertFalse( checker.isValidSyntax( "DEFuNCT" ) );
+        assertFalse( checker.isValidSyntax( " DEFUNCT" ) );
+        assertFalse( checker.isValidSyntax( "DEFUNCT$desc" ) );
+        assertFalse( checker.isValidSyntax( "EXPERIMENTAL#test @ bad <desc>" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "DEFUNCT" ) );
+        assertTrue( checker.isValidSyntax( "EXPERIMENTAL" ) );
+        assertTrue( checker.isValidSyntax( "BEST-EFFORT" ) );
+        assertTrue( checker.isValidSyntax( "PILOT-SERVICE" ) );
+        assertTrue( checker.isValidSyntax( "FULL-SERVICE" ) );
+        assertTrue( checker.isValidSyntax( "EXPERIMENTAL#test desc" ) );
+        assertTrue( checker.isValidSyntax( "DEFUNCT#" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DseTypeSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DseTypeSyntaxCheckerTest.java
new file mode 100644
index 0000000..f404597
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/DseTypeSyntaxCheckerTest.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DseTypeSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for DSETypeSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DseTypeSyntaxCheckerTest
+{
+    DseTypeSyntaxChecker checker = new DseTypeSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(xyz)" ) );
+        assertFalse( checker.isValidSyntax( "sa" ) );
+        assertFalse( checker.isValidSyntax( "(SA)" ) );
+        assertFalse( checker.isValidSyntax( " () " ) );
+        assertFalse( checker.isValidSyntax( " (sa) " ) );
+        assertFalse( checker.isValidSyntax( "(sa) " ) );
+        assertFalse( checker.isValidSyntax( "(sa$)" ) );
+        assertFalse( checker.isValidSyntax( "(sa$ )" ) );
+        assertFalse( checker.isValidSyntax( "( sa $ sa )" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "(sa)" ) );
+        assertTrue( checker.isValidSyntax( "(  sa   )" ) );
+        assertTrue( checker.isValidSyntax( "( root $ glue $ cp $ entry $ alias $ subr $ " +
+            "nssr $ supr $ xr $ admPoint $ subentry $ " +
+            "shadow $ zombie $ immSupr $ rhob $ sa )" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/EnhancedGuideSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/EnhancedGuideSyntaxCheckerTest.java
new file mode 100644
index 0000000..d30f140
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/EnhancedGuideSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.EnhancedGuideSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for EnhancedGuideSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class EnhancedGuideSyntaxCheckerTest
+{
+    EnhancedGuideSyntaxChecker checker = new EnhancedGuideSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.21", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/FacsimileTelephoneNumberSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/FacsimileTelephoneNumberSyntaxCheckerTest.java
new file mode 100644
index 0000000..a49f3b6
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/FacsimileTelephoneNumberSyntaxCheckerTest.java
@@ -0,0 +1,135 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.FacsimileTelephoneNumberSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for FacsimileTelephoneNumberSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class FacsimileTelephoneNumberSyntaxCheckerTest
+{
+    FacsimileTelephoneNumberSyntaxChecker checker = new FacsimileTelephoneNumberSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "A" ) );
+        assertFalse( checker.isValidSyntax( "+" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "123 456 f" ) );
+        assertFalse( checker.isValidSyntax( "+ ()" ) );
+        assertFalse( checker.isValidSyntax( " +2 (123) 456-789 +" ) );
+    }
+
+
+    @Test
+    public void testCorrectTelephoneNumber()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "1111" ) );
+        assertTrue( checker.isValidSyntax( "1 (2) 3" ) );
+        assertTrue( checker.isValidSyntax( "+ 123 ( 456 )7891   12345" ) );
+        assertTrue( checker.isValidSyntax( " 12 34 56 78 90 " ) );
+    }
+
+
+    @Test
+    public void testWithNewMandatoryRegexp()
+    {
+        // Adding french telephone number regexp
+        checker.setDefaultRegexp( " *0[1-8](( *|[-/.]{1})\\d\\d){4} *" );
+
+        assertFalse( checker.isValidSyntax( "+ 123 ( 456 )7891   12345" ) );
+        assertTrue( checker.isValidSyntax( " 01 02 03 04 05 " ) );
+        assertTrue( checker.isValidSyntax( " 0102 03 04 05 " ) );
+        assertTrue( checker.isValidSyntax( " 01 02 03 04  05 " ) );
+        assertTrue( checker.isValidSyntax( " 01/02/03/04/05 " ) );
+        assertFalse( checker.isValidSyntax( " 01 / 02 .03 04--  05 " ) );
+    }
+
+
+    @Test
+    public void testCorrectTelephoneNumberAndFaxParam()
+    {
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$twoDimensional" ) );
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$fineResolution" ) );
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$unlimitedLength" ) );
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$b4Length" ) );
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$a3Width" ) );
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$b4Width" ) );
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$twoDimensional" ) );
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$uncompressed" ) );
+    }
+
+
+    @Test
+    public void testCorrectTelephoneNumberAndFaxParams()
+    {
+        assertTrue( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$twoDimensional$fineResolution$a3Width" ) );
+    }
+
+
+    @Test
+    public void testCorrectTelephoneNumberBadFaxParams()
+    {
+        assertFalse( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$" ) );
+        assertFalse( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$$" ) );
+        assertFalse( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$twoDimensionnal" ) );
+        assertFalse( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$ twoDimensional" ) );
+        assertFalse( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$twoDimensional$" ) );
+        assertFalse( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$twoDimensional$twoDimensional" ) );
+        assertFalse( checker.isValidSyntax( "+ 33 1 (456) 7891   12345$b4Width$ $a3Width" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/FaxSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/FaxSyntaxCheckerTest.java
new file mode 100644
index 0000000..b952066
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/FaxSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.FaxSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for FaxSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class FaxSyntaxCheckerTest
+{
+    FaxSyntaxChecker checker = new FaxSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.23", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/GeneralizedTimeSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/GeneralizedTimeSyntaxCheckerTest.java
new file mode 100644
index 0000000..841cc5e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/GeneralizedTimeSyntaxCheckerTest.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.GeneralizedTimeSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for GeneralizedTimeSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class GeneralizedTimeSyntaxCheckerTest
+{
+    GeneralizedTimeSyntaxChecker checker = new GeneralizedTimeSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "'" ) );
+        assertFalse( checker.isValidSyntax( "1" ) );
+        assertFalse( checker.isValidSyntax( "B" ) );
+    }
+
+
+    @Test
+    public void testErrorCase()
+    {
+        assertFalse( checker.isValidSyntax( "20060005184527Z" ) );
+        assertFalse( checker.isValidSyntax( "20061305184527Z" ) );
+        assertFalse( checker.isValidSyntax( "20062205184527Z" ) );
+        assertFalse( checker.isValidSyntax( "20061200184527Z" ) );
+        assertFalse( checker.isValidSyntax( "20061235184527Z" ) );
+        assertFalse( checker.isValidSyntax( "20061205604527Z" ) );
+        assertFalse( checker.isValidSyntax( "20061205186027Z" ) );
+        assertFalse( checker.isValidSyntax( "20061205184561Z" ) );
+        assertFalse( checker.isValidSyntax( "20061205184527Z+" ) );
+        assertFalse( checker.isValidSyntax( "20061205184527+2400" ) );
+        assertFalse( checker.isValidSyntax( "20061205184527+9900" ) );
+        assertFalse( checker.isValidSyntax( "20061205184527+1260" ) );
+        assertFalse( checker.isValidSyntax( "20061205184527+1299" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "20061205184527Z" ) );
+        assertTrue( checker.isValidSyntax( "20061205184527+0500" ) );
+        assertTrue( checker.isValidSyntax( "20061205184527-1234" ) );
+        assertTrue( checker.isValidSyntax( "20061205184527.123Z" ) );
+        assertTrue( checker.isValidSyntax( "20061205184527,123+0100" ) );
+        assertTrue( checker.isValidSyntax( "2006120519Z" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/GuideSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/GuideSyntaxCheckerTest.java
new file mode 100644
index 0000000..a96a0b5
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/GuideSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.GuideSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for GuideSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class GuideSyntaxCheckerTest
+{
+    GuideSyntaxChecker checker = new GuideSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.25", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/Ia5StringSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/Ia5StringSyntaxCheckerTest.java
new file mode 100644
index 0000000..79c0e69
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/Ia5StringSyntaxCheckerTest.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.Ia5StringSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for Ia5StringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class Ia5StringSyntaxCheckerTest
+{
+    Ia5StringSyntaxChecker checker = new Ia5StringSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "\u00E9" ) );
+        assertFalse( checker.isValidSyntax( "\u00A7" ) );
+        assertFalse( checker.isValidSyntax( "\u00E8" ) );
+        assertFalse( checker.isValidSyntax( "\u00C7" ) );
+        assertFalse( checker.isValidSyntax( "\u00E0" ) );
+        assertFalse( checker.isValidSyntax( "\u00B0" ) );
+        assertFalse( checker.isValidSyntax( "\u00F9" ) );
+        assertFalse( checker.isValidSyntax( "\u00A3" ) );
+        assertFalse( checker.isValidSyntax( "\u20AC" ) );
+        assertFalse( checker.isValidSyntax( "\u00B4" ) );
+        assertFalse( checker.isValidSyntax( "\u00B8" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "0123456789" ) );
+        assertTrue( checker.isValidSyntax( "abcdefghijklmnopqrstuvwxyz" ) );
+        assertTrue( checker.isValidSyntax( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) );
+        assertTrue( checker.isValidSyntax( "'()+,-.=/:? " ) );
+
+        byte[] bytes = new byte[128];
+
+        for ( int i = 0; i < 128; i++ )
+        {
+            bytes[i] = ( byte ) i;
+        }
+
+        assertTrue( checker.isValidSyntax( new String( bytes ) ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/IntegerSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/IntegerSyntaxCheckerTest.java
new file mode 100644
index 0000000..5687dc8
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/IntegerSyntaxCheckerTest.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.IntegerSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for IntegerSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class IntegerSyntaxCheckerTest
+{
+    IntegerSyntaxChecker checker = new IntegerSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "-" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "000" ) );
+        assertFalse( checker.isValidSyntax( "-0" ) );
+        assertFalse( checker.isValidSyntax( " 1" ) );
+        assertFalse( checker.isValidSyntax( "1 " ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "10" ) );
+        assertTrue( checker.isValidSyntax( "1111" ) );
+        assertTrue( checker.isValidSyntax( "-1" ) );
+        assertTrue( checker.isValidSyntax( "-1234567891" ) );
+        assertTrue( checker.isValidSyntax( "123456789" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaByteSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaByteSyntaxCheckerTest.java
new file mode 100644
index 0000000..c2422c6
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaByteSyntaxCheckerTest.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.JavaByteSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for JavaByteSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class JavaByteSyntaxCheckerTest
+{
+    JavaByteSyntaxChecker checker = new JavaByteSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "-" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "000" ) );
+        assertFalse( checker.isValidSyntax( "-0" ) );
+        assertFalse( checker.isValidSyntax( " 1" ) );
+        assertFalse( checker.isValidSyntax( "1 " ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "10" ) );
+        assertTrue( checker.isValidSyntax( "111" ) );
+        assertTrue( checker.isValidSyntax( "-1" ) );
+        assertTrue( checker.isValidSyntax( "-123" ) );
+        assertTrue( checker.isValidSyntax( "123" ) );
+    }
+
+
+    @Test
+    public void testMinValueBoundry()
+    {
+        int min = Byte.MIN_VALUE;
+        assertTrue( checker.isValidSyntax( Integer.toString( min ) ) );
+        min--;
+        assertFalse( checker.isValidSyntax( Integer.toString( min ) ) );
+        min--;
+        assertFalse( checker.isValidSyntax( Integer.toString( min ) ) );
+    }
+
+
+    @Test
+    public void testMaxValueBoundry()
+    {
+        int max = Byte.MAX_VALUE;
+        assertTrue( checker.isValidSyntax( Integer.toString( max ) ) );
+        max++;
+        assertFalse( checker.isValidSyntax( Integer.toString( max ) ) );
+        max++;
+        assertFalse( checker.isValidSyntax( Integer.toString( max ) ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaIntegerSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaIntegerSyntaxCheckerTest.java
new file mode 100644
index 0000000..95dfab3
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaIntegerSyntaxCheckerTest.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigInteger;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.JavaIntegerSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for IntegerSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class JavaIntegerSyntaxCheckerTest
+{
+    JavaIntegerSyntaxChecker checker = new JavaIntegerSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "-" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "000" ) );
+        assertFalse( checker.isValidSyntax( "-0" ) );
+        assertFalse( checker.isValidSyntax( " 1" ) );
+        assertFalse( checker.isValidSyntax( "1 " ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "10" ) );
+        assertTrue( checker.isValidSyntax( "1111" ) );
+        assertTrue( checker.isValidSyntax( "-1" ) );
+        assertTrue( checker.isValidSyntax( "-1234567891" ) );
+        assertTrue( checker.isValidSyntax( "123456789" ) );
+    }
+
+
+    @Test
+    public void testMinValueBoundry()
+    {
+        BigInteger min = new BigInteger( Integer.toString( Integer.MIN_VALUE ) );
+        assertTrue( checker.isValidSyntax( min.toString() ) );
+        min = min.subtract( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( min.toString() ) );
+        min = min.subtract( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( min.toString() ) );
+    }
+
+
+    @Test
+    public void testMaxValueBoundry()
+    {
+        BigInteger max = new BigInteger( Integer.toString( Integer.MAX_VALUE ) );
+        assertTrue( checker.isValidSyntax( max.toString() ) );
+        max = max.add( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( max.toString() ) );
+        max = max.add( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( max.toString() ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaLongSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaLongSyntaxCheckerTest.java
new file mode 100644
index 0000000..ba69eee
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaLongSyntaxCheckerTest.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigInteger;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.JavaLongSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for JavaLongSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class JavaLongSyntaxCheckerTest
+{
+    JavaLongSyntaxChecker checker = new JavaLongSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "-" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "000" ) );
+        assertFalse( checker.isValidSyntax( "-0" ) );
+        assertFalse( checker.isValidSyntax( " 1" ) );
+        assertFalse( checker.isValidSyntax( "1 " ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "10" ) );
+        assertTrue( checker.isValidSyntax( "111" ) );
+        assertTrue( checker.isValidSyntax( "-1" ) );
+        assertTrue( checker.isValidSyntax( "-123" ) );
+        assertTrue( checker.isValidSyntax( "123" ) );
+    }
+
+
+    @Test
+    public void testMinValueBoundry()
+    {
+        BigInteger min = new BigInteger( Long.toString( Long.MIN_VALUE ) );
+        assertTrue( checker.isValidSyntax( min.toString() ) );
+        min = min.subtract( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( min.toString() ) );
+        min = min.subtract( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( min.toString() ) );
+    }
+
+
+    @Test
+    public void testMaxValueBoundry()
+    {
+        BigInteger max = new BigInteger( Long.toString( Long.MAX_VALUE ) );
+        assertTrue( checker.isValidSyntax( max.toString() ) );
+        max = max.add( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( max.toString() ) );
+        max = max.add( BigInteger.ONE );
+        assertFalse( checker.isValidSyntax( max.toString() ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaShortSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaShortSyntaxCheckerTest.java
new file mode 100644
index 0000000..0182d73
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JavaShortSyntaxCheckerTest.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.JavaShortSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for JavaShortSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class JavaShortSyntaxCheckerTest
+{
+    JavaShortSyntaxChecker checker = new JavaShortSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "-" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "000" ) );
+        assertFalse( checker.isValidSyntax( "-0" ) );
+        assertFalse( checker.isValidSyntax( " 1" ) );
+        assertFalse( checker.isValidSyntax( "1 " ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "10" ) );
+        assertTrue( checker.isValidSyntax( "111" ) );
+        assertTrue( checker.isValidSyntax( "-1" ) );
+        assertTrue( checker.isValidSyntax( "-123" ) );
+        assertTrue( checker.isValidSyntax( "123" ) );
+    }
+
+
+    @Test
+    public void testMinValueBoundry()
+    {
+        int min = Short.MIN_VALUE;
+        assertTrue( checker.isValidSyntax( Integer.toString( min ) ) );
+        min--;
+        assertFalse( checker.isValidSyntax( Integer.toString( min ) ) );
+        min--;
+        assertFalse( checker.isValidSyntax( Integer.toString( min ) ) );
+    }
+
+
+    @Test
+    public void testMaxValueBoundry()
+    {
+        int max = Short.MAX_VALUE;
+        assertTrue( checker.isValidSyntax( Integer.toString( max ) ) );
+        max++;
+        assertFalse( checker.isValidSyntax( Integer.toString( max ) ) );
+        max++;
+        assertFalse( checker.isValidSyntax( Integer.toString( max ) ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JpegSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JpegSyntaxCheckerTest.java
new file mode 100644
index 0000000..ada74cf
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/JpegSyntaxCheckerTest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.JpegSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for JpegSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class JpegSyntaxCheckerTest
+{
+    JpegSyntaxChecker checker = new JpegSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "this is not a jpeg file..." ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        byte[] array = new byte[256];
+
+        for ( int i = 0; i < 256; i++ )
+        {
+            array[i] = ( byte ) i;
+        }
+
+        array[0] = ( byte ) 0xFF;
+        array[1] = ( byte ) 0xD8;
+        array[2] = ( byte ) 0xFF;
+        array[3] = ( byte ) 0xE0;
+        array[4] = ( byte ) 0x00;
+        array[5] = ( byte ) 0x10;
+        array[6] = 'J';
+        array[7] = 'F';
+        array[8] = 'I';
+        array[9] = 'F';
+        array[10] = '\0';
+
+        assertTrue( checker.isValidSyntax( array ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/LdapSyntaxDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/LdapSyntaxDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..e5c26e5
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/LdapSyntaxDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.LdapSyntaxDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for LdapSyntaxDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserLdapSyntaxDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapSyntaxDescriptionSyntaxCheckerTest
+{
+    private LdapSyntaxDescriptionSyntaxChecker checker = new LdapSyntaxDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( ( "( 1.3.6.1.4.1.1466.115.121.1.15 )" ) ) );
+        assertTrue( checker.isValidSyntax( ( "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ABC-DEF 'test' )" ) ) );
+
+        // spaces
+        assertTrue( checker.isValidSyntax( "(1.3.6.1.4.1.1466.115.121.1.15)" ) );
+        assertTrue( checker
+            .isValidSyntax( "(      1.3.6.1.4.1.1466.115.121.1.15        DESC 'Directory String' X-ABC-DEF     'test'     )" ) );
+
+        // lowercase DESC
+        assertTrue( checker.isValidSyntax( "( 1.3.6.1.4.1.1466.115.121.1.15 desc 'Directory String' )" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid OID
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 1.3.6.1.4.1.1466.115.121.1.15 " ) );
+
+        // missing quotes
+        assertFalse( checker.isValidSyntax( "( 1.3.6.1.4.1.1466.115.121.1.15 DESC Directory String )" ) );
+
+        // invalid extension
+        assertFalse( checker.isValidSyntax( "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ABC-DEF )" ) );
+        assertFalse( checker
+            .isValidSyntax( "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ABC-123 'test' )" ) );
+
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MailPreferenceSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MailPreferenceSyntaxCheckerTest.java
new file mode 100644
index 0000000..e31a73a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MailPreferenceSyntaxCheckerTest.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.MailPreferenceSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for MailPreferenceSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MailPreferenceSyntaxCheckerTest
+{
+    MailPreferenceSyntaxChecker checker = new MailPreferenceSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "F" ) );
+        assertFalse( checker.isValidSyntax( "t" ) );
+        assertFalse( checker.isValidSyntax( "T" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "any-list" ) );
+        assertFalse( checker.isValidSyntax( "no-lists" ) );
+        assertFalse( checker.isValidSyntax( "PROFESSIONAL-LISTs" ) );
+        assertFalse( checker.isValidSyntax( "abc" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "ANY-LIST" ) );
+        assertTrue( checker.isValidSyntax( "NO-LISTS" ) );
+        assertTrue( checker.isValidSyntax( "PROFESSIONAL-LISTS" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MasterAndShadowAccessPointSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MasterAndShadowAccessPointSyntaxCheckerTest.java
new file mode 100644
index 0000000..74bc8e0
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MasterAndShadowAccessPointSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.MasterAndShadowAccessPointSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for MasterAndShadowAccessPointSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MasterAndShadowAccessPointSyntaxCheckerTest
+{
+    MasterAndShadowAccessPointSyntaxChecker checker = new MasterAndShadowAccessPointSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.29", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MatchingRuleDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MatchingRuleDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..7d70c3e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MatchingRuleDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.MatchingRuleDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for MatchingRuleDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserMatchingRuleDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MatchingRuleDescriptionSyntaxCheckerTest
+{
+    private MatchingRuleDescriptionSyntaxChecker checker = new MatchingRuleDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( ( "( 2.5.13.5 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "( 2.5.13.5 NAME 'caseExactMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "( 2.5.13.5 NAME 'caseExactMatch' DESC 'caseExactMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "( 2.5.13.5 NAME 'caseExactMatch' DESC 'caseExactMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ABC-DEF 'test' )" ) ) );
+
+        // spaces
+        assertTrue( checker.isValidSyntax( "(2.5.13.5 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)" ) );
+        assertTrue( checker
+            .isValidSyntax( "(    2.5.13.5     NAME    'caseExactMatch'     DESC    'caseExactMatch'      SYNTAX       1.3.6.1.4.1.1466.115.121.1.15     X-ABC-DEF     'test')" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid OID
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 2.5.13.5 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " ) );
+
+        // missing quotes
+        assertFalse( checker.isValidSyntax( "( 2.5.13.5 DESC Description SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" ) );
+
+        // lowercase DESC
+        assertFalse( checker.isValidSyntax( "( 2.5.13.5 desc 'Directory String' )" ) );
+
+        // invalid extension
+        assertFalse( checker
+            .isValidSyntax( "( 2.5.13.5 DESC 'Description' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ABC-DEF )" ) );
+        assertFalse( checker
+            .isValidSyntax( "( 2.5.13.5 DESC 'Description' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ABC-123 'test' )" ) );
+
+        // SYNTAX is required
+        assertFalse( checker.isValidSyntax( "( 2.5.13.5 NAME 'caseExactMatch' )" ) );
+
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MatchingRuleUseDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MatchingRuleUseDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..a9562c8
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MatchingRuleUseDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.MatchingRuleUseDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for MatchingRuleUseDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserMatchingRuleUseDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MatchingRuleUseDescriptionSyntaxCheckerTest
+{
+    private MatchingRuleUseDescriptionSyntaxChecker checker = new MatchingRuleUseDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( ( "( 2.5.13.17 APPLIES userPassword )" ) ) );
+        assertTrue( checker.isValidSyntax( ( "( 2.5.13.17 APPLIES ( javaSerializedData $ userPassword ) )" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "( 2.5.13.17 NAME 'octetStringMatch' APPLIES ( javaSerializedData $ userPassword ) )" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "( 2.5.13.17 NAME 'octetStringMatch' DESC 'octetStringMatch' APPLIES ( javaSerializedData $ userPassword ) )" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "( 2.5.13.17 NAME 'octetStringMatch' DESC 'octetStringMatch' APPLIES ( javaSerializedData $ userPassword ) X-ABC-DEF 'test' )" ) ) );
+
+        // spaces
+        assertTrue( checker.isValidSyntax( ( "(2.5.13.17 APPLIES userPassword)" ) ) );
+        assertTrue( checker
+            .isValidSyntax( ( "(   2.5.13.17   NAME   'octetStringMatch'   DESC   'octetStringMatch'   APPLIES   (javaSerializedData   $    userPassword)  X-ABC-DEF     'test'   )" ) ) );
+
+        // lowercase DESC
+        assertTrue( checker.isValidSyntax( "( 2.5.13.17 desc 'Directory String' APPLIES userPassword )" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid OID
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 2.5.13.17 APPLIES userPassword " ) );
+
+        // missing quotes
+        assertFalse( checker.isValidSyntax( "( 2.5.13.17 DESC Directory String APPLIES userPassword )" ) );
+
+        // invalid extension
+        assertFalse( checker.isValidSyntax( "( 2.5.13.17 APPLIES userPassword X-ABC-DEF )" ) );
+        assertFalse( checker.isValidSyntax( "( 2.5.13.17 APPLIES userPassword X-ABC-123 'test' )" ) );
+
+        // APPLIES is required
+        assertFalse( checker.isValidSyntax( ( "( 2.5.13.17 NAME 'octetStringMatch' )" ) ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MhsOrAddressSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MhsOrAddressSyntaxCheckerTest.java
new file mode 100644
index 0000000..d408746
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/MhsOrAddressSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.MhsOrAddressSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for MHSORAddressSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MhsOrAddressSyntaxCheckerTest
+{
+    MhsOrAddressSyntaxChecker checker = new MhsOrAddressSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.33", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameAndOptionalUIDSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameAndOptionalUIDSyntaxCheckerTest.java
new file mode 100644
index 0000000..5946f7a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameAndOptionalUIDSyntaxCheckerTest.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.NameAndOptionalUIDSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for NameAndOptionalUIDSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NameAndOptionalUIDSyntaxCheckerTest
+{
+    NameAndOptionalUIDSyntaxChecker checker = new NameAndOptionalUIDSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "'" ) );
+        assertFalse( checker.isValidSyntax( "1" ) );
+        assertFalse( checker.isValidSyntax( "#" ) );
+    }
+
+
+    @Test
+    public void testWrongDN()
+    {
+        assertFalse( checker.isValidSyntax( "a=b," ) );
+        assertFalse( checker.isValidSyntax( "a=#0101'B" ) );
+        assertFalse( checker.isValidSyntax( "a=b+" ) );
+        assertFalse( checker.isValidSyntax( "a=b,c=d," ) );
+    }
+
+
+    @Test
+    public void testWrongUID()
+    {
+        assertFalse( checker.isValidSyntax( "#'0101'B" ) );
+        assertFalse( checker.isValidSyntax( "a=\\#,e=f#'1010'B" ) );
+        assertFalse( checker.isValidSyntax( "a=b##'0101'B" ) );
+        assertFalse( checker.isValidSyntax( "a=b#'0101'C" ) );
+    }
+
+
+    @Test
+    public void testCorrectDN()
+    {
+        assertTrue( checker.isValidSyntax( "a=b" ) );
+        assertTrue( checker.isValidSyntax( "a = b" ) );
+        assertTrue( checker.isValidSyntax( "a=b + c=d" ) );
+        assertTrue( checker.isValidSyntax( "a=b,c=d" ) );
+        assertTrue( checker.isValidSyntax( "a=b\\,c \\= d, e=f" ) );
+    }
+
+
+    @Test
+    public void testCorrectDNAndUID()
+    {
+        assertTrue( checker.isValidSyntax( "a=b#'1010'B" ) );
+        assertTrue( checker.isValidSyntax( "a = b#'1010'B" ) );
+        assertTrue( checker.isValidSyntax( "a=b + c=d#'1010'B" ) );
+        assertTrue( checker.isValidSyntax( "a=b,c=d#'1010'B" ) );
+        assertTrue( checker.isValidSyntax( "a=b\\,c \\= d, e=f#'1010'B" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameFormDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameFormDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..70c64b7
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameFormDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.NameFormDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for NameFormDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserNameFormDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NameFormDescriptionSyntaxCheckerTest
+{
+    private NameFormDescriptionSyntaxChecker checker = new NameFormDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( "( 2.5.15.3 OC o MUST m )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.15.3 OC o MUST m NAME 'orgNameForm' )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.15.3 OC o MUST m NAME 'orgNameForm' DESC 'orgNameForm' )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.15.3 MUST m NAME 'orgNameForm' DESC 'orgNameForm' OC organization )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.15.3 NAME 'orgNameForm' DESC 'orgNameForm' OC organization MUST o )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.15.3 NAME 'orgNameForm' DESC 'orgNameForm' OC organization MUST ( o ) MAY ( ou $ cn ) )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.15.3 NAME 'orgNameForm' DESC 'orgNameForm' OC organization MUST ( o ) MAY ( ou $ cn ) )" ) );
+
+        assertTrue( checker.isValidSyntax( "(2.5.15.3 OC o MUST m)" ) );
+        assertTrue( checker
+            .isValidSyntax( "(   2.5.15.3   NAME   'orgNameForm'    DESC    'orgNameForm'   OC   organization   MUST   (o)   MAY   (ou$cn))" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid OID
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 2.5.15.3 NAME 'orgNameForm'" ) );
+
+        // missing quotes
+        assertFalse( checker.isValidSyntax( "( 2.5.15.3 NAME orgNameForm )" ) );
+
+        // lowercase NAME, DESC, AUX
+        assertFalse( checker.isValidSyntax( "( 2.5.15.3 name 'orgNameForm' desc 'orgNameForm' oc o )" ) );
+
+        assertFalse( checker.isValidSyntax( "( 2.5.15.3 )" ) );
+        assertFalse( checker.isValidSyntax( "( 2.5.15.3 NAME 'orgNameForm' )" ) );
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameOrNumericIdSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameOrNumericIdSyntaxCheckerTest.java
new file mode 100644
index 0000000..934cd6d
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NameOrNumericIdSyntaxCheckerTest.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.NumericOidSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * A test case for the NameOrNumericId test.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NameOrNumericIdSyntaxCheckerTest
+{
+    NumericOidSyntaxChecker checker = new NumericOidSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testNumericIds()
+    {
+        assertFalse( checker.isValidSyntax( "111" ) );
+        assertFalse( checker.isValidSyntax( "11.a" ) );
+        assertFalse( checker.isValidSyntax( "11.1a" ) );
+        assertTrue( checker.isValidSyntax( "1.1" ) );
+        assertTrue( checker.isValidSyntax( "1.3.6.1.2.67.3.2" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NumericStringSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NumericStringSyntaxCheckerTest.java
new file mode 100644
index 0000000..f2c7898
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/NumericStringSyntaxCheckerTest.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.NumericStringSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for NumericStringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NumericStringSyntaxCheckerTest
+{
+    NumericStringSyntaxChecker checker = new NumericStringSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "f" ) );
+        assertFalse( checker.isValidSyntax( "-" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "123 456 f" ) );
+        assertFalse( checker.isValidSyntax( "1aB" ) );
+        assertFalse( checker.isValidSyntax( " +2" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "1111" ) );
+        assertTrue( checker.isValidSyntax( "1 2 3" ) );
+        assertTrue( checker.isValidSyntax( "1234567891 12345" ) );
+        assertTrue( checker.isValidSyntax( " 12 34 56 78 9 " ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectClassDescriptionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectClassDescriptionSyntaxCheckerTest.java
new file mode 100644
index 0000000..075c30e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectClassDescriptionSyntaxCheckerTest.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.ObjectClassDescriptionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for ObjectClassDescriptionSyntaxChecker.
+ * 
+ * There are also many test cases in SchemaParserObjectClassDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ObjectClassDescriptionSyntaxCheckerTest
+{
+    private ObjectClassDescriptionSyntaxChecker checker = new ObjectClassDescriptionSyntaxChecker();
+
+
+    @Test
+    public void testValid()
+    {
+        assertTrue( checker.isValidSyntax( "( 2.5.6.6 )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME person )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top )" ) );
+        assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) )" ) );
+        assertTrue( checker
+            .isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )" ) );
+
+        assertTrue( checker.isValidSyntax( "(2.5.6.6)" ) );
+        assertTrue( checker.isValidSyntax( "(      2.5.6.6      NAME      'person'      )" ) );
+    }
+
+
+    @Test
+    public void testInvalid()
+    {
+        // null 
+        assertFalse( checker.isValidSyntax( null ) );
+
+        // empty 
+        assertFalse( checker.isValidSyntax( "" ) );
+
+        // missing/invalid OID
+        assertFalse( checker.isValidSyntax( "()" ) );
+        assertFalse( checker.isValidSyntax( "(  )" ) );
+        assertFalse( checker.isValidSyntax( "( . )" ) );
+        assertFalse( checker.isValidSyntax( "( 1 )" ) );
+        assertFalse( checker.isValidSyntax( "( 1. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+        assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+        assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+        // missing right parenthesis
+        assertFalse( checker.isValidSyntax( "( 2.5.6.6 NAME 'person'" ) );
+
+        // lowercase NAME, DESC, SUP
+        assertFalse( checker.isValidSyntax( "( 2.5.6.6 name 'person' desc 'RFC2256: a person' sup top " ) );
+
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectClassTypeSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectClassTypeSyntaxCheckerTest.java
new file mode 100644
index 0000000..2a3de54
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectClassTypeSyntaxCheckerTest.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.ObjectClassTypeSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for ObjectClassTypeSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ObjectClassTypeSyntaxCheckerTest
+{
+    ObjectClassTypeSyntaxChecker checker = new ObjectClassTypeSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "." ) );
+        assertFalse( checker.isValidSyntax( "a" ) );
+        assertFalse( checker.isValidSyntax( "-" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "auxiliary" ) );
+        assertFalse( checker.isValidSyntax( "abstract" ) );
+        assertFalse( checker.isValidSyntax( "structural" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "AUXILIARY" ) );
+        assertTrue( checker.isValidSyntax( "ABSTRACT" ) );
+        assertTrue( checker.isValidSyntax( "STRUCTURAL" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectNameSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectNameSyntaxCheckerTest.java
new file mode 100644
index 0000000..f279298
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ObjectNameSyntaxCheckerTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.ObjectNameSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for ObjectNameSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ObjectNameSyntaxCheckerTest
+{
+    ObjectNameSyntaxChecker checker = new ObjectNameSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testName()
+    {
+        assertTrue( checker.isValidSyntax( "a" ) );
+        assertTrue( checker.isValidSyntax( "azerty" ) );
+        assertTrue( checker.isValidSyntax( "A" ) );
+        assertTrue( checker.isValidSyntax( "AZERTY" ) );
+        assertTrue( checker.isValidSyntax( "AzErTy" ) );
+        assertTrue( checker.isValidSyntax( "a123;-bcdEf0" ) );
+    }
+
+
+    @Test
+    public void testWrongName()
+    {
+        assertFalse( checker.isValidSyntax( "1test" ) );
+        assertFalse( checker.isValidSyntax( ";test" ) );
+        assertFalse( checker.isValidSyntax( "-test" ) );
+        assertFalse( checker.isValidSyntax( "tes " ) );
+        assertFalse( checker.isValidSyntax( "http://test" ) );
+        assertFalse( checker.isValidSyntax( "a name" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/OctetStringSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/OctetStringSyntaxCheckerTest.java
new file mode 100644
index 0000000..dfaec3e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/OctetStringSyntaxCheckerTest.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+import org.apache.directory.api.util.StringConstants;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for OctetStringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class OctetStringSyntaxCheckerTest
+{
+    OctetStringSyntaxChecker checker = new OctetStringSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyOctetString()
+    {
+        assertTrue( checker.isValidSyntax( StringConstants.EMPTY_BYTES ) );
+    }
+
+
+    @Test
+    public void testStringOctetString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        byte[] array = new byte[256];
+
+        for ( int i = 0; i < 256; i++ )
+        {
+            array[i] = ( byte ) i;
+        }
+
+        assertTrue( checker.isValidSyntax( array ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/OtherMailboxSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/OtherMailboxSyntaxCheckerTest.java
new file mode 100644
index 0000000..bbcefc9
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/OtherMailboxSyntaxCheckerTest.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OtherMailboxSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for OtherMailboxSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class OtherMailboxSyntaxCheckerTest
+{
+    OtherMailboxSyntaxChecker checker = new OtherMailboxSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase() throws Exception
+    {
+        assertFalse( checker.isValidSyntax( "mailType" ) );
+        assertFalse( checker.isValidSyntax( "%$test" ) );
+        assertFalse( checker.isValidSyntax( "test$test$test" ) );
+        assertFalse( checker.isValidSyntax( "test$test$" ) );
+        assertFalse( checker.isValidSyntax( "mail$\u0000\u007F\u0080" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "SMTP$dev@directory.apache.org" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PostalAddressSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PostalAddressSyntaxCheckerTest.java
new file mode 100644
index 0000000..62a07c9
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PostalAddressSyntaxCheckerTest.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.PostalAddressSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for PostalAddressSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PostalAddressSyntaxCheckerTest
+{
+    PostalAddressSyntaxChecker checker = new PostalAddressSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "$" ) );
+        assertFalse( checker.isValidSyntax( "test $" ) );
+        assertFalse( checker.isValidSyntax( "$ test" ) );
+        assertFalse( checker.isValidSyntax( "test$$test" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "test" ) );
+        assertTrue( checker.isValidSyntax( "test$test" ) );
+        assertTrue( checker.isValidSyntax( "test$test$test" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PresentationAddressSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PresentationAddressSyntaxCheckerTest.java
new file mode 100644
index 0000000..38c80ad
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PresentationAddressSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.PresentationAddressSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for PresentationAddress.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PresentationAddressSyntaxCheckerTest
+{
+    PresentationAddressSyntaxChecker checker = new PresentationAddressSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.43", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PrintableStringSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PrintableStringSyntaxCheckerTest.java
new file mode 100644
index 0000000..d613340
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/PrintableStringSyntaxCheckerTest.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.PrintableStringSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for PrintableStringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class PrintableStringSyntaxCheckerTest
+{
+    PrintableStringSyntaxChecker checker = new PrintableStringSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    /**
+     * 
+     * Check that non printable Strings are not accepted. We created Strings
+     * which contains only one char which is not in the acceptable set of
+     * printable chars.
+     *
+     */
+    @Test
+    public void testWrongStrings()
+    {
+        for ( int i = 0; i < 0x1F; i++ )
+        {
+            assertFalse( checker.isValidSyntax( new String( new byte[]
+                { ( byte ) i } ) ) );
+        }
+
+        for ( int i = 0x21; i < 0x26; i++ )
+        {
+            assertFalse( checker.isValidSyntax( new String( new byte[]
+                { ( byte ) i } ) ) );
+        }
+
+        for ( int i = 0x5B; i < 0x60; i++ )
+        {
+            assertFalse( checker.isValidSyntax( new String( new byte[]
+                { ( byte ) i } ) ) );
+        }
+
+        for ( int i = 0x7B; i < 0x7F; i++ )
+        {
+            assertFalse( checker.isValidSyntax( new String( new byte[]
+                { ( byte ) i } ) ) );
+        }
+
+        assertFalse( checker.isValidSyntax( new String( new byte[]
+            { ( byte ) 0x2A } ) ) );
+        assertFalse( checker.isValidSyntax( new String( new byte[]
+            { ( byte ) 0x3B } ) ) );
+        assertFalse( checker.isValidSyntax( new String( new byte[]
+            { ( byte ) 0x3C } ) ) );
+        assertFalse( checker.isValidSyntax( new String( new byte[]
+            { ( byte ) 0x3E } ) ) );
+        assertFalse( checker.isValidSyntax( new String( new byte[]
+            { ( byte ) 0x40 } ) ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "0123456789" ) );
+        assertTrue( checker.isValidSyntax( "abcdefghijklmnopqrstuvwxyz" ) );
+        assertTrue( checker.isValidSyntax( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) );
+        assertTrue( checker.isValidSyntax( "'()+,-.=/:? " ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ProtocolInformationSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ProtocolInformationSyntaxCheckerTest.java
new file mode 100644
index 0000000..5ca0845
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/ProtocolInformationSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.ProtocolInformationSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for ProtocolInformationSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ProtocolInformationSyntaxCheckerTest
+{
+    ProtocolInformationSyntaxChecker checker = new ProtocolInformationSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.42", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SubstringAssertionSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SubstringAssertionSyntaxCheckerTest.java
new file mode 100644
index 0000000..4b16247
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SubstringAssertionSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.SubstringAssertionSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for SubstringAssertionSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SubstringAssertionSyntaxCheckerTest
+{
+    SubstringAssertionSyntaxChecker checker = new SubstringAssertionSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.58", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierAndConsumerSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierAndConsumerSyntaxCheckerTest.java
new file mode 100644
index 0000000..e41c6b7
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierAndConsumerSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupplierAndConsumerSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for SupplierAndConsumerSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SupplierAndConsumerSyntaxCheckerTest
+{
+    SupplierAndConsumerSyntaxChecker checker = new SupplierAndConsumerSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.48", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierInformationSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierInformationSyntaxCheckerTest.java
new file mode 100644
index 0000000..012ea56
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierInformationSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupplierInformationSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for SupplierInformationSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SupplierInformationSyntaxCheckerTest
+{
+    SupplierInformationSyntaxChecker checker = new SupplierInformationSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.46", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierOrConsumerSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierOrConsumerSyntaxCheckerTest.java
new file mode 100644
index 0000000..df78247
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupplierOrConsumerSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupplierOrConsumerSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for SupplierOrConsumerSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SupplierOrConsumerSyntaxCheckerTest
+{
+    SupplierOrConsumerSyntaxChecker checker = new SupplierOrConsumerSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.47", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupportedAlgorithmSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupportedAlgorithmSyntaxCheckerTest.java
new file mode 100644
index 0000000..ed0b202
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/SupportedAlgorithmSyntaxCheckerTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupportedAlgorithmSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for SupportedAlgorithmSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SupportedAlgorithmSyntaxCheckerTest
+{
+    SupportedAlgorithmSyntaxChecker checker = new SupportedAlgorithmSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertTrue( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertTrue( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOid()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.49", checker.getOid() );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "FALSE" ) );
+        assertTrue( checker.isValidSyntax( new byte[]
+            { 0x01, ( byte ) 0xFF } ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TelephoneNumberSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TelephoneNumberSyntaxCheckerTest.java
new file mode 100644
index 0000000..f8b66ae
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TelephoneNumberSyntaxCheckerTest.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.TelephoneNumberSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test cases for NumericStringSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TelephoneNumberSyntaxCheckerTest
+{
+    TelephoneNumberSyntaxChecker checker = new TelephoneNumberSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testOID()
+    {
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.50", checker.getOid() );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "A" ) );
+        assertFalse( checker.isValidSyntax( "+" ) );
+    }
+
+
+    @Test
+    public void testWrongCase()
+    {
+        assertFalse( checker.isValidSyntax( "123 456 f" ) );
+        assertFalse( checker.isValidSyntax( "+ ()" ) );
+        assertFalse( checker.isValidSyntax( " +2 (123) 456-789 +" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "1" ) );
+        assertTrue( checker.isValidSyntax( "1111" ) );
+        assertTrue( checker.isValidSyntax( "1 (2) 3" ) );
+        assertTrue( checker.isValidSyntax( "+ 123 ( 456 )7891   12345" ) );
+        assertTrue( checker.isValidSyntax( " 12 34 56 78 90 " ) );
+        assertTrue( checker.isValidSyntax( " + 12 34 ; 56* 78 90, # " ) );
+    }
+
+
+    @Test
+    public void testWithNewMandatoryRegexp()
+    {
+        // Adding french telephone number regexp
+        checker.setDefaultRegexp( " *0[1-8](( *|[-/.]{1})\\d\\d){4} *" );
+
+        assertFalse( checker.isValidSyntax( "+ 123 ( 456 )7891   12345" ) );
+        assertTrue( checker.isValidSyntax( " 01 02 03 04 05 " ) );
+        assertTrue( checker.isValidSyntax( " 0102 03 04 05 " ) );
+        assertTrue( checker.isValidSyntax( " 01 02 03 04  05 " ) );
+        assertTrue( checker.isValidSyntax( " 01/02/03/04/05 " ) );
+        assertFalse( checker.isValidSyntax( " 01 / 02 .03 04--  05 " ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TeletexTerminalIdentifierSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TeletexTerminalIdentifierSyntaxCheckerTest.java
new file mode 100644
index 0000000..61766ba
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TeletexTerminalIdentifierSyntaxCheckerTest.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.TeletexTerminalIdentifierSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for TeletexTerminalIdentifierSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TeletexTerminalIdentifierSyntaxCheckerTest
+{
+    TeletexTerminalIdentifierSyntaxChecker checker = new TeletexTerminalIdentifierSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase() throws Exception
+    {
+        assertFalse( checker.isValidSyntax( "test$" ) );
+        assertFalse( checker.isValidSyntax( new String( new byte[]
+            { 't', 'e', 's', 't', 0x00, 0x7F, ( byte ) 0x80, '$', 't', 'e', 's', 't' }, "UTF-8" ) ) );
+        assertFalse( checker.isValidSyntax( "test$$" ) );
+        assertFalse( checker.isValidSyntax( "test$a:b" ) );
+        assertFalse( checker.isValidSyntax( "test$misc" ) );
+        assertFalse( checker.isValidSyntax( "test$misc:" ) );
+        assertFalse( checker.isValidSyntax( "test$:" ) );
+        assertFalse( checker.isValidSyntax( "test$:abc" ) );
+        assertFalse( checker.isValidSyntax( "test$misc:a$b" ) );
+        assertFalse( checker.isValidSyntax( "test$misc:a\\b" ) );
+        assertFalse( checker.isValidSyntax( "test$misc:a\\2b" ) );
+        assertFalse( checker.isValidSyntax( "test$misc:a\\5b" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase() throws Exception
+    {
+        assertTrue( checker.isValidSyntax( "test" ) );
+        assertTrue( checker.isValidSyntax( "test$graphic:abc" ) );
+        assertTrue( checker.isValidSyntax( "test$misc:abc" ) );
+        assertTrue( checker.isValidSyntax( "test$control:abc" ) );
+        assertTrue( checker.isValidSyntax( "test$page:abc" ) );
+        assertTrue( checker.isValidSyntax( "test$private:abc" ) );
+        assertTrue( checker.isValidSyntax( "test$private:abc$misc:def" ) );
+        assertTrue( checker.isValidSyntax( "test$misc:" + new String( new byte[]
+            { 't', 'e', 's', 't', 0x00, 0x7F, ( byte ) 0xFF }, "UTF-8" ) ) );
+        assertTrue( checker.isValidSyntax( "test$misc:a\\5c" ) );
+        assertTrue( checker.isValidSyntax( "test$misc:a\\5C" ) );
+        assertTrue( checker.isValidSyntax( "test$misc:a\\24" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TelexNumberSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TelexNumberSyntaxCheckerTest.java
new file mode 100644
index 0000000..1b7988e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/TelexNumberSyntaxCheckerTest.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.TelexNumberSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for TelexNumberSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TelexNumberSyntaxCheckerTest
+{
+    TelexNumberSyntaxChecker checker = new TelexNumberSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testWrongCase() throws Exception
+    {
+        assertFalse( checker.isValidSyntax( "test" ) );
+        assertFalse( checker.isValidSyntax( "test$test" ) );
+        assertFalse( checker.isValidSyntax( "test$test$" ) );
+        assertFalse( checker.isValidSyntax( "test$$test" ) );
+        assertFalse( checker.isValidSyntax( "$test$test" ) );
+        assertFalse( checker.isValidSyntax( "test$test$test$test" ) );
+        assertFalse( checker.isValidSyntax( new String( new byte[]
+            { 't', 'e', 's', 't', '$', 0x00, 0x7F, ( byte ) 0x80, '$', 't', 'e', 's', 't' }, "UTF-8" ) ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "test$test$test" ) );
+        assertTrue( checker.isValidSyntax( "t$t$t" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/UtcTimeSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/UtcTimeSyntaxCheckerTest.java
new file mode 100644
index 0000000..a2a5d64
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/UtcTimeSyntaxCheckerTest.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.UtcTimeSyntaxChecker;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for UtcTimeSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UtcTimeSyntaxCheckerTest
+{
+    UtcTimeSyntaxChecker checker = new UtcTimeSyntaxChecker();
+
+
+    @Test
+    public void testNullString()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyString()
+    {
+        assertFalse( checker.isValidSyntax( "" ) );
+    }
+
+
+    @Test
+    public void testOneCharString()
+    {
+        assertFalse( checker.isValidSyntax( "0" ) );
+        assertFalse( checker.isValidSyntax( "'" ) );
+        assertFalse( checker.isValidSyntax( "1" ) );
+        assertFalse( checker.isValidSyntax( "B" ) );
+    }
+
+
+    @Test
+    public void testErrorCase()
+    {
+        assertFalse( checker.isValidSyntax( "060005184527Z" ) );
+        assertFalse( checker.isValidSyntax( "061305184527Z" ) );
+        assertFalse( checker.isValidSyntax( "062205184527Z" ) );
+        assertFalse( checker.isValidSyntax( "061200184527Z" ) );
+        assertFalse( checker.isValidSyntax( "061235184527Z" ) );
+        assertFalse( checker.isValidSyntax( "061205604527Z" ) );
+        assertFalse( checker.isValidSyntax( "061205186027Z" ) );
+        assertFalse( checker.isValidSyntax( "061205184561Z" ) );
+        assertFalse( checker.isValidSyntax( "061205184527Z+" ) );
+        assertFalse( checker.isValidSyntax( "061205184527+2400" ) );
+        assertFalse( checker.isValidSyntax( "061205184527+9900" ) );
+        assertFalse( checker.isValidSyntax( "061205184527+1260" ) );
+        assertFalse( checker.isValidSyntax( "061205184527+1299" ) );
+        assertFalse( checker.isValidSyntax( "061205184527-12" ) );
+    }
+
+
+    @Test
+    public void testCorrectCase()
+    {
+        assertTrue( checker.isValidSyntax( "061205184527Z" ) );
+        assertTrue( checker.isValidSyntax( "061205184527+0500" ) );
+        assertTrue( checker.isValidSyntax( "061205184527-1234" ) );
+        assertTrue( checker.isValidSyntax( "0612051845Z" ) );
+        assertTrue( checker.isValidSyntax( "0612051845+0100" ) );
+        assertTrue( checker.isValidSyntax( "061205194527" ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/UuidSyntaxCheckerTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/UuidSyntaxCheckerTest.java
new file mode 100644
index 0000000..11fcdba
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/UuidSyntaxCheckerTest.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.UuidSyntaxChecker;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test cases for UuidSyntaxChecker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UuidSyntaxCheckerTest
+{
+    UuidSyntaxChecker checker = new UuidSyntaxChecker();
+
+
+    @Test
+    public void testNullUuid()
+    {
+        assertFalse( checker.isValidSyntax( null ) );
+    }
+
+
+    @Test
+    public void testEmptyUuid()
+    {
+        assertFalse( checker.isValidSyntax( StringConstants.EMPTY_BYTES ) );
+    }
+
+
+    @Test
+    public void testStringUuid()
+    {
+        assertFalse( checker.isValidSyntax( "01234567788ABCDEF" ) );
+    }
+
+
+    @Test
+    public void testCorrectUuid()
+    {
+        byte[] array = new byte[16];
+
+        for ( int i = 0; i < 16; i++ )
+        {
+            array[i] = ( byte ) i;
+        }
+
+        assertTrue( checker.isValidSyntax( Strings.uuidToString( array ) ) );
+    }
+
+
+    @Test
+    public void testWrongSizeUuid()
+    {
+        byte[] array = new byte[15];
+
+        for ( int i = 0; i < 15; i++ )
+        {
+            array[i] = ( byte ) i;
+        }
+
+        assertFalse( checker.isValidSyntax( array ) );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/AttributeTypeDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/AttributeTypeDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..1d7c67d
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/AttributeTypeDescriptionSchemaParserTest.java
@@ -0,0 +1,1125 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+import org.apache.directory.api.ldap.model.schema.parsers.AttributeTypeDescriptionSchemaParser;
+import org.apache.directory.api.ldap.model.schema.parsers.ConsoleParserMonitor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the AttributeTypeDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class AttributeTypeDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private AttributeTypeDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new AttributeTypeDescriptionSchemaParser();
+        parser.setParserMonitor( new ConsoleParserMonitor() );
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    /**
+     * Test numericoid
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "SYNTAX 1.1" );
+    }
+
+
+    /**
+     * Tests NAME and its values
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    /**
+     * Tests DESC
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    /**
+     * Tests OBSOLETE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testObsolete() throws ParseException
+    {
+        SchemaParserTestUtils.testObsolete( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    /**
+     * Test SUP and its value.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testSuperType() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // no SUP
+        value = "( 1.1 SYNTAX 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNull( attributeType.getSuperiorOid() );
+
+        // SUP numericoid
+        value = "( 1.1 SYNTAX 1.1 SUP 1.2.3.4.5.6.7.8.9.0 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", attributeType.getSuperiorOid() );
+
+        // SUP descr, no space
+        value = "(1.1 SYNTAX1.1 SUPabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getSuperiorOid() );
+
+        // SUP descr, newline
+        value = "\t(\t1.1\tSYNTAX\t1.1\tSUP\tabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789\t)\t";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getSuperiorOid() );
+
+        // quoted SUP value
+        value = "( 1.1 SYNTAX 1.1 SUP 'name' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "name", attributeType.getSuperiorOid() );
+
+        // quoted SUP value
+        value = "( 1.1 SYNTAX 1.1 SUP '1.2.3.4' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4", attributeType.getSuperiorOid() );
+
+        // quoted SUP value
+        value = "( 1.1 SYNTAX 1.1 SUP ('1.2.3.4') )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4", attributeType.getSuperiorOid() );
+
+        // invalid character
+        value = "( 1.1 SYNTAX 1.1 SUP 1.2.3.4.A )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid SUP '1.2.3.4.A' (invalid character)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // only single SUP allowed
+        value = "( 1.1 SYNTAX 1.1 SUP ( name1 $ name2 ) )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, only single SUP allowed" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // empty sup
+        value = "( 1.1 SYNTAX 1.1 SUP )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, no SUP value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests EQUALITY and its values.
+     * Very similar to SUP, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testEquality() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // no EQUALITY
+        value = "( 1.1 SYNTAX 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNull( attributeType.getEqualityOid() );
+
+        // EQUALITY numericoid
+        value = "( 1.1 SYNTAX 1.1 EQUALITY 1.2.3.4567.8.9.0 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getEqualityOid() );
+
+        // EQUALITY descr, no space
+        value = "(1.1 SYNTAX1.1 EQUALITYabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getEqualityOid() );
+
+        // EQUALITY descr, newline
+        value = "\n(\n1.1\nSYNTAX\n1.1\nEQUALITY\nabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789\n)\n";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getEqualityOid() );
+
+        // quoted value
+        value = "( 1.1 SYNTAX 1.1 EQUALITY 'caseExcactMatch' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "caseExcactMatch", attributeType.getEqualityOid() );
+
+        // quote value in parentheses 
+        value = "( 1.1 SYNTAX 1.1 EQUALITY ('caseExcactMatch') )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "caseExcactMatch", attributeType.getEqualityOid() );
+    }
+
+
+    /**
+     * Tests ORDERING and its values.
+     * Very similar to SUP, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testOrdering() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // no ORDERING
+        value = "( 1.1 SYNTAX 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNull( attributeType.getOrderingOid() );
+
+        // ORDERING numericoid
+        value = "( 1.1 SYNTAX 1.1 ORDERING 1.2.3.4567.8.9.0 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getOrderingOid() );
+
+        // ORDERING descr, no space
+        value = "(1.1 SYNTAX1.1 ORDERINGabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getOrderingOid() );
+
+        // ORDERING descr, newline
+        value = "\r(\r1.1\rSYNTAX\r1.1\rORDERING\rabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789\r)\r";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getOrderingOid() );
+
+        // quoted value
+        value = "( 1.1 SYNTAX 1.1 ORDERING 'generalizedTimeOrderingMatch' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "generalizedTimeOrderingMatch", attributeType.getOrderingOid() );
+
+        // quote value in parentheses
+        value = "( 1.1 SYNTAX 1.1 ORDERING ('generalizedTimeOrderingMatch') )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "generalizedTimeOrderingMatch", attributeType.getOrderingOid() );
+    }
+
+
+    /**
+     * Tests SUBSTRING and its values.
+     * Very similar to SUP, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testSubstring() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // no SUBSTR
+        value = "( 1.1 SYNTAX 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNull( attributeType.getSubstringOid() );
+
+        // SUBSTR numericoid
+        value = "( 1.1 SYNTAX 1.1 SUBSTR 1.2.3.4567.8.9.0 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getSubstringOid() );
+
+        // SUBSTR descr, no space
+        value = "(1.1 SYNTAX1.1 SUBSTRabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getSubstringOid() );
+
+        // SUBSTR descr, newline
+        value = "\r\n(\r\n1.1\r\nSYNTAX\r\n1.1\r\nSUBSTR\r\nabcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789\r\n)\r\n";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getSubstringOid() );
+
+        // quoted value
+        value = "( 1.1 SYNTAX 1.1 SUBSTR 'caseIgnoreSubstringsMatch' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "caseIgnoreSubstringsMatch", attributeType.getSubstringOid() );
+
+        // quote value in parentheses
+        value = "( 1.1 SYNTAX 1.1 SUBSTR ('caseIgnoreSubstringsMatch') )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "caseIgnoreSubstringsMatch", attributeType.getSubstringOid() );
+    }
+
+
+    /**
+     * Tests SYNTAX
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testSyntax() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // no SYNTAX
+        value = "( 1.1 SUP 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNull( attributeType.getSyntaxOid() );
+        assertEquals( 0, attributeType.getSyntaxLength() );
+
+        // SYNTAX string
+        value = "( 1.1 SYNTAX IA5String )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "IA5String", attributeType.getSyntaxOid() );
+        assertEquals( 0, attributeType.getSyntaxLength() );
+
+        // SYNTAX numericoid
+        value = "( 1.1 SYNTAX 1.2.3.4567.8.9.0 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getSyntaxOid() );
+        assertEquals( 0, attributeType.getSyntaxLength() );
+
+        // quoted numericoid
+        value = "( 1.1 SYNTAX '1.2.3.4567.8.9.0' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getSyntaxOid() );
+        assertEquals( 0, attributeType.getSyntaxLength() );
+
+        // quoted numericoid
+        value = "( 1.1 SYNTAX ('1.2.3.4567.8.9.0') )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getSyntaxOid() );
+        assertEquals( 0, attributeType.getSyntaxLength() );
+
+        // SYNTAX numericoid and length, no spaces
+        value = "(1.1 SYNTAX1.2.3.4567.8.9.0{1234567890})";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getSyntaxOid() );
+        assertEquals( 1234567890, attributeType.getSyntaxLength() );
+
+        // SYNTAX, with tabs
+        value = "\t(\t1.1\tSYNTAX\t1.2.3.4567.8.9.0\t{1234567890}\t)\t";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4567.8.9.0", attributeType.getSyntaxOid() );
+        assertEquals( 1234567890, attributeType.getSyntaxLength() );
+
+        // SYNTAX numericoid and zero length
+        value = "( 1.1 SYNTAX 1.2.3 {0} )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3", attributeType.getSyntaxOid() );
+        assertEquals( 0, attributeType.getSyntaxLength() );
+
+        // quoted value
+        value = "( 1.1 SYNTAX '1.2.3{32}' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3", attributeType.getSyntaxOid() );
+        assertEquals( 32, attributeType.getSyntaxLength() );
+
+        // quote value in parentheses
+        value = "( 1.1 SYNTAX ( '1.2.3{32}' ) )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3", attributeType.getSyntaxOid() );
+        assertEquals( 32, attributeType.getSyntaxLength() );
+
+        // empty length
+        value = "( 1.1 SYNTAX 1.2.3.4{} )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid SYNTAX 1.2.3.4{} (empty length)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // leading zero in length
+        value = "( 1.1 SYNTAX 1.2.3.4{01} )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( "1.2.3.4", attributeType.getSyntaxOid() );
+        assertEquals( 1, attributeType.getSyntaxLength() );
+
+        // invalid syntax length
+        value = "( 1.1 SYNTAX 1.2.3.4{X} )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid SYNTAX 1.2.3.4{X} (invalid length)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no syntax
+        value = "( 1.1 SYNTAX {32} )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid SYNTAX {32} (no syntax)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // length overflow
+        value = "( 1.1 SYNTAX 1.2.3.4{123456789012234567890} )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid SYNTAX 1.2.3.4{12345678901234567890} (length overflow)" );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests SINGLE-VALUE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testSingleValue() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // not single-value
+        value = "( 1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertFalse( attributeType.isSingleValued() );
+
+        // single-value
+        value = "(1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' SINGLE-VALUE)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertTrue( attributeType.isSingleValued() );
+
+        // single-value 
+        value = "(1.1 SYNTAX 1.1 SINGLE-VALUE)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertTrue( attributeType.isSingleValued() );
+
+        // invalid
+        value = "(1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' SINGLE-VALU )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid SINGLE-VALUE value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests COLLECTIVE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testCollective() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // not collective
+        value = "( 1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertFalse( attributeType.isCollective() );
+
+        // single-value
+        value = "(1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' COLLECTIVE )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertTrue( attributeType.isCollective() );
+
+        // single-value 
+        value = "(1.1 SYNTAX 1.1 COLLECTIVE)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertTrue( attributeType.isCollective() );
+
+        // ivalid
+        value = "(1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' COLLECTIV )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid COLLECTIVE value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests NO-USER-MODIFICATION
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNoUserModification() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // not NO-USER-MODIFICATION
+        value = "( 1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertTrue( attributeType.isUserModifiable() );
+
+        // NO-USER-MODIFICATION
+        value = "(1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' NO-USER-MODIFICATION USAGE directoryOperation )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertFalse( attributeType.isUserModifiable() );
+
+        // NO-USER-MODIFICATION 
+        value = "(1.1 SYNTAX 1.1 NO-USER-MODIFICATION USAGE directoryOperation )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertFalse( attributeType.isUserModifiable() );
+
+        // ivalid
+        value = "(1.1 SYNTAX 1.1 NAME 'test' DESC 'Descripton' NO-USER-MODIFICATIO USAGE directoryOperation )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid NO-USER-MODIFICATION value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests usage 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUsage() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        // DEFAULT is userApplications
+        value = "( 1.1 SYNTAX 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+
+        // userApplications
+        value = "( 1.1 SYNTAX 1.1 USAGE userApplications )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+
+        // directoryOperation
+        value = "( 1.1 SYNTAX 1.1 USAGE directoryOperation )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( UsageEnum.DIRECTORY_OPERATION, attributeType.getUsage() );
+
+        // distributedOperation, tabs
+        value = "\t(\t1.1\tSYNTAX\t1.1\tUSAGE\tdistributedOperation\t)\t";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( UsageEnum.DISTRIBUTED_OPERATION, attributeType.getUsage() );
+
+        // dSAOperation, no space
+        value = "(1.1 SYNTAX1.1 USAGEdSAOperation)";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( UsageEnum.DSA_OPERATION, attributeType.getUsage() );
+
+        // directoryOperation, case insensitivity
+        value = "( 1.1 SYNTAX 1.1 USAGE DiReCtOrYoPeRaTiOn )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertEquals( UsageEnum.DIRECTORY_OPERATION, attributeType.getUsage() );
+
+        // ivalid
+        value = "( 1.1 SYNTAX 1.1 USAGE abc )";
+        try
+        {
+            attributeType = parser.parseAttributeTypeDescription( value );
+            fail( "Exception expected, invalid USAGE value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Test extensions.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    /**
+     * Test full attribute type description.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testFull() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE SUP abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 EQUALITY 2.3.4.5.6.7.8.9.0.1 ORDERING 3.4.5.6.7.8.9.0.1.2 SUBSTR 4.5.6.7.8.9.0.1.2.3 SYNTAX 5.6.7.8.9.0.1.2.3.4{1234567890} SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", attributeType.getOid() );
+        assertEquals( 2, attributeType.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType.getNames().get(
+            0 ) );
+        assertEquals( "test", attributeType.getNames().get( 1 ) );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", attributeType.getDescription() );
+        assertTrue( attributeType.isObsolete() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", attributeType
+            .getSuperiorOid() );
+        assertEquals( "2.3.4.5.6.7.8.9.0.1", attributeType.getEqualityOid() );
+        assertEquals( "3.4.5.6.7.8.9.0.1.2", attributeType.getOrderingOid() );
+        assertEquals( "4.5.6.7.8.9.0.1.2.3", attributeType.getSubstringOid() );
+        assertEquals( "5.6.7.8.9.0.1.2.3.4", attributeType.getSyntaxOid() );
+        assertEquals( 1234567890, attributeType.getSyntaxLength() );
+
+        assertTrue( attributeType.isSingleValued() );
+        assertFalse( attributeType.isCollective() );
+        assertFalse( attributeType.isUserModifiable() );
+        assertEquals( UsageEnum.DSA_OPERATION, attributeType.getUsage() );
+
+        assertEquals( 2, attributeType.getExtensions().size() );
+        assertNotNull( attributeType.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, attributeType.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", attributeType.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", attributeType.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( attributeType.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, attributeType.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", attributeType.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", attributeType.getExtension( "X-TEST-b" ).get( 1 ) );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1.1 SYNTAX 1.1 NAME 'test1' NAME 'test2' )", "( 1.1 SYNTAX 1.1 DESC 'test1' DESC 'test2' )",
+                "( 1.1 SYNTAX 1.1 OBSOLETE OBSOLETE )", "( 1.1 SYNTAX 1.1 SUP test1 SUP test2 )",
+                "( 1.1 SYNTAX 1.1 EQUALITY test1 EQUALITY test2 )", "( 1.1 SYNTAX 1.1 ORDERING test1 ORDERING test2 )",
+                "( 1.1 SYNTAX 1.1 SUBSTR test1 SUBSTR test2 )", "( 1.1 SYNTAX 1.1 SYNTAX 2.2 SYNTAX 3.3 )",
+                "( 1.1 SYNTAX 1.1 SINGLE-VALUE SINGLE-VALUE )", "( 1.1 SYNTAX 1.1 COLLECTIVE COLLECTIVE )",
+                "( 1.1 SYNTAX 1.1 USAGE directoryOperation NO-USER-MODIFICATION NO-USER-MODIFICATION )",
+                "( 1.1 SYNTAX 1.1 USAGE directoryOperation USAGE userApplications )",
+                "( 1.1 SYNTAX 1.1 X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 SYNTAX 1.1 SUP 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNotNull( attributeType.getSyntaxOid() );
+        assertNotNull( attributeType.getSuperiorOid() );
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 SYNTAX 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNotNull( attributeType.getSyntaxOid() );
+        assertNull( attributeType.getSuperiorOid() );
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 SUP 1.1 )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertNull( attributeType.getSyntaxOid() );
+        assertNotNull( attributeType.getSuperiorOid() );
+
+        if ( !parser.isQuirksMode() )
+        {
+            value = "( 1.2.3.4.5.6.7.8.9.0 )";
+            try
+            {
+                parser.parseAttributeTypeDescription( value );
+                fail( "Exception expected, SYNTAX or SUP is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test collective constraint:
+     * COLLECTIVE requires USAGE userApplications
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testCollecitveConstraint() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        value = "( 1.1 SYNTAX 1.1 COLLECTIVE )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertTrue( attributeType.isCollective() );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+
+        value = "( 1.1 SYNTAX 1.1 COLLECTIVE USAGE userApplications )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertTrue( attributeType.isCollective() );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+
+        if ( !parser.isQuirksMode() )
+        {
+            value = "( 1.1 SYNTAX 1.1 COLLECTIVE USAGE directoryOperation )";
+            try
+            {
+                parser.parseAttributeTypeDescription( value );
+                fail( "Exception expected, COLLECTIVE requires USAGE userApplications" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            value = "( 1.1 SYNTAX 1.1 COLLECTIVE USAGE dSAOperation )";
+            try
+            {
+                parser.parseAttributeTypeDescription( value );
+                fail( "Exception expected, COLLECTIVE requires USAGE userApplications" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            value = "( 1.1 SYNTAX 1.1 COLLECTIVE USAGE distributedOperation )";
+            try
+            {
+                parser.parseAttributeTypeDescription( value );
+                fail( "Exception expected, COLLECTIVE requires USAGE userApplications" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test no-user-modification constraint:
+     * NO-USER-MODIFICATION requires an operational USAGE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNoUserModificatonConstraint() throws ParseException
+    {
+        String value = null;
+        AttributeType attributeType = null;
+
+        value = "( 1.1 SYNTAX 1.1 NO-USER-MODIFICATION USAGE directoryOperation )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertFalse( attributeType.isUserModifiable() );
+        assertEquals( UsageEnum.DIRECTORY_OPERATION, attributeType.getUsage() );
+
+        value = "( 1.1 SYNTAX 1.1 NO-USER-MODIFICATION USAGE dSAOperation )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertFalse( attributeType.isUserModifiable() );
+        assertEquals( UsageEnum.DSA_OPERATION, attributeType.getUsage() );
+
+        value = "( 1.1 SYNTAX 1.1 NO-USER-MODIFICATION USAGE distributedOperation )";
+        attributeType = parser.parseAttributeTypeDescription( value );
+        assertFalse( attributeType.isUserModifiable() );
+        assertEquals( UsageEnum.DISTRIBUTED_OPERATION, attributeType.getUsage() );
+
+        if ( !parser.isQuirksMode() )
+        {
+            value = "( 1.1 SYNTAX 1.1 NO-USER-MODIFICATION USAGE userApplications )";
+            try
+            {
+                parser.parseAttributeTypeDescription( value );
+                fail( "Exception expected, NO-USER-MODIFICATION requires an operational USAGE" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            value = "( 1.1 SYNTAX 1.1 NO-USER-MODIFICATION )";
+            try
+            {
+                parser.parseAttributeTypeDescription( value );
+                fail( "Exception expected, NO-USER-MODIFICATION requires an operational USAGE" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Ensure that element order is ignored
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testIgnoreElementOrder() throws ParseException
+    {
+        String value = "( 2.5.4.3 SUP name SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications DESC 'RFC2256: common name(s) for which the entity is known by'  EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch NAME ( 'cn' 'commonName' )  )";
+        AttributeType attributeType = parser.parseAttributeTypeDescription( value );
+
+        assertEquals( "2.5.4.3", attributeType.getOid() );
+        assertEquals( 2, attributeType.getNames().size() );
+        assertEquals( "cn", attributeType.getNames().get( 0 ) );
+        assertEquals( "commonName", attributeType.getNames().get( 1 ) );
+        assertEquals( "RFC2256: common name(s) for which the entity is known by", attributeType.getDescription() );
+        assertEquals( "name", attributeType.getSuperiorOid() );
+        assertEquals( "caseIgnoreMatch", attributeType.getEqualityOid() );
+        assertEquals( "caseIgnoreSubstringsMatch", attributeType.getSubstringOid() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", attributeType.getSyntaxOid() );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+        assertEquals( 0, attributeType.getExtensions().size() );
+    }
+
+
+    ////////////////////////////////////////////////////////////////
+    //         Some real-world attribute type definitions         //
+    ////////////////////////////////////////////////////////////////
+
+    @Test
+    public void testRfcUid() throws ParseException
+    {
+        String value = "( 0.9.2342.19200300.100.1.1 NAME ( 'uid' 'userid' ) DESC 'RFC1274: user identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} USAGE userApplications )";
+        AttributeType attributeType = parser.parseAttributeTypeDescription( value );
+
+        assertEquals( "0.9.2342.19200300.100.1.1", attributeType.getOid() );
+        assertEquals( 2, attributeType.getNames().size() );
+        assertEquals( "uid", attributeType.getNames().get( 0 ) );
+        assertEquals( "userid", attributeType.getNames().get( 1 ) );
+        assertEquals( "RFC1274: user identifier", attributeType.getDescription() );
+        assertNull( attributeType.getSuperiorOid() );
+
+        assertEquals( "caseIgnoreMatch", attributeType.getEqualityOid() );
+        assertEquals( "caseIgnoreSubstringsMatch", attributeType.getSubstringOid() );
+        assertNull( attributeType.getOrderingOid() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", attributeType.getSyntaxOid() );
+        assertEquals( 256, attributeType.getSyntaxLength() );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+
+        assertFalse( attributeType.isObsolete() );
+        assertFalse( attributeType.isCollective() );
+        assertFalse( attributeType.isSingleValued() );
+        assertTrue( attributeType.isUserModifiable() );
+
+        assertEquals( 0, attributeType.getExtensions().size() );
+    }
+
+
+    /**
+     * Tests the parse of a simple AttributeType
+     */
+    @Test
+    public void testAddAttributeType() throws ParseException
+    {
+        String substrate = "( 1.3.6.1.4.1.18060.0.4.0.2.10000 NAME ( 'bogus' 'bogusName' ) "
+            + "DESC 'bogus description' SUP name SINGLE-VALUE )";
+        AttributeType desc = parser.parseAttributeTypeDescription( substrate );
+        assertEquals( "1.3.6.1.4.1.18060.0.4.0.2.10000", desc.getOid() );
+        assertEquals( "bogus", desc.getNames().get( 0 ) );
+        assertEquals( "bogusName", desc.getNames().get( 1 ) );
+        assertEquals( "bogus description", desc.getDescription() );
+        assertEquals( "name", desc.getSuperiorOid() );
+        assertEquals( true, desc.isSingleValued() );
+    }
+
+
+    /**
+     * Tests the parse of a simple AttributeType with the schema extension.
+     */
+    @Test
+    public void testAttributeTypeWithSchemaExtension() throws ParseException
+    {
+        String substrate = "( 1.3.6.1.4.1.18060.0.4.0.2.10000 NAME ( 'bogus' 'bogusName' ) "
+            + "DESC 'bogus description' SUP name SINGLE-VALUE X-SCHEMA 'blah' )";
+        AttributeType desc = parser.parseAttributeTypeDescription( substrate );
+        assertEquals( "1.3.6.1.4.1.18060.0.4.0.2.10000", desc.getOid() );
+        assertEquals( "bogus", desc.getNames().get( 0 ) );
+        assertEquals( "bogusName", desc.getNames().get( 1 ) );
+        assertEquals( "bogus description", desc.getDescription() );
+        assertEquals( "name", desc.getSuperiorOid() );
+        assertEquals( true, desc.isSingleValued() );
+        assertEquals( "blah", desc.getExtension( "X-SCHEMA" ).get( 0 ) );
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1.1 SYNTAX 1.1 )",
+                "( 2.5.4.41 NAME 'name' DESC 'RFC2256: common supertype of name attributes'  EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} USAGE userApplications )",
+                "( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by'  SUP name EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE SUP abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 EQUALITY 2.3.4.5.6.7.8.9.0.1 ORDERING 3.4.5.6.7.8.9.0.1.2 SUBSTR 4.5.6.7.8.9.0.1.2.3 SYNTAX 5.6.7.8.9.0.1.2.3.4{1234567890} SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "SYNTAX 1.1" );
+
+        try
+        {
+            String value = null;
+            AttributeType attributeType = null;
+
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testNames();
+            testDescription();
+            testObsolete();
+            testSuperType();
+            testEquality();
+            testOrdering();
+            testSubstring();
+            testSyntax();
+            testSingleValue();
+            testCollective();
+            testNoUserModification();
+            testUsage();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testRequiredElements();
+            testCollecitveConstraint();
+            testNoUserModificatonConstraint();
+            testIgnoreElementOrder();
+            testRfcUid();
+            testAddAttributeType();
+            testMultiThreaded();
+
+            // NAME with special chars
+            value = "( 1.2.3 SYNTAX te_st NAME 't-e_s.t;' )";
+            attributeType = parser.parseAttributeTypeDescription( value );
+            assertEquals( 1, attributeType.getNames().size() );
+            assertEquals( "t-e_s.t;", attributeType.getNames().get( 0 ) );
+
+            // SYNTAX with underscore
+            value = "( 1.1 SYNTAX te_st )";
+            attributeType = parser.parseAttributeTypeDescription( value );
+            assertEquals( "te_st", attributeType.getSyntaxOid() );
+
+            // SUPERTYPE with underscore
+            value = "( 1.1 SYNTAX 1.1 SUP te_st )";
+            attributeType = parser.parseAttributeTypeDescription( value );
+            assertEquals( "te_st", attributeType.getSuperiorOid() );
+
+            // EQUALITY with underscore
+            value = "( 1.1 SYNTAX 1.1 EQUALITY te_st )";
+            attributeType = parser.parseAttributeTypeDescription( value );
+            assertEquals( "te_st", attributeType.getEqualityOid() );
+
+            // SUBSTR with underscore
+            value = "( 1.1 SYNTAX 1.1 SUBSTR te_st )";
+            attributeType = parser.parseAttributeTypeDescription( value );
+            assertEquals( "te_st", attributeType.getSubstringOid() );
+
+            // ORDERING with underscore
+            value = "( 1.1 SYNTAX 1.1 ORDERING te_st )";
+            attributeType = parser.parseAttributeTypeDescription( value );
+            assertEquals( "te_st", attributeType.getOrderingOid() );
+
+            // Netscape attribute 
+            value = "( nsAdminGroupName-oid NAME 'nsAdminGroupName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )";
+            attributeType = parser.parseAttributeTypeDescription( value );
+            assertEquals( "nsAdminGroupName-oid", attributeType.getOid() );
+            assertEquals( 1, attributeType.getNames().size() );
+            assertEquals( "nsAdminGroupName", attributeType.getNames().get( 0 ) );
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+
+    /**
+     * Tests without EQUALITY
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNoqualityMR() throws ParseException
+    {
+        String value = "( 2.5.4.58 NAME 'attributeCertificateAttribute' " + "DESC 'attribute certificate use ;binary' "
+            + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 ) ";
+        AttributeType attributeType = parser.parseAttributeTypeDescription( value );
+
+        assertEquals( "2.5.4.58", attributeType.getOid() );
+        assertEquals( 1, attributeType.getNames().size() );
+        assertEquals( "attributeCertificateAttribute", attributeType.getNames().get( 0 ) );
+        assertEquals( "attribute certificate use ;binary", attributeType.getDescription() );
+        assertNull( attributeType.getSuperiorOid() );
+        assertNull( attributeType.getEqualityOid() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.8", attributeType.getSyntaxOid() );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+        assertEquals( 0, attributeType.getExtensions().size() );
+    }
+
+
+    /**
+     * Tests with spaces in DESC
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testATWithSpacesInDesc() throws ParseException
+    {
+        String value = "( 1.3.18.0.2.4.216 NAME 'SAFDfpDataClass' DESC '  ' " +
+            "EQUALITY 2.5.13.2 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )";
+        AttributeType attributeType = parser.parseAttributeTypeDescription( value );
+
+        assertEquals( "1.3.18.0.2.4.216", attributeType.getOid() );
+        assertEquals( 1, attributeType.getNames().size() );
+        assertEquals( "SAFDfpDataClass", attributeType.getNames().get( 0 ) );
+        assertEquals( "  ", attributeType.getDescription() );
+        assertNull( attributeType.getSuperiorOid() );
+        assertEquals( "2.5.13.2", attributeType.getEqualityOid() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", attributeType.getSyntaxOid() );
+        assertEquals( UsageEnum.USER_APPLICATIONS, attributeType.getUsage() );
+        assertTrue( attributeType.isSingleValued() );
+        assertEquals( 0, attributeType.getExtensions().size() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/ComparatorDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/ComparatorDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..e803284
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/ComparatorDescriptionSchemaParserTest.java
@@ -0,0 +1,199 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.text.ParseException;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the ComparatorDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ComparatorDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private LdapComparatorDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new LdapComparatorDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "FQCN org.apache.directory.SimpleComparator" );
+    }
+
+
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "FQCN org.apache.directory.SimpleComparator" );
+    }
+
+
+    @Test
+    public void testFqcn() throws ParseException
+    {
+        String value = null;
+        LdapComparatorDescription ldapComparatorDescription = null;
+
+        // FQCN simple
+        value = "( 1.1 FQCN org.apache.directory.SimpleComparator )";
+        ldapComparatorDescription = parser.parseComparatorDescription( value );
+        assertNotNull( ldapComparatorDescription.getFqcn() );
+        assertEquals( "org.apache.directory.SimpleComparator", ldapComparatorDescription.getFqcn() );
+    }
+
+
+    @Test
+    public void testBytecode() throws ParseException
+    {
+        String value = null;
+        LdapComparatorDescription ldapComparatorDescription = null;
+
+        // FQCN simple p
+        value = "( 1.1 FQCN org.apache.directory.SimpleComparator BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        ldapComparatorDescription = parser.parseComparatorDescription( value );
+        assertNotNull( ldapComparatorDescription.getBytecode() );
+        assertEquals( "ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789====", ldapComparatorDescription
+            .getBytecode() );
+
+        // FQCN simple, no spaces
+        value = "(1.1 FQCNorg.apache.directory.SimpleComparator BYTECODEABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789====)";
+        ldapComparatorDescription = parser.parseComparatorDescription( value );
+        assertNotNull( ldapComparatorDescription.getBytecode() );
+        assertEquals( "ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789====", ldapComparatorDescription
+            .getBytecode() );
+
+        // FQCN simple, tabs
+        value = "\t(\t1.1\tFQCN\torg.apache.directory.SimpleComparator\tBYTECODE\tABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789====\t)\t";
+        ldapComparatorDescription = parser.parseComparatorDescription( value );
+        assertNotNull( ldapComparatorDescription.getBytecode() );
+        assertEquals( "ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789====", ldapComparatorDescription
+            .getBytecode() );
+    }
+
+
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "FQCN org.apache.directory.SimpleComparator" );
+    }
+
+
+    @Test
+    public void testFull()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        // TODO
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "FQCN org.apache.directory.SimpleComparator" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testDescription();
+            testFqcn();
+            testBytecode();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/DitContentRuleDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/DitContentRuleDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..75bf4d9
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/DitContentRuleDescriptionSchemaParserTest.java
@@ -0,0 +1,541 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.schema.DitContentRule;
+import org.apache.directory.api.ldap.model.schema.parsers.DitContentRuleDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the DitContentRuleDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DitContentRuleDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private DitContentRuleDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new DitContentRuleDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    /**
+     * Test numericoid
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "" );
+    }
+
+
+    /**
+     * Tests NAME and its values
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Tests DESC
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Tests OBSOLETE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testObsolete() throws ParseException
+    {
+        SchemaParserTestUtils.testObsolete( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Test AUX and its values.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testAux() throws ParseException
+    {
+        String value = null;
+        DitContentRule ditContentRule = null;
+
+        // no AUX
+        value = "( 1.1 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 0, ditContentRule.getAuxObjectClassOids().size() );
+
+        // AUX simple numericoid
+        value = "( 1.1 AUX 1.2.3 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "1.2.3", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+
+        // AUX simple descr
+        value = "( 1.1 AUX top )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "top", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+
+        // AUX single numericoid
+        value = "( 1.1 AUX ( 1.2.3.4.5 ) )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "1.2.3.4.5", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+
+        // AUX single descr
+        value = "( 1.1 AUX ( A-Z-0-9 ) )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "A-Z-0-9", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+
+        // AUX multi numericoid
+        value = "( 1.1 AUX ( 1.2.3 $ 1.2.3.4.5 ) )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 2, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "1.2.3", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+        assertEquals( "1.2.3.4.5", ditContentRule.getAuxObjectClassOids().get( 1 ) );
+
+        // AUX multi descr
+        value = "( 1.1 AUX ( top1 $ top2 ) )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 2, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "top1", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+        assertEquals( "top2", ditContentRule.getAuxObjectClassOids().get( 1 ) );
+
+        // AUX multi mixed
+        value = "( 1.1 AUX ( top1 $ 1.2.3.4 $ top2 ) )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 3, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "top1", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+        assertEquals( "1.2.3.4", ditContentRule.getAuxObjectClassOids().get( 1 ) );
+        assertEquals( "top2", ditContentRule.getAuxObjectClassOids().get( 2 ) );
+
+        // AUX multi mixed no space
+        value = "(1.1 AUX(TOP-1$1.2.3.4$TOP-2))";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 3, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "TOP-1", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+        assertEquals( "1.2.3.4", ditContentRule.getAuxObjectClassOids().get( 1 ) );
+        assertEquals( "TOP-2", ditContentRule.getAuxObjectClassOids().get( 2 ) );
+
+        // AUX multi mixed many spaces
+        value = "(          1.1          AUX          (          top1          $          1.2.3.4$top2          )          )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 3, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "top1", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+        assertEquals( "1.2.3.4", ditContentRule.getAuxObjectClassOids().get( 1 ) );
+        assertEquals( "top2", ditContentRule.getAuxObjectClassOids().get( 2 ) );
+
+        // no quote allowed
+        value = "( 1.1 AUX 'top' )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "top", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+
+        // quoted value
+        value = "( 1.1 AUX '1.2.3.4' )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "1.2.3.4", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+
+        // no $ separator
+        value = "( 1.1 AUX ( top1 top2 ) )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 2, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "top1", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+        assertEquals( "top2", ditContentRule.getAuxObjectClassOids().get( 1 ) );
+
+        // invalid character
+        value = "( 1.1 AUX 1.2.3.4.A )";
+        try
+        {
+            ditContentRule = parser.parseDITContentRuleDescription( value );
+            fail( "Exception expected, invalid AUX '1.2.3.4.A' (invalid character)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // empty AUX
+        value = "( 1.1 AUX )";
+        try
+        {
+            ditContentRule = parser.parseDITContentRuleDescription( value );
+            fail( "Exception expected, no AUX value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid start
+            value = "( 1.1 AUX ( top1 $ -top2 ) )";
+            try
+            {
+                ditContentRule = parser.parseDITContentRuleDescription( value );
+                fail( "Exception expected, invalid AUX '-top' (starts with hypen)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test MUST and its values.
+     * Very similar to AUX, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testMust() throws ParseException
+    {
+        String value = null;
+        DitContentRule ditContentRule = null;
+
+        // no MUST
+        value = "( 1.1 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 0, ditContentRule.getMustAttributeTypeOids().size() );
+
+        // MUST simple numericoid
+        value = "( 1.1 MUST 1.2.3 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getMustAttributeTypeOids().size() );
+        assertEquals( "1.2.3", ditContentRule.getMustAttributeTypeOids().get( 0 ) );
+
+        // MUST mulitple
+        value = "(1.1 MUST (cn\rsn       $11.22.33.44.55            objectClass\t))";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 4, ditContentRule.getMustAttributeTypeOids().size() );
+        assertEquals( "cn", ditContentRule.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", ditContentRule.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", ditContentRule.getMustAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", ditContentRule.getMustAttributeTypeOids().get( 3 ) );
+
+        // no MUST values
+        value = "( 1.1 MUST )";
+        try
+        {
+            ditContentRule = parser.parseDITContentRuleDescription( value );
+            fail( "Exception expected, no MUST value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid value
+            value = "( 1.1 MUST ( c_n ) )";
+            try
+            {
+                ditContentRule = parser.parseDITContentRuleDescription( value );
+                fail( "Exception expected, invalid value c_n" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test MAY and its values.
+     * Very similar to AUX, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testMay() throws ParseException
+    {
+        String value = null;
+        DitContentRule ditContentRule = null;
+
+        // no MAY
+        value = "( 1.1 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 0, ditContentRule.getMayAttributeTypeOids().size() );
+
+        // MAY simple numericoid
+        value = "( 1.1 MAY 1.2.3 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getMayAttributeTypeOids().size() );
+        assertEquals( "1.2.3", ditContentRule.getMayAttributeTypeOids().get( 0 ) );
+
+        // MAY mulitple
+        value = "(1.1 MAY (cn$sn       $11.22.33.44.55         $  objectClass   ))";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 4, ditContentRule.getMayAttributeTypeOids().size() );
+        assertEquals( "cn", ditContentRule.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", ditContentRule.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", ditContentRule.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", ditContentRule.getMayAttributeTypeOids().get( 3 ) );
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid value
+            value = "( 1.1 MAY ( c_n ) )";
+            try
+            {
+                ditContentRule = parser.parseDITContentRuleDescription( value );
+                fail( "Exception expected, invalid value c_n" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test NOT and its values.
+     * Very similar to AUX, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNot() throws ParseException
+    {
+        String value = null;
+        DitContentRule ditContentRule = null;
+
+        // no NOT
+        value = "( 1.1 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 0, ditContentRule.getNotAttributeTypeOids().size() );
+
+        // NOT simple numericoid
+        value = "( 1.1 NOT 1.2.3 )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 1, ditContentRule.getNotAttributeTypeOids().size() );
+        assertEquals( "1.2.3", ditContentRule.getNotAttributeTypeOids().get( 0 ) );
+
+        // NOT mulitple
+        value = "(1.1 NOT (cn\nsn\t$11.22.33.44.55         $  objectClass   ))";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+        assertEquals( 4, ditContentRule.getNotAttributeTypeOids().size() );
+        assertEquals( "cn", ditContentRule.getNotAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", ditContentRule.getNotAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", ditContentRule.getNotAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", ditContentRule.getNotAttributeTypeOids().get( 3 ) );
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid value
+            value = "( 1.1 NOT ( c_n ) )";
+            try
+            {
+                ditContentRule = parser.parseDITContentRuleDescription( value );
+                fail( "Exception expected, invalid value c_n" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test extensions.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "" );
+
+    }
+
+
+    /**
+     * Test full object class description.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testFull() throws ParseException
+    {
+        String value = null;
+        DitContentRule ditContentRule = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE AUX ( 2.3.4.5.6.7.8.9.0.1 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) MUST ( 3.4.5.6.7.8.9.0.1.2 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) MAY ( 4.5.6.7.8.9.0.1.2.3 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) NOT ( 5.6.7.8.9.0.1.2.3.4 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        ditContentRule = parser.parseDITContentRuleDescription( value );
+
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", ditContentRule.getOid() );
+        assertEquals( 2, ditContentRule.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", ditContentRule.getNames()
+            .get( 0 ) );
+        assertEquals( "test", ditContentRule.getNames().get( 1 ) );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", ditContentRule.getDescription() );
+        assertTrue( ditContentRule.isObsolete() );
+        assertEquals( 2, ditContentRule.getAuxObjectClassOids().size() );
+        assertEquals( "2.3.4.5.6.7.8.9.0.1", ditContentRule.getAuxObjectClassOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", ditContentRule
+            .getAuxObjectClassOids().get( 1 ) );
+        assertEquals( 2, ditContentRule.getMustAttributeTypeOids().size() );
+        assertEquals( "3.4.5.6.7.8.9.0.1.2", ditContentRule.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", ditContentRule
+            .getMustAttributeTypeOids()
+            .get( 1 ) );
+        assertEquals( 2, ditContentRule.getMayAttributeTypeOids().size() );
+        assertEquals( "4.5.6.7.8.9.0.1.2.3", ditContentRule.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", ditContentRule
+            .getMayAttributeTypeOids()
+            .get( 1 ) );
+        assertEquals( 2, ditContentRule.getNotAttributeTypeOids().size() );
+        assertEquals( "5.6.7.8.9.0.1.2.3.4", ditContentRule.getNotAttributeTypeOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", ditContentRule
+            .getNotAttributeTypeOids()
+            .get( 1 ) );
+        assertEquals( 2, ditContentRule.getExtensions().size() );
+        assertNotNull( ditContentRule.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, ditContentRule.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", ditContentRule.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", ditContentRule.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( ditContentRule.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, ditContentRule.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", ditContentRule.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", ditContentRule.getExtension( "X-TEST-b" ).get( 1 ) );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1.1 NAME 'test1' NAME 'test2' )", "( 1.1 DESC 'test1' DESC 'test2' )", "( 1.1 OBSOLETE OBSOLETE )",
+                "( 1.1 AUX test1 AUX test2 )", "( 1.1 MUST test1 MUST test2 )", "( 1.1 MAY test1 MAY test2 )",
+                "( 1.1 NOT test1 NOT test2 )", "( 1.1 X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1.1 )",
+                "( 2.5.6.4 DESC 'content rule for organization' NOT ( x121Address $ telexNumber ) )",
+                "( 2.5.6.4 DESC 'content rule for organization' NOT ( x121Address $ telexNumber ) )",
+                "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE AUX ( 2.3.4.5.6.7.8.9.0.1 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) MUST ( 3.4.5.6.7.8.9.0.1.2 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) MAY ( 4.5.6.7.8.9.0.1.2.3 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) NOT ( 5.6.7.8.9.0.1.2.3.4 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testDescription();
+            testObsolete();
+            testAux();
+            testMust();
+            testMay();
+            testNot();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/DitStructureRuleDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/DitStructureRuleDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..9b84a8a
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/DitStructureRuleDescriptionSchemaParserTest.java
@@ -0,0 +1,483 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.schema.DitStructureRule;
+import org.apache.directory.api.ldap.model.schema.parsers.DitStructureRuleDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the DitStructureRuleDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class DitStructureRuleDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private DitStructureRuleDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new DitStructureRuleDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    /**
+     * Test ruleid
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNumericRuleId() throws ParseException
+    {
+        String value = null;
+        DitStructureRule ditStructureRule = null;
+
+        // null test
+        value = null;
+        try
+        {
+            parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, null" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no ruleid
+        value = "( )";
+        try
+        {
+            parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, no ruleid" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // simple
+        value = "( 1 FORM 1.1 )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( 1, ditStructureRule.getRuleId() );
+
+        // simple
+        value = "( 1234567890 FORM 1.1 )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( 1234567890, ditStructureRule.getRuleId() );
+
+        // simple with spaces
+        value = "(      1234567890   FORM   1.1     )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( 1234567890, ditStructureRule.getRuleId() );
+
+        // non-numeric not allowed
+        value = "( test FORM 1.1 )";
+        try
+        {
+            parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, invalid ruleid test (non-numeric)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // oid not allowed
+        value = "( 1.2.3.4 FORM 1.1 )";
+        try
+        {
+            parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, invalid ruleid 1.2.3.4 (oid)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // quotes not allowed
+        value = "( '1234567890' FORM 1.1 )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, invalid ruleid '1234567890' (quoted)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+    }
+
+
+    /**
+     * Tests NAME and its values
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1", "FORM 1.1" );
+    }
+
+
+    /**
+     * Tests DESC
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1", "FORM 1.1" );
+    }
+
+
+    /**
+     * Tests OBSOLETE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testObsolete() throws ParseException
+    {
+        SchemaParserTestUtils.testObsolete( parser, "1", "FORM 1.1" );
+    }
+
+
+    /**
+     * Tests FORM
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testForm() throws ParseException
+    {
+        String value = null;
+        DitStructureRule ditStructureRule = null;
+
+        // numeric oid
+        value = "( 1 FORM 1.2.3.4.5.6.7.8.9.0 )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", ditStructureRule.getForm() );
+
+        // numeric oid
+        value = "(   1    FORM    123.4567.890    )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( "123.4567.890", ditStructureRule.getForm() );
+
+        // descr
+        value = "( 1 FORM abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", ditStructureRule.getForm() );
+
+        // descr, no space
+        value = "(1 FORMabc)";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( "abc", ditStructureRule.getForm() );
+
+        // descr, tab
+        value = "\t(\t1\tFORM\tabc\t)\t";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( "abc", ditStructureRule.getForm() );
+
+        // quoted value
+        value = "( 1 FORM '1.2.3.4.5.6.7.8.9.0' )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", ditStructureRule.getForm() );
+
+        // no quote allowed
+        value = "( 1 FORM ('test') )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( "test", ditStructureRule.getForm() );
+
+        // invalid character
+        value = "( 1 FORM 1.2.3.4.A )";
+        try
+        {
+            ditStructureRule = parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, invalid FORM 1.2.3.4.A (invalid character)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no multiple values
+        value = "( 1 FORM ( test1 test2 ) )";
+        try
+        {
+            ditStructureRule = parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, FORM must be single valued" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid start
+            value = "( 1 FORM -test ) )";
+            try
+            {
+                ditStructureRule = parser.parseDITStructureRuleDescription( value );
+                fail( "Exception expected, invalid FORM '-test' (starts with hypen)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Tests SUP
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testSup() throws ParseException
+    {
+        String value = null;
+        DitStructureRule ditStructureRule = null;
+
+        // no SUP
+        value = "( 1 FORM 1.1 )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( 0, ditStructureRule.getSuperRules().size() );
+
+        // SUP simple number
+        value = "( 1 FORM 1.1 SUP 1 )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( 1, ditStructureRule.getSuperRules().size() );
+        assertEquals( Integer.valueOf( 1 ), ditStructureRule.getSuperRules().get( 0 ) );
+
+        // SUP single number
+        value = "( 1 FORM 1.1 SUP ( 1 ) )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( 1, ditStructureRule.getSuperRules().size() );
+        assertEquals( Integer.valueOf( 1 ), ditStructureRule.getSuperRules().get( 0 ) );
+
+        // SUP multi number
+        value = "( 1 FORM 1.1 SUP(12345 67890))";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertEquals( 2, ditStructureRule.getSuperRules().size() );
+        assertEquals( Integer.valueOf( 12345 ), ditStructureRule.getSuperRules().get( 0 ) );
+        assertEquals( Integer.valueOf( 67890 ), ditStructureRule.getSuperRules().get( 1 ) );
+
+        // non-numeric not allowed
+        value = "( 1 FORM 1.1 SUP test )";
+        try
+        {
+            parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, invalid SUP test (non-numeric)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // oid not allowed
+        value = "( 1 FORM 1.1 SUP 1.2.3.4 )";
+        try
+        {
+            parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, invalid SUP 1.2.3.4 (oid)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+    }
+
+
+    /**
+     * Test extensions.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1", "FORM 1.1" );
+
+    }
+
+
+    /**
+     * Test full object class description.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testFull() throws ParseException
+    {
+        String value = null;
+        DitStructureRule ditStructureRule = null;
+
+        value = "( 1234567890 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE FORM 2.3.4.5.6.7.8.9.0.1 SUP ( 1 1234567890 5 ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+
+        assertEquals( 1234567890, ditStructureRule.getRuleId() );
+        assertEquals( 2, ditStructureRule.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", ditStructureRule.getNames()
+            .get( 0 ) );
+        assertEquals( "test", ditStructureRule.getNames().get( 1 ) );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", ditStructureRule.getDescription() );
+        assertTrue( ditStructureRule.isObsolete() );
+        assertEquals( "2.3.4.5.6.7.8.9.0.1", ditStructureRule.getForm() );
+        assertEquals( 3, ditStructureRule.getSuperRules().size() );
+        assertEquals( Integer.valueOf( 1 ), ditStructureRule.getSuperRules().get( 0 ) );
+        assertEquals( Integer.valueOf( 1234567890 ), ditStructureRule.getSuperRules().get( 1 ) );
+        assertEquals( Integer.valueOf( 5 ), ditStructureRule.getSuperRules().get( 2 ) );
+        assertEquals( 2, ditStructureRule.getExtensions().size() );
+        assertNotNull( ditStructureRule.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, ditStructureRule.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", ditStructureRule.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", ditStructureRule.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( ditStructureRule.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, ditStructureRule.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", ditStructureRule.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", ditStructureRule.getExtension( "X-TEST-b" ).get( 1 ) );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1 FORM 1.1 NAME 'test1' NAME 'test2' )", "( 1 FORM 1.1 DESC 'test1' DESC 'test2' )",
+                "( 1 FORM 1.1 OBSOLETE OBSOLETE )", "( 1 FORM 1.1 FORM test1 FORM test2 )",
+                "( 1 FORM 1.1 SUP 1 SUP 2 )", "( 1 FORM 1.1 X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements() throws ParseException
+    {
+        String value = null;
+        DitStructureRule ditStructureRule = null;
+
+        value = "( 1 FORM 1.1 )";
+        ditStructureRule = parser.parseDITStructureRuleDescription( value );
+        assertNotNull( ditStructureRule.getForm() );
+
+        value = "( 1 )";
+        try
+        {
+            parser.parseDITStructureRuleDescription( value );
+            fail( "Exception expected, FORM is required" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1 FORM 1.1 )",
+                "( 2 DESC 'organization structure rule' FORM 2.5.15.3 )",
+                "( 2 DESC 'organization structure rule' FORM 2.5.15.3 )",
+                "( 1234567890 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE FORM 2.3.4.5.6.7.8.9.0.1 SUP ( 1 1234567890 5 ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericRuleId();
+            testNames();
+            testDescription();
+            testObsolete();
+            testForm();
+            testSup();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/LdapSyntaxDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/LdapSyntaxDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..5cd8040
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/LdapSyntaxDescriptionSchemaParserTest.java
@@ -0,0 +1,236 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapSyntaxDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the LdapSyntaxDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapSyntaxDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private LdapSyntaxDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new LdapSyntaxDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    /**
+     * Test numericoid
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "" );
+    }
+
+
+    /**
+     * Tests NAMES
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Tests DESC
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Test extensions.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Test full sytax description.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testFull() throws ParseException
+    {
+        String value = null;
+        LdapSyntax ldapSyntax = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        ldapSyntax = parser.parseLdapSyntaxDescription( value );
+
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", ldapSyntax.getOid() );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", ldapSyntax.getDescription() );
+        assertEquals( 2, ldapSyntax.getExtensions().size() );
+        assertNotNull( ldapSyntax.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, ldapSyntax.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", ldapSyntax.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", ldapSyntax.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( ldapSyntax.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, ldapSyntax.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", ldapSyntax.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", ldapSyntax.getExtension( "X-TEST-b" ).get( 1 ) );
+        assertEquals( value, ldapSyntax.getSpecification() );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1.1 DESC 'test1' DESC 'test2' )", "( 1.1 X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    ////////////////////////////////////////////////////////////////
+    //         Some real-world attribute type definitions         //
+    ////////////////////////////////////////////////////////////////
+
+    @Test
+    public void testRfcBinary() throws ParseException
+    {
+        String value = "( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' X-NOT-HUMAN-READABLE 'TRUE' )";
+        LdapSyntax ldapSyntax = parser.parseLdapSyntaxDescription( value );
+
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.5", ldapSyntax.getOid() );
+        assertEquals( "Binary", ldapSyntax.getDescription() );
+        assertEquals( 1, ldapSyntax.getExtensions().size() );
+        assertNotNull( ldapSyntax.getExtension( "X-NOT-HUMAN-READABLE" ) );
+        assertEquals( 1, ldapSyntax.getExtension( "X-NOT-HUMAN-READABLE" ).size() );
+        assertEquals( "TRUE", ldapSyntax.getExtension( "X-NOT-HUMAN-READABLE" ).get( 0 ) );
+        assertEquals( value, ldapSyntax.getSpecification() );
+    }
+
+
+    /**
+     * Tests the parse of a simple AttributeType with the schema extension.
+     */
+    @Test
+    public void testSyntaxWithExtensions() throws ParseException
+    {
+        String substrate = "( 1.3.6.1.4.1.18060.0.4.0.2.10000 DESC 'bogus description' X-SCHEMA 'blah' X-NOT-HUMAN-READABLE 'false' )";
+        LdapSyntax ldapSyntax = parser.parseLdapSyntaxDescription( substrate );
+        assertEquals( "1.3.6.1.4.1.18060.0.4.0.2.10000", ldapSyntax.getOid() );
+        assertEquals( "bogus description", ldapSyntax.getDescription() );
+        assertNotNull( ldapSyntax.getExtension( "X-NOT-HUMAN-READABLE" ) );
+        assertEquals( substrate, ldapSyntax.getSpecification() );
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1.1 )",
+                "( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
+                "( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' X-NOT-HUMAN-READABLE 'TRUE' )",
+                "( 1.2.3.4.5.6.7.8.9.0 DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testNames();
+            testDescription();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testRfcBinary();
+            testSyntaxWithExtensions();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/MatchingRuleDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/MatchingRuleDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..5899aab
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/MatchingRuleDescriptionSchemaParserTest.java
@@ -0,0 +1,369 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import javax.naming.NamingException;
+
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the MatchingRuleDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MatchingRuleDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private MatchingRuleDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new MatchingRuleDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "SYNTAX 1.1" );
+    }
+
+
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    @Test
+    public void testObsolete() throws ParseException
+    {
+        SchemaParserTestUtils.testObsolete( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    @Test
+    public void testSyntax() throws ParseException, NamingException
+    {
+        String value = null;
+        MatchingRule matchingRule = null;
+
+        // simple
+        value = "( 1.1 SYNTAX 0.1.2.3.4.5.6.7.8.9 )";
+        matchingRule = parser.parseMatchingRuleDescription( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", matchingRule.getSyntaxOid() );
+
+        // simple
+        value = "(1.1 SYNTAX 123.456.789.0)";
+        matchingRule = parser.parseMatchingRuleDescription( value );
+        assertEquals( "123.456.789.0", matchingRule.getSyntaxOid() );
+
+        // simple with spaces
+        value = "( 1.1    SYNTAX    0.1.2.3.4.5.6.7.8.9    )";
+        matchingRule = parser.parseMatchingRuleDescription( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", matchingRule.getSyntaxOid() );
+
+        // quoted value in parentheses
+        value = "( 1.1    SYNTAX ('0.1.2.3.4.5.6.7.8.9')    )";
+        matchingRule = parser.parseMatchingRuleDescription( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", matchingRule.getSyntaxOid() );
+
+        // SYNTAX must only appear once
+        value = "( 1.1 SYNTAX 2.2 SYNTAX 3.3 )";
+        try
+        {
+            matchingRule = parser.parseMatchingRuleDescription( value );
+            fail( "Exception expected, SYNTAX appears twice" );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // non-numeric not allowed
+            value = "( test )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, SYNTAX is require" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // SYNTAX is required
+            value = "( 1.1 )";
+            try
+            {
+                matchingRule = parser.parseMatchingRuleDescription( value );
+                fail( "Exception expected, SYNTAX is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "SYNTAX 1.1" );
+    }
+
+
+    @Test
+    public void testFull() throws ParseException, NamingException
+    {
+        String value = null;
+        MatchingRule matchingRule = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE SYNTAX 0.1.2.3.4.5.6.7.8.9 X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        matchingRule = parser.parseMatchingRuleDescription( value );
+
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", matchingRule.getOid() );
+        assertEquals( 2, matchingRule.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789",
+            matchingRule.getNames().get( 0 ) );
+        assertEquals( "test", matchingRule.getNames().get( 1 ) );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", matchingRule.getDescription() );
+        assertTrue( matchingRule.isObsolete() );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", matchingRule.getSyntaxOid() );
+        assertEquals( 2, matchingRule.getExtensions().size() );
+        assertNotNull( matchingRule.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, matchingRule.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", matchingRule.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", matchingRule.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( matchingRule.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, matchingRule.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", matchingRule.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", matchingRule.getExtension( "X-TEST-b" ).get( 1 ) );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1.1 SYNTAX 1.1 NAME 'test1' NAME 'test2' )", "( 1.1 SYNTAX 1.1 DESC 'test1' DESC 'test2' )",
+                "( 1.1 SYNTAX 1.1 OBSOLETE OBSOLETE )", "( 1.1 SYNTAX 1.1 SYNTAX 2.2 SYNTAX 3.3 )",
+                "( 1.1 SYNTAX 1.1 X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements() throws ParseException, NamingException
+    {
+        String value = null;
+        MatchingRule matchingRule = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 SYNTAX 1.1 )";
+        matchingRule = parser.parseMatchingRuleDescription( value );
+        assertNotNull( matchingRule.getSyntaxOid() );
+
+        if ( !parser.isQuirksMode() )
+        {
+            value = "( 1.2.3.4.5.6.7.8.9.0 )";
+            try
+            {
+                parser.parseMatchingRuleDescription( value );
+                fail( "Exception expected, SYNTAX is required" );
+            }
+            catch ( ParseException pe )
+            {
+                assertTrue( true );
+            }
+        }
+    }
+
+
+    ////////////////////////////////////////////////////////////////
+    //         Some real-world matching rule descriptons          //
+    ////////////////////////////////////////////////////////////////
+
+    @Test
+    public void testRfc1() throws ParseException, NamingException
+    {
+        String value = "( 2.5.13.5 NAME 'caseExactMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )";
+        MatchingRule matchingRule = parser.parseMatchingRuleDescription( value );
+
+        assertEquals( "2.5.13.5", matchingRule.getOid() );
+        assertEquals( 1, matchingRule.getNames().size() );
+        assertEquals( "caseExactMatch", matchingRule.getNames().get( 0 ) );
+        assertNull( matchingRule.getDescription() );
+        assertFalse( matchingRule.isObsolete() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", matchingRule.getSyntaxOid() );
+        assertEquals( 0, matchingRule.getExtensions().size() );
+    }
+
+
+    @Test
+    public void testSun1() throws ParseException, NamingException
+    {
+        String value = "( 2.5.13.5 NAME 'caseExactMatch' DESC 'Case Exact Matching on Directory String [defined in X.520]' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )";
+        MatchingRule matchingRule = parser.parseMatchingRuleDescription( value );
+
+        assertEquals( "2.5.13.5", matchingRule.getOid() );
+        assertEquals( 1, matchingRule.getNames().size() );
+        assertEquals( "caseExactMatch", matchingRule.getNames().get( 0 ) );
+        assertEquals( "Case Exact Matching on Directory String [defined in X.520]", matchingRule.getDescription() );
+        assertFalse( matchingRule.isObsolete() );
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", matchingRule.getSyntaxOid() );
+        assertEquals( 0, matchingRule.getExtensions().size() );
+    }
+
+
+    /**
+     * This is a real matching rule from Sun Directory 5.2. It has an invalid 
+     * syntax, no DOTs allowed in NAME value. 
+     */
+    @Test
+    public void testSun2() throws ParseException, NamingException
+    {
+        String value = "( 1.3.6.1.4.1.42.2.27.9.4.34.3.6 NAME 'caseExactSubstringMatch-2.16.840.1.113730.3.3.2.11.3' DESC 'en' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )";
+        if ( !parser.isQuirksMode() )
+        {
+            try
+            {
+                parser.parseMatchingRuleDescription( value );
+                fail( "Exception expected, invalid NAME value 'caseExactSubstringMatch-2.16.840.1.113730.3.3.2.11.3' (contains DOTs)" );
+            }
+            catch ( ParseException pe )
+            {
+                assertTrue( true );
+            }
+        }
+        else
+        {
+            MatchingRule matchingRule = parser.parseMatchingRuleDescription( value );
+            assertEquals( "1.3.6.1.4.1.42.2.27.9.4.34.3.6", matchingRule.getOid() );
+            assertEquals( 1, matchingRule.getNames().size() );
+            assertEquals( "caseExactSubstringMatch-2.16.840.1.113730.3.3.2.11.3", matchingRule.getNames().get( 0 ) );
+            assertEquals( "en", matchingRule.getDescription() );
+            assertFalse( matchingRule.isObsolete() );
+            assertEquals( "1.3.6.1.4.1.1466.115.121.1.15", matchingRule.getSyntaxOid() );
+            assertEquals( 0, matchingRule.getExtensions().size() );
+        }
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1.1 SYNTAX 1.1 )",
+                "( 2.5.13.5 NAME 'caseExactMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+                "( 2.5.13.5 NAME 'caseExactMatch' DESC 'Case Exact Matching on Directory String [defined in X.520]' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+                "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE SYNTAX 0.1.2.3.4.5.6.7.8.9 X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException, NamingException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "SYNTAX 1.1" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testNames();
+            testDescription();
+            testObsolete();
+            testSyntax();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testRequiredElements();
+            testRfc1();
+            testSun1();
+            testSun2();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/MatchingRuleUseDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/MatchingRuleUseDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..00f1355
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/MatchingRuleUseDescriptionSchemaParserTest.java
@@ -0,0 +1,408 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.api.ldap.model.schema.parsers.MatchingRuleUseDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the MatchingRuleUseDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MatchingRuleUseDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private MatchingRuleUseDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new MatchingRuleUseDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "APPLIES 1.1" );
+    }
+
+
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1.1", "APPLIES 1.1" );
+    }
+
+
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "APPLIES 1.1" );
+    }
+
+
+    @Test
+    public void testObsolete() throws ParseException
+    {
+        SchemaParserTestUtils.testObsolete( parser, "1.1", "APPLIES 1.1" );
+    }
+
+
+    @Test
+    public void testApplies() throws ParseException
+    {
+
+        String value = null;
+        MatchingRuleUse matchingRuleUse = null;
+
+        // APPLIES simple numericoid
+        value = "( 1.1 APPLIES 1.2.3.4.5.6.7.8.9.0 )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 1, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+
+        // SUP simple descr
+        value = "( 1.1 APPLIES abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 1, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", matchingRuleUse
+            .getApplicableAttributeOids().get( 0 ) );
+
+        // APPLIES single numericoid
+        value = "( 1.1 APPLIES ( 123.4567.890 ) )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 1, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "123.4567.890", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+
+        // APPLIES single descr
+        value = "(1.1 APPLIES(a-z-A-Z-0-9))";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 1, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "a-z-A-Z-0-9", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+
+        // APPLIES multi numericoid
+        value = "( 1.1 APPLIES ( 1.2.3 $ 4.5.6 $ 7.8.90 ) )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 3, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "1.2.3", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "4.5.6", matchingRuleUse.getApplicableAttributeOids().get( 1 ) );
+        assertEquals( "7.8.90", matchingRuleUse.getApplicableAttributeOids().get( 2 ) );
+
+        // APPLIES multi descr
+        value = "( 1.1 APPLIES ( test1 $ test2 ) )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 2, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "test1", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "test2", matchingRuleUse.getApplicableAttributeOids().get( 1 ) );
+
+        // APPLIES multi mixed, tabs
+        value = "\t(\t1.1\tAPPLIES\t(\ttest1\t$\t1.2.3.4\t$\ttest2\t)\t)\t";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 3, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "test1", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "1.2.3.4", matchingRuleUse.getApplicableAttributeOids().get( 1 ) );
+        assertEquals( "test2", matchingRuleUse.getApplicableAttributeOids().get( 2 ) );
+
+        // APPLIES multi mixed no space
+        value = "(1.1 APPLIES(TEST-1$1.2.3.4$TEST-2))";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 3, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "TEST-1", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "1.2.3.4", matchingRuleUse.getApplicableAttributeOids().get( 1 ) );
+        assertEquals( "TEST-2", matchingRuleUse.getApplicableAttributeOids().get( 2 ) );
+
+        // APPLIES multi mixed many spaces
+        value = "(          1.1          APPLIES          (          test1          $          1.2.3.4$test2          )          )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 3, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "test1", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "1.2.3.4", matchingRuleUse.getApplicableAttributeOids().get( 1 ) );
+        assertEquals( "test2", matchingRuleUse.getApplicableAttributeOids().get( 2 ) );
+
+        // quoted value
+        value = "( 1.1 APPLIES 'test' )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 1, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "test", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+
+        // quoted value
+        value = "( 1.1 APPLIES '1.2.3.4' )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 1, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "1.2.3.4", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+
+        // no $ separator
+        value = "( 1.1 APPLIES ( test1 test2 ) )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 2, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "test1", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "test2", matchingRuleUse.getApplicableAttributeOids().get( 1 ) );
+
+        // invalid character
+        value = "( 1.1 APPLIES 1.2.3.4.A )";
+        try
+        {
+            matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+            fail( "Exception expected, invalid APPLIES '1.2.3.4.A' (invalid character)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // empty APPLIES
+        value = "( 1.1 APPLIES )";
+        try
+        {
+            matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+            fail( "Exception expected, no APPLIES value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // APPLIES must only appear once
+        value = "( 1.1 APPLIES test1 APPLIES test2 )";
+        try
+        {
+            matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+            fail( "Exception expected, APPLIES appears twice" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // APPLIES is required
+            value = "( 1.1 )";
+            try
+            {
+                matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+                fail( "Exception expected, APPLIES is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // invalid start
+            value = "( 1.1 APPLIES ( test1 $ -test2 ) )";
+            try
+            {
+                matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+                fail( "Exception expected, invalid APPLIES '-test' (starts with hypen)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "APPLIES 1.1" );
+    }
+
+
+    @Test
+    public void testFull() throws ParseException
+    {
+        String value = null;
+        MatchingRuleUse matchingRuleUse = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE APPLIES ( 0.1.2.3.4.5.6.7.8.9 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", matchingRuleUse.getOid() );
+        assertEquals( 2, matchingRuleUse.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", matchingRuleUse.getNames()
+            .get( 0 ) );
+        assertEquals( "test", matchingRuleUse.getNames().get( 1 ) );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", matchingRuleUse.getDescription() );
+        assertTrue( matchingRuleUse.isObsolete() );
+        assertEquals( 2, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", matchingRuleUse
+            .getApplicableAttributeOids().get( 1 ) );
+        assertEquals( 2, matchingRuleUse.getExtensions().size() );
+        assertNotNull( matchingRuleUse.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, matchingRuleUse.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", matchingRuleUse.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", matchingRuleUse.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( matchingRuleUse.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, matchingRuleUse.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", matchingRuleUse.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", matchingRuleUse.getExtension( "X-TEST-b" ).get( 1 ) );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1.1 APPLIES 1.1 NAME 'test1' NAME 'test2' )", "( 1.1 APPLIES 1.1 DESC 'test1' DESC 'test2' )",
+                "( 1.1 APPLIES 1.1 OBSOLETE OBSOLETE )", "( 1.1 APPLIES 1.1 APPLIES test1 APPLIES test2 )",
+                "( 1.1 APPLIES 1.1 X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements() throws ParseException
+    {
+        String value = null;
+        MatchingRuleUse matchingRuleUse = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 APPLIES a )";
+        matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+        assertEquals( 1, matchingRuleUse.getApplicableAttributeOids().size() );
+
+        if ( !parser.isQuirksMode() )
+        {
+            value = "( 1.2.3.4.5.6.7.8.9.0 )";
+            try
+            {
+                parser.parseMatchingRuleUseDescription( value );
+                fail( "Exception expected, APPLIES is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    ////////////////////////////////////////////////////////////////
+    //       Some real-world matching rule use descriptons        //
+    ////////////////////////////////////////////////////////////////
+
+    @Test
+    public void testOpenldap1() throws ParseException
+    {
+        String value = "( 2.5.13.17 NAME 'octetStringMatch' APPLIES ( javaSerializedData $ userPassword ) )";
+        MatchingRuleUse matchingRuleUse = parser.parseMatchingRuleUseDescription( value );
+
+        assertEquals( "2.5.13.17", matchingRuleUse.getOid() );
+        assertEquals( 1, matchingRuleUse.getNames().size() );
+        assertEquals( "octetStringMatch", matchingRuleUse.getNames().get( 0 ) );
+        assertNull( matchingRuleUse.getDescription() );
+        assertFalse( matchingRuleUse.isObsolete() );
+        assertEquals( 2, matchingRuleUse.getApplicableAttributeOids().size() );
+        assertEquals( "javaSerializedData", matchingRuleUse.getApplicableAttributeOids().get( 0 ) );
+        assertEquals( "userPassword", matchingRuleUse.getApplicableAttributeOids().get( 1 ) );
+        assertEquals( 0, matchingRuleUse.getExtensions().size() );
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1.1 APPLIES 1.1 )",
+                "( 2.5.13.17 NAME 'octetStringMatch' APPLIES ( javaSerializedData $ userPassword ) )",
+                "( 2.5.13.1 NAME 'distinguishedNameMatch' APPLIES ( memberOf $ dITRedirect $ associatedName $ secretary $ documentAuthor $ manager $ seeAlso $ roleOccupant $ owner $ member $ distinguishedName $ aliasedObjectName $ namingContexts $ subschemaSubentry $ modifiersName $ creatorsName ) )",
+                "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE APPLIES ( 0.1.2.3.4.5.6.7.8.9 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "APPLIES 1.1" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testNames();
+            testDescription();
+            testObsolete();
+            testApplies();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testRequiredElements();
+            testOpenldap1();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/NameFormDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/NameFormDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..c45e347
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/NameFormDescriptionSchemaParserTest.java
@@ -0,0 +1,564 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.NameForm;
+import org.apache.directory.api.ldap.model.schema.parsers.NameFormDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the NameFormDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NameFormDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private NameFormDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new NameFormDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    /**
+     * Test numericoid
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "OC o MUST m" );
+    }
+
+
+    /**
+     * Tests NAME and its values
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1.1", "OC o MUST m" );
+    }
+
+
+    /**
+     * Tests DESC
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "OC o MUST m" );
+    }
+
+
+    /**
+     * Tests OBSOLETE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testObsolete() throws ParseException
+    {
+        SchemaParserTestUtils.testObsolete( parser, "1.1", "OC o MUST m" );
+    }
+
+
+    /**
+     * Test OC and its value.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testOc() throws ParseException, LdapException
+    {
+        String value = null;
+        NameForm nf = null;
+
+        // numeric oid
+        value = "( 1.1 MUST m OC 1.2.3.4.5.6.7.8.9.0 )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", nf.getStructuralObjectClassOid() );
+
+        // numeric oid
+        value = "(   1.1 MUST m   OC    123.4567.890    )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( "123.4567.890", nf.getStructuralObjectClassOid() );
+
+        // descr
+        value = "( 1.1 MUST m OC abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", nf
+            .getStructuralObjectClassOid() );
+
+        // quoted value
+        value = "( 1.1 MUST m OC '1.2.3.4.5.6.7.8.9.0' )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", nf.getStructuralObjectClassOid() );
+
+        // quoted value
+        value = "( 1.1 MUST m OC 'test' )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( "test", nf.getStructuralObjectClassOid() );
+
+        // invalid character
+        value = "( 1.1 MUST m OC 1.2.3.4.A )";
+        try
+        {
+            nf = parser.parseNameFormDescription( value );
+            fail( "Exception expected, invalid OC 1.2.3.4.A (invalid character)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no multi value allowed
+        value = "( 1.1 MUST m OC ( test1 test2 ) )";
+        try
+        {
+            nf = parser.parseNameFormDescription( value );
+            fail( "Exception expected, OC must be single valued" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // OC must only appear once
+        value = "( 1.1 MUST m OC test1 OC test2 )";
+        try
+        {
+            nf = parser.parseNameFormDescription( value );
+            fail( "Exception expected, OC appears twice" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // OC is required
+            value = "( 1.1 MUST m )";
+            try
+            {
+                nf = parser.parseNameFormDescription( value );
+                fail( "Exception expected, OC is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // invalid start
+            value = "( 1.1 MUST m OC -test ) )";
+            try
+            {
+                nf = parser.parseNameFormDescription( value );
+                fail( "Exception expected, invalid OC '-test' (starts with hypen)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test MUST and its values.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testMust() throws ParseException, LdapException
+    {
+        String value = null;
+        NameForm nf = null;
+
+        // MUST simple numericoid
+        value = "( 1.1 OC o MUST 1.2.3 )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( 1, nf.getMustAttributeTypeOids().size() );
+        assertEquals( "1.2.3", nf.getMustAttributeTypeOids().get( 0 ) );
+
+        // MUST mulitple
+        value = "(1.1 OC o MUST (cn$sn       $11.22.33.44.55         $  objectClass   ))";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( 4, nf.getMustAttributeTypeOids().size() );
+        assertEquals( "cn", nf.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", nf.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", nf.getMustAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", nf.getMustAttributeTypeOids().get( 3 ) );
+
+        // no MUST values
+        value = "( 1.1 OC o MUST )";
+        try
+        {
+            nf = parser.parseNameFormDescription( value );
+            fail( "Exception expected, no MUST value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // MUST must only appear once
+        value = "( 1.1 OC o MUST test1 MUST test2 )";
+        try
+        {
+            nf = parser.parseNameFormDescription( value );
+            fail( "Exception expected, MUST appears twice" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // MUST is required
+            value = "( 1.1 OC o )";
+            try
+            {
+                nf = parser.parseNameFormDescription( value );
+                fail( "Exception expected, MUST is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // invalid value
+            value = "( 1.1 OC o MUST ( c_n ) )";
+            try
+            {
+                nf = parser.parseNameFormDescription( value );
+                fail( "Exception expected, invalid value c_n" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test MAY and its values.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testMay() throws ParseException, LdapException
+    {
+        String value = null;
+        NameForm nf = null;
+
+        // no MAY
+        value = "( 1.1 OC o MUST m )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( 0, nf.getMayAttributeTypeOids().size() );
+
+        // MAY simple numericoid
+        value = "( 1.1 OC o MUST m MAY 1.2.3 )";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( 1, nf.getMayAttributeTypeOids().size() );
+        assertEquals( "1.2.3", nf.getMayAttributeTypeOids().get( 0 ) );
+
+        // MAY mulitple
+        value = "(1.1 OC o MUST m MAY (cn$sn       $11.22.33.44.55         $  objectClass   ))";
+        nf = parser.parseNameFormDescription( value );
+        assertEquals( 4, nf.getMayAttributeTypeOids().size() );
+        assertEquals( "cn", nf.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", nf.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", nf.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", nf.getMayAttributeTypeOids().get( 3 ) );
+
+        // MAY must only appear once
+        value = "( 1.1 OC o MUST m MAY test1 MAY test2 )";
+        try
+        {
+            nf = parser.parseNameFormDescription( value );
+            fail( "Exception expected, MAY appears twice" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid value
+            value = "( 1.1 OC o MUST m MAY ( c_n ) )";
+            try
+            {
+                nf = parser.parseNameFormDescription( value );
+                fail( "Exception expected, invalid value c_n" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test extensions.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "OC o MUST m" );
+
+    }
+
+
+    /**
+     * Test full object class description.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testFull() throws ParseException, LdapException
+    {
+        String value = null;
+        NameForm nf = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE OC bcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789a MUST ( 3.4.5.6.7.8.9.0.1.2 $ cdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789ab ) MAY ( 4.5.6.7.8.9.0.1.2.3 $ defghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789abc ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        nf = parser.parseNameFormDescription( value );
+
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", nf.getOid() );
+        assertEquals( 2, nf.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", nf.getNames().get( 0 ) );
+        assertEquals( "test", nf.getNames().get( 1 ) );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", nf.getDescription() );
+        assertTrue( nf.isObsolete() );
+        assertEquals( "bcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789a", nf
+            .getStructuralObjectClassOid() );
+        assertEquals( 2, nf.getMustAttributeTypeOids().size() );
+        assertEquals( "3.4.5.6.7.8.9.0.1.2", nf.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "cdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789ab", nf.getMustAttributeTypeOids()
+            .get( 1 ) );
+        assertEquals( 2, nf.getMayAttributeTypeOids().size() );
+        assertEquals( "4.5.6.7.8.9.0.1.2.3", nf.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "defghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789abc", nf.getMayAttributeTypeOids()
+            .get( 1 ) );
+        assertEquals( 2, nf.getExtensions().size() );
+        assertNotNull( nf.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, nf.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", nf.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", nf.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( nf.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, nf.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", nf.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", nf.getExtension( "X-TEST-b" ).get( 1 ) );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1.1 OC o MUST m NAME 'test1' NAME 'test2' )", "( 1.1 OC o MUST m DESC 'test1' DESC 'test2' )",
+                "( 1.1 OC o MUST m OBSOLETE OBSOLETE )", "( 1.1 OC o MUST m OC test1 OC test2 )",
+                "( 1.1 OC o MUST m MUST test1 MUST test2 )", "( 1.1 OC o MUST m MAY test1 MAY test2 )",
+                "( 1.1 OC o MUST m X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements() throws ParseException, LdapException
+    {
+        String value = null;
+        NameForm nf = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 OC o MUST m )";
+        nf = parser.parseNameFormDescription( value );
+        assertNotNull( nf.getStructuralObjectClassOid() );
+        assertEquals( 1, nf.getMustAttributeTypeOids().size() );
+
+        if ( !parser.isQuirksMode() )
+        {
+            value = "( 1.2.3.4.5.6.7.8.9.0 MUST m )";
+            try
+            {
+                nf = parser.parseNameFormDescription( value );
+                fail( "Exception expected, OC is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            value = "( 1.2.3.4.5.6.7.8.9.0 OC o )";
+            try
+            {
+                nf = parser.parseNameFormDescription( value );
+                fail( "Exception expected, MUST is required" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    //    /**
+    //     * Test if MUST and MAY are disjoint.
+    //     * 
+    //     * Problem: What if MUST is a numeric oid and MAY is a name?
+    //     * 
+    //     * @throws ParseException
+    //     */
+    //    @Test
+    //    public void testDisjoint() throws ParseException
+    //    {
+    //        String value = null;
+    //        NameFormDescription nfd = null;
+    //
+    //        value = "( 1.2.3.4.5.6.7.8.9.0 OC o MUST test1 MAY test2 )";
+    //        nfd = parser.parseNameFormDescription( value );
+    //        assertNotNull( nfd.getStructuralObjectClassOid() );
+    //        assertEquals( 1, nfd.getMustAttributeTypeOids().size() );
+    //
+    //        value = "( 1.2.3.4.5.6.7.8.9.0 OC o MUST test1 MAY test1 )";
+    //        try
+    //        {
+    //            nfd = parser.parseNameFormDescription( value );
+    //            fail( "Exception expected, MUST and MAY must be disjoint" );
+    //        }
+    //        catch ( ParseException pe )
+    //        {
+    //            // expected
+    //        }
+    //
+    //        value = "( 1.2.3.4.5.6.7.8.9.0 OC o MUST ( test1 $ test2 ) MAY ( test4 $ test3 $ test2 ) )";
+    //        try
+    //        {
+    //            nfd = parser.parseNameFormDescription( value );
+    //            fail( "Exception expected, MUST and MAY must be disjoint" );
+    //        }
+    //        catch ( ParseException pe )
+    //        {
+    //            // expected
+    //        }
+    //
+    //    }
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1.1 OC o MUST m )",
+                "( 2.5.15.3 NAME 'orgNameForm' OC organization MUST o )",
+                "( 2.5.15.3 NAME 'orgNameForm' OC organization MUST o )",
+                "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE OC bcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789a MUST ( 3.4.5.6.7.8.9.0.1.2 $ cdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789ab ) MAY ( 4.5.6.7.8.9.0.1.2.3 $ defghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789abc ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException, LdapException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "OC o MUST m" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testNames();
+            testDescription();
+            testObsolete();
+            testOc();
+            testMust();
+            testMay();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testRequiredElements();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/NormalizerDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/NormalizerDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..8dca44e
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/NormalizerDescriptionSchemaParserTest.java
@@ -0,0 +1,184 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.text.ParseException;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the NormalizerDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NormalizerDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private NormalizerDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new NormalizerDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "FQCN org.apache.directory.SimpleNormalizer" );
+    }
+
+
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "FQCN org.apache.directory.SimpleNormalizer" );
+    }
+
+
+    @Test
+    public void testFqcn() throws ParseException
+    {
+        String value = null;
+        NormalizerDescription nd = null;
+
+        // FQCN simple p
+        value = "( 1.1 FQCN org.apache.directory.SimpleNormalizer )";
+        nd = parser.parseNormalizerDescription( value );
+        assertNotNull( nd.getFqcn() );
+        assertEquals( "org.apache.directory.SimpleNormalizer", nd.getFqcn() );
+    }
+
+
+    @Test
+    public void testBytecode() throws ParseException
+    {
+        String value = null;
+        NormalizerDescription nd = null;
+
+        // FQCN simple p
+        value = "( 1.1 FQCN org.apache.directory.SimpleNormalizer BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        nd = parser.parseNormalizerDescription( value );
+        assertNotNull( nd.getBytecode() );
+        assertEquals( "ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789====", nd.getBytecode() );
+    }
+
+
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "FQCN org.apache.directory.SimpleNormalizer" );
+    }
+
+
+    @Test
+    public void testFull()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        // TODO
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "FQCN org.apache.directory.SimpleNormalizer" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testDescription();
+            testFqcn();
+            testBytecode();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testRequiredElements();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/ObjectClassDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/ObjectClassDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..df51b60
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/ObjectClassDescriptionSchemaParserTest.java
@@ -0,0 +1,870 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import javax.naming.NamingException;
+
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+import org.apache.directory.api.ldap.model.schema.parsers.ObjectClassDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the ObjectClassDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ObjectClassDescriptionSchemaParserTest
+{
+    /** the parser instance */
+    private ObjectClassDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new ObjectClassDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    /**
+     * Test numericoid
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "" );
+    }
+
+
+    /**
+     * Tests NAME and its values
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testNames() throws ParseException
+    {
+        SchemaParserTestUtils.testNames( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Tests DESC
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Tests OBSOLETE
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testObsolete() throws ParseException
+    {
+        SchemaParserTestUtils.testObsolete( parser, "1.1", "" );
+    }
+
+
+    /**
+     * Test SUP and its values.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testSuperior() throws ParseException, NamingException
+    {
+        String value = null;
+        ObjectClass objectClass = null;
+
+        // no SUP
+        value = "( 1.1 )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 0, objectClass.getSuperiorOids().size() );
+
+        // SUP simple numericoid
+        value = "( 1.1 SUP 1.2.3 )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "1.2.3", objectClass.getSuperiorOids().get( 0 ) );
+
+        // SUP simple descr
+        value = "( 1.1 SUP top )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+
+        // SUP single numericoid
+        value = "( 1.1 SUP ( 1.2.3.4.5 ) )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "1.2.3.4.5", objectClass.getSuperiorOids().get( 0 ) );
+
+        // SUP single descr
+        value = "( 1.1 SUP ( A-Z-0-9 ) )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "A-Z-0-9", objectClass.getSuperiorOids().get( 0 ) );
+
+        // SUP multi numericoid
+        value = "( 1.1 SUP ( 1.2.3 $ 1.2.3.4.5 ) )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 2, objectClass.getSuperiorOids().size() );
+        assertEquals( "1.2.3", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( "1.2.3.4.5", objectClass.getSuperiorOids().get( 1 ) );
+
+        // SUP multi descr
+        value = "( 1.1 SUP ( top1 $ top2 ) )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 2, objectClass.getSuperiorOids().size() );
+        assertEquals( "top1", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( "top2", objectClass.getSuperiorOids().get( 1 ) );
+
+        // SUP multi mixed, tabs
+        value = "\t(\t1.1\tSUP\t(\ttop1\t$\t1.2.3.4\t$\ttop2\t)\t)\t";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 3, objectClass.getSuperiorOids().size() );
+        assertEquals( "top1", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( "1.2.3.4", objectClass.getSuperiorOids().get( 1 ) );
+        assertEquals( "top2", objectClass.getSuperiorOids().get( 2 ) );
+
+        // SUP multi mixed, no space
+        value = "(1.1 SUP(TOP-1$1.2.3.4$TOP-2))";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 3, objectClass.getSuperiorOids().size() );
+        assertEquals( "TOP-1", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( "1.2.3.4", objectClass.getSuperiorOids().get( 1 ) );
+        assertEquals( "TOP-2", objectClass.getSuperiorOids().get( 2 ) );
+
+        // SUP multi mixed many spaces
+        value = "(          1.1          SUP          (          top1          $          1.2.3.4$top2          )          )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 3, objectClass.getSuperiorOids().size() );
+        assertEquals( "top1", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( "1.2.3.4", objectClass.getSuperiorOids().get( 1 ) );
+        assertEquals( "top2", objectClass.getSuperiorOids().get( 2 ) );
+
+        // quoted value
+        value = "( 1.1 SUP 'top' )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+
+        // quoted value
+        value = "( 1.1 SUP '1.2.3.4' )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "1.2.3.4", objectClass.getSuperiorOids().get( 0 ) );
+
+        // no $ separator
+        value = "( 1.1 SUP ( top1 top2 ) )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 2, objectClass.getSuperiorOids().size() );
+        assertEquals( "top1", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( "top2", objectClass.getSuperiorOids().get( 1 ) );
+
+        // invalid character
+        value = "( 1.1 SUP 1.2.3.4.A )";
+        try
+        {
+            objectClass = parser.parseObjectClassDescription( value );
+            fail( "Exception expected, invalid SUP '1.2.3.4.A' (invalid character)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // empty sup
+        value = "( 1.1 SUP )";
+        try
+        {
+            objectClass = parser.parseObjectClassDescription( value );
+            fail( "Exception expected, no SUP value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid start
+            value = "( 1.1 SUP ( top1 $ -top2 ) )";
+            try
+            {
+                objectClass = parser.parseObjectClassDescription( value );
+                fail( "Exception expected, invalid SUP '-top' (starts with hypen)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Tests kind (ABSTRACT, AUXILIARY, STRUCTURAL)
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testKind() throws ParseException
+    {
+        String value = null;
+        ObjectClass objectClass = null;
+
+        // DEFAULT is STRUCTURAL
+        value = "( 1.1 )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+
+        // ABSTRACT
+        value = "( 1.1 ABSTRACT )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( ObjectClassTypeEnum.ABSTRACT, objectClass.getType() );
+
+        // AUXILIARY, tab
+        value = "\t(\t1.1\tAUXILIARY\t)\t";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( ObjectClassTypeEnum.AUXILIARY, objectClass.getType() );
+
+        // STRUCTURAL, no space
+        value = "(1.1 STRUCTURAL)";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+
+        // STRUCTURAL, case-insensitive
+        value = "(1.1 sTrUcTuRaL )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+
+        // invalid
+        value = "( 1.1 FOO )";
+        try
+        {
+            objectClass = parser.parseObjectClassDescription( value );
+            fail( "Exception expected, invalid KIND value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Test MUST and its values.
+     * Very similar to SUP, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testMust() throws ParseException
+    {
+        String value = null;
+        ObjectClass objectClass = null;
+
+        // no MUST
+        value = "( 1.1 )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 0, objectClass.getMustAttributeTypeOids().size() );
+
+        // MUST simple numericoid
+        value = "( 1.1 MUST 1.2.3 )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "1.2.3", objectClass.getMustAttributeTypeOids().get( 0 ) );
+
+        // MUST multiple
+        value = "(1.1 MUST(cn$sn\r$11.22.33.44.55         $  objectClass   ))";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 4, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "cn", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", objectClass.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", objectClass.getMustAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", objectClass.getMustAttributeTypeOids().get( 3 ) );
+
+        // MUST multiple, no $ separator
+        value = "(1.1 MUST(cn sn\t'11.22.33.44.55'\n'objectClass'))";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 4, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "cn", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", objectClass.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", objectClass.getMustAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", objectClass.getMustAttributeTypeOids().get( 3 ) );
+
+        // no MUST values
+        value = "( 1.1 MUST )";
+        try
+        {
+            objectClass = parser.parseObjectClassDescription( value );
+            fail( "Exception expected, no MUST value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid value
+            value = "( 1.1 MUST ( c_n ) )";
+            try
+            {
+                objectClass = parser.parseObjectClassDescription( value );
+                fail( "Exception expected, invalid value c_n" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test MAY and its values.
+     * Very similar to SUP, so here are less test cases. 
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testMay() throws ParseException
+    {
+        String value = null;
+        ObjectClass objectClass = null;
+
+        // no MAY
+        value = "( 1.1 )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 0, objectClass.getMayAttributeTypeOids().size() );
+
+        // MAY simple numericoid
+        value = "( 1.1 MAY 1.2.3 )";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 1, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "1.2.3", objectClass.getMayAttributeTypeOids().get( 0 ) );
+
+        // MAY multiple
+        value = "(1.1 MAY(cn$sn       $11.22.33.44.55\n$  objectClass   ))";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 4, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "cn", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", objectClass.getMayAttributeTypeOids().get( 3 ) );
+
+        // MAY multiple, no $ separator, quoted
+        value = "(1.1 MAY('cn' sn\t'11.22.33.44.55'\nobjectClass))";
+        objectClass = parser.parseObjectClassDescription( value );
+        assertEquals( 4, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "cn", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "sn", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "11.22.33.44.55", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "objectClass", objectClass.getMayAttributeTypeOids().get( 3 ) );
+
+        if ( !parser.isQuirksMode() )
+        {
+            // invalid value
+            value = "( 1.1 MAY ( c_n ) )";
+            try
+            {
+                objectClass = parser.parseObjectClassDescription( value );
+                fail( "Exception expected, invalid value c_n" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Test extensions.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "" );
+
+    }
+
+
+    /**
+     * Test full object class description.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testFull() throws ParseException, NamingException
+    {
+        String value = null;
+        ObjectClass objectClass = null;
+
+        value = "( 1.2.3.4.5.6.7.8.9.0 NAME ( 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' 'test' ) DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' OBSOLETE SUP ( 2.3.4.5.6.7.8.9.0.1 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) STRUCTURAL MUST ( 3.4.5.6.7.8.9.0.1.2 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) MAY ( 4.5.6.7.8.9.0.1.2.3 $ abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789 ) X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2') )";
+        objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "1.2.3.4.5.6.7.8.9.0", objectClass.getOid() );
+        assertEquals( 2, objectClass.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", objectClass.getNames()
+            .get( 0 ) );
+        assertEquals( "test", objectClass.getNames().get( 1 ) );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", objectClass.getDescription() );
+        assertTrue( objectClass.isObsolete() );
+        assertEquals( 2, objectClass.getSuperiorOids().size() );
+        assertEquals( "2.3.4.5.6.7.8.9.0.1", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", objectClass
+            .getSuperiorOids().get( 1 ) );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( 2, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "3.4.5.6.7.8.9.0.1.2", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", objectClass
+            .getMustAttributeTypeOids()
+            .get( 1 ) );
+        assertEquals( 2, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "4.5.6.7.8.9.0.1.2.3", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", objectClass
+            .getMayAttributeTypeOids()
+            .get( 1 ) );
+        assertEquals( 2, objectClass.getExtensions().size() );
+        assertNotNull( objectClass.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, objectClass.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", objectClass.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", objectClass.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( objectClass.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, objectClass.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", objectClass.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", objectClass.getExtension( "X-TEST-b" ).get( 1 ) );
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        String[] testValues = new String[]
+            { "( 1.1 NAME 'test1' NAME 'test2' )", "( 1.1 DESC 'test1' DESC 'test2' )", "( 1.1 OBSOLETE OBSOLETE )",
+                "( 1.1 SUP test1 SUP test2 )", "( 1.1 STRUCTURAL STRUCTURAL )", "( 1.1 ABSTRACT ABSTRACT )",
+                "( 1.1 AUXILIARY AUXILIARY )", "( 1.1 STRUCTURAL AUXILIARY AUXILIARY )",
+                "( 1.1 MUST test1 MUST test2 )", "( 1.1 MAY test1 MAY test2 )", "( 1.1 X-TEST 'test1' X-TEST 'test2' )" };
+        SchemaParserTestUtils.testUnique( parser, testValues );
+    }
+
+
+    /**
+     * Ensure that element order is ignored
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testIgnoreElementOrder() throws ParseException, NamingException
+    {
+        String value = "( 2.5.6.6 STRUCTURAL MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) SUP top DESC 'RFC2256: a person' MUST ( sn $ cn ) NAME 'person' )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "2.5.6.6", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "person", objectClass.getNames().get( 0 ) );
+        assertEquals( "RFC2256: a person", objectClass.getDescription() );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( 2, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "sn", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "cn", objectClass.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( 4, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "userPassword", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "telephoneNumber", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "seeAlso", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "description", objectClass.getMayAttributeTypeOids().get( 3 ) );
+        assertEquals( 0, objectClass.getExtensions().size() );
+
+    }
+
+
+    ////////////////////////////////////////////////////////////////
+    //          Some real-world object class definitions          //
+    ////////////////////////////////////////////////////////////////
+
+    @Test
+    public void testRfcTop() throws ParseException, NamingException
+    {
+        String value = "( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "2.5.6.0", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "top", objectClass.getNames().get( 0 ) );
+        assertEquals( "top of the superclass chain", objectClass.getDescription() );
+        assertEquals( 0, objectClass.getSuperiorOids().size() );
+        assertEquals( ObjectClassTypeEnum.ABSTRACT, objectClass.getType() );
+        assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "objectClass", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( 0, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( 0, objectClass.getExtensions().size() );
+    }
+
+
+    @Test
+    public void testRfcPerson() throws ParseException, NamingException
+    {
+        String value = "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "2.5.6.6", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "person", objectClass.getNames().get( 0 ) );
+        assertEquals( "RFC2256: a person", objectClass.getDescription() );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( 2, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "sn", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( "cn", objectClass.getMustAttributeTypeOids().get( 1 ) );
+        assertEquals( 4, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "userPassword", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "telephoneNumber", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "seeAlso", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "description", objectClass.getMayAttributeTypeOids().get( 3 ) );
+        assertEquals( 0, objectClass.getExtensions().size() );
+    }
+
+
+    @Test
+    public void testRfcSimpleSecurityObject() throws ParseException, NamingException
+    {
+        String value = "( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject' DESC 'RFC1274: simple security object' SUP top AUXILIARY MUST userPassword )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "0.9.2342.19200300.100.4.19", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "simpleSecurityObject", objectClass.getNames().get( 0 ) );
+        assertEquals( "RFC1274: simple security object", objectClass.getDescription() );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( ObjectClassTypeEnum.AUXILIARY, objectClass.getType() );
+        assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "userPassword", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( 0, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( 0, objectClass.getExtensions().size() );
+    }
+
+
+    @Test
+    public void testSunAlias() throws ParseException, NamingException
+    {
+        String value = "( 2.5.6.1 NAME 'alias' DESC 'Standard LDAP objectclass' SUP top ABSTRACT MUST aliasedObjectName X-ORIGIN 'RFC 2256' )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "2.5.6.1", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "alias", objectClass.getNames().get( 0 ) );
+        assertEquals( "Standard LDAP objectclass", objectClass.getDescription() );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( ObjectClassTypeEnum.ABSTRACT, objectClass.getType() );
+        assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "aliasedObjectName", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( 0, objectClass.getMayAttributeTypeOids().size() );
+
+        assertEquals( 1, objectClass.getExtensions().size() );
+        assertNotNull( objectClass.getExtension( "X-ORIGIN" ) );
+        assertEquals( 1, objectClass.getExtension( "X-ORIGIN" ).size() );
+        assertEquals( "RFC 2256", objectClass.getExtension( "X-ORIGIN" ).get( 0 ) );
+    }
+
+
+    @Test
+    public void testNovellDcObject() throws ParseException, NamingException
+    {
+        String value = "( 1.3.6.1.4.1.1466.344 NAME 'dcObject' AUXILIARY MUST dc X-NDS_NAMING 'dc' X-NDS_NOT_CONTAINER '1' X-NDS_NONREMOVABLE '1' )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "1.3.6.1.4.1.1466.344", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "dcObject", objectClass.getNames().get( 0 ) );
+        assertNull( objectClass.getDescription() );
+        assertEquals( 0, objectClass.getSuperiorOids().size() );
+        assertEquals( ObjectClassTypeEnum.AUXILIARY, objectClass.getType() );
+        assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "dc", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( 0, objectClass.getMayAttributeTypeOids().size() );
+
+        assertEquals( 3, objectClass.getExtensions().size() );
+        assertNotNull( objectClass.getExtension( "X-NDS_NAMING" ) );
+        assertEquals( 1, objectClass.getExtension( "X-NDS_NAMING" ).size() );
+        assertEquals( "dc", objectClass.getExtension( "X-NDS_NAMING" ).get( 0 ) );
+        assertNotNull( objectClass.getExtension( "X-NDS_NOT_CONTAINER" ) );
+        assertEquals( 1, objectClass.getExtension( "X-NDS_NOT_CONTAINER" ).size() );
+        assertEquals( "1", objectClass.getExtension( "X-NDS_NOT_CONTAINER" ).get( 0 ) );
+        assertNotNull( objectClass.getExtension( "X-NDS_NONREMOVABLE" ) );
+        assertEquals( 1, objectClass.getExtension( "X-NDS_NONREMOVABLE" ).size() );
+        assertEquals( "1", objectClass.getExtension( "X-NDS_NONREMOVABLE" ).get( 0 ) );
+    }
+
+
+    @Test
+    public void testNovellList() throws ParseException, NamingException
+    {
+        String value = "( 2.16.840.1.113719.1.1.6.1.30 NAME 'List' SUP Top STRUCTURAL MUST cn MAY ( description $ l $ member $ ou $ o $ eMailAddress $ mailboxLocation $ mailboxID $ owner $ seeAlso $ fullName ) X-NDS_NAMING 'cn' X-NDS_CONTAINMENT ( 'Organization' 'organizationalUnit' 'domain' ) X-NDS_NOT_CONTAINER '1' X-NDS_NONREMOVABLE '1' X-NDS_ACL_TEMPLATES '2#entry#[Root Template]#member' )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "2.16.840.1.113719.1.1.6.1.30", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "List", objectClass.getNames().get( 0 ) );
+        assertNull( objectClass.getDescription() );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "Top", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "cn", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( 11, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "description", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "fullName", objectClass.getMayAttributeTypeOids().get( 10 ) );
+
+        assertEquals( 5, objectClass.getExtensions().size() );
+        assertNotNull( objectClass.getExtension( "X-NDS_NAMING" ) );
+        assertEquals( 1, objectClass.getExtension( "X-NDS_NAMING" ).size() );
+        assertEquals( "cn", objectClass.getExtension( "X-NDS_NAMING" ).get( 0 ) );
+
+        assertNotNull( objectClass.getExtension( "X-NDS_NOT_CONTAINER" ) );
+        assertEquals( 1, objectClass.getExtension( "X-NDS_NOT_CONTAINER" ).size() );
+        assertEquals( "1", objectClass.getExtension( "X-NDS_NOT_CONTAINER" ).get( 0 ) );
+
+        assertNotNull( objectClass.getExtension( "X-NDS_NONREMOVABLE" ) );
+        assertEquals( 1, objectClass.getExtension( "X-NDS_NONREMOVABLE" ).size() );
+        assertEquals( "1", objectClass.getExtension( "X-NDS_NONREMOVABLE" ).get( 0 ) );
+
+        // X-NDS_CONTAINMENT ( 'Organization' 'organizationalUnit' 'domain' )
+        assertNotNull( objectClass.getExtension( "X-NDS_CONTAINMENT" ) );
+        assertEquals( 3, objectClass.getExtension( "X-NDS_CONTAINMENT" ).size() );
+        assertEquals( "Organization", objectClass.getExtension( "X-NDS_CONTAINMENT" ).get( 0 ) );
+        assertEquals( "organizationalUnit", objectClass.getExtension( "X-NDS_CONTAINMENT" ).get( 1 ) );
+        assertEquals( "domain", objectClass.getExtension( "X-NDS_CONTAINMENT" ).get( 2 ) );
+
+        // X-NDS_ACL_TEMPLATES '2#entry#[Root Template]#member'
+        assertNotNull( objectClass.getExtension( "X-NDS_ACL_TEMPLATES" ) );
+        assertEquals( 1, objectClass.getExtension( "X-NDS_ACL_TEMPLATES" ).size() );
+        assertEquals( "2#entry#[Root Template]#member", objectClass.getExtension( "X-NDS_ACL_TEMPLATES" )
+            .get( 0 ) );
+    }
+
+
+    @Test
+    public void testMicrosoftAds2000Locality() throws ParseException, NamingException
+    {
+        String value = "( 2.5.6.3 NAME 'locality' SUP top STRUCTURAL MUST (l ) MAY (st $ street $ searchGuide $ seeAlso ) )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "2.5.6.3", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "locality", objectClass.getNames().get( 0 ) );
+        assertNull( objectClass.getDescription() );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( "l", objectClass.getMustAttributeTypeOids().get( 0 ) );
+        assertEquals( 4, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "st", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "street", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "searchGuide", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( "seeAlso", objectClass.getMayAttributeTypeOids().get( 3 ) );
+        assertEquals( 0, objectClass.getExtensions().size() );
+    }
+
+
+    @Test
+    public void testMicrosoftAds2003Msieee() throws ParseException, NamingException
+    {
+        String value = "( 1.2.840.113556.1.5.240 NAME 'msieee80211-Policy' SUP top STRUCTURAL MAY (msieee80211-Data $ msieee80211-DataType $ msieee80211-ID ) )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "1.2.840.113556.1.5.240", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "msieee80211-Policy", objectClass.getNames().get( 0 ) );
+        assertNull( objectClass.getDescription() );
+        assertEquals( 1, objectClass.getSuperiorOids().size() );
+        assertEquals( "top", objectClass.getSuperiorOids().get( 0 ) );
+        assertEquals( ObjectClassTypeEnum.STRUCTURAL, objectClass.getType() );
+        assertEquals( 0, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( 3, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "msieee80211-Data", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "msieee80211-DataType", objectClass.getMayAttributeTypeOids().get( 1 ) );
+        assertEquals( "msieee80211-ID", objectClass.getMayAttributeTypeOids().get( 2 ) );
+        assertEquals( 0, objectClass.getExtensions().size() );
+    }
+
+
+    @Test
+    public void testSiemensDirxX500Subschema() throws ParseException, NamingException
+    {
+        String value = "( 2.5.20.1 NAME 'x500subSchema' AUXILIARY MAY (dITStructureRules $ nameForms $ dITContentRules $ x500objectClasses $ x500attributeTypes $ matchingRules $ matchingRuleUse) )";
+        ObjectClass objectClass = parser.parseObjectClassDescription( value );
+
+        assertEquals( "2.5.20.1", objectClass.getOid() );
+        assertEquals( 1, objectClass.getNames().size() );
+        assertEquals( "x500subSchema", objectClass.getNames().get( 0 ) );
+        assertNull( objectClass.getDescription() );
+        assertEquals( 0, objectClass.getSuperiorOids().size() );
+        assertEquals( ObjectClassTypeEnum.AUXILIARY, objectClass.getType() );
+        assertEquals( 0, objectClass.getMustAttributeTypeOids().size() );
+        assertEquals( 7, objectClass.getMayAttributeTypeOids().size() );
+        assertEquals( "dITStructureRules", objectClass.getMayAttributeTypeOids().get( 0 ) );
+        assertEquals( "matchingRuleUse", objectClass.getMayAttributeTypeOids().get( 6 ) );
+        assertEquals( 0, objectClass.getExtensions().size() );
+    }
+
+
+    /**
+     * Tests the multi-threaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        String[] testValues = new String[]
+            {
+                "( 1.1 )",
+                "( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )",
+                "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )",
+                "( 2.16.840.1.113719.1.1.6.1.30 NAME 'List' SUP Top STRUCTURAL MUST cn MAY ( description $ l $ member $ ou $ o $ eMailAddress $ mailboxLocation $ mailboxID $ owner $ seeAlso $ fullName ) X-NDS_NAMING 'cn' X-NDS_CONTAINMENT ( 'Organization' 'organizationalUnit' 'domain' ) X-NDS_NOT_CONTAINER '1' X-NDS_NONREMOVABLE '1' X-NDS_ACL_TEMPLATES '2#entry#[Root Template]#member' )" };
+        SchemaParserTestUtils.testMultiThreaded( parser, testValues );
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException, NamingException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "" );
+
+        try
+        {
+            String value = null;
+            ObjectClass objectClass = null;
+
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testNames();
+            testDescription();
+            testObsolete();
+            testSuperior();
+            testKind();
+            testMust();
+            testMay();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testIgnoreElementOrder();
+            testRfcTop();
+            testRfcSimpleSecurityObject();
+            testSunAlias();
+            testNovellDcObject();
+            testNovellList();
+            testMicrosoftAds2000Locality();
+            testMicrosoftAds2003Msieee();
+            testSiemensDirxX500Subschema();
+            testMultiThreaded();
+
+            // NAME with special chars
+            value = "( 1.2.3 NAME 't-e_s.t;' )";
+            objectClass = parser.parseObjectClassDescription( value );
+            assertEquals( 1, objectClass.getNames().size() );
+            assertEquals( "t-e_s.t;", objectClass.getNames().get( 0 ) );
+
+            // SUP with underscore
+            value = "( 1.1 SUP te_st )";
+            objectClass = parser.parseObjectClassDescription( value );
+            assertEquals( 1, objectClass.getSuperiorOids().size() );
+            assertEquals( "te_st", objectClass.getSuperiorOids().get( 0 ) );
+
+            // MAY with underscore
+            value = "( 1.1 MAY te_st )";
+            objectClass = parser.parseObjectClassDescription( value );
+            assertEquals( 1, objectClass.getMayAttributeTypeOids().size() );
+            assertEquals( "te_st", objectClass.getMayAttributeTypeOids().get( 0 ) );
+
+            // MUST with underscore
+            value = "( 1.1 MUST te_st )";
+            objectClass = parser.parseObjectClassDescription( value );
+            assertEquals( 1, objectClass.getMustAttributeTypeOids().size() );
+            assertEquals( "te_st", objectClass.getMustAttributeTypeOids().get( 0 ) );
+
+            // Netscape object class 
+            value = "( nsAdminGroup-oid NAME 'nsAdminGroup' DESC 'Netscape defined objectclass' SUP top STRUCTURAL MUST cn MAY ( nsAdminGroupName $ description $ nsConfigRoot $ nsAdminSIEDN ) X-ORIGIN 'Netscape' )";
+            objectClass = parser.parseObjectClassDescription( value );
+            assertEquals( "nsAdminGroup-oid", objectClass.getOid() );
+            assertEquals( 1, objectClass.getNames().size() );
+            assertEquals( "nsAdminGroup", objectClass.getNames().get( 0 ) );
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/SchemaParserTestUtils.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/SchemaParserTestUtils.java
new file mode 100644
index 0000000..f858b6c
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/SchemaParserTestUtils.java
@@ -0,0 +1,727 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.parsers.AbstractSchemaParser;
+
+
+/**
+ * Utils for schema parser test. Contains tests that are common
+ * for many schema parsers like OID, name, desc, extension.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaParserTestUtils
+{
+
+    /**
+     * Test numericoid
+     * 
+     * @throws ParseException
+     */
+    public static void testNumericOid( AbstractSchemaParser parser, String required ) throws ParseException
+    {
+        String value = null;
+        SchemaObject asd = null;
+
+        // null test
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, null" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no oid
+        value = "( )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, no NUMERICOID" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // simple
+        value = "( 0.1.2.3.4.5.6.7.8.9 " + required + " )";
+        asd = parser.parse( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", asd.getOid() );
+
+        // simple
+        value = "( 123.4567.890 " + required + ")";
+        asd = parser.parse( value );
+        assertEquals( "123.4567.890", asd.getOid() );
+
+        // simple with multiple spaces
+        value = "(          0.1.2.3.4.5.6.7.8.9         " + required + " )";
+        asd = parser.parse( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", asd.getOid() );
+
+        // simple w/o spaces
+        value = "(0.1.2.3.4.5.6.7.8.9 " + required + ")";
+        asd = parser.parse( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", asd.getOid() );
+
+        // simple with tabs, newline, comment.
+        value = "(\t0.1.2.3.4.5.6.7.8.9\n#comment\n" + required + "\r\n)\r";
+        asd = parser.parse( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", asd.getOid() );
+
+        // quoted OID
+        value = "( '0.1.2.3.4.5.6.7.8.9' " + required + " )";
+        asd = parser.parse( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", asd.getOid() );
+
+        // quoted OID in parentheses
+        value = "( ('0.1.2.3.4.5.6.7.8.9') " + required + " )";
+        asd = parser.parse( value );
+        assertEquals( "0.1.2.3.4.5.6.7.8.9", asd.getOid() );
+
+        // too short
+        value = "( 1 " + required + " )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, invalid NUMERICOID 1" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // dot only
+        value = "( . " + required + " )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, invalid NUMERICOID ." );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // ends with dot
+        value = "( 1.1. " + required + " )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, invalid NUMERICOID 1.1." );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // multiple not allowed
+        value = "( ( 1.2.3 4.5.6 ) " + required + " )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, invalid multiple OIDs not allowed.)" );
+        }
+        catch ( ParseException pe )
+        {
+            // excpected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // non-numeric not allowed
+            value = "( test " + required + " )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, invalid NUMERICOID test" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // leading 0 not allowed
+            value = "( 01.1 " + required + " )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, invalid NUMERICOID 01.1 (leading zero)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // alpha not allowed
+            value = "( 1.2.a.4 " + required + " )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, invalid NUMERICOID 1.2.a.4 (alpha not allowed)" );
+            }
+            catch ( ParseException pe )
+            {
+                // excpected
+            }
+
+        }
+    }
+
+
+    /**
+     * Tests NAME and its values
+     * 
+     * @throws ParseException
+     */
+    public static void testNames( AbstractSchemaParser parser, String oid, String required ) throws ParseException
+    {
+        String value = null;
+        SchemaObject asd = null;
+
+        // alpha
+        value = "( " + oid + " " + required + " NAME 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' )";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", asd.getNames().get( 0 ) );
+
+        // alpha-num-hypen
+        value = "( " + oid + " " + required
+            + " NAME 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789' )";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getNames().size() );
+        assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789", asd.getNames().get( 0 ) );
+
+        // with parentheses
+        value = "( " + oid + " " + required + " NAME ( 'a-z-0-9' ) )";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getNames().size() );
+        assertEquals( "a-z-0-9", asd.getNames().get( 0 ) );
+
+        // with parentheses, without space
+        value = "(" + oid + " " + required + " NAME('a-z-0-9'))";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getNames().size() );
+        assertEquals( "a-z-0-9", asd.getNames().get( 0 ) );
+
+        // multi with space
+        value = " ( " + oid + " " + required + " NAME ( 'test1' 'test2' ) ) ";
+        asd = parser.parse( value );
+        assertEquals( 2, asd.getNames().size() );
+        assertEquals( "test1", asd.getNames().get( 0 ) );
+        assertEquals( "test2", asd.getNames().get( 1 ) );
+
+        // multi without space
+        value = "(" + oid + " " + required + " NAME('test1''test2''test3'))";
+        asd = parser.parse( value );
+        assertEquals( 3, asd.getNames().size() );
+        assertEquals( "test1", asd.getNames().get( 0 ) );
+        assertEquals( "test2", asd.getNames().get( 1 ) );
+        assertEquals( "test3", asd.getNames().get( 2 ) );
+
+        // multi with many spaces
+        value = "(          " + oid + " " + required
+            + "          NAME          (          'test1'          'test2'          'test3'          )          )";
+        asd = parser.parse( value );
+        assertEquals( 3, asd.getNames().size() );
+        assertEquals( "test1", asd.getNames().get( 0 ) );
+        assertEquals( "test2", asd.getNames().get( 1 ) );
+        assertEquals( "test3", asd.getNames().get( 2 ) );
+
+        // multi with tabs, newline, comment, etc.
+        value = "(\r\n" + oid + "\r" + required
+            + "\nNAME\t(\t\t\t'test1'\t\n\t'test2'\t\r\t'test3'\t\r\n\t)\n#comment\n)";
+        asd = parser.parse( value );
+        assertEquals( 3, asd.getNames().size() );
+        assertEquals( "test1", asd.getNames().get( 0 ) );
+        assertEquals( "test2", asd.getNames().get( 1 ) );
+        assertEquals( "test3", asd.getNames().get( 2 ) );
+
+        // lowercase NAME
+        value = "( " + oid + " " + required + " name 'test' )";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getNames().size() );
+        assertEquals( "test", asd.getNames().get( 0 ) );
+
+        // unquoted NAME value
+        value = "( " + oid + " " + required + " NAME test )";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getNames().size() );
+        assertEquals( "test", asd.getNames().get( 0 ) );
+
+        // multi unquoted NAME values
+        value = " ( " + oid + " " + required + " NAME (test1 test2) ) ";
+        asd = parser.parse( value );
+        assertEquals( 2, asd.getNames().size() );
+        assertEquals( "test1", asd.getNames().get( 0 ) );
+        assertEquals( "test2", asd.getNames().get( 1 ) );
+
+        // NAM unknown
+        value = "( " + oid + " " + required + " NAM 'test' )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, invalid token NAM" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        if ( !parser.isQuirksMode() )
+        {
+            // start with number
+            value = "( " + oid + " " + required + " NAME '1test' )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, invalid NAME 1test (starts with number)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // start with hypen
+            value = "( " + oid + " " + required + " NAME '-test' )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, invalid NAME -test (starts with hypen)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // invalid character
+            value = "( " + oid + " " + required + " NAME 'te_st' )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, invalid NAME te_st (contains invalid character)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+
+            // one valid, one invalid
+            value = "( " + oid + " " + required + " NAME ( 'test' 'te_st' ) )";
+            try
+            {
+                parser.parse( value );
+                fail( "Exception expected, invalid NAME te_st (contains invalid character)" );
+            }
+            catch ( ParseException pe )
+            {
+                // expected
+            }
+        }
+    }
+
+
+    /**
+     * Tests DESC
+     * 
+     * @throws ParseException
+     */
+    public static void testDescription( AbstractSchemaParser parser, String oid, String required )
+        throws ParseException
+    {
+        String value = null;
+        SchemaObject asd = null;
+
+        // simple
+        value = "(" + oid + " " + required + " DESC 'Descripton')";
+        asd = parser.parse( value );
+        assertEquals( "Descripton", asd.getDescription() );
+
+        // simple with tabs, newline, comment, etc.
+        value = "(" + oid + "\n" + required + "\tDESC#comment\n\n\r\n\r\t'Descripton')";
+        asd = parser.parse( value );
+        assertEquals( "Descripton", asd.getDescription() );
+
+        // simple w/o space
+        value = "(" + oid + " " + required + " DESC'Descripton')";
+        asd = parser.parse( value );
+        assertEquals( "Descripton", asd.getDescription() );
+
+        // simple parentheses and quotes
+        value = "(" + oid + " " + required + " DESC ('Descripton') )";
+        asd = parser.parse( value );
+        assertEquals( "Descripton", asd.getDescription() );
+
+        // unicode
+        value = "( " + oid + " " + required + " DESC 'Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577' )";
+        asd = parser.parse( value );
+        assertEquals( "Descripton \u00E4\u00F6\u00FC\u00DF \u90E8\u9577", asd.getDescription() );
+
+        // escaped characters
+        value = "( " + oid + " " + required + " DESC 'test\\5Ctest' )";
+        asd = parser.parse( value );
+        assertEquals( "test\\test", asd.getDescription() );
+        value = "( " + oid + " " + required + " DESC 'test\\5ctest' )";
+        asd = parser.parse( value );
+        assertEquals( "test\\test", asd.getDescription() );
+        value = "( " + oid + " " + required + " DESC 'test\\27test' )";
+        asd = parser.parse( value );
+        assertEquals( "test'test", asd.getDescription() );
+        value = "( " + oid + " " + required + " DESC '\\5C\\27\\5c' )";
+        asd = parser.parse( value );
+        assertEquals( "\\'\\", asd.getDescription() );
+
+        // lowercase DESC
+        value = "( " + oid + " " + required + " desc 'Descripton' )";
+        asd = parser.parse( value );
+        assertEquals( "Descripton", asd.getDescription() );
+
+        // empty DESC
+        value = "( " + oid + " " + required + " DESC '' )";
+        asd = parser.parse( value );
+        assertEquals( "", asd.getDescription() );
+
+        // multiple not allowed
+        value = "(" + oid + " " + required + " DESC ( 'Descripton1' 'Description 2' )  )";
+        try
+        {
+            parser.parse( value );
+            fail( "Exception expected, invalid multiple DESC not allowed.)" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Test extensions.
+     * 
+     * @throws ParseException
+     */
+    public static void testExtensions( AbstractSchemaParser parser, String oid, String required ) throws ParseException
+    {
+        String value = null;
+        SchemaObject asd = null;
+
+        // no extension
+        value = "( " + oid + " " + required + " )";
+        asd = parser.parse( value );
+        assertEquals( 0, asd.getExtensions().size() );
+
+        // single extension with one value
+        value = "( " + oid + " " + required + " X-TEST 'test' )";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getExtensions().size() );
+        assertNotNull( asd.getExtension( "X-TEST" ) );
+        assertEquals( 1, asd.getExtension( "X-TEST" ).size() );
+        assertEquals( "test", asd.getExtension( "X-TEST" ).get( 0 ) );
+
+        // single extension with multiple values
+        value = "( " + oid + " " + required
+            + " X-TEST-ABC ('test1' 'test \u00E4\u00F6\u00FC\u00DF'       'test \u90E8\u9577' ) )";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getExtensions().size() );
+        assertNotNull( asd.getExtension( "X-TEST-ABC" ) );
+        assertEquals( 3, asd.getExtension( "X-TEST-ABC" ).size() );
+        assertEquals( "test1", asd.getExtension( "X-TEST-ABC" ).get( 0 ) );
+        assertEquals( "test \u00E4\u00F6\u00FC\u00DF", asd.getExtension( "X-TEST-ABC" ).get( 1 ) );
+        assertEquals( "test \u90E8\u9577", asd.getExtension( "X-TEST-ABC" ).get( 2 ) );
+
+        // multiple extensions
+        value = "(" + oid + " " + required + " X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2'))";
+        asd = parser.parse( value );
+        assertEquals( 2, asd.getExtensions().size() );
+        assertNotNull( asd.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, asd.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", asd.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", asd.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( asd.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, asd.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", asd.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", asd.getExtension( "X-TEST-b" ).get( 1 ) );
+
+        // multiple extensions, no spaces
+        value = "(" + oid + " " + required + " X-TEST-a('test1-1''test1-2')X-TEST-b('test2-1''test2-2'))";
+        asd = parser.parse( value );
+        assertEquals( 2, asd.getExtensions().size() );
+        assertNotNull( asd.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, asd.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", asd.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", asd.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( asd.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, asd.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", asd.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", asd.getExtension( "X-TEST-b" ).get( 1 ) );
+
+        // multiple extensions, tabs, newline, comments
+        value = "(" + oid + "\n#comment\n" + required
+            + "\nX-TEST-a\n(\t'test1-1'\t\n'test1-2'\n\r)\tX-TEST-b\n(\n'test2-1'\t'test2-2'\t)\r)";
+        asd = parser.parse( value );
+        assertEquals( 2, asd.getExtensions().size() );
+        assertNotNull( asd.getExtension( "X-TEST-a" ) );
+        assertEquals( 2, asd.getExtension( "X-TEST-a" ).size() );
+        assertEquals( "test1-1", asd.getExtension( "X-TEST-a" ).get( 0 ) );
+        assertEquals( "test1-2", asd.getExtension( "X-TEST-a" ).get( 1 ) );
+        assertNotNull( asd.getExtension( "X-TEST-b" ) );
+        assertEquals( 2, asd.getExtension( "X-TEST-b" ).size() );
+        assertEquals( "test2-1", asd.getExtension( "X-TEST-b" ).get( 0 ) );
+        assertEquals( "test2-2", asd.getExtension( "X-TEST-b" ).get( 1 ) );
+
+        // some more complicated
+        value = "(" + oid + " " + required
+            + " X-_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ('\\5C\\27\\5c'))";
+        asd = parser.parse( value );
+        assertEquals( 1, asd.getExtensions().size() );
+        assertNotNull( asd.getExtension( "X-_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ) );
+        assertEquals( 1, asd.getExtension( "X-_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" )
+            .size() );
+        assertEquals( "\\'\\", asd.getExtension(
+            "X-_-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ).get( 0 ) );
+
+        // invalid extension, no number allowed
+        value = "( " + oid + " " + required + " X-TEST1 'test' )";
+        try
+        {
+            asd = parser.parse( value );
+            fail( "Exception expected, invalid extension X-TEST1 (no number allowed)" );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+
+    }
+
+
+    /**
+     * Tests OBSOLETE
+     * 
+     * @throws ParseException
+     */
+    public static void testObsolete( AbstractSchemaParser parser, String oid, String required ) throws ParseException
+    {
+        String value = null;
+        SchemaObject asd = null;
+
+        // not obsolete
+        value = "( " + oid + " " + required + " )";
+        asd = parser.parse( value );
+        assertFalse( asd.isObsolete() );
+
+        // not obsolete
+        value = "( " + oid + " " + required + " NAME 'test' DESC 'Descripton' )";
+        asd = parser.parse( value );
+        assertFalse( asd.isObsolete() );
+
+        // obsolete
+        value = "(" + oid + " " + required + " NAME 'test' DESC 'Descripton' OBSOLETE)";
+        asd = parser.parse( value );
+        assertTrue( asd.isObsolete() );
+
+        // obsolete
+        value = "(" + oid + " " + required + " OBSOLETE)";
+        asd = parser.parse( value );
+        assertTrue( asd.isObsolete() );
+
+        // lowercased obsolete
+        value = "(" + oid + " " + required + " obsolete)";
+        asd = parser.parse( value );
+        assertTrue( asd.isObsolete() );
+
+        // invalid
+        value = "(" + oid + " " + required + " NAME 'test' DESC 'Descripton' OBSOLET )";
+        try
+        {
+            asd = parser.parse( value );
+            fail( "Exception expected, invalid OBSOLETE value" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // trailing value not allowed
+        value = "(" + oid + " " + required + " NAME 'test' DESC 'Descripton' OBSOLETE 'true' )";
+        try
+        {
+            asd = parser.parse( value );
+            fail( "Exception expected, trailing value ('true') now allowed" );
+        }
+        catch ( ParseException pe )
+        {
+            assertTrue( true );
+        }
+
+    }
+
+
+    /**
+     * Tests for unique elements.
+     * 
+     * @throws ParseException
+     */
+    public static void testUnique( AbstractSchemaParser parser, String[] testValues )
+    {
+        for ( int i = 0; i < testValues.length; i++ )
+        {
+            String testValue = testValues[i];
+            try
+            {
+                parser.parse( testValue );
+                fail( "Exception expected, element appears twice in " + testValue );
+            }
+            catch ( ParseException pe )
+            {
+                assertTrue( true );
+            }
+        }
+
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    public static void testMultiThreaded( AbstractSchemaParser parser, String[] testValues )
+    {
+        final boolean[] isSuccessMultithreaded = new boolean[1];
+        isSuccessMultithreaded[0] = true;
+
+        // start up and track all threads (40 threads)
+        List<Thread> threads = new ArrayList<Thread>();
+        for ( int ii = 0; ii < 10; ii++ )
+        {
+            for ( int i = 0; i < testValues.length; i++ )
+            {
+                Thread t = new Thread( new ParseSpecification( parser, testValues[i], isSuccessMultithreaded ) );
+                threads.add( t );
+                t.start();
+            }
+        }
+
+        // wait until all threads have died
+        boolean hasLiveThreads = false;
+        do
+        {
+            hasLiveThreads = false;
+
+            for ( int ii = 0; ii < threads.size(); ii++ )
+            {
+                Thread t = threads.get( ii );
+                hasLiveThreads = hasLiveThreads || t.isAlive();
+            }
+        }
+        while ( hasLiveThreads );
+
+        // check that no one thread failed to parse and generate a SS object
+        assertTrue( isSuccessMultithreaded[0] );
+
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    public static void testQuirksMode( AbstractSchemaParser parser, String required ) throws ParseException
+    {
+        try
+        {
+            String value = null;
+            SchemaObject asd = null;
+
+            parser.setQuirksMode( true );
+
+            // alphanum OID
+            value = "( abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789 " + required + " )";
+            asd = parser.parse( value );
+            assertEquals( "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789", asd
+                .getOid() );
+
+            // start with hypen
+            value = "( -oid " + required + " )";
+            asd = parser.parse( value );
+            assertEquals( "-oid", asd.getOid() );
+
+            // start with number
+            value = "( 1oid " + required + " )";
+            asd = parser.parse( value );
+            assertEquals( "1oid", asd.getOid() );
+
+            // start with dot
+            value = "( .oid " + required + " )";
+            asd = parser.parse( value );
+            assertEquals( ".oid", asd.getOid() );
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+    static class ParseSpecification implements Runnable
+    {
+        private final AbstractSchemaParser parser;
+        private final String value;
+        private final boolean[] isSuccessMultithreaded;
+
+        private SchemaObject result;
+
+
+        public ParseSpecification( AbstractSchemaParser parser, String value, boolean[] isSuccessMultithreaded )
+        {
+            this.parser = parser;
+            this.value = value;
+            this.isSuccessMultithreaded = isSuccessMultithreaded;
+        }
+
+
+        public void run()
+        {
+            try
+            {
+                result = parser.parse( value );
+            }
+            catch ( ParseException e )
+            {
+                e.printStackTrace();
+            }
+
+            isSuccessMultithreaded[0] = isSuccessMultithreaded[0] && ( result != null );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/SyntaxCheckerDescriptionSchemaParserTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/SyntaxCheckerDescriptionSchemaParserTest.java
new file mode 100644
index 0000000..67e784b
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/schema/syntaxes/parser/SyntaxCheckerDescriptionSchemaParserTest.java
@@ -0,0 +1,270 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.model.schema.syntaxes.parser;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.text.ParseException;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescriptionSchemaParser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the SyntaxCheckerDescriptionSchemaParser class.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SyntaxCheckerDescriptionSchemaParserTest
+{
+    private static final String OID = "1.3.6.1.4.1.18060.0.4.0.2.10000";
+    private static final String FQCN = "org.foo.Bar";
+    private static final String DESC = "bogus desc";
+    private static final String BYTECODE = "14561234";
+
+    /** the parser instance */
+    private SyntaxCheckerDescriptionSchemaParser parser;
+
+
+    @Before
+    public void setUp() throws Exception
+    {
+        parser = new SyntaxCheckerDescriptionSchemaParser();
+    }
+
+
+    @After
+    public void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    @Test
+    public void testNumericOid() throws ParseException
+    {
+        SchemaParserTestUtils.testNumericOid( parser, "FQCN org.apache.directory.SimpleSyntaxChecker" );
+    }
+
+
+    @Test
+    public void testDescription() throws ParseException
+    {
+        SchemaParserTestUtils.testDescription( parser, "1.1", "FQCN org.apache.directory.SimpleSyntaxChecker" );
+    }
+
+
+    @Test
+    public void testFqcn() throws ParseException
+    {
+        String value = null;
+        SyntaxCheckerDescription syntaxCheckerDescription = null;
+
+        // FQCN simple p
+        value = "( 1.1 FQCN org.apache.directory.SimpleSyntaxChecker )";
+        syntaxCheckerDescription = parser.parseSyntaxCheckerDescription( value );
+        assertNotNull( syntaxCheckerDescription.getFqcn() );
+        assertEquals( "org.apache.directory.SimpleSyntaxChecker", syntaxCheckerDescription.getFqcn() );
+    }
+
+
+    @Test
+    public void testBytecode() throws ParseException
+    {
+        String value = null;
+        SyntaxCheckerDescription syntaxCheckerDescription = null;
+
+        // FQCN simple p
+        value = "( 1.1 FQCN org.apache.directory.SimpleSyntaxChecker BYTECODE ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789==== )";
+        syntaxCheckerDescription = parser.parseSyntaxCheckerDescription( value );
+        assertNotNull( syntaxCheckerDescription.getBytecode() );
+        assertEquals( "ABCDEFGHIJKLMNOPQRSTUVWXYZ+/abcdefghijklmnopqrstuvwxyz0123456789====", syntaxCheckerDescription
+            .getBytecode() );
+    }
+
+
+    @Test
+    public void testExtensions() throws ParseException
+    {
+        SchemaParserTestUtils.testExtensions( parser, "1.1", "FQCN org.apache.directory.SimpleSyntaxChecker" );
+    }
+
+
+    @Test
+    public void testFull()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Test unique elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testUniqueElements()
+    {
+        // TODO
+    }
+
+
+    /**
+     * Test required elements.
+     * 
+     * @throws ParseException
+     */
+    @Test
+    public void testRequiredElements()
+    {
+        // TODO
+    }
+
+
+    @Test
+    public void testSimpleSyntaxChecker() throws ParseException
+    {
+        String simple = "( " + OID + " FQCN " + FQCN + " )";
+        SyntaxCheckerDescription syntaxCheckerDescription = parser.parseSyntaxCheckerDescription( simple );
+        assertNotNull( syntaxCheckerDescription );
+        assertEquals( OID, syntaxCheckerDescription.getOid() );
+        assertEquals( FQCN, syntaxCheckerDescription.getFqcn() );
+        assertNull( syntaxCheckerDescription.getBytecode() );
+        assertNull( syntaxCheckerDescription.getDescription() );
+    }
+
+
+    @Test
+    public void testSyntaxCheckerWithDesc() throws ParseException
+    {
+        String simple = "( " + OID + " DESC '" + DESC + "' FQCN " + FQCN + " )";
+        SyntaxCheckerDescription syntaxCheckerDescription = parser.parseSyntaxCheckerDescription( simple );
+        assertNotNull( syntaxCheckerDescription );
+        assertEquals( OID, syntaxCheckerDescription.getOid() );
+        assertEquals( FQCN, syntaxCheckerDescription.getFqcn() );
+        assertNull( syntaxCheckerDescription.getBytecode() );
+        assertEquals( DESC, syntaxCheckerDescription.getDescription() );
+    }
+
+
+    @Test
+    public void testSyntaxCheckerWithDescAndByteCode() throws ParseException
+    {
+        String simple = "( " + OID + " DESC '" + DESC + "' FQCN " + FQCN + " BYTECODE " + BYTECODE + " )";
+        SyntaxCheckerDescription syntaxCheckerDescription = parser.parseSyntaxCheckerDescription( simple );
+        assertNotNull( syntaxCheckerDescription );
+        assertEquals( OID, syntaxCheckerDescription.getOid() );
+        assertEquals( FQCN, syntaxCheckerDescription.getFqcn() );
+        assertEquals( BYTECODE, syntaxCheckerDescription.getBytecode() );
+        assertEquals( DESC, syntaxCheckerDescription.getDescription() );
+    }
+
+
+    @Test
+    public void testSyntaxCheckerExample() throws ParseException
+    {
+        String simple = "( 1.3.6.1.4.1.18060.0.4.1.0.10000 DESC 'bogus desc' FQCN org.apache.directory.shared.ldap.schema.syntax.OctetStringSyntaxChecker )";
+        SyntaxCheckerDescription syntaxCheckerDescription = parser.parseSyntaxCheckerDescription( simple );
+        assertNotNull( syntaxCheckerDescription );
+    }
+
+
+    @Test
+    public void testRealByteCodeExample() throws ParseException
+    {
+        String simple = "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' "
+            + "FQCN DummySyntaxChecker BYTECODE yv66vgAAADEAHgoABAAYCQADABkHABoHABsHABwBAANvaWQBABJMam"
+            + "F2YS9sYW5nL1N0cmluZzsBAAY8aW5pdD4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51b"
+            + "WJlclRhYmxlAQADKClWAQAMc2V0U3ludGF4T2lkAQAMZ2V0U3ludGF4T2lkAQAUKClMamF2YS9sYW5nL1N0cmlu"
+            + "ZzsBAA1pc1ZhbGlkU3ludGF4AQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQAMYXNzZXJ0U3ludGF4AQAVKExqYXZ"
+            + "hL2xhbmcvT2JqZWN0OylWAQAKRXhjZXB0aW9ucwcAHQEAClNvdXJjZUZpbGUBABdEdW1teVN5bnRheENoZWNrZX"
+            + "IuamF2YQwACAAMDAAGAAcBABJEdW1teVN5bnRheENoZWNrZXIBABBqYXZhL2xhbmcvT2JqZWN0AQA8b3JnL2FwY"
+            + "WNoZS9kaXJlY3Rvcnkvc2hhcmVkL2xkYXAvc2NoZW1hL3N5bnRheC9TeW50YXhDaGVja2VyAQAcamF2YXgvbmFt"
+            + "aW5nL05hbWluZ0V4Y2VwdGlvbgAhAAMABAABAAUAAQACAAYABwAAAAYAAQAIAAkAAQAKAAAAKgACAAIAAAAKKrc"
+            + "AASortQACsQAAAAEACwAAAA4AAwAAAAsABAAMAAkADQABAAgADAABAAoAAAAhAAEAAQAAAAUqtwABsQAAAAEACw"
+            + "AAAAoAAgAAABEABAASAAEADQAJAAEACgAAACIAAgACAAAABiortQACsQAAAAEACwAAAAoAAgAAABcABQAYAAEAD"
+            + "gAPAAEACgAAAB0AAQABAAAABSq0AAKwAAAAAQALAAAABgABAAAAHQABABAAEQABAAoAAAAaAAEAAgAAAAIErAAA"
+            + "AAEACwAAAAYAAQAAACMAAQASABMAAgAKAAAAGQAAAAIAAAABsQAAAAEACwAAAAYAAQAAACkAFAAAAAQAAQAVAAE"
+            + "AFgAAAAIAFw== X-SCHEMA 'nis' )";
+        SyntaxCheckerDescription syntaxCheckerDescription = parser.parseSyntaxCheckerDescription( simple );
+        assertNotNull( syntaxCheckerDescription );
+        assertEquals( "1.3.6.1.4.1.18060.0.4.1.0.10002", syntaxCheckerDescription.getOid() );
+        assertEquals( "DummySyntaxChecker", syntaxCheckerDescription.getFqcn() );
+        assertNotNull( syntaxCheckerDescription.getBytecode() );
+        assertEquals( "bogus desc", syntaxCheckerDescription.getDescription() );
+    }
+
+
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    @Test
+    public void testMultiThreaded() throws ParseException
+    {
+        // TODO
+    }
+
+
+    /**
+     * Tests quirks mode.
+     */
+    @Test
+    public void testQuirksMode() throws ParseException
+    {
+        SchemaParserTestUtils.testQuirksMode( parser, "FQCN org.apache.directory.SimpleComparator" );
+
+        try
+        {
+            parser.setQuirksMode( true );
+
+            // ensure all other test pass in quirks mode
+            testNumericOid();
+            testDescription();
+            testFqcn();
+            testBytecode();
+            testExtensions();
+            testFull();
+            testUniqueElements();
+            testSimpleSyntaxChecker();
+            testSyntaxCheckerWithDesc();
+            testSyntaxCheckerWithDescAndByteCode();
+            testSyntaxCheckerExample();
+            testRealByteCodeExample();
+            testMultiThreaded();
+        }
+        finally
+        {
+            parser.setQuirksMode( false );
+        }
+    }
+
+}
diff --git a/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/url/LdapUrlTest.java b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/url/LdapUrlTest.java
new file mode 100644
index 0000000..a57acc4
--- /dev/null
+++ b/trunk/ldap/model/src/test/java/org/apache/directory/api/ldap/model/url/LdapUrlTest.java
@@ -0,0 +1,1656 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.model.url;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.url.LdapUrl;
+import org.apache.directory.api.ldap.model.url.LdapUrl.Extension;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the class LdapUrl
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdapUrlTest
+{
+    /**
+     * Test a null LdapUrl
+     */
+    @Test
+    public void testLdapUrlNull()
+    {
+        assertEquals( "ldap:///", new LdapUrl().toString() );
+    }
+
+
+    /**
+     * test an empty LdapUrl
+     */
+    @Test
+    public void testDnEmpty() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap:///", new LdapUrl( "" ).toString() );
+    }
+
+
+    /**
+     * test a simple LdapUrl
+     */
+    @Test
+    public void testDnSimple() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:80/", new LdapUrl( "ldap://directory.apache.org:80/" )
+            .toString() );
+    }
+
+
+    /**
+     * test a LdapUrl host 1
+     */
+    @Test
+    public void testDnWithMinus() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://d-a.org:80/", new LdapUrl( "ldap://d-a.org:80/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad port
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testDnBadPort() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://directory.apache.org:/" );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad port 2
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testDnBadPort2() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://directory.apache.org:-1/" );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad port 3
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testDnBadPort3() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://directory.apache.org:abc/" );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad port 4
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testDnBadPort4() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://directory.apache.org:65536/" );
+    }
+
+
+    /**
+     * test a LdapUrl with no host
+     */
+    @Test
+    public void testDnBadHost1() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap:///", new LdapUrl( "ldap:///" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad host 2
+     */
+    @Test
+    public void testDnBadHost2() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://./", new LdapUrl( "ldap://./" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad host 3
+     */
+    @Test
+    public void testDnBadHost3() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://a..b/", new LdapUrl( "ldap://a..b/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad host 4
+     */
+    @Test
+    public void testDnBadHost4() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://-/", new LdapUrl( "ldap://-/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad host 5
+     */
+    @Test
+    public void testDnBadHost5() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://a.b.c-/", new LdapUrl( "ldap://a.b.c-/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad host 6
+     */
+    @Test
+    public void testDnBadHost6() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://a.b.-c/", new LdapUrl( "ldap://a.b.-c/" ).toString() );
+        new LdapUrl( "ldap://a.b.-c/" );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad host 7
+     */
+    @Test
+    public void testDnBadHost7() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://a.-.c/", new LdapUrl( "ldap://a.-.c/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl IP host
+     */
+    @Test
+    public void testDnIPV4Host() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://1.2.3.4/", new LdapUrl( "ldap://1.2.3.4/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl IP host and port
+     */
+    @Test
+    public void testDnIPV4HostPort() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://1.2.3.4:80/", new LdapUrl( "ldap://1.2.3.4:80/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad IP host 1 : we should not get an error, but the host will not be considered 
+     * as an IPV4 address
+     */
+    @Test
+    public void testDnBadHostIP1() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://1.1.1/", new LdapUrl( "ldap://1.1.1/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad IP host 1 : we should not get an error, but the host will not be considered 
+     * as an IPV4 address
+     */
+    @Test
+    public void testDnBadHostIP2() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://1.1.1./", new LdapUrl( "ldap://1.1.1./" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad IP host 1 : we should not get an error, but the host will not be considered 
+     * as an IPV4 address
+     */
+    @Test
+    public void testDnBadHostIP3() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://1.1.1.100000/", new LdapUrl( "ldap://1.1.1.100000/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a bad IP host 4
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testDnBadHostIP4() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://1.1.1.1.1/" );
+    }
+
+
+    /**
+     * test a LdapUrl with a valid host hich is not an IP
+     */
+    @Test
+    public void testDnNotAnIP() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://1.1.1.100000.a/", new LdapUrl( "ldap://1.1.1.100000.a/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl IPv6 host
+     */
+    @Test
+    public void testDnIPv6Host() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://[::]/", new LdapUrl( "ldap://[::]/" ).toString() );
+        assertEquals( "ldap://[1::2]/", new LdapUrl( "ldap://[1::2]/" ).toString() );
+        assertEquals( "ldap://[abcd:EF01:0234:5678:abcd:EF01:0234:5678]/", new LdapUrl( "ldap://[abcd:EF01:0234:5678:abcd:EF01:0234:5678]/" ).toString() );
+        assertEquals( "ldap://[::2]/", new LdapUrl( "ldap://[::2]/" ).toString() );
+        assertEquals( "ldap://[1:2::3:4]/", new LdapUrl( "ldap://[1:2::3:4]/" ).toString() );
+        assertEquals( "ldap://[1:2:3:4:5:6::]/", new LdapUrl( "ldap://[1:2:3:4:5:6::]/" ).toString() );
+    }
+
+
+    /**
+     * test a bad LdapUrl IPv6 host
+     * @throws LdapURLEncodingException 
+     */
+    @Test( expected=LdapURLEncodingException.class )
+    public void testDnIPv6BadHost() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://[:]/" );
+    }
+
+
+    /**
+     * test a bad LdapUrl IPv6 host
+     * @throws LdapURLEncodingException 
+     */
+    @Test( expected=LdapURLEncodingException.class )
+    public void testDnIPv6BadHost2() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://[1::2::3]/" );
+    }
+
+
+    /**
+     * test a LdapUrl with valid simpleDN
+     */
+    @Test
+    public void testDnSimpleDN() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:389/dc=example,dc=org/", new LdapUrl(
+            "ldap://directory.apache.org:389/dc=example,dc=org/" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with valid simpleDN 2
+     */
+    @Test
+    public void testDnSimpleDN2() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:389/dc=example", new LdapUrl(
+            "ldap://directory.apache.org:389/dc=example" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a valid encoded Dn
+     */
+    @Test
+    public void testDnSimpleDNEncoded() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:389/dc=example%202,dc=org", new LdapUrl(
+            "ldap://directory.apache.org:389/dc=example%202,dc=org" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with an invalid Dn
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testDnInvalidDN() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://directory.apache.org:389/dc=example%202,dc : org" );
+    }
+
+
+    /**
+     * test a LdapUrl with an invalid Dn 2
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testDnInvalidDN2() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://directory.apache.org:389/dc=example%202,dc = org," );
+    }
+
+
+    /**
+     * test a LdapUrl with valid unique attributes
+     */
+    @Test
+    public void testDnUniqueAttribute() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:389/dc=example,dc=org?ou", new LdapUrl(
+            "ldap://directory.apache.org:389/dc=example,dc=org?ou" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with valid attributes
+     */
+    @Test
+    public void testDnAttributes() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:389/dc=example,dc=org?ou,objectclass,dc", new LdapUrl(
+            "ldap://directory.apache.org:389/dc=example,dc=org?ou,objectclass,dc" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with valid duplicated attributes
+     */
+    @Test
+    public void testDnDuplicatedAttributes() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:389/dc=example,dc=org?ou,dc", new LdapUrl(
+            "ldap://directory.apache.org:389/dc=example,dc=org?ou,dc,ou" ).toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with invalid attributes
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testLdapInvalideAttributes() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://directory.apache.org:389/dc=example,dc=org?ou=,dc" );
+    }
+
+
+    /**
+     * test a LdapUrl with attributes but no Dn
+     */
+    @Test
+    public void testLdapNoDNAttributes() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://directory.apache.org:389/?ou,dc",
+            new LdapUrl( "ldap://directory.apache.org:389/?ou,dc" ).toString() );
+    }
+
+
+    /**
+     * test 1 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_1() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap:///o=University%20of%20Michigan,c=US", new LdapUrl(
+            "ldap:///o=University%20of%20Michigan,c=US" ).toString() );
+    }
+
+
+    /**
+     * test 2 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_2() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US", new LdapUrl(
+            "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US" ).toString() );
+    }
+
+
+    /**
+     * test 3 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_3() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress", new LdapUrl(
+            "ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US?postalAddress" ).toString() );
+    }
+
+
+    /**
+     * test 4 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_4() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)",
+            new LdapUrl( "ldap://host.com:6666/o=University%20of%20Michigan,c=US??sub?(cn=Babs%20Jensen)" ).toString() );
+    }
+
+
+    /**
+     * test 5 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_5() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://ldap.itd.umich.edu/c=GB?objectClass?one", new LdapUrl(
+            "ldap://ldap.itd.umich.edu/c=GB?objectClass?one" ).toString() );
+    }
+
+
+    /**
+     * test 6 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_6() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://ldap.question.com/o=Question%3F,c=US?mail", new LdapUrl(
+            "ldap://ldap.question.com/o=Question%3f,c=US?mail" ).toString() );
+    }
+
+
+    /**
+     * test 7 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_7() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5C00%5C00%5C00%5C04)", new LdapUrl(
+            "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)" ).toString() );
+    }
+
+
+    /**
+     * test 8 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_8() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap:///??sub??bindname=cn=Manager%2co=Foo", new LdapUrl(
+            "ldap:///??sub??bindname=cn=Manager%2co=Foo" ).toString() );
+    }
+
+
+    /**
+     * test 9 from RFC 2255 LdapUrl
+     */
+    @Test
+    public void testLdapRFC2255_9() throws LdapURLEncodingException
+    {
+        assertEquals( "ldap:///??sub??!bindname=cn=Manager%2co=Foo", new LdapUrl(
+            "ldap:///??sub??!bindname=cn=Manager%2co=Foo" ).toString() );
+    }
+
+
+    /**
+     * test an empty ldaps:// LdapUrl
+     */
+    @Test
+    public void testDnEmptyLdaps() throws LdapURLEncodingException
+    {
+        assertEquals( "ldaps:///", new LdapUrl( "ldaps:///" ).toString() );
+    }
+
+
+    /**
+     * test an simple ldaps:// LdapUrl
+     */
+    @Test
+    public void testDnSimpleLdaps() throws LdapURLEncodingException
+    {
+        assertEquals( "ldaps://directory.apache.org:80/", new LdapUrl( "ldaps://directory.apache.org:80/" )
+            .toString() );
+    }
+
+
+    /**
+     * test the setScheme() method
+     */
+    @Test
+    public void testDnSetScheme() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl();
+        assertEquals( "ldap://", url.getScheme() );
+
+        url.setScheme( "invalid" );
+        assertEquals( "ldap://", url.getScheme() );
+
+        url.setScheme( "ldap://" );
+        assertEquals( "ldap://", url.getScheme() );
+
+        url.setScheme( "ldaps://" );
+        assertEquals( "ldaps://", url.getScheme() );
+
+        url.setScheme( null );
+        assertEquals( "ldap://", url.getScheme() );
+    }
+
+
+    /**
+     * test the setHost() method
+     */
+    @Test
+    public void testDnSetHost() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl();
+        assertNull( url.getHost() );
+
+        url.setHost( "ldap.apache.org" );
+        assertEquals( "ldap.apache.org", url.getHost() );
+        assertEquals( "ldap://ldap.apache.org/", url.toString() );
+
+        url.setHost( null );
+        assertNull( url.getHost() );
+        assertEquals( "ldap:///", url.toString() );
+    }
+
+
+    /**
+     * test the setPort() method
+     */
+    @Test
+    public void testDnSetPort() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl();
+        assertEquals( -1, url.getPort() );
+
+        url.setPort( 389 );
+        assertEquals( 389, url.getPort() );
+        assertEquals( "ldap://:389/", url.toString() );
+
+        url.setPort( 0 );
+        assertEquals( -1, url.getPort() );
+        assertEquals( "ldap:///", url.toString() );
+
+        url.setPort( 65536 );
+        assertEquals( -1, url.getPort() );
+        assertEquals( "ldap:///", url.toString() );
+    }
+
+
+    /**
+     * test the setDn() method
+     */
+    @Test
+    public void testDnSetDn() throws LdapURLEncodingException, LdapInvalidDnException
+    {
+        LdapUrl url = new LdapUrl();
+        assertNull( url.getDn() );
+
+        Dn dn = new Dn( "dc=example,dc=com" );
+        url.setDn( dn );
+        assertEquals( dn, url.getDn() );
+        assertEquals( "ldap:///dc=example,dc=com", url.toString() );
+
+        url.setDn( null );
+        assertNull( url.getDn() );
+        assertEquals( "ldap:///", url.toString() );
+    }
+
+
+    /**
+     * test the setAttributes() method
+     */
+    @Test
+    public void testDnSetAttributes() throws LdapURLEncodingException, LdapInvalidDnException
+    {
+        LdapUrl url = new LdapUrl();
+        assertNotNull( url.getAttributes() );
+        assertTrue( url.getAttributes().isEmpty() );
+
+        List<String> attributes = new ArrayList<String>();
+        url.setDn( new Dn( "dc=example,dc=com" ) );
+
+        url.setAttributes( null );
+        assertNotNull( url.getAttributes() );
+        assertTrue( url.getAttributes().isEmpty() );
+        assertEquals( "ldap:///dc=example,dc=com", url.toString() );
+
+        attributes.add( "cn" );
+        url.setAttributes( attributes );
+        assertNotNull( url.getAttributes() );
+        assertEquals( 1, url.getAttributes().size() );
+        assertEquals( "ldap:///dc=example,dc=com?cn", url.toString() );
+
+        attributes.add( "userPassword;binary" );
+        url.setAttributes( attributes );
+        assertNotNull( url.getAttributes() );
+        assertEquals( 2, url.getAttributes().size() );
+        assertEquals( "ldap:///dc=example,dc=com?cn,userPassword;binary", url.toString() );
+    }
+
+
+    /**
+     * test the setScope() method
+     */
+    @Test
+    public void testDnSetScope() throws LdapURLEncodingException, LdapInvalidDnException
+    {
+        LdapUrl url = new LdapUrl();
+        assertEquals( SearchScope.OBJECT, url.getScope() );
+
+        url.setDn( new Dn( "dc=example,dc=com" ) );
+
+        url.setScope( SearchScope.ONELEVEL );
+        assertEquals( SearchScope.ONELEVEL, url.getScope() );
+        assertEquals( "ldap:///dc=example,dc=com??one", url.toString() );
+
+        url.setScope( SearchScope.SUBTREE );
+        assertEquals( SearchScope.SUBTREE, url.getScope() );
+        assertEquals( "ldap:///dc=example,dc=com??sub", url.toString() );
+
+        url.setScope( -1 );
+        assertEquals( SearchScope.OBJECT, url.getScope() );
+        assertEquals( "ldap:///dc=example,dc=com", url.toString() );
+    }
+
+
+    /**
+     * test the setFilter() method
+     */
+    @Test
+    public void testDnSetFilter() throws LdapURLEncodingException, LdapInvalidDnException
+    {
+        LdapUrl url = new LdapUrl();
+        assertNull( url.getFilter() );
+
+        url.setDn( new Dn( "dc=example,dc=com" ) );
+
+        url.setFilter( "(objectClass=person)" );
+        assertEquals( "(objectClass=person)", url.getFilter() );
+        assertEquals( "ldap:///dc=example,dc=com???(objectClass=person)", url.toString() );
+
+        url.setFilter( "(cn=Babs Jensen)" );
+        assertEquals( "(cn=Babs Jensen)", url.getFilter() );
+        assertEquals( "ldap:///dc=example,dc=com???(cn=Babs%20Jensen)", url.toString() );
+
+        url.setFilter( null );
+        assertNull( url.getFilter() );
+        assertEquals( "ldap:///dc=example,dc=com", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl without a scheme
+     *
+     */
+    @Test
+    public void testLdapURLNoScheme() throws LdapURLEncodingException
+    {
+        try
+        {
+            new LdapUrl( "/ou=system" );
+            fail();
+        }
+        catch ( LdapURLEncodingException luee )
+        {
+            assertTrue( true );
+        }
+    }
+
+
+    /**
+     * test a LdapUrl without a host but with a Dn
+     *
+     */
+    @Test
+    public void testLdapURLNoHostDN() throws LdapURLEncodingException
+    {
+        try
+        {
+            LdapUrl url = new LdapUrl( "ldap:///ou=system" );
+
+            assertEquals( "ldap:///ou=system", url.toString() );
+
+        }
+        catch ( LdapURLEncodingException luee )
+        {
+            fail();
+        }
+    }
+
+
+    /**
+     * test a LdapUrl with a host, no port, and a Dn
+     *
+     */
+    @Test
+    public void testLdapURLHostNoPortDN() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost/ou=system" );
+
+        assertEquals( "ldap://localhost/ou=system", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no host, a port, and a Dn
+     *
+     */
+    @Test(expected = LdapURLEncodingException.class)
+    public void testLdapURLNoHostPortDN() throws LdapURLEncodingException
+    {
+        new LdapUrl( "ldap://:123/ou=system" );
+
+        fail();
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn
+     *
+     */
+    @Test
+    public void testLdapURLNoDN() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/" );
+
+        assertEquals( "ldap://localhost:123/", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn and no attributes
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrs() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?" );
+
+        assertEquals( "ldap://localhost:123/", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes and no scope
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsNoScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??" );
+
+        assertEquals( "ldap://localhost:123/", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, no scope and no filter
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsNoScopeNoFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/???" );
+
+        assertEquals( "ldap://localhost:123/", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn and attributes
+     *
+     */
+    @Test
+    public void testLdapURLDN() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system" );
+
+        assertEquals( "ldap://localhost:123/ou=system", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn and attributes
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrs() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?ou,dc,cn" );
+
+        assertEquals( "ldap://localhost:123/ou=system?ou,dc,cn", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn and attributes
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrs() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?ou,dc,cn" );
+
+        assertEquals( "ldap://localhost:123/?ou,dc,cn", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes an scope
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??sub" );
+
+        assertEquals( "ldap://localhost:123/??sub", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes an scope base
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScopeBase() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??base" );
+
+        assertEquals( "ldap://localhost:123/", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes an default scope
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsDefaultScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??" );
+
+        assertEquals( "ldap://localhost:123/", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes an scope
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??sub" );
+
+        assertEquals( "ldap://localhost:123/ou=system??sub", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes an scope base
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScopeBase() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??base" );
+
+        assertEquals( "ldap://localhost:123/ou=system", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes an default scope
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsDefaultScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??" );
+
+        assertEquals( "ldap://localhost:123/ou=system", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes an scope
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?ou,cn?sub" );
+
+        assertEquals( "ldap://localhost:123/?ou,cn?sub", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes an scope base
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScopeBase() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?ou,cn?base" );
+
+        assertEquals( "ldap://localhost:123/?ou,cn", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes an default scope
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsDefaultScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?ou,cn?" );
+
+        assertEquals( "ldap://localhost:123/?ou,cn", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes an scope
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?ou,cn?sub" );
+
+        assertEquals( "ldap://localhost:123/ou=system?ou,cn?sub", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes an scope base
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScopeBase() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?ou,cn?base" );
+
+        assertEquals( "ldap://localhost:123/ou=system?ou,cn", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes an default scope
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsDefaultScope() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?ou,cn?" );
+
+        assertEquals( "ldap://localhost:123/ou=system?ou,cn", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, no scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsNoScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/???(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/???(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, no scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsNoScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system???(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/ou=system???(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, no scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsNoScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,ou,dc??(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/?cn,ou,dc??(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, a scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??sub?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/??sub?(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, a base scope, and filter
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScopeBaseFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??base?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/???(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, a scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,ou,dc?sub?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/?cn,ou,dc?sub?(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, a base scope, and filter
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScopeBaseFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,ou,dc?base?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/?cn,ou,dc??(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, a scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??sub?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/ou=system??sub?(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, a base scope, and filter
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScopeBaseFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??base?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/ou=system???(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, no scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsNoScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,dc,ou??(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,dc,ou??(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, a scope and filter
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScopeFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc?sub?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc?sub?(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, a base scope, and filter
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScopeBaseFilter() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc?base?(cn=test)" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc??(cn=test)", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, no scope, no filter and no extension
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsNoScopeNoFilterNoExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/????" );
+
+        assertEquals( "ldap://localhost:123/", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, no scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsNoScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/????!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/????!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, no scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsNoScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/???(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/???(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, a scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??sub??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/??sub??!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, a base scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScopeBaseNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??base??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/????!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, a scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??sub?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/??sub?(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, no attributes, a base scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNNoAttrsScopeBaseFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/??base?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/???(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, no scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsNoScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,dc,ou???!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/?cn,dc,ou???!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, no scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsNoScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,dc,ou??(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/?cn,dc,ou??(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, a scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,dc,ou?sub??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/?cn,dc,ou?sub??!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, a base scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScopeBaseNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,dc,ou?base??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/?cn,dc,ou???!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, a scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,dc,ou?sub?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/?cn,dc,ou?sub?(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with no Dn, some attributes, a base scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLNoDNAttrsScopeBaseFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/?cn,dc,ou?base?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/?cn,dc,ou??(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, no scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsNoScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system????!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system????!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, no scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsNoScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system???(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system???(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, a scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??sub??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system??sub??!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, a base scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScopeBaseNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??base??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system????!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, a scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??sub?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system??sub?(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, no attributes, a base scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNNoAttrsScopeBaseFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system??base?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system???(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, no scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsNoScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc???!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc???!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, no scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsNoScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc??(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc??(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, a scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScopeNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc?sub??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc?sub??!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, a base scope, no filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScopeBaseNoFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc?base??!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc???!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, a scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScopeFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc?sub?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc?sub?(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * test a LdapUrl with a Dn, some attributes, a base scope, a filter and some extensions
+     *
+     */
+    @Test
+    public void testLdapURLDNAttrsScopeBaseFilterExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/ou=system?cn,ou,dc?base?(cn=test)?!a=b,!c" );
+
+        assertEquals( "ldap://localhost:123/ou=system?cn,ou,dc??(cn=test)?!a=b,!c", url.toString() );
+    }
+
+
+    /**
+     * Test a LdapUrl with an extension after an empty extension.
+     */
+    @Test
+    public void testLdapURLExtensionAfterEmptyExtension() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/????!a=b,!c,d=e" );
+
+        assertEquals( "ldap://localhost:123/????!a=b,!c,d=e", url.toString() );
+    }
+
+
+    /**
+     * Test the extension order of an LdapUrl.
+     */
+    @Test
+    public void testLdapURLExtensionOrder() throws LdapURLEncodingException
+    {
+        LdapUrl url = new LdapUrl( "ldap://localhost:123/????!a=b,!c,!x,d=e,f=g,!h=i" );
+
+        assertEquals( "ldap://localhost:123/????!a=b,!c,!x,d=e,f=g,!h=i", url.toString() );
+
+        List<Extension> extensions = url.getExtensions();
+
+        assertTrue( extensions.get( 0 ).isCritical() );
+        assertEquals( "a", extensions.get( 0 ).getType() );
+        assertEquals( "b", extensions.get( 0 ).getValue() );
+
+        assertTrue( extensions.get( 1 ).isCritical() );
+        assertEquals( "c", extensions.get( 1 ).getType() );
+        assertNull( extensions.get( 1 ).getValue() );
+
+        assertTrue( extensions.get( 2 ).isCritical() );
+        assertEquals( "x", extensions.get( 2 ).getType() );
+        assertNull( extensions.get( 2 ).getValue() );
+
+        assertFalse( extensions.get( 3 ).isCritical() );
+        assertEquals( "d", extensions.get( 3 ).getType() );
+        assertEquals( "e", extensions.get( 3 ).getValue() );
+
+        assertFalse( extensions.get( 4 ).isCritical() );
+        assertEquals( "f", extensions.get( 4 ).getType() );
+        assertEquals( "g", extensions.get( 4 ).getValue() );
+
+        assertTrue( extensions.get( 5 ).isCritical() );
+        assertEquals( "h", extensions.get( 5 ).getType() );
+        assertEquals( "i", extensions.get( 5 ).getValue() );
+    }
+
+
+    /**
+     * Test UTF-8 values in extension values.
+     */
+    @Test
+    public void testLdapURLExtensionWithUtf8Values() throws Exception
+    {
+        String germanChars = new String(
+            new byte[]
+                { ( byte ) 0xC3, ( byte ) 0x84, ( byte ) 0xC3, ( byte ) 0x96, ( byte ) 0xC3, ( byte ) 0x9C,
+                    ( byte ) 0xC3, ( byte ) 0x9F, ( byte ) 0xC3, ( byte ) 0xA4, ( byte ) 0xC3, ( byte ) 0xB6,
+                    ( byte ) 0xC3, ( byte ) 0xBC }, "UTF-8" );
+
+        LdapUrl url1 = new LdapUrl();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( Dn.EMPTY_DN );
+        url1.getExtensions().add( new Extension( false, "X-CONNECTION-NAME", germanChars ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%C3%84%C3%96%C3%9C%C3%9F%C3%A4%C3%B6%C3%BC", url1
+            .toString() );
+
+        LdapUrl url2 = new LdapUrl(
+            "ldap://localhost:123/????X-CONNECTION-NAME=%c3%84%c3%96%c3%9c%c3%9f%c3%a4%c3%b6%c3%bc" );
+        assertEquals( germanChars, url1.getExtensionValue( "X-CONNECTION-NAME" ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%C3%84%C3%96%C3%9C%C3%9F%C3%A4%C3%B6%C3%BC", url2
+            .toString() );
+    }
+
+
+    /**
+     * Test comma in extension value.
+     */
+    @Test
+    public void testLdapURLExtensionWithCommaValue() throws Exception
+    {
+        LdapUrl url1 = new LdapUrl();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( Dn.EMPTY_DN );
+        url1.getExtensions().add( new Extension( false, "X-CONNECTION-NAME", "," ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%2c", url1.toString() );
+
+        LdapUrl url2 = new LdapUrl( "ldap://localhost:123/????X-CONNECTION-NAME=%2c" );
+        assertEquals( ",", url1.getExtensionValue( "X-CONNECTION-NAME" ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%2c", url2.toString() );
+    }
+
+
+    /**
+     * Test with RFC 3986 reserved characters in extension value.
+     *
+     *   reserved    = gen-delims / sub-delims
+     *   gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+     *   sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
+     *                 / "*" / "+" / "," / ";" / "="
+     *
+     * RFC 4516 specifies that '?' and a ',' must be percent encoded.
+     *
+     */
+    @Test
+    public void testLdapURLExtensionWithRFC3986ReservedCharsAndRFC4616Exception() throws Exception
+    {
+        LdapUrl url1 = new LdapUrl();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( Dn.EMPTY_DN );
+        url1.getExtensions().add( new Extension( false, "X-CONNECTION-NAME", ":/?#[]@!$&'()*+,;=" ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=:/%3F#[]@!$&'()*+%2c;=", url1.toString() );
+
+        LdapUrl url2 = new LdapUrl( "ldap://localhost:123/????X-CONNECTION-NAME=:/%3f#[]@!$&'()*+%2c;=" );
+        assertEquals( ":/?#[]@!$&'()*+,;=", url1.getExtensionValue( "X-CONNECTION-NAME" ) );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=:/%3F#[]@!$&'()*+%2c;=", url2.toString() );
+    }
+
+
+    /**
+     * Test with RFC 3986 unreserved characters in extension value.
+     *
+     *   unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
+     */
+    @Test
+    public void testLdapURLExtensionWithRFC3986UnreservedChars() throws Exception
+    {
+        LdapUrl url1 = new LdapUrl();
+        url1.setHost( "localhost" );
+        url1.setPort( 123 );
+        url1.setDn( Dn.EMPTY_DN );
+        url1.getExtensions().add(
+            new Extension( false, "X-CONNECTION-NAME",
+                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~" ) );
+        assertEquals(
+            "ldap://localhost:123/????X-CONNECTION-NAME=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~",
+            url1.toString() );
+
+        LdapUrl url2 = new LdapUrl(
+            "ldap://localhost:123/????X-CONNECTION-NAME=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~" );
+        assertEquals( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~", url1
+            .getExtensionValue( "X-CONNECTION-NAME" ) );
+        assertEquals(
+            "ldap://localhost:123/????X-CONNECTION-NAME=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~",
+            url2.toString() );
+    }
+}
diff --git a/trunk/ldap/model/src/test/resources/log4j.properties b/trunk/ldap/model/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/model/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/collective.schema b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/collective.schema
new file mode 100644
index 0000000..504104d
--- /dev/null
+++ b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/collective.schema
@@ -0,0 +1,82 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License. 
+
+# collective.schema -- Collective attribute schema
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/collective.schema,v 1.12.2.2 2007/08/31 23:14:06 quanah Exp $
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2007 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+#
+
+# The version of this file as distributed by the OpenLDAP Foundation
+# contains text from an IETF RFC explaining the schema.  Unfortunately,
+# that text is covered by a license that doesn't meet Debian's Free
+# Software Guidelines.  This is a stripped version of the schema that
+# contains only the functional schema definition, not the text of the
+# RFC.
+#
+# For an explanation of this schema, see RFC 3671, at (among other
+# places):  http://www.ietf.org/rfc/rfc3671.txt
+
+attributeType      ( 2.5.4.7.1 NAME 'c-l'
+	SUP l COLLECTIVE )
+
+attributeType      ( 2.5.4.8.1 NAME 'c-st'
+	SUP st COLLECTIVE )
+
+attributeType      ( 2.5.4.9.1 NAME 'c-street'
+	SUP street COLLECTIVE )
+
+attributeType      ( 2.5.4.10.1 NAME 'c-o'
+	SUP o COLLECTIVE )
+
+attributeType      ( 2.5.4.11.1 NAME 'c-ou'
+	SUP ou COLLECTIVE )
+
+attributeType      ( 2.5.4.16.1 NAME 'c-PostalAddress'
+	SUP postalAddress COLLECTIVE )
+
+attributeType      ( 2.5.4.17.1 NAME 'c-PostalCode'
+	SUP postalCode COLLECTIVE )
+
+attributeType ( 2.5.4.18.1 NAME 'c-PostOfficeBox'
+	SUP postOfficeBox COLLECTIVE )
+
+attributeType ( 2.5.4.19.1 NAME 'c-PhysicalDeliveryOfficeName'
+	SUP physicalDeliveryOfficeName COLLECTIVE )
+
+attributeType ( 2.5.4.20.1 NAME 'c-TelephoneNumber'
+	SUP telephoneNumber COLLECTIVE )
+
+attributeType ( 2.5.4.21.1 NAME 'c-TelexNumber'
+	SUP telexNumber COLLECTIVE )
+
+attributeType ( 2.5.4.23.1 NAME 'c-FacsimileTelephoneNumber'
+	SUP facsimileTelephoneNumber COLLECTIVE )
+
+attributeType ( 2.5.4.25.1 NAME 'c-InternationalISDNNumber'
+	SUP internationalISDNNumber COLLECTIVE )
+
diff --git a/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/core.schema b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/core.schema
new file mode 100644
index 0000000..93b465a
--- /dev/null
+++ b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/core.schema
@@ -0,0 +1,620 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.  
+
+# OpenLDAP Core schema
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/core.schema,v 1.79.2.8 2007/01/02 21:44:09 kurt Exp $
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2007 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+#
+
+# The version of this file as distributed by the OpenLDAP Foundation
+# contains text claiming copyright by the Internet Society and including
+# the IETF RFC license, which does not meet Debian's Free Software
+# Guidelines.  However, apart from short and obvious comments, the text of
+# this file is purely a functional interface specification, which is not
+# subject to that license and is not copyrightable under US law.
+#
+# The license statement is retained below so as not to remove credit, but
+# as best as we can determine, it is not applicable to the contents of
+# this file.
+
+## Portions Copyright (C) The Internet Society (1997-2003).
+## All Rights Reserved.
+##
+## This document and translations of it may be copied and furnished to
+## others, and derivative works that comment on or otherwise explain it
+## or assist in its implementation may be prepared, copied, published
+## and distributed, in whole or in part, without restriction of any
+## kind, provided that the above copyright notice and this paragraph are
+## included on all such copies and derivative works.  However, this
+## document itself may not be modified in any way, such as by removing
+## the copyright notice or references to the Internet Society or other
+## Internet organizations, except as needed for the purpose of
+## developing Internet standards in which case the procedures for
+## copyrights defined in the Internet Standards process must be         
+## followed, or as required to translate it into languages other than
+## English.
+##                                                                      
+## The limited permissions granted above are perpetual and will not be  
+## revoked by the Internet Society or its successors or assigns.        
+## 
+## This document and the information contained herein is provided on an 
+## "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+## TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+## BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+## HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+## MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+#
+#
+# Includes LDAPv3 schema items from:
+#	RFC 2252/2256 (LDAPv3)
+#
+# Select standard track schema items:
+#	RFC 1274 (uid/dc)
+#	RFC 2079 (URI)
+#	RFC 2247 (dc/dcObject)
+#	RFC 2587 (PKI)
+#	RFC 2589 (Dynamic Directory Services)
+#
+# Select informational schema items:
+#	RFC 2377 (uidObject)
+
+#
+# Standard attribute types from RFC 2256
+#
+
+# system schema
+#attributetype ( 2.5.4.0 NAME 'objectClass'
+#	DESC 'RFC2256: object classes of the entity'
+#	EQUALITY objectIdentifierMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+# system schema
+#attributetype ( 2.5.4.1 NAME ( 'aliasedObjectName' 'aliasedEntryName' )
+#	DESC 'RFC2256: name of aliased object'
+#	EQUALITY distinguishedNameMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
+
+attributetype ( 2.5.4.2 NAME 'knowledgeInformation'
+	DESC 'RFC2256: knowledge information'
+	EQUALITY caseIgnoreMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+# system schema
+#attributetype ( 2.5.4.3 NAME ( 'cn' 'commonName' )
+#	DESC 'RFC2256: common name(s) for which the entity is known by'
+#	SUP name )
+
+attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' )
+	DESC 'RFC2256: last (family) name(s) for which the entity is known by'
+	SUP name )
+
+attributetype ( 2.5.4.5 NAME 'serialNumber'
+	DESC 'RFC2256: serial number of the entity'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
+
+attributetype ( 2.5.4.6 NAME ( 'c' 'countryName' )
+	DESC 'RFC2256: ISO-3166 country 2-letter code'
+	SUP name SINGLE-VALUE )
+
+attributetype ( 2.5.4.7 NAME ( 'l' 'localityName' )
+	DESC 'RFC2256: locality which this object resides in'
+	SUP name )
+
+attributetype ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' )
+	DESC 'RFC2256: state or province which this object resides in'
+	SUP name )
+
+attributetype ( 2.5.4.9 NAME ( 'street' 'streetAddress' )
+	DESC 'RFC2256: street address of this object'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.10 NAME ( 'o' 'organizationName' )
+	DESC 'RFC2256: organization this object belongs to'
+	SUP name )
+
+attributetype ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' )
+	DESC 'RFC2256: organizational unit this object belongs to'
+	SUP name )
+
+attributetype ( 2.5.4.12 NAME 'title'
+	DESC 'RFC2256: title associated with the entity'
+	SUP name )
+
+# system schema
+#attributetype ( 2.5.4.13 NAME 'description'
+#	DESC 'RFC2256: descriptive information'
+#	EQUALITY caseIgnoreMatch
+#	SUBSTR caseIgnoreSubstringsMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
+
+# Deprecated by enhancedSearchGuide
+attributetype ( 2.5.4.14 NAME 'searchGuide'
+	DESC 'RFC2256: search guide, deprecated by enhancedSearchGuide'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
+
+attributetype ( 2.5.4.15 NAME 'businessCategory'
+	DESC 'RFC2256: business category'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.16 NAME 'postalAddress'
+	DESC 'RFC2256: postal address'
+	EQUALITY caseIgnoreListMatch
+	SUBSTR caseIgnoreListSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attributetype ( 2.5.4.17 NAME 'postalCode'
+	DESC 'RFC2256: postal code'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attributetype ( 2.5.4.18 NAME 'postOfficeBox'
+	DESC 'RFC2256: Post Office Box'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
+
+attributetype ( 2.5.4.19 NAME 'physicalDeliveryOfficeName'
+	DESC 'RFC2256: Physical Delivery Office Name'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 2.5.4.20 NAME 'telephoneNumber'
+	DESC 'RFC2256: Telephone Number'
+	EQUALITY telephoneNumberMatch
+	SUBSTR telephoneNumberSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
+
+attributetype ( 2.5.4.21 NAME 'telexNumber'
+	DESC 'RFC2256: Telex Number'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
+
+attributetype ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
+	DESC 'RFC2256: Teletex Terminal Identifier'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
+
+attributetype ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
+	DESC 'RFC2256: Facsimile (Fax) Telephone Number'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
+
+attributetype ( 2.5.4.24 NAME 'x121Address'
+	DESC 'RFC2256: X.121 Address'
+	EQUALITY numericStringMatch
+	SUBSTR numericStringSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )
+
+attributetype ( 2.5.4.25 NAME 'internationaliSDNNumber'
+	DESC 'RFC2256: international ISDN number'
+	EQUALITY numericStringMatch
+	SUBSTR numericStringSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
+
+attributetype ( 2.5.4.26 NAME 'registeredAddress'
+	DESC 'RFC2256: registered postal address'
+	SUP postalAddress
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
+
+attributetype ( 2.5.4.27 NAME 'destinationIndicator'
+	DESC 'RFC2256: destination indicator'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
+
+attributetype ( 2.5.4.28 NAME 'preferredDeliveryMethod'
+	DESC 'RFC2256: preferred delivery method'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
+	SINGLE-VALUE )
+
+attributetype ( 2.5.4.29 NAME 'presentationAddress'
+	DESC 'RFC2256: presentation address'
+	EQUALITY presentationAddressMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.43
+	SINGLE-VALUE )
+
+attributetype ( 2.5.4.30 NAME 'supportedApplicationContext'
+	DESC 'RFC2256: supported application context'
+	EQUALITY objectIdentifierMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
+
+attributetype ( 2.5.4.31 NAME 'member'
+	DESC 'RFC2256: member of a group'
+	SUP distinguishedName )
+
+attributetype ( 2.5.4.32 NAME 'owner'
+	DESC 'RFC2256: owner (of the object)'
+	SUP distinguishedName )
+
+attributetype ( 2.5.4.33 NAME 'roleOccupant'
+	DESC 'RFC2256: occupant of role'
+	SUP distinguishedName )
+
+# system schema
+#attributetype ( 2.5.4.34 NAME 'seeAlso'
+#	DESC 'RFC2256: DN of related object'
+#	SUP distinguishedName )
+
+# system schema
+#attributetype ( 2.5.4.35 NAME 'userPassword'
+#	DESC 'RFC2256/2307: password of user'
+#	EQUALITY octetStringMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
+
+# Must be transferred using ;binary
+# with certificateExactMatch rule (per X.509)
+attributetype ( 2.5.4.36 NAME 'userCertificate'
+	DESC 'RFC2256: X.509 user certificate, use ;binary'
+	EQUALITY certificateExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# Must be transferred using ;binary
+# with certificateExactMatch rule (per X.509)
+attributetype ( 2.5.4.37 NAME 'cACertificate'
+	DESC 'RFC2256: X.509 CA certificate, use ;binary'
+	EQUALITY certificateExactMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.38 NAME 'authorityRevocationList'
+	DESC 'RFC2256: X.509 authority revocation list, use ;binary'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.39 NAME 'certificateRevocationList'
+	DESC 'RFC2256: X.509 certificate revocation list, use ;binary'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+# Must be stored and requested in the binary form
+attributetype ( 2.5.4.40 NAME 'crossCertificatePair'
+	DESC 'RFC2256: X.509 cross certificate pair, use ;binary'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
+
+# system schema
+#attributetype ( 2.5.4.41 NAME 'name'
+#	EQUALITY caseIgnoreMatch
+#	SUBSTR caseIgnoreSubstringsMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+attributetype ( 2.5.4.42 NAME ( 'givenName' 'gn' )
+	DESC 'RFC2256: first name(s) for which the entity is known by'
+	SUP name )
+
+attributetype ( 2.5.4.43 NAME 'initials'
+	DESC 'RFC2256: initials of some or all of names, but not the surname(s).'
+	SUP name )
+
+attributetype ( 2.5.4.44 NAME 'generationQualifier'
+	DESC 'RFC2256: name qualifier indicating a generation'
+	SUP name )
+
+attributetype ( 2.5.4.45 NAME 'x500UniqueIdentifier'
+	DESC 'RFC2256: X.500 unique identifier'
+	EQUALITY bitStringMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )
+
+attributetype ( 2.5.4.46 NAME 'dnQualifier'
+	DESC 'RFC2256: DN qualifier'
+	EQUALITY caseIgnoreMatch
+	ORDERING caseIgnoreOrderingMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
+
+attributetype ( 2.5.4.47 NAME 'enhancedSearchGuide'
+	DESC 'RFC2256: enhanced search guide'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
+
+attributetype ( 2.5.4.48 NAME 'protocolInformation'
+	DESC 'RFC2256: protocol information'
+	EQUALITY protocolInformationMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )
+
+# system schema
+#attributetype ( 2.5.4.49 NAME 'distinguishedName'
+#	EQUALITY distinguishedNameMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+
+attributetype ( 2.5.4.50 NAME 'uniqueMember'
+	DESC 'RFC2256: unique member of a group'
+	EQUALITY uniqueMemberMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
+
+attributetype ( 2.5.4.51 NAME 'houseIdentifier'
+	DESC 'RFC2256: house identifier'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.52 NAME 'supportedAlgorithms'
+	DESC 'RFC2256: supported algorithms'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
+
+# Must be transferred using ;binary
+attributetype ( 2.5.4.53 NAME 'deltaRevocationList'
+	DESC 'RFC2256: delta revocation list; use ;binary'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
+
+attributetype ( 2.5.4.54 NAME 'dmdName'
+	DESC 'RFC2256: name of DMD'
+	SUP name )
+
+attributetype ( 2.5.4.65 NAME 'pseudonym'
+	DESC 'X.520(4th): pseudonym for the object'
+	SUP name )
+
+# Standard object classes from RFC2256
+
+# system schema
+#objectclass ( 2.5.6.0 NAME 'top'
+#	DESC 'RFC2256: top of the superclass chain'
+#	ABSTRACT
+#	MUST objectClass )
+
+# system schema
+#objectclass ( 2.5.6.1 NAME 'alias'
+#	DESC 'RFC2256: an alias'
+#	SUP top STRUCTURAL
+#	MUST aliasedObjectName )
+
+objectclass ( 2.5.6.2 NAME 'country'
+	DESC 'RFC2256: a country'
+	SUP top STRUCTURAL
+	MUST c
+	MAY ( searchGuide $ description ) )
+
+objectclass ( 2.5.6.3 NAME 'locality'
+	DESC 'RFC2256: a locality'
+	SUP top STRUCTURAL
+	MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
+
+objectclass ( 2.5.6.4 NAME 'organization'
+	DESC 'RFC2256: an organization'
+	SUP top STRUCTURAL
+	MUST o
+	MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+		x121Address $ registeredAddress $ destinationIndicator $
+		preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+		telephoneNumber $ internationaliSDNNumber $ 
+		facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+		postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.5 NAME 'organizationalUnit'
+	DESC 'RFC2256: an organizational unit'
+	SUP top STRUCTURAL
+	MUST ou
+	MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+		x121Address $ registeredAddress $ destinationIndicator $
+		preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+		telephoneNumber $ internationaliSDNNumber $
+		facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+		postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
+
+objectclass ( 2.5.6.6 NAME 'person'
+	DESC 'RFC2256: a person'
+	SUP top STRUCTURAL
+	MUST ( sn $ cn )
+	MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
+
+objectclass ( 2.5.6.7 NAME 'organizationalPerson'
+	DESC 'RFC2256: an organizational person'
+	SUP person STRUCTURAL
+	MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
+		preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+		telephoneNumber $ internationaliSDNNumber $ 
+		facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
+		postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
+
+objectclass ( 2.5.6.8 NAME 'organizationalRole'
+	DESC 'RFC2256: an organizational role'
+	SUP top STRUCTURAL
+	MUST cn
+	MAY ( x121Address $ registeredAddress $ destinationIndicator $
+		preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+		telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
+		seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $
+		postOfficeBox $ postalCode $ postalAddress $
+		physicalDeliveryOfficeName $ ou $ st $ l $ description ) )
+
+objectclass ( 2.5.6.9 NAME 'groupOfNames'
+	DESC 'RFC2256: a group of names (DNs)'
+	SUP top STRUCTURAL
+	MUST ( member $ cn )
+	MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+objectclass ( 2.5.6.10 NAME 'residentialPerson'
+	DESC 'RFC2256: an residential person'
+	SUP person STRUCTURAL
+	MUST l
+	MAY ( businessCategory $ x121Address $ registeredAddress $
+		destinationIndicator $ preferredDeliveryMethod $ telexNumber $
+		teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $
+		facsimileTelephoneNumber $ preferredDeliveryMethod $ street $
+		postOfficeBox $ postalCode $ postalAddress $
+		physicalDeliveryOfficeName $ st $ l ) )
+
+objectclass ( 2.5.6.11 NAME 'applicationProcess'
+	DESC 'RFC2256: an application process'
+	SUP top STRUCTURAL
+	MUST cn
+	MAY ( seeAlso $ ou $ l $ description ) )
+
+objectclass ( 2.5.6.12 NAME 'applicationEntity'
+	DESC 'RFC2256: an application entity'
+	SUP top STRUCTURAL
+	MUST ( presentationAddress $ cn )
+	MAY ( supportedApplicationContext $ seeAlso $ ou $ o $ l $
+	description ) )
+
+objectclass ( 2.5.6.13 NAME 'dSA'
+	DESC 'RFC2256: a directory system agent (a server)'
+	SUP applicationEntity STRUCTURAL
+	MAY knowledgeInformation )
+
+objectclass ( 2.5.6.14 NAME 'device'
+	DESC 'RFC2256: a device'
+	SUP top STRUCTURAL
+	MUST cn
+	MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) )
+
+objectclass ( 2.5.6.15 NAME 'strongAuthenticationUser'
+	DESC 'RFC2256: a strong authentication user'
+	SUP top AUXILIARY
+	MUST userCertificate )
+
+objectclass ( 2.5.6.16 NAME 'certificationAuthority'
+	DESC 'RFC2256: a certificate authority'
+	SUP top AUXILIARY
+	MUST ( authorityRevocationList $ certificateRevocationList $
+		cACertificate ) MAY crossCertificatePair )
+
+objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames'
+	DESC 'RFC2256: a group of unique names (DN and Unique Identifier)'
+	SUP top STRUCTURAL
+	MUST ( uniqueMember $ cn )
+	MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
+
+objectclass ( 2.5.6.18 NAME 'userSecurityInformation'
+	DESC 'RFC2256: a user security information'
+	SUP top AUXILIARY
+	MAY ( supportedAlgorithms ) )
+
+objectclass ( 2.5.6.16.2 NAME 'certificationAuthority-V2'
+	SUP certificationAuthority
+	AUXILIARY MAY ( deltaRevocationList ) )
+
+objectclass ( 2.5.6.19 NAME 'cRLDistributionPoint'
+	SUP top STRUCTURAL
+	MUST ( cn )
+	MAY ( certificateRevocationList $ authorityRevocationList $
+		deltaRevocationList ) )
+
+objectclass ( 2.5.6.20 NAME 'dmd'
+	SUP top STRUCTURAL
+	MUST ( dmdName )
+	MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
+		x121Address $ registeredAddress $ destinationIndicator $
+		preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
+		telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
+		street $ postOfficeBox $ postalCode $ postalAddress $
+		physicalDeliveryOfficeName $ st $ l $ description ) )
+
+#
+# Object Classes from RFC 2587
+#
+objectclass ( 2.5.6.21 NAME 'pkiUser'
+	DESC 'RFC2587: a PKI user'
+	SUP top AUXILIARY
+	MAY userCertificate )
+
+objectclass ( 2.5.6.22 NAME 'pkiCA'
+	DESC 'RFC2587: PKI certificate authority'
+	SUP top AUXILIARY
+	MAY ( authorityRevocationList $ certificateRevocationList $
+		cACertificate $ crossCertificatePair ) )
+
+objectclass ( 2.5.6.23 NAME 'deltaCRL'
+	DESC 'RFC2587: PKI user'
+	SUP top AUXILIARY
+	MAY deltaRevocationList )
+
+#
+# Standard Track URI label schema from RFC 2079
+# system schema
+#attributetype ( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI'
+#	DESC 'RFC2079: Uniform Resource Identifier with optional label'
+#	EQUALITY caseExactMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+objectclass ( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject'
+	DESC 'RFC2079: object that contains the URI attribute type'
+	SUP top AUXILIARY
+	MAY ( labeledURI ) )
+
+#
+# Derived from RFC 1274, but with new "short names"
+#
+#attributetype ( 0.9.2342.19200300.100.1.1
+#	NAME ( 'uid' 'userid' )
+#	DESC 'RFC1274: user identifier'
+#	EQUALITY caseIgnoreMatch
+#	SUBSTR caseIgnoreSubstringsMatch
+#	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+attributetype ( 0.9.2342.19200300.100.1.3
+	NAME ( 'mail' 'rfc822Mailbox' )
+	DESC 'RFC1274: RFC822 Mailbox'
+    EQUALITY caseIgnoreIA5Match
+    SUBSTR caseIgnoreIA5SubstringsMatch
+    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
+	DESC 'RFC1274: simple security object'
+	SUP top AUXILIARY
+	MUST userPassword )
+
+# RFC 1274 + RFC 2247
+attributetype ( 0.9.2342.19200300.100.1.25
+	NAME ( 'dc' 'domainComponent' )
+	DESC 'RFC1274/2247: domain component'
+	EQUALITY caseIgnoreIA5Match
+	SUBSTR caseIgnoreIA5SubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+# RFC 2247
+objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
+	DESC 'RFC2247: domain component object'
+	SUP top AUXILIARY MUST dc )
+
+# RFC 2377
+objectclass ( 1.3.6.1.1.3.1 NAME 'uidObject'
+	DESC 'RFC2377: uid object'
+	SUP top AUXILIARY MUST uid )
+
+# From COSINE Pilot
+attributetype ( 0.9.2342.19200300.100.1.37
+	NAME 'associatedDomain'
+	DESC 'RFC1274: domain associated with object'
+	EQUALITY caseIgnoreIA5Match
+	SUBSTR caseIgnoreIA5SubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# RFC 2459 -- deprecated in favor of 'mail' (in cosine.schema)
+attributetype ( 1.2.840.113549.1.9.1
+	NAME ( 'email' 'emailAddress' 'pkcs9email' )
+	DESC 'RFC3280: legacy attribute for email addresses in DNs'
+	EQUALITY caseIgnoreIA5Match
+	SUBSTR caseIgnoreIA5SubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
diff --git a/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/dyngroup.schema b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/dyngroup.schema
new file mode 100644
index 0000000..70dea02
--- /dev/null
+++ b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/dyngroup.schema
@@ -0,0 +1,99 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.  
+
+# dyngroup.schema -- Dynamic Group schema
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/dyngroup.schema,v 1.6.2.2 2007/08/31 23:14:06 quanah Exp $
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2007 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+#
+# Dynamic Group schema (experimental), as defined by Netscape.  See
+# http://www.redhat.com/docs/manuals/ent-server/pdf/esadmin611.pdf
+# page 70 for details on how these groups were used.
+#
+# A description of the objectclass definition is available here:
+# http://www.redhat.com/docs/manuals/dir-server/schema/7.1/oc_dir.html#1303745
+#
+# depends upon:
+#	core.schema
+#
+# These definitions are considered experimental due to the lack of
+# a formal specification (e.g., RFC).
+#
+# NOT RECOMMENDED FOR PRODUCTION USE!  USE WITH CAUTION!
+#
+# The Netscape documentation describes this as an auxiliary objectclass
+# but their implementations have always defined it as a structural class.
+# The sloppiness here is because Netscape-derived servers don't actually
+# implement the X.500 data model, and they don't honor the distinction
+# between structural and auxiliary classes. This fact is noted here:
+# http://forum.java.sun.com/thread.jspa?threadID=5016864&messageID=9034636
+#
+# In accordance with other existing implementations, we define it as a
+# structural class.
+#
+# Our definition of memberURL also does not match theirs but again
+# their published definition and what works in practice do not agree.
+# In other words, the Netscape definitions are broken and interoperability
+# is not guaranteed.
+#
+# Also see the new DynGroup proposed spec at
+# http://tools.ietf.org/html/draft-haripriya-dynamicgroup-02
+
+objectIdentifier NetscapeRoot 2.16.840.1.113730
+
+objectIdentifier NetscapeLDAP NetscapeRoot:3
+objectIdentifier NetscapeLDAPattributeType NetscapeLDAP:1
+objectIdentifier NetscapeLDAPobjectClass NetscapeLDAP:2
+
+objectIdentifier OpenLDAPExp11	1.3.6.1.4.1.4203.666.11
+objectIdentifier DynGroupBase	OpenLDAPExp11:8
+objectIdentifier DynGroupAttr	DynGroupBase:1
+objectIdentifier DynGroupOC	DynGroupBase:2
+
+attributetype ( NetscapeLDAPattributeType:198
+	NAME 'memberURL'
+	DESC 'Identifies an URL associated with each member of a group. Any type of labeled URL can be used.'
+	SUP labeledURI )
+
+attributetype ( DynGroupAttr:1
+	NAME 'dgIdentity'
+	DESC 'Identity to use when processing the memberURL'
+	SUP distinguishedName SINGLE-VALUE )
+
+objectClass ( NetscapeLDAPobjectClass:33
+	NAME 'groupOfURLs'
+	SUP top STRUCTURAL
+	MUST cn
+	MAY ( memberURL $ businessCategory $ description $ o $ ou $
+		owner $ seeAlso ) )
+
+# The Haripriya dyngroup schema still needs a lot of work.
+# We're just adding support for the dgIdentity attribute for now...
+objectClass ( DynGroupOC:1
+	NAME 'dgIdentityAux'
+	SUP top AUXILIARY
+	MAY dgIdentity )
diff --git a/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/inetorgperson.schema b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/inetorgperson.schema
new file mode 100644
index 0000000..77e568a
--- /dev/null
+++ b/trunk/ldap/model/src/test/resources/org/apache/directory/api/ldap/model/schema/parsers/inetorgperson.schema
@@ -0,0 +1,172 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.  
+
+# inetorgperson.schema -- InetOrgPerson (RFC2798)
+# $OpenLDAP: pkg/ldap/servers/slapd/schema/inetorgperson.schema,v 1.18.2.2 2007/08/31 23:14:06 quanah Exp $
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 1998-2007 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+#
+# InetOrgPerson (RFC2798)
+#
+# Depends upon
+#   Definition of an X.500 Attribute Type and an Object Class to Hold
+#   Uniform Resource Identifiers (URIs) [RFC2079]
+#	(core.schema)
+#
+#   A Summary of the X.500(96) User Schema for use with LDAPv3 [RFC2256]
+#	(core.schema)
+#
+#   The COSINE and Internet X.500 Schema [RFC1274] (cosine.schema)
+
+# carLicense
+# This multivalued field is used to record the values of the license or
+# registration plate associated with an individual.
+attributetype ( 2.16.840.1.113730.3.1.1
+	NAME 'carLicense'
+	DESC 'RFC2798: vehicle license or registration plate'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# departmentNumber
+# Code for department to which a person belongs.  This can also be
+# strictly numeric (e.g., 1234) or alphanumeric (e.g., ABC/123).
+attributetype ( 2.16.840.1.113730.3.1.2
+	NAME 'departmentNumber'
+	DESC 'RFC2798: identifies a department within an organization'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# displayName
+# When displaying an entry, especially within a one-line summary list, it
+# is useful to be able to identify a name to be used.  Since other attri-
+# bute types such as 'cn' are multivalued, an additional attribute type is
+# needed.  Display name is defined for this purpose.
+attributetype ( 2.16.840.1.113730.3.1.241
+	NAME 'displayName'
+	DESC 'RFC2798: preferred name to be used when displaying entries'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+	SINGLE-VALUE )
+
+# employeeNumber
+# Numeric or alphanumeric identifier assigned to a person, typically based
+# on order of hire or association with an organization.  Single valued.
+attributetype ( 2.16.840.1.113730.3.1.3
+	NAME 'employeeNumber'
+	DESC 'RFC2798: numerically identifies an employee within an organization'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+	SINGLE-VALUE )
+
+# employeeType
+# Used to identify the employer to employee relationship.  Typical values
+# used will be "Contractor", "Employee", "Intern", "Temp", "External", and
+# "Unknown" but any value may be used.
+attributetype ( 2.16.840.1.113730.3.1.4
+	NAME 'employeeType'
+	DESC 'RFC2798: type of employment for a person'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+# jpegPhoto
+# Used to store one or more images of a person using the JPEG File
+# Interchange Format [JFIF].
+# Note that the jpegPhoto attribute type was defined for use in the
+# Internet X.500 pilots but no referencable definition for it could be
+# located.
+attributetype ( 0.9.2342.19200300.100.1.60
+	NAME 'jpegPhoto'
+	DESC 'RFC2798: a JPEG image'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
+
+# preferredLanguage
+# Used to indicate an individual's preferred written or spoken
+# language.  This is useful for international correspondence or human-
+# computer interaction.  Values for this attribute type MUST conform to
+# the definition of the Accept-Language header field defined in
+# [RFC2068] with one exception:  the sequence "Accept-Language" ":"
+# should be omitted.  This is a single valued attribute type.
+attributetype ( 2.16.840.1.113730.3.1.39
+	NAME 'preferredLanguage'
+	DESC 'RFC2798: preferred written or spoken language for a person'
+	EQUALITY caseIgnoreMatch
+	SUBSTR caseIgnoreSubstringsMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+	SINGLE-VALUE )
+
+# userSMIMECertificate
+# A PKCS#7 [RFC2315] SignedData, where the content that is signed is
+# ignored by consumers of userSMIMECertificate values.  It is
+# recommended that values have a `contentType' of data with an absent
+# `content' field.  Values of this attribute contain a person's entire
+# certificate chain and an smimeCapabilities field [RFC2633] that at a
+# minimum describes their SMIME algorithm capabilities.  Values for
+# this attribute are to be stored and requested in binary form, as
+# 'userSMIMECertificate;binary'.  If available, this attribute is
+# preferred over the userCertificate attribute for S/MIME applications.
+## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
+attributetype ( 2.16.840.1.113730.3.1.40
+	NAME 'userSMIMECertificate'
+	DESC 'RFC2798: PKCS#7 SignedData used to support S/MIME'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
+# userPKCS12
+# PKCS #12 [PKCS12] provides a format for exchange of personal identity
+# information.  When such information is stored in a directory service,
+# the userPKCS12 attribute should be used. This attribute is to be stored
+# and requested in binary form, as 'userPKCS12;binary'.  The attribute
+# values are PFX PDUs stored as binary data.
+## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
+attributetype ( 2.16.840.1.113730.3.1.216
+	NAME 'userPKCS12'
+	DESC 'RFC2798: personal identity information, a PKCS #12 PFX'
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
+
+
+# inetOrgPerson
+# The inetOrgPerson represents people who are associated with an
+# organization in some way.  It is a structural class and is derived
+# from the organizationalPerson which is defined in X.521 [X521].
+objectclass	( 2.16.840.1.113730.3.2.2
+    NAME 'inetOrgPerson'
+	DESC 'RFC2798: Internet Organizational Person'
+    SUP organizationalPerson
+    STRUCTURAL
+	MAY (
+		audio $ businessCategory $ carLicense $ departmentNumber $
+		displayName $ employeeNumber $ employeeType $ givenName $
+		homePhone $ homePostalAddress $ initials $ jpegPhoto $
+		labeledURI $ mail $ manager $ mobile $ o $ pager $
+		photo $ roomNumber $ secretary $ uid $ userCertificate $
+		x500uniqueIdentifier $ preferredLanguage $
+		userSMIMECertificate $ userPKCS12 )
+	)
diff --git a/trunk/ldap/net/mina/pom.xml b/trunk/ldap/net/mina/pom.xml
new file mode 100644
index 0000000..26808f7
--- /dev/null
+++ b/trunk/ldap/net/mina/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-net-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-net-mina</artifactId>
+  <name>Apache Directory LDAP API Network MINA</name>
+  <packaging>bundle</packaging>
+  <description>LDAP ProtocolCodecFactory implementation based on MINA</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-codec-core</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>org.apache.mina</groupId>
+      <artifactId>mina-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-ActivationPolicy>lazy</Bundle-ActivationPolicy>
+            <Bundle-SymbolicName>${project.groupId}.ldap.net.mina</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.codec.protocol.mina;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1;version=${project.version},
+              org.apache.directory.api.asn1.ber;version=${project.version},
+              org.apache.directory.api.asn1.ber.tlv;version=${project.version},
+              org.apache.directory.api.ldap.codec.api;version=${project.version},
+              org.apache.directory.api.ldap.model.constants;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.apache.mina.core.buffer;version=${mina.core.version},
+              org.apache.mina.core.session;version=${mina.core.version},
+              org.apache.mina.filter.codec;version=${mina.core.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              org.osgi.framework;version="[1.0.0,2.0.0)",
+              org.osgi.util.tracker;version="[1.0.0,2.0.0)"
+            </Import-Package>
+            <Bundle-Activator>
+              org.apache.directory.api.ldap.codec.protocol.mina.LdapProtocolCodecActivator
+            </Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/net/mina/src/checkstyle/suppressions.xml b/trunk/ldap/net/mina/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..74a4604
--- /dev/null
+++ b/trunk/ldap/net/mina/src/checkstyle/suppressions.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+</suppressions>
diff --git a/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolCodecActivator.java b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolCodecActivator.java
new file mode 100644
index 0000000..aa21547
--- /dev/null
+++ b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolCodecActivator.java
@@ -0,0 +1,118 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.codec.protocol.mina;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+
+/**
+ * The {@link org.osgi.framework.BundleActivator} for the codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapProtocolCodecActivator implements BundleActivator
+{
+
+    private ServiceTracker<LdapApiService, LdapApiService> serviceTracker;
+
+    class LdapApiServiceTracker implements ServiceTrackerCustomizer<LdapApiService, LdapApiService>
+    {
+        private BundleContext bundleContext;
+        private ServiceRegistration<?> registration;
+
+
+        public LdapApiServiceTracker( BundleContext context )
+        {
+            this.bundleContext = context;
+        }
+
+
+        @Override
+        public LdapApiService addingService( ServiceReference<LdapApiService> reference )
+        {
+            LdapApiService ldapApiService = bundleContext.getService( reference );
+            LdapProtocolCodecFactory factory = new LdapProtocolCodecFactory( ldapApiService );
+            registration = bundleContext.registerService( LdapProtocolCodecFactory.class.getName(), factory, null );
+            ldapApiService.registerProtocolCodecFactory( factory );
+            return ldapApiService;
+        }
+
+
+        @Override
+        public void modifiedService( ServiceReference<LdapApiService> reference, LdapApiService service )
+        {
+        }
+
+
+        @Override
+        public void removedService( ServiceReference<LdapApiService> reference, LdapApiService service )
+        {
+            // TODO should we unregister the LdapProtocolCodecFactory at LdapApiService?
+            // ldapApiService.unregisterProtocolCodecFactory( factory );
+            registration.unregister();
+        }
+    }
+
+
+    /**
+     * Create a new instance of a LdapProtocolCodecActivator 
+     */
+    public LdapProtocolCodecActivator()
+    {
+    }
+
+
+    /**
+     * This class does nothing. It's just a nasty hack to force the bundle
+     * to get started lazy by calling this method.
+     */
+    public static void lazyStart()
+    {
+        // Does nothing
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start( BundleContext bundleContext ) throws Exception
+    {
+        LdapApiServiceTracker ldapApiServiceTracker = new LdapApiServiceTracker( bundleContext );
+        serviceTracker = new ServiceTracker<LdapApiService, LdapApiService>( bundleContext, LdapApiService.class,
+            ldapApiServiceTracker );
+        serviceTracker.open();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop( BundleContext bundleContext ) throws Exception
+    {
+        serviceTracker.close();
+    }
+}
diff --git a/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolCodecFactory.java b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolCodecFactory.java
new file mode 100644
index 0000000..a962503
--- /dev/null
+++ b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolCodecFactory.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.protocol.mina;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+
+
+/**
+ * The factory used to create the LDAP encoder and decoder.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapProtocolCodecFactory implements ProtocolCodecFactory
+{
+    /** The tag stored into the session if we want to set a max PDU size */
+    public static final String MAX_PDU_SIZE = "MAX_PDU_SIZE";
+
+    /** The LdapDecoder key */
+    public static final String LDAP_DECODER = "LDAP_DECODER";
+
+    /** The LdapEncoder key */
+    public static final String LDAP_ENCODER = "LDAP_ENCODER";
+
+    /** The statefull LDAP decoder */
+    private LdapProtocolDecoder ldapDecoder;
+
+    /** The statefull LDAP edcoder */
+    private LdapProtocolEncoder ldapEncoder;
+    
+    
+    /**
+     * Creates a new instance of LdapProtocolCodecFactory.
+     */
+    public LdapProtocolCodecFactory() 
+    {
+        this( LdapApiServiceFactory.getSingleton() );
+    }
+
+    
+    /**
+     * 
+     * Creates a new instance of LdapProtocolCodecFactory.
+     *
+     * @param ldapApiService The associated LdapApiService instance
+     */
+    public LdapProtocolCodecFactory( LdapApiService ldapApiService ) 
+    {
+        ldapDecoder = new LdapProtocolDecoder();
+        ldapEncoder = new LdapProtocolEncoder( ldapApiService );
+    }
+    
+
+    /**
+     * Get the LDAP decoder.
+     *
+     * @param session the IO session
+     * @return the decoder
+     */
+    public ProtocolDecoder getDecoder( IoSession session )
+    {
+        return ldapDecoder;
+    }
+
+
+    /**
+     * Get the LDAP encoder.
+     *
+     * @param session the IO session
+     * @return the encoder
+     */
+    public ProtocolEncoder getEncoder( IoSession session )
+    {
+        return ldapEncoder;
+    }
+}
diff --git a/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolDecoder.java b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolDecoder.java
new file mode 100644
index 0000000..74bd029
--- /dev/null
+++ b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolDecoder.java
@@ -0,0 +1,200 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.codec.protocol.mina;
+
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.api.ldap.codec.api.LdapDecoder;
+import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
+import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.exception.ResponseCarryingMessageException;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A LDAP message decoder. It is based on api-ldap decoder.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapProtocolDecoder implements ProtocolDecoder
+{
+    /** The logger */
+    private static final Logger CODEC_LOG = LoggerFactory.getLogger( Loggers.CODEC_LOG.getName() );
+
+    /** A speedup for logger */
+    private static final boolean IS_DEBUG = CODEC_LOG.isDebugEnabled();
+
+    /** The ASN 1 decoder instance */
+    private Asn1Decoder asn1Decoder;
+
+
+    /**
+     * Creates a new instance of LdapProtocolEncoder.
+     *
+     * @param codec The LDAP codec service associated with this encoder.
+     */
+    public LdapProtocolDecoder()
+    {
+        asn1Decoder = new Asn1Decoder();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void decode( IoSession session, IoBuffer in, ProtocolDecoderOutput out ) throws Exception
+    {
+        @SuppressWarnings("unchecked")
+        LdapMessageContainer<MessageDecorator<? extends Message>> messageContainer =
+            ( LdapMessageContainer<MessageDecorator<? extends Message>> )
+            session.getAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR );
+
+        if ( session.containsAttribute( LdapDecoder.MAX_PDU_SIZE_ATTR ) )
+        {
+            int maxPDUSize = ( Integer ) session.getAttribute( LdapDecoder.MAX_PDU_SIZE_ATTR );
+
+            messageContainer.setMaxPDUSize( maxPDUSize );
+        }
+
+        List<Message> decodedMessages = new ArrayList<Message>();
+        ByteBuffer buf = in.buf();
+
+        decode( buf, messageContainer, decodedMessages );
+
+        for ( Message message : decodedMessages )
+        {
+            out.write( message );
+        }
+    }
+
+
+    /**
+     * Decode an incoming buffer into LDAP messages. The result can be 0, 1 or many
+     * LDAP messages, which will be stored into the array the caller has created.
+     * 
+     * @param buffer The incoming byte buffer
+     * @param messageContainer The LdapMessageContainer which will be used to store the
+     * message being decoded. If the message is not fully decoded, the ucrrent state
+     * is stored into this container
+     * @param decodedMessages The list of decoded messages
+     * @throws Exception If the decoding failed
+     */
+    private void decode( ByteBuffer buffer, LdapMessageContainer<MessageDecorator<? extends Message>> messageContainer,
+        List<Message> decodedMessages ) throws DecoderException
+    {
+        buffer.mark();
+
+        while ( buffer.hasRemaining() )
+        {
+            try
+            {
+                if ( IS_DEBUG )
+                {
+                    CODEC_LOG.debug( "Decoding the PDU : " );
+
+                    int size = buffer.limit();
+                    int position = buffer.position();
+                    int pduLength = size - position;
+
+                    byte[] array = new byte[pduLength];
+
+                    System.arraycopy( buffer.array(), position, array, 0, pduLength );
+
+                    if ( array.length == 0 )
+                    {
+                        CODEC_LOG.debug( "NULL buffer, what the HELL ???" );
+                    }
+                    else
+                    {
+                        CODEC_LOG.debug( Strings.dumpBytes( array ) );
+                    }
+                }
+
+                asn1Decoder.decode( buffer, messageContainer );
+
+                if ( messageContainer.getState() == TLVStateEnum.PDU_DECODED )
+                {
+                    if ( IS_DEBUG )
+                    {
+                        CODEC_LOG.debug( "Decoded LdapMessage : " + messageContainer.getMessage() );
+                    }
+
+                    Message message = messageContainer.getMessage();
+
+                    decodedMessages.add( message );
+
+                    messageContainer.clean();
+                }
+            }
+            catch ( ResponseCarryingException rce )
+            {
+                buffer.clear();
+                messageContainer.clean();
+                
+                // Transform the DecoderException message to a MessageException
+                ResponseCarryingMessageException rcme = new ResponseCarryingMessageException( rce.getMessage(), rce );
+                rcme.setResponse( ( ( ResponseCarryingException ) rce ).getResponse() );
+
+                throw rcme;
+            }
+            catch ( DecoderException de )
+            {
+                buffer.clear();
+                messageContainer.clean();
+
+                // TODO : This is certainly not the way we should handle such an exception !
+                throw new ResponseCarryingException( de.getMessage(), de );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void finishDecode( IoSession session, ProtocolDecoderOutput out ) throws Exception
+    {
+        // Nothing to do
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void dispose( IoSession session ) throws Exception
+    {
+        // Nothing to do
+    }
+}
diff --git a/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolEncoder.java b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolEncoder.java
new file mode 100644
index 0000000..14c2895
--- /dev/null
+++ b/trunk/ldap/net/mina/src/main/java/org/apache/directory/api/ldap/codec/protocol/mina/LdapProtocolEncoder.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.codec.protocol.mina;
+
+
+import java.nio.ByteBuffer;
+
+
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.codec.api.LdapEncoder;
+import org.apache.directory.api.ldap.model.constants.Loggers;
+import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.util.Strings;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A LDAP message encoder. It is based on api-ldap encoder.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapProtocolEncoder implements ProtocolEncoder
+{
+    /** logger for reporting errors that might not be handled properly upstream */
+    private static final Logger CODEC_LOG = LoggerFactory.getLogger( Loggers.CODEC_LOG.getName() );
+
+    /** A speedup for logger */
+    private static final boolean IS_DEBUG = CODEC_LOG.isDebugEnabled();
+
+    /** The stateful encoder */
+    private LdapEncoder encoder;
+
+
+    /**
+     * Creates a new instance of LdapProtocolEncoder.
+     *
+     * @param codec The LDAP codec service associated with this encoder.
+     */
+    public LdapProtocolEncoder()
+    {
+        this( LdapApiServiceFactory.getSingleton() );
+    }
+
+    public LdapProtocolEncoder( LdapApiService ldapApiService )
+    {
+        this.encoder = new LdapEncoder( ldapApiService );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void encode( IoSession session, Object message, ProtocolEncoderOutput out ) throws Exception
+    {
+        ByteBuffer buffer = encoder.encodeMessage( ( Message ) message );
+
+        IoBuffer ioBuffer = IoBuffer.wrap( buffer );
+
+        if ( IS_DEBUG )
+        {
+            byte[] dumpBuffer = new byte[buffer.limit()];
+            buffer.get( dumpBuffer );
+            buffer.flip();
+            CODEC_LOG.debug( "Encoded message \n " + message + "\n : " + Strings.dumpBytes( dumpBuffer ) );
+        }
+
+        out.write( ioBuffer );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void dispose( IoSession session ) throws Exception
+    {
+        // Nothing to do
+    }
+}
diff --git a/trunk/ldap/net/mina/src/site/site.xml b/trunk/ldap/net/mina/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/net/mina/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/net/pom.xml b/trunk/ldap/net/pom.xml
new file mode 100644
index 0000000..6e44a11
--- /dev/null
+++ b/trunk/ldap/net/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-net-parent</artifactId>
+  <name>Apache Directory LDAP API Net Parent</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>mina</module>
+  </modules>
+
+</project>
diff --git a/trunk/ldap/net/src/site/site.xml b/trunk/ldap/net/src/site/site.xml
new file mode 100644
index 0000000..b6ec180
--- /dev/null
+++ b/trunk/ldap/net/src/site/site.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="modules" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/pom.xml b/trunk/ldap/pom.xml
new file mode 100644
index 0000000..0338f22
--- /dev/null
+++ b/trunk/ldap/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-parent</artifactId>
+  <name>Apache Directory LDAP API Parent</name>
+  <inceptionYear>2003</inceptionYear>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>model</module>
+    <module>codec</module>
+    <module>schema</module>
+    <module>net</module>
+    <module>client</module>
+    <module>extras</module>
+  </modules>
+
+</project>
diff --git a/trunk/ldap/schema/converter/pom.xml b/trunk/ldap/schema/converter/pom.xml
new file mode 100644
index 0000000..9e8ded3
--- /dev/null
+++ b/trunk/ldap/schema/converter/pom.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-schema-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-schema-converter</artifactId>
+  <name>Apache Directory LDAP API Schema Converter</name>
+  <packaging>bundle</packaging>
+  <description>LDAP Schema Converter</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency>
+
+  <!-- The original antlr artifact is needed by the antlr-maven-plugin which 
+    checks for its existence within the classpath. Use scope provided to avoid 
+    propagation to dependent projects. Choosen artifact is a valid OSGi bundle 
+    repackaged by ServiceMix team, kudos to them. -->
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.antlr</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>generate-sources</phase>
+            <configuration />
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>antlr-maven-plugin</artifactId>
+        <configuration>
+          <grammars>*.g</grammars>
+        </configuration>
+        <executions>
+           <execution>
+              <goals>
+                 <goal>generate</goal>
+              </goals>
+           </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/Abstract*</exclude>
+            <exclude>**/*RegressionTest*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.schema.converter</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.schema.converter;version="${project.version}";-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              <![CDATA[
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.model.constants;version=${project.version},
+              org.apache.directory.api.ldap.model.entry;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.ldif;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.schema;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              antlr;version=${antlr.version},
+              *
+              ]]>
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/ldap/schema/converter/src/checkstyle/suppressions.xml b/trunk/ldap/schema/converter/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..158cae0
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/checkstyle/suppressions.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <!-- Exclude Antlr generated sources -->
+    <suppress files="[\\/]generated-sources[\\/]" checks="[a-zA-Z0-9]*"/>
+</suppressions>
diff --git a/trunk/ldap/schema/converter/src/main/antlr/schemaConverter.g b/trunk/ldap/schema/converter/src/main/antlr/schemaConverter.g
new file mode 100644
index 0000000..1b6bff9
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/antlr/schemaConverter.g
@@ -0,0 +1,462 @@
+// ============================================================================
+//
+//
+//                    OpenLDAP Schema Parser
+//
+//
+// ============================================================================
+// $Rev$
+// ============================================================================
+
+
+header {
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+/*
+ * Keep the semicolon right next to the package name or else there will be a
+ * bug that comes into the foreground in the new antlr release.
+ */
+package org.apache.directory.api.ldap.schema.converter;
+import java.util.List ;
+import java.util.ArrayList ;
+import java.util.Collections;
+import java.io.IOException;
+
+import org.apache.directory.api.ldap.schema.converter.SchemaElement;
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+}
+
+
+class antlrSchemaConverterLexer extends Lexer ;
+
+options    {
+    k = 7 ;
+    exportVocab=antlrSchema ;
+    charVocabulary = '\3'..'\377' ;
+    caseSensitive = false ;
+    defaultErrorHandler = false ;
+}
+
+
+WS  :   (   '#' (~'\n')* '\n' { newline(); }
+        |    ' '
+        |   '\t'
+        |   '\r' '\n' { newline(); }
+        |   '\n'      { newline(); }
+        |   '\r'      { newline(); }
+        )
+        {$setType(Token.SKIP);} //ignore this token
+    ;
+
+QUOTE              : '\''
+    ;
+
+DIGIT              : '0' .. '9'
+    ;
+
+DOLLAR             : '$'
+    ;
+
+OPEN_PAREN         : '('
+    ;
+
+CLOSE_PAREN        : ')'
+    ;
+
+OPEN_BRACKET       : '{'
+    ;
+
+CLOSE_BRACKET      : '}'
+    ;
+
+protected NUMERIC_STRING : ('0' .. '9')+
+    ;
+
+NUMERICOID         :
+        NUMERIC_STRING ( '.' NUMERIC_STRING )+
+    ;
+
+IDENTIFIER options { testLiterals=true; }
+    : 
+        ( 'a' .. 'z') ( 'a' .. 'z' | '0' .. '9' | '-' | ';' )*
+    ;
+
+DESC
+    :
+        "desc" WS QUOTE ( ~'\'' | '\\' '\'' )+ QUOTE
+    ;
+
+SYNTAX
+    :
+        "syntax" WS NUMERICOID ( OPEN_BRACKET ( DIGIT )+ CLOSE_BRACKET )?
+    ;
+
+class antlrSchemaConverterParser extends Parser ;
+
+options    {
+    k = 5 ;
+    defaultErrorHandler = false ;
+}
+
+
+{
+    private List<SchemaElement> schemaElements = new ArrayList<SchemaElement>();
+
+    // ------------------------------------------------------------------------
+    // Public Methods
+    // ------------------------------------------------------------------------
+    public void clear()
+    {
+        schemaElements.clear();
+    }
+
+
+    public List<SchemaElement> getSchemaElements()
+    {
+        return Collections.unmodifiableList( schemaElements );
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// Main Entry Point Production
+// ----------------------------------------------------------------------------
+
+
+parseSchema
+    :
+    ( attributeType | objectClass )* "END"
+    ;
+
+
+// ----------------------------------------------------------------------------
+// AttributeType Productions
+// ----------------------------------------------------------------------------
+
+
+objectClass
+{
+    ObjectClassHolder objectClass = null;
+}
+    :
+    "objectclass"
+    OPEN_PAREN oid:NUMERICOID
+    {
+        objectClass = new ObjectClassHolder( oid.getText() );
+    }
+    ( objectClassNames[objectClass] )?
+    ( objectClassDesc[objectClass] )?
+    ( "OBSOLETE" { objectClass.setObsolete( true ); } )?
+    ( objectClassSuperiors[objectClass] )?
+    ( 
+        "ABSTRACT"   { objectClass.setClassType( ObjectClassTypeEnum.ABSTRACT ); } |
+        "STRUCTURAL" { objectClass.setClassType( ObjectClassTypeEnum.STRUCTURAL ); } |
+        "AUXILIARY"  { objectClass.setClassType( ObjectClassTypeEnum.AUXILIARY ); }
+    )?
+    ( must[objectClass] )?
+    ( may[objectClass] )?
+    // @TODO : add ( extension[type] )*
+    CLOSE_PAREN
+    {
+        schemaElements.add( objectClass );
+    }
+    ;
+
+
+may [ObjectClassHolder objectClass]
+{
+    List<String> list = null;
+}
+    : "MAY" list=woidlist
+    {
+        objectClass.setMay( list );
+    }
+    ;
+
+
+must [ObjectClassHolder objectClass]
+{
+    List<String> list = null;
+}
+    : "MUST" list=woidlist
+    {
+        objectClass.setMust( list );
+    }
+    ;
+
+
+objectClassSuperiors [ObjectClassHolder objectClass]
+{
+    List<String> list = null;
+}
+    : "SUP" list=woidlist
+    {
+        objectClass.setSuperiors( list );
+    }
+    ;
+
+
+woid returns [String oid]
+{
+    oid = null;
+}
+    :
+    (
+        opt1:NUMERICOID
+        {
+            oid = opt1.getText();
+        }
+        |
+        opt2:IDENTIFIER
+        {
+            oid = opt2.getText();
+        }
+    )
+    ;
+
+
+woidlist returns [List<String> list]
+{
+    list = new ArrayList<String>( 2 );
+    String oid = null;
+}
+    :
+    (
+        oid=woid { list.add( oid ); } |
+        (
+            OPEN_PAREN
+            oid=woid { list.add( oid ); } ( DOLLAR oid=woid { list.add( oid ); } )*
+            CLOSE_PAREN
+        )
+    )
+    ;
+
+objectClassDesc [ObjectClassHolder objectClass]
+    : d:DESC
+    {
+		String text = d.getText();
+		int start = text.indexOf( '\'' );
+        String desc = text.substring( start + 1, text.length() - 1 );
+		desc = desc.replace( "\\\"", "\"" );
+		desc = desc.replace( "\\'", "'" );
+		desc = desc.replace( "\\27", "'" );
+		desc = desc.replace( "\\5C", "\"" );
+        objectClass.setDescription( desc );
+    }
+    ;
+
+
+objectClassNames [ObjectClassHolder objectClass]
+{
+    List<String> list = new ArrayList<String>();
+}
+    :
+    (
+        "NAME"
+        ( QUOTE id0:IDENTIFIER QUOTE
+        {
+            list.add( id0.getText() );
+        }
+        |
+        ( OPEN_PAREN QUOTE id1:IDENTIFIER
+        {
+            list.add( id1.getText() );
+        } QUOTE
+        ( QUOTE id2:IDENTIFIER QUOTE
+        {
+            list.add( id2.getText() );
+        } )* CLOSE_PAREN )
+        )
+    )
+    {
+        objectClass.setNames( list );
+    }
+    ;
+
+
+// ----------------------------------------------------------------------------
+// AttributeType Productions
+// ----------------------------------------------------------------------------
+
+
+attributeType
+{
+    AttributeTypeHolder type = null;
+}
+    :
+    "attributetype"
+    OPEN_PAREN oid:NUMERICOID
+    {
+        type = new AttributeTypeHolder( oid.getText() );
+    }
+        ( names[type] )?
+        ( attributeTypeDesc[type] )?
+        ( "OBSOLETE" { type.setObsolete( true ); } )?
+        ( superior[type] )?
+        ( equality[type] )?
+        ( ordering[type] )?
+        ( substr[type] )?
+        ( syntax[type] )?
+        ( "SINGLE-VALUE" { type.setSingleValue( true ); } )?
+        ( "COLLECTIVE" { type.setCollective( true ); } )?
+        ( "NO-USER-MODIFICATION" { type.setNoUserModification( true ); } )?
+        ( usage[type] )?
+        // @TODO : add ( extension[type] )*
+
+    CLOSE_PAREN
+    {
+        schemaElements.add( type );
+    }
+    ;
+
+
+attributeTypeDesc [AttributeTypeHolder type]
+    : d:DESC
+    {
+		String text = d.getText();
+		int start = text.indexOf( '\'' );
+        String desc = text.substring( start +1, text.length() - 1 );
+		desc = desc.replace( "\\\"", "\"" );
+		desc = desc.replace( "\\'", "'" );
+		desc = desc.replace( "\\27", "'" );
+		desc = desc.replace( "\\5C", "\"" );
+        type.setDescription( desc );
+    }
+    ;
+
+
+superior [AttributeTypeHolder type]
+    : "SUP"
+    (
+        oid:NUMERICOID
+        {
+            type.setSuperior( oid.getText() );
+        }
+        |
+        id:IDENTIFIER
+        {
+            type.setSuperior( id.getText() );
+        }
+    );
+
+
+equality [AttributeTypeHolder type]
+    : "EQUALITY"
+    (
+        oid:NUMERICOID
+        {
+            type.setEquality( oid.getText() );
+        }
+        |
+        id:IDENTIFIER
+        {
+            type.setEquality( id.getText() );
+        }
+    );
+
+
+substr [AttributeTypeHolder type]
+    : "SUBSTR"
+    (
+        oid:NUMERICOID
+        {
+            type.setSubstr( oid.getText() );
+        }
+        |
+        id:IDENTIFIER
+        {
+            type.setSubstr( id.getText() );
+        }
+    );
+
+
+ordering [AttributeTypeHolder type]
+    : "ORDERING"
+    (
+        oid:NUMERICOID
+        {
+            type.setOrdering( oid.getText() );
+        }
+        |
+        id:IDENTIFIER
+        {
+            type.setOrdering( id.getText() );
+        }
+    );
+
+
+names [AttributeTypeHolder type]
+{
+    List<String> list = new ArrayList<String>();
+}
+    :
+        "NAME"
+    (
+        QUOTE id0:IDENTIFIER QUOTE 
+        { 
+            list.add( id0.getText() ); 
+        } 
+        |
+        ( OPEN_PAREN
+            ( QUOTE id1:IDENTIFIER
+                {
+                    list.add( id1.getText() );
+                }
+              QUOTE
+            )+
+        CLOSE_PAREN )
+    )
+    {
+        type.setNames( list );
+    }
+    ;
+
+
+syntax [AttributeTypeHolder type]
+    : token:SYNTAX
+    {
+        String[] comps = token.getText().split( " " );
+
+        int index = comps[1].indexOf( "{" );
+        if ( index == -1 )
+        {
+            type.setSyntax( comps[1] );
+            return;
+        }
+
+        String oid = comps[1].substring( 0, index );
+        String length = comps[1].substring( index + 1, comps[1].length() - 1 );
+
+        type.setSyntax( oid );
+        type.setOidLen( Long.parseLong( length ) );
+    }
+    ;
+
+
+usage [AttributeTypeHolder type]
+    :
+    "USAGE"
+    (
+        "userApplications" { type.setUsage( UsageEnum.USER_APPLICATIONS ); } |
+        "directoryOperation" { type.setUsage( UsageEnum.DIRECTORY_OPERATION ); } |
+        "distributedOperation" { type.setUsage( UsageEnum.DISTRIBUTED_OPERATION ); } |
+        "dSAOperation" { type.setUsage( UsageEnum.DSA_OPERATION ); }
+    );
diff --git a/trunk/ldap/schema/converter/src/main/appended-resources/META-INF/LICENSE b/trunk/ldap/schema/converter/src/main/appended-resources/META-INF/LICENSE
new file mode 100644
index 0000000..857d336
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/appended-resources/META-INF/LICENSE
@@ -0,0 +1,21 @@
+--------------------------------------------------------------
+                            ANTLR 2 License
+
+ANTLR 2 License
+
+We reserve no legal rights to the ANTLR--it is fully in the public domain. An 
+individual or company may do whatever they wish with source code distributed 
+with ANTLR or the code generated by ANTLR, including the incorporation of 
+ANTLR, or its output, into commerical software.
+
+We encourage users to develop software with ANTLR. However, we do ask that 
+credit is given to us for developing ANTLR. By "credit", we mean that if you 
+use ANTLR or incorporate any source code into one of your programs (commercial 
+product, research project, or otherwise) that you acknowledge this fact 
+somewhere in the documentation, research report, etc... If you like ANTLR 
+and have developed a nice tool with the output, please mention that you 
+developed it using ANTLR. In addition, we ask that the headers remain intact 
+in our source code. As long as these guidelines are kept, we expect to 
+continue enhancing this system and expect to make other tools available as 
+they are completed. 
+
diff --git a/trunk/ldap/schema/converter/src/main/appended-resources/META-INF/NOTICE b/trunk/ldap/schema/converter/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..c4d94e5
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,3 @@
+
+This software includes code generated by ANTLR 2.
+
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/AttributeTypeHolder.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/AttributeTypeHolder.java
new file mode 100755
index 0000000..d0bc76c
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/AttributeTypeHolder.java
@@ -0,0 +1,413 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+
+
+/**
+ * A bean used to hold the literal values of an AttributeType parsed out of an
+ * OpenLDAP schema configuration file.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeTypeHolder extends SchemaElementImpl
+{
+    /** A flag for single valued attributes. Default to false */
+    private boolean singleValue = false;
+
+    /** A flag for collective attribute. Default to false */
+    private boolean collective = false;
+
+    /** A flaf for immutable attribue. Default to false */
+    private boolean noUserModification = false;
+
+    /** The optional superior */
+    private String superior;
+
+    /** The equality matching rule */
+    private String equality;
+
+    /** The ordering matching rule */
+    private String ordering;
+
+    /** The substring matching rule */
+    private String substr;
+
+    /** The syntax this attribute respects */
+    private String syntax;
+
+    /** The optional length for this attribute */
+    private long oidLen = -1;
+
+    /** The attribute uase. Default to userApplication */
+    private UsageEnum usage = UsageEnum.USER_APPLICATIONS;
+
+
+    /**
+     * Create an instance of an attributeType
+     * 
+     * @param oid The attributeType's OID
+     */
+    public AttributeTypeHolder( String oid )
+    {
+        this.oid = oid;
+    }
+
+
+    /**
+     * Tells if the attribute is single-valued
+     * 
+     * @return true if the attribute is single-valued, false otherwise
+     */
+    public boolean isSingleValue()
+    {
+        return singleValue;
+    }
+
+
+    /**
+     * Set the attributeType singleValue flag
+     * 
+     * @param singleValue The value for this flag
+     */
+    public void setSingleValue( boolean singleValue )
+    {
+        this.singleValue = singleValue;
+    }
+
+
+    /**
+     * Tells if the attributeType is collectove or not
+     * 
+     * @return True if the attributeType is collective, false otherwise
+     */
+    public boolean isCollective()
+    {
+        return collective;
+    }
+
+
+    /**
+     * Set the attributeType collective flag
+     * 
+     * @param collective The value for this flag
+     */
+    public void setCollective( boolean collective )
+    {
+        this.collective = collective;
+    }
+
+
+    /**
+     * Tells if the attributeType is mutable or not
+     * 
+     * @return True if the attributeType is immutable, false otherwise
+     */
+    public boolean isNoUserModification()
+    {
+        return noUserModification;
+    }
+
+
+    /**
+     * Set the attributeType noUserModification flag
+     * 
+     * @param noUserModification The value for this flag
+     */
+    public void setNoUserModification( boolean noUserModification )
+    {
+        this.noUserModification = noUserModification;
+    }
+
+
+    /**
+     * Get the optional attributeType's superior
+     * 
+     * @return The attributeType's superior, if any
+     */
+    public String getSuperior()
+    {
+        return superior;
+    }
+
+
+    /**
+     * Set the attributeType's superior
+     * 
+     * @param superior The attributeType's superior
+     */
+    public void setSuperior( String superior )
+    {
+        this.superior = superior;
+    }
+
+
+    /**
+     * Get the equality Matching Rule
+     * 
+     * @return The equality matchingRule
+     */
+    public String getEquality()
+    {
+        return equality;
+    }
+
+
+    /**
+     * Set the equality Matching Rule
+     * 
+     * @param equality The equality Matching Rule
+     */
+    public void setEquality( String equality )
+    {
+        this.equality = equality;
+    }
+
+
+    /**
+     * Get the ordering Matching Rule
+     * 
+     * @return The ordering matchingRule
+     */
+    public String getOrdering()
+    {
+        return ordering;
+    }
+
+
+    /**
+     * Set the ordering Matching Rule
+     * 
+     * @param ordering The ordering Matching Rule
+     */
+    public void setOrdering( String ordering )
+    {
+        this.ordering = ordering;
+    }
+
+
+    /**
+     * Get the substring Matching Rule
+     * 
+     * @return The substring matchingRule
+     */
+    public String getSubstr()
+    {
+        return substr;
+    }
+
+
+    /**
+     * Set the substring Matching Rule
+     * 
+     * @param substr The substring Matching Rule
+     */
+    public void setSubstr( String substr )
+    {
+        this.substr = substr;
+    }
+
+
+    /**
+     * Get the attributeType's syntax
+     * 
+     * @return The attributeType's syntax
+     */
+    public String getSyntax()
+    {
+        return syntax;
+    }
+
+
+    /**
+     * Set the attributeType's syntax
+     * 
+     * @param syntax The attributeType's syntax
+     */
+    public void setSyntax( String syntax )
+    {
+        this.syntax = syntax;
+    }
+
+
+    /**
+     * Get the attributeType's usage
+     * 
+     * @return The attributeType's usage
+     */
+    public UsageEnum getUsage()
+    {
+        return usage;
+    }
+
+
+    /**
+     * Set the attributeType's usage
+     * 
+     * @param usage The attributeType's usage
+     */
+    public void setUsage( UsageEnum usage )
+    {
+        this.usage = usage;
+    }
+
+
+    /**
+     * Get the attributeType's syntax length
+     * 
+     * @return The attributeType's syntax length
+     */
+    public long getOidLen()
+    {
+        return oidLen;
+    }
+
+
+    /**
+     * Set the attributeType's syntax length
+     * 
+     * @param oidLen The attributeType's syntax length
+     */
+    public void setOidLen( long oidLen )
+    {
+        this.oidLen = oidLen;
+    }
+
+
+    /**
+     * Convert this attributeType to a Ldif string
+     * 
+     * @param schemaName The name of the schema file containing this attributeType
+     * @return A ldif formatted string
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If something went wrong
+     */
+    public String toLdif( String schemaName ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( schemaToLdif( schemaName, "metaAttributeType" ) );
+
+        // The superior
+        if ( superior != null )
+        {
+            sb.append( "m-supAttributeType: " ).append( superior ).append( '\n' );
+        }
+
+        // The equality matching rule
+        if ( equality != null )
+        {
+            sb.append( "m-equality: " ).append( equality ).append( '\n' );
+        }
+
+        // The ordering matching rule
+        if ( ordering != null )
+        {
+            sb.append( "m-ordering: " ).append( ordering ).append( '\n' );
+        }
+
+        // The substrings matching rule
+        if ( substr != null )
+        {
+            sb.append( "m-substr: " ).append( substr ).append( '\n' );
+        }
+
+        // The value syntax
+        if ( syntax != null )
+        {
+            sb.append( "m-syntax: " ).append( syntax ).append( '\n' );
+
+            if ( oidLen != -1 )
+            {
+                sb.append( "m-length: " ).append( oidLen ).append( '\n' );
+            }
+        }
+
+        // The single value flag
+        if ( singleValue )
+        {
+            sb.append( "m-singleValue: TRUE\n" );
+        }
+
+        // The collective flag
+        if ( collective )
+        {
+            sb.append( "m-collective: TRUE\n" );
+        }
+
+        // The not user modifiable flag
+        if ( noUserModification )
+        {
+            sb.append( "m-noUserModification: TRUE\n" );
+        }
+
+        // The usage value
+        if ( usage != UsageEnum.USER_APPLICATIONS )
+        {
+            sb.append( "m-usage: " ).append( usage.render() ).append( '\n' );
+        }
+
+        // The extensions
+        if ( extensions.size() != 0 )
+        {
+            extensionsToLdif( "m-extensionAttributeType" );
+        }
+
+        return sb.toString();
+
+    }
+
+
+    /**
+     * @return a String representing this AttributeType.
+     */
+    public String toString()
+    {
+        return getOid();
+    }
+
+
+    /**
+     * Transform a schema name to a Dn pointing to the correct position in the DIT
+     * 
+     * @param schemaName The schema name
+     * @return the Dn associated with this schema in the DIT
+     */
+    public String dnToLdif( String schemaName ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        String dn = "m-oid=" + oid + ", " + SchemaConstants.ATTRIBUTE_TYPES_PATH + ", cn="
+            + Rdn.escapeValue( schemaName ) + ", ou=schema";
+
+        // First dump the Dn only
+        Entry entry = new DefaultEntry( dn );
+        sb.append( LdifUtils.convertToLdif( entry ) );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/ObjectClassHolder.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/ObjectClassHolder.java
new file mode 100755
index 0000000..497996c
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/ObjectClassHolder.java
@@ -0,0 +1,228 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+
+
+/**
+ * A bean used to encapsulate the literal String values of an ObjectClass
+ * definition found within an OpenLDAP schema configuration file.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ObjectClassHolder extends SchemaElementImpl
+{
+    /** The list of superiors */
+    private List<String> superiors = new ArrayList<String>();
+
+    /** The list of mandatory attributes */
+    private List<String> must = new ArrayList<String>();
+
+    /** The list of optional attributes */
+    private List<String> may = new ArrayList<String>();
+
+    /** The ObjectClass type */
+    private ObjectClassTypeEnum classType = ObjectClassTypeEnum.STRUCTURAL;
+
+
+    /**
+     * Create an instance of ObjectClass element
+     * 
+     * @param OID the OjectClass OID
+     */
+    public ObjectClassHolder( String oid )
+    {
+        this.oid = oid;
+    }
+
+
+    /**
+     * Get the list of superior for this objectClass
+     * @return A list of all inherited objectClasses 
+     */
+    public List<String> getSuperiors()
+    {
+        return superiors;
+    }
+
+
+    /**
+     * Set the list of inherited objectClasses
+     * @param superiors The list of inherited objectClasses
+     */
+    public void setSuperiors( List<String> superiors )
+    {
+        this.superiors = superiors;
+    }
+
+
+    /**
+     * @return The list of mandatory attributes
+     */
+    public List<String> getMust()
+    {
+        return must;
+    }
+
+
+    /**
+     * Set the list of mandatory attributes
+     * @param must The list of mandatory attributes
+     */
+    public void setMust( List<String> must )
+    {
+        this.must = must;
+    }
+
+
+    /**
+     * @return The list of optional attributes
+     */
+    public List<String> getMay()
+    {
+        return may;
+    }
+
+
+    /**
+     * Set the list of optional attributes
+     * @param may The list of optional attributes
+     */
+    public void setMay( List<String> may )
+    {
+        this.may = may;
+    }
+
+
+    /**
+     * @return The objectClass type
+     */
+    public ObjectClassTypeEnum getClassType()
+    {
+        return classType;
+    }
+
+
+    /**
+     * Set the objectClass type. 
+     * @param classType The objectClass type. 
+     */
+    public void setClassType( ObjectClassTypeEnum classType )
+    {
+        this.classType = classType;
+    }
+
+
+    /**
+     * Convert this objectClass to a Ldif string
+     * 
+     * @param schemaName The name of the schema file containing this objectClass
+     * @return A ldif formatted string
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If something went wrong
+     */
+    public String toLdif( String schemaName ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( schemaToLdif( schemaName, "metaObjectClass" ) );
+
+        // The superiors
+        if ( superiors.size() != 0 )
+        {
+            for ( String superior : superiors )
+            {
+                sb.append( "m-supObjectClass: " ).append( superior ).append( '\n' );
+            }
+        }
+
+        // The kind of class
+        if ( classType != ObjectClassTypeEnum.STRUCTURAL )
+        {
+            sb.append( "m-typeObjectClass: " ).append( classType ).append( '\n' );
+        }
+
+        // The 'must'
+        if ( must.size() != 0 )
+        {
+            for ( String attr : must )
+            {
+                sb.append( "m-must: " ).append( attr ).append( '\n' );
+            }
+        }
+
+        // The 'may'
+        if ( may.size() != 0 )
+        {
+            for ( String attr : may )
+            {
+                sb.append( "m-may: " ).append( attr ).append( '\n' );
+            }
+        }
+
+        // The extensions
+        if ( extensions.size() != 0 )
+        {
+            extensionsToLdif( "m-extensionObjectClass" );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * @return a String representing this ObjectClass.
+     */
+    public String toString()
+    {
+        return getOid();
+    }
+
+
+    /**
+     * Transform a schema name to a Dn pointing to the correct position in the DIT
+     * 
+     * @param schemaName The schema name
+     * @return the Dn associated with this schema in the DIT
+     */
+    public String dnToLdif( String schemaName ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        String dn = "m-oid=" + oid + ", " + SchemaConstants.OBJECT_CLASSES_PATH + ", cn="
+            + Rdn.escapeValue( schemaName ) + ", ou=schema";
+
+        // First dump the Dn only
+        Entry entry = new DefaultEntry( dn );
+        sb.append( LdifUtils.convertToLdif( entry ) );
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/ParserException.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/ParserException.java
new file mode 100644
index 0000000..fe739df
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/ParserException.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+/**
+ * An exception thrown if we have an error while parsing a schema file.
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ParserException extends Exception
+{
+    /** The serial Version UID */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * A strandard constuctor
+     */
+    public ParserException()
+    {
+        super();
+    }
+
+
+    /**
+     * A constructor with a message
+     * @param msg The message containg the error's cause
+     */
+    public ParserException( String msg )
+    {
+        super( msg );
+    }
+}
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/Schema.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/Schema.java
new file mode 100644
index 0000000..64b9028
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/Schema.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import java.io.InputStream;
+import java.io.Writer;
+
+
+/**
+ * A bean used to hold a schema. We keep its name and we associate with this
+ * object an inputStream mapped on the OpenLdap schema to read, and a writer
+ * in which the ldif file will be dumped.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class Schema
+{
+    /** The schema name */
+    private String name;
+
+    /** The inputStream mapped on the file to read */
+    private InputStream in;
+
+    /** The writer where we dump the ldif lines */
+    private Writer out;
+
+
+    /**
+     * Set the schema name to parse. This name is the prefix of the
+     * schema file, which postfix is '.schema'.
+     * 
+     * For instance, 'test.schema' being the file to parse, its name 
+     * will be 'test'
+     * @param name The schema name
+     */
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+
+    /**
+     * @return The schema name.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * Set the inputStream mapped on the schema file
+     * @param in The InputStream mapped on the schema file
+     */
+    public void setInput( InputStream in )
+    {
+        this.in = in;
+    }
+
+
+    /**
+     * @return The InputStream mapped on the schema file
+     */
+    public InputStream getInput()
+    {
+        return in;
+    }
+
+
+    /**
+     * @return The writer in which the ldif lines will be dumped
+     */
+    public Writer getOutput()
+    {
+        return out;
+    }
+
+
+    /**
+     * Set a writer to dump the ldif files
+     * @param out The writer 
+     */
+    public void setOutput( Writer out )
+    {
+        this.out = out;
+    }
+    
+    
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return "Schema " + name + ".schema";
+    }
+}
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaElement.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaElement.java
new file mode 100644
index 0000000..aee481a
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaElement.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.api.ldap.model.exception.LdapException;
+
+
+/**
+ * An interface defining the methods to be implemented by the SchemaElement 
+ * classes
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SchemaElement
+{
+    /**
+     * Tells if the attributeType is obsolete
+     * 
+     * @return true if the schema element is obsolete, folse otherwise
+     */
+    boolean isObsolete();
+
+
+    /**
+     * Set the obsolete flag
+     * 
+     * @param isObsolete The value to be set
+     */
+    void setObsolete( boolean isObsolete );
+
+
+    /**
+     * Returns the schema element's OID
+     */
+    String getOid();
+
+
+    /**
+     * @return Return the schema element description
+     */
+    String getDescription();
+
+
+    /**
+     * Set the schema element's description
+     * @param description The schema element's description
+     */
+    void setDescription( String description );
+
+
+    /**
+     * @return The list of names for the schemaElement
+     */
+    List<String> getNames();
+
+
+    /**
+     * Set a list of names for a schemaElement
+     * @param names The list of names of this schemaElement
+     */
+    void setNames( List<String> names );
+
+
+    /**
+     * @return The list of extensions for the schemaElement
+     */
+    Map<String, List<String>> getExtensions();
+
+
+    /**
+     * @param key the Extension key
+     * @return The list of a values for a given extension
+     */
+    List<String> getExtension( String key );
+
+
+    /**
+     * Set a list of extensions for a schemaElement
+     * @param extensions The list of extensions of this schemaElement
+     */
+    void setExtensions( Map<String, List<String>> extensions );
+
+
+    /**
+     * Generate a String representation of this schemaElement, formated
+     * as a ldif string 
+     * @param schemaName The schema from which is extracted this schemaElement
+     * @return A string representing the schemaElement as a Ldif formated  String 
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If any error occurs.
+     */
+    String toLdif( String schemaName ) throws LdapException;
+}
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaElementImpl.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaElementImpl.java
new file mode 100644
index 0000000..0773372
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaElementImpl.java
@@ -0,0 +1,283 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.util.Strings;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * An abstract SchemaElement implementation. It contains shared
+ * elements from AttributeType and ObjectClass, like obsolete, oid, 
+ * description, names and extensions (not implemented)
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class SchemaElementImpl implements SchemaElement
+{
+    /** The schema element oid */
+    protected String oid;
+
+    /** The schema element description */
+    protected String description;
+
+    /** The list of names for this schemaElements */
+    protected List<String> names = new ArrayList<String>();
+
+    /** The obsolete flag */
+    protected boolean obsolete = false;
+
+    /** The optional list of extensions */
+    protected Map<String, List<String>> extensions = new HashMap<String, List<String>>();
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isObsolete()
+    {
+        return obsolete;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setObsolete( boolean obsolete )
+    {
+        this.obsolete = obsolete;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return oid;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getDescription()
+    {
+        return description;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setDescription( String description )
+    {
+        this.description = description;
+    }
+
+
+    /**
+     * @see SchemaElement#getNames()
+     */
+    public List<String> getNames()
+    {
+        return names;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setNames( List<String> names )
+    {
+        this.names = names;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getExtension( String key )
+    {
+        return extensions.get( key );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, List<String>> getExtensions()
+    {
+        return extensions;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setExtensions( Map<String, List<String>> extensions )
+    {
+        this.extensions = extensions;
+    }
+
+
+    /**
+     * @return The OID as a Ldif line
+     */
+    private String oidToLdif()
+    {
+        return "m-oid: " + oid + '\n';
+    }
+
+
+    /**
+     * @return the Names as Ldif lines
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If the conversion goes wrong
+     */
+    private String nameToLdif() throws LdapException
+    {
+        if ( names.size() == 0 )
+        {
+            return "";
+        }
+        else
+        {
+            Entry entry = new DefaultEntry();
+            Attribute attribute = new DefaultAttribute( "m-name" );
+
+            for ( String name : names )
+            {
+                attribute.add( name );
+            }
+
+            entry.put( attribute );
+
+            return LdifUtils.convertAttributesToLdif( entry );
+        }
+    }
+
+
+    /**
+     * @return The description as a ldif line
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If the conversion goes wrong
+     */
+    private String descToLdif() throws LdapException
+    {
+        if ( Strings.isEmpty( description ) )
+        {
+            return "";
+        }
+        else
+        {
+            Entry entry = new DefaultEntry();
+            Attribute attribute = new DefaultAttribute( "m-description", description );
+
+            entry.put( attribute );
+
+            return LdifUtils.convertAttributesToLdif( entry );
+        }
+    }
+
+
+    /**
+     * Transform a Schema Element to a LDIF String
+     *
+     * @param schemaName The schema element to transform
+     * @return The Schema Element as a ldif String
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If the conversion goes wrong
+     */
+    public abstract String dnToLdif( String schemaName ) throws LdapException;
+
+
+    /**
+     * Return the extensions formated as Ldif lines
+     *
+     * @param id The attributeId : can be m-objectClassExtension or
+     * m-attributeTypeExtension
+     * @return The extensions formated as ldif lines
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If the conversion goes wrong
+     */
+    protected String extensionsToLdif( String id ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        Entry entry = new DefaultEntry();
+        Attribute attribute = new DefaultAttribute( id );
+
+        for ( String extension : extensions.keySet() )
+        {
+            attribute.add( extension );
+        }
+
+        sb.append( LdifUtils.convertAttributesToLdif( entry ) );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Transform a Schema to a LDIF formated String
+     *
+     * @param schemaName The schema to transform
+     * @param type The ObjectClass type
+     * @return A LDIF String representing the schema
+     * @throws org.apache.directory.api.ldap.model.exception.LdapException If the transformation can't be done
+     */
+    protected String schemaToLdif( String schemaName, String type ) throws LdapException
+    {
+        StringBuilder sb = new StringBuilder();
+
+        // The Dn
+        sb.append( dnToLdif( schemaName ) );
+
+        // ObjectClasses
+        sb.append( "objectclass: " ).append( type ).append( '\n' );
+        sb.append( "objectclass: metaTop\n" );
+        sb.append( "objectclass: top\n" );
+
+        // The oid
+        sb.append( oidToLdif() );
+
+        // The name
+        sb.append( nameToLdif() );
+
+        // The desc
+        sb.append( descToLdif() );
+
+        // The obsolete flag, only if "true"
+        if ( obsolete )
+        {
+            sb.append( "m-obsolete: TRUE\n" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaParser.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaParser.java
new file mode 100755
index 0000000..5614137
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaParser.java
@@ -0,0 +1,232 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.text.ParseException;
+import java.util.List;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.util.Strings;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper for antlr generated schema parsers.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaParser
+{
+    /** The antlr generated parser */
+    private antlrSchemaConverterParser parser = null;
+
+    /** A pipe into the parser */
+    private PipedOutputStream parserIn = null;
+
+    /** A temporary buffer storing the read schema bytes */
+    private byte[] buf = new byte[128];
+
+    /** The inputStream mapped over the schema file to parse */
+    private InputStream schemaIn;
+
+    /** The thread used to read the schema */
+    private Thread producerThread;
+
+
+    /**
+     * Creates a reusable instance of an SchemaParser.
+     *
+     * @throws java.io.IOException if the pipe cannot be formed
+     */
+    public SchemaParser() throws IOException
+    {
+        init();
+    }
+
+
+    /**
+     * Initializes a parser and its plumbing.
+     *
+     * @throws java.io.IOException if a pipe cannot be formed.
+     */
+    public synchronized void init() throws IOException
+    {
+        parserIn = new PipedOutputStream();
+        PipedInputStream in = new PipedInputStream();
+        parserIn.connect( in );
+        antlrSchemaConverterLexer lexer = new antlrSchemaConverterLexer( in );
+        parser = new antlrSchemaConverterParser( lexer );
+    }
+
+
+    /**
+     * Clear the parser.
+     */
+    public synchronized void clear()
+    {
+        parser.clear();
+    }
+
+
+    /**
+     * Thread safe method parses an OpenLDAP schemaObject element/object.
+     *
+     * @param schemaObject the String image of a complete schema object
+     * @return The list of parsed schema elements
+     * @throws java.io.IOException If the schema file can't be processed
+     * @throws java.text.ParseException If we weren't able to parse the schema
+     */
+    public synchronized List<SchemaElement> parse( String schemaObject ) throws IOException, ParseException
+    {
+        if ( ( schemaObject == null ) || ( schemaObject.trim().equals( Strings.EMPTY_STRING ) ) )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_06001_EMPTY_OR_NULL_SCHEMA_OBJECT ), 0 );
+        }
+
+        schemaIn = new ByteArrayInputStream( Strings.getBytesUtf8( schemaObject ) );
+
+        if ( producerThread == null )
+        {
+            producerThread = new Thread( new DataProducer() );
+        }
+
+        producerThread.start();
+        
+        return invokeParser( schemaObject );
+    }
+
+
+    /**
+     * Invoke the parser
+     * 
+     * @param schemaName The schema to be parsed
+     * @return A list of schema elements
+     * @throws java.io.IOException If the schema file can't be processed
+     * @throws java.text.ParseException If we weren't able to parse the schema
+     */
+    private List<SchemaElement> invokeParser( String schemaName ) throws IOException, ParseException
+    {
+        try
+        {
+            parser.parseSchema();
+
+            return parser.getSchemaElements();
+        }
+        catch ( RecognitionException re )
+        {
+            String msg = I18n.err( I18n.ERR_06002_PARSER_FAILURE, schemaName, ExceptionUtils.getFullStackTrace( re ) );
+            init();
+            throw new ParseException( msg, re.getColumn() );
+        }
+        catch ( TokenStreamException tse )
+        {
+            String msg = I18n.err( I18n.ERR_06002_PARSER_FAILURE, schemaName, ExceptionUtils.getFullStackTrace( tse ) );
+            init();
+            throw new ParseException( msg, 0 );
+        }
+    }
+
+
+    /**
+     * Thread safe method parses a stream of OpenLDAP schemaObject elements/objects.
+     *
+     * @param schemaIn a stream of schema objects
+     * @return A list of schema elements
+     * @throws java.io.IOException If the schema file can't be processed
+     * @throws java.text.ParseException If we weren't able to parse the schema
+     */
+    public synchronized List<SchemaElement> parse( InputStream schemaIn ) throws IOException, ParseException
+    {
+        this.schemaIn = schemaIn;
+
+        if ( producerThread == null )
+        {
+            producerThread = new Thread( new DataProducer() );
+        }
+
+        producerThread.start();
+
+        return invokeParser( "schema input stream ==> " + schemaIn.toString() );
+    }
+
+
+    /**
+     * Thread safe method parses a file of OpenLDAP schemaObject elements/objects.
+     *
+     * @param schemaFile a file of schema objects
+     * @throws java.io.IOException If the schema file can't be processed
+     * @throws java.text.ParseException If we weren't able to parse the schema
+     */
+    public synchronized void parse( File schemaFile ) throws IOException, ParseException
+    {
+        schemaIn = new FileInputStream( schemaFile );
+
+        if ( producerThread == null )
+        {
+            producerThread = new Thread( new DataProducer() );
+        }
+
+        producerThread.start();
+        invokeParser( "schema file ==> " + schemaFile.getAbsolutePath() );
+    }
+    
+
+    /**
+     * The thread which read the schema files and fill the
+     * temporary buffer used by the lexical analyzer.
+     */
+    private class DataProducer implements Runnable
+    {
+        /**
+         * {@inheritDoc}
+         */
+        public void run()
+        {
+            int count = -1;
+
+            try
+            {
+                while ( ( count = schemaIn.read( buf ) ) != -1 )
+                {
+                    parserIn.write( buf, 0, count );
+                    parserIn.flush();
+                }
+
+                // using an input termination token END - need extra space to return
+                parserIn.write( Strings.getBytesUtf8( "END " ) );
+            }
+            catch ( IOException e )
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaToLdif.java b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaToLdif.java
new file mode 100644
index 0000000..eae1a67
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/main/java/org/apache/directory/api/ldap/schema/converter/SchemaToLdif.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class used to translate a OpenLdap schema file to a Ldif file compatible
+ * with the ApacheDS meta schema format
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SchemaToLdif
+{
+    /** The ASF Header */
+    private static final String HEADER = "#\n" + "#  Licensed to the Apache Software Foundation (ASF) under one\n"
+        + "#  or more contributor license agreements.  See the NOTICE file\n"
+        + "#  distributed with this work for additional information\n"
+        + "#  regarding copyright ownership.  The ASF licenses this file\n"
+        + "#  to you under the Apache License, Version 2.0 (the\n"
+        + "#  \"License\"); you may not use this file except in compliance\n"
+        + "#  with the License.  You may obtain a copy of the License at\n" + "#  \n"
+        + "#    http://www.apache.org/licenses/LICENSE-2.0\n" + "#  \n"
+        + "#  Unless required by applicable law or agreed to in writing,\n"
+        + "#  software distributed under the License is distributed on an\n"
+        + "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n"
+        + "#  KIND, either express or implied.  See the License for the\n"
+        + "#  specific language governing permissions and limitations\n" + "#  under the License. \n" + "#\n"
+        + "version: 1\n" + "\n";
+
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( SchemaToLdif.class );
+
+
+    /**
+     * Private constructor.
+     */
+    private SchemaToLdif()
+    {
+    }
+
+
+    /**
+     * This method takes a list of schema and transform them to Ldif files 
+     * 
+     * @param schemas The list of schema to be transformed
+     * @throws ParserException If we get an error while converting the schemas
+     */
+    public static void transform( List<Schema> schemas ) throws ParserException
+    {
+        // Bypass if no schemas have yet been defined 
+        if ( ( schemas == null ) || ( schemas.size() == 0 ) )
+        {
+            LOG.warn( "No schemas defined!" );
+            return;
+        }
+
+        // Make sure schema configurations have a name field and set defaults
+        // for any other missing properties of the bean: pkg and owner.
+        int i = 1;
+
+        for ( Schema schema : schemas )
+        {
+            if ( schema.getName() == null )
+            {
+                String msg = I18n.err( I18n.ERR_06003_NO_NAME, i );
+                LOG.error( msg );
+                throw new ParserException( msg );
+            }
+
+        }
+
+        // Generate for each schema 
+        for ( Schema schema : schemas )
+        {
+            try
+            {
+                LOG.info( "Generating {} schema.", schema.getName() );
+                generate( schema );
+            }
+            catch ( Exception e )
+            {
+                throw new ParserException( I18n.err( I18n.ERR_06004_CANNOT_GENERATE_SOURCES, schema.getName(),
+                    e.getMessage() ) );
+            }
+        }
+    }
+
+
+    /**
+     * Generate the ldif from a schema. The schema contains the inputStream
+     * and Writer.
+     * 
+     * @param schema The schema to transfom
+     * @throws Exception If the conversion fails
+     */
+    private static void generate( Schema schema ) throws Exception
+    {
+        if ( schema == null )
+        {
+            LOG.error( I18n.err( I18n.ERR_06005_NULL_SCHEMA ) );
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_06006_NO_PROPERTY ) );
+        }
+
+        InputStream in = schema.getInput();
+        Writer out = schema.getOutput();
+
+        // First parse the schema
+        SchemaParser parser = new SchemaParser();
+        List<SchemaElement> elements = parser.parse( in );
+
+        // Start with the header (apache licence)
+        out.write( HEADER );
+
+        // Iterate through each schema elemnts
+        for ( SchemaElement element : elements )
+        {
+            out.write( element.toLdif( schema.getName() ) );
+
+            out.write( '\n' );
+        }
+
+        // Done. Flush the result and close the reader and writer
+        out.flush();
+
+        out.close();
+        in.close();
+    }
+}
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/site/site.xml b/trunk/ldap/schema/converter/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/schema/converter/src/test/java/org/apache/directory/api/ldap/schema/converter/TestSchemaToLdif.java b/trunk/ldap/schema/converter/src/test/java/org/apache/directory/api/ldap/schema/converter/TestSchemaToLdif.java
new file mode 100644
index 0000000..e6ff89f
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/java/org/apache/directory/api/ldap/schema/converter/TestSchemaToLdif.java
@@ -0,0 +1,892 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.converter;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class TestSchemaToLdif
+{
+    private static final String HEADER =
+        "#\n" +
+            "#  Licensed to the Apache Software Foundation (ASF) under one\n" +
+            "#  or more contributor license agreements.  See the NOTICE file\n" +
+            "#  distributed with this work for additional information\n" +
+            "#  regarding copyright ownership.  The ASF licenses this file\n" +
+            "#  to you under the Apache License, Version 2.0 (the\n" +
+            "#  \"License\"); you may not use this file except in compliance\n" +
+            "#  with the License.  You may obtain a copy of the License at\n" +
+            "#  \n" +
+            "#    http://www.apache.org/licenses/LICENSE-2.0\n" +
+            "#  \n" +
+            "#  Unless required by applicable law or agreed to in writing,\n" +
+            "#  software distributed under the License is distributed on an\n" +
+            "#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n" +
+            "#  KIND, either express or implied.  See the License for the\n" +
+            "#  specific language governing permissions and limitations\n" +
+            "#  under the License. \n" +
+            "#\n" +
+            "version: 1\n" +
+            "\n";
+
+
+    private String transform( String name ) throws ParserException, IOException
+    {
+        List<Schema> schemas = new ArrayList<Schema>();
+        Schema schema = new Schema();
+        schema.setName( name );
+        schema.setInput( getClass().getResourceAsStream( name + ".schema" ) );
+
+        Writer out = new StringWriter( 2048 );
+        schema.setOutput( out );
+        schemas.add( schema );
+
+        SchemaToLdif.transform( schemas );
+
+        String res = out.toString();
+        out.close();
+
+        return res;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Tests for ObjectClass
+    //-------------------------------------------------------------------------
+    @Test
+    public void testConvertOC() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOC, ou=schema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-name: objectClass\n" +
+                "m-description: An objectClass\n" +
+                "m-obsolete: TRUE\n" +
+                "m-supObjectClass: top\n" +
+                "m-typeObjectClass: ABSTRACT\n" +
+                "m-must: attr1\n" +
+                "m-must: attr2\n" +
+                "m-may: attr3\n" +
+                "m-may: attr4\n\n";
+
+        assertEquals( expected, transform( "testOC" ) );
+    }
+
+
+    @Test
+    public void testConvertOCMinimal() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCMinimal, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n\n";
+
+        assertEquals( expected, transform( "testOCMinimal" ) );
+    }
+
+
+    @Test
+    public void testConvertOCNoName() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCNoName, ou=sc\n" +
+                " hema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-description: An objectClass\n" +
+                "m-obsolete: TRUE\n" +
+                "m-supObjectClass: top\n" +
+                "m-typeObjectClass: ABSTRACT\n" +
+                "m-must: attr1\n" +
+                "m-must: attr2\n" +
+                "m-may: attr3\n" +
+                "m-may: attr4\n\n";
+
+        assertEquals( expected, transform( "testOCNoName" ) );
+    }
+
+
+    @Test
+    public void testConvertOCAbstract() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCAbstract, ou=\n" +
+                " schema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-typeObjectClass: ABSTRACT\n\n";
+
+        assertEquals( expected, transform( "testOCAbstract" ) );
+    }
+
+
+    @Test
+    public void testConvertOCAuxiliary() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCAuxiliary, ou\n" +
+                " =schema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-typeObjectClass: AUXILIARY\n\n";
+
+        assertEquals( expected, transform( "testOCAuxiliary" ) );
+    }
+
+
+    @Test
+    public void testConvertOCDesc() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCDesc, ou=sche\n" +
+                " ma\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-description: An objectClass\n\n";
+
+        assertEquals( expected, transform( "testOCDesc" ) );
+    }
+
+
+    @Test
+    public void testConvertOCMayOne() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCMayOne, ou=sc\n" +
+                " hema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-may: attr1\n\n";
+
+        assertEquals( expected, transform( "testOCMayOne" ) );
+    }
+
+
+    @Test
+    public void testConvertOCMay2() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCMay2, ou=sche\n" +
+                " ma\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-may: attr1\n" +
+                "m-may: attr2\n\n";
+
+        assertEquals( expected, transform( "testOCMay2" ) );
+    }
+
+
+    @Test
+    public void testConvertOCMayMany() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCMayMany, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-may: attr1\n" +
+                "m-may: attr2\n" +
+                "m-may: attr3\n\n";
+
+        assertEquals( expected, transform( "testOCMayMany" ) );
+    }
+
+
+    @Test
+    public void testConvertOCMustOne() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCMustOne, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-must: attr1\n\n";
+
+        assertEquals( expected, transform( "testOCMustOne" ) );
+    }
+
+
+    @Test
+    public void testConvertOCMust2() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCMust2, ou=sch\n" +
+                " ema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-must: attr1\n" +
+                "m-must: attr2\n\n";
+
+        assertEquals( expected, transform( "testOCMust2" ) );
+    }
+
+
+    @Test
+    public void testConvertOCMustMany() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCMustMany, ou=\n" +
+                " schema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-must: attr1\n" +
+                "m-must: attr2\n" +
+                "m-must: attr3\n\n";
+
+        assertEquals( expected, transform( "testOCMustMany" ) );
+    }
+
+
+    @Test
+    public void testConvertOCNameOne() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCNameOne, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-name: objectClass\n\n";
+
+        assertEquals( expected, transform( "testOCNameOne" ) );
+    }
+
+
+    @Test
+    public void testConvertOCName2() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCName2, ou=sch\n" +
+                " ema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-name: oc\n" +
+                "m-name: objectClass\n\n";
+
+        assertEquals( expected, transform( "testOCName2" ) );
+    }
+
+
+    @Test
+    public void testConvertOCNameMany() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCNameMany, ou=\n" +
+                " schema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-name: oc\n" +
+                "m-name: objectClass\n" +
+                "m-name: object\n\n";
+
+        assertEquals( expected, transform( "testOCNameMany" ) );
+    }
+
+
+    @Test
+    public void testConvertOCObsolete() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCObsolete, ou=\n" +
+                " schema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-obsolete: TRUE\n\n";
+
+        assertEquals( expected, transform( "testOCObsolete" ) );
+    }
+
+
+    @Test
+    public void testConvertOCSupOne() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCSupOne, ou=sc\n" +
+                " hema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-supObjectClass: top\n\n";
+
+        assertEquals( expected, transform( "testOCSupOne" ) );
+    }
+
+
+    @Test
+    public void testConvertOCSup2() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCSup2, ou=sche\n" +
+                " ma\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-supObjectClass: top\n" +
+                "m-supObjectClass: 1.3.6.1.4.1.18060.0.4.2.3.15\n\n";
+
+        assertEquals( expected, transform( "testOCSup2" ) );
+    }
+
+
+    @Test
+    public void testConvertOCSupMany() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=objectclasses, cn=testOCSupMany, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaObjectClass\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-supObjectClass: top\n" +
+                "m-supObjectClass: 1.3.6.1.4.1.18060.0.4.2.3.15\n" +
+                "m-supObjectClass: metaTop\n\n";
+
+        assertEquals( expected, transform( "testOCSupMany" ) );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Tests for Attributetype
+    //-------------------------------------------------------------------------
+    @Test
+    public void testConvertATMinimal() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATMinimal, ou=\n" +
+                " schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n\n";
+
+        assertEquals( expected, transform( "testATMinimal" ) );
+    }
+
+
+    @Test
+    public void testConvertATNoName() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATNoName, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n\n";
+
+        assertEquals( expected, transform( "testATNoName" ) );
+    }
+
+
+    @Test
+    public void testConvertATNameOne() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATNameOne, ou=\n" +
+                " schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-name: attribute\n\n";
+
+        assertEquals( expected, transform( "testATNameOne" ) );
+    }
+
+
+    @Test
+    public void testConvertATName2() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATName2, ou=sc\n" +
+                " hema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-name: at\n" +
+                "m-name: attribute\n\n";
+
+        assertEquals( expected, transform( "testATName2" ) );
+    }
+
+
+    @Test
+    public void testConvertATNameMany() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATNameMany, ou\n" +
+                " =schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-name: at\n" +
+                "m-name: attribute\n" +
+                "m-name: attribute2\n\n";
+
+        assertEquals( expected, transform( "testATNameMany" ) );
+    }
+
+
+    @Test
+    public void testConvertATDesc() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATDesc, ou=sch\n" +
+                " ema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-description: An attributeType\n\n";
+
+        assertEquals( expected, transform( "testATDesc" ) );
+    }
+
+
+    @Test
+    public void testConvertATDesWithEscapedChars() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATDescWithEsca\n" +
+                " ped, ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-description: Some 'escaped' chars\n\n";
+
+        assertEquals( expected, transform( "testATDescWithEscaped" ) );
+    }
+
+
+    @Test
+    public void testConvertATObsolete() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATObsolete, ou\n" +
+                " =schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-obsolete: TRUE\n\n";
+
+        assertEquals( expected, transform( "testATObsolete" ) );
+    }
+
+
+    @Test
+    public void testConvertATSup() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATSup, ou=sche\n" +
+                " ma\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-supAttributeType: anotherAttribute\n\n";
+
+        assertEquals( expected, transform( "testATSup" ) );
+    }
+
+
+    @Test
+    public void testConvertATSupOID() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATSupOID, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-supAttributeType: 1.3.6.1.4.1.18060.0.4.2.3.15\n\n";
+
+        assertEquals( expected, transform( "testATSupOID" ) );
+    }
+
+
+    @Test
+    public void testConvertATEquality() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATEquality, ou\n" +
+                " =schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-equality: booleanMatch\n\n";
+
+        assertEquals( expected, transform( "testATEquality" ) );
+    }
+
+
+    @Test
+    public void testConvertATEqualityOID() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATEqualityOID,\n" +
+                "  ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-equality: 1.3.6.1.4.1.18060.0.4.2.3.15\n\n";
+
+        assertEquals( expected, transform( "testATEqualityOID" ) );
+    }
+
+
+    @Test
+    public void testConvertATOrdering() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATOrdering, ou\n" +
+                " =schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-ordering: booleanMatch\n\n";
+
+        assertEquals( expected, transform( "testATOrdering" ) );
+    }
+
+
+    @Test
+    public void testConvertATOrderingOID() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATOrderingOID,\n" +
+                "  ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-ordering: 1.3.6.1.4.1.18060.0.4.2.3.15\n\n";
+
+        assertEquals( expected, transform( "testATOrderingOID" ) );
+    }
+
+
+    @Test
+    public void testConvertATSubstr() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATSubstr, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-substr: booleanMatch\n\n";
+
+        assertEquals( expected, transform( "testATSubstr" ) );
+    }
+
+
+    @Test
+    public void testConvertATSubstrOID() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATSubstrOID, o\n" +
+                " u=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-substr: 1.3.6.1.4.1.18060.0.4.2.3.15\n\n";
+
+        assertEquals( expected, transform( "testATSubstrOID" ) );
+    }
+
+
+    @Test
+    public void testConvertATSyntax() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATSyntax, ou=s\n" +
+                " chema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-syntax: 1.3.6.1.4.1.18060.0.4.2.3.15\n\n";
+
+        assertEquals( expected, transform( "testATSyntax" ) );
+    }
+
+
+    @Test
+    public void testConvertATSyntaxOidLen() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATSyntaxOidLen\n" +
+                " , ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-syntax: 1.3.6.1.4.1.18060.0.4.2.3.15\n" +
+                "m-length: 123\n\n";
+
+        assertEquals( expected, transform( "testATSyntaxOidLen" ) );
+    }
+
+
+    @Test
+    public void testConvertATSingleValue() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATSingleValue,\n" +
+                "  ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-singleValue: TRUE\n\n";
+
+        assertEquals( expected, transform( "testATSingleValue" ) );
+    }
+
+
+    @Test
+    public void testConvertATCollective() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATCollective, \n" +
+                " ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-collective: TRUE\n\n";
+
+        assertEquals( expected, transform( "testATCollective" ) );
+    }
+
+
+    @Test
+    public void testConvertATNoUserModification() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATNoUserModifi\n" +
+                " cation, ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-noUserModification: TRUE\n\n";
+
+        assertEquals( expected, transform( "testATNoUserModification" ) );
+    }
+
+
+    @Test
+    public void testConvertATUsageUserApp() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATUsageUserApp\n" +
+                " , ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n\n";
+
+        assertEquals( expected, transform( "testATUsageUserApp" ) );
+    }
+
+
+    @Test
+    public void testConvertATUsageDirOp() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATUsageDirOp, \n" +
+                " ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-usage: directoryOperation\n\n";
+
+        assertEquals( expected, transform( "testATUsageDirOp" ) );
+    }
+
+
+    @Test
+    public void testConvertATUsageDistrOp() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATUsageDistrOp\n" +
+                " , ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-usage: distributedOperation\n\n";
+
+        assertEquals( expected, transform( "testATUsageDistrOp" ) );
+    }
+
+
+    @Test
+    public void testConvertATUsageDSAOp() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.14, ou=attributetypes, cn=testATUsageDsaOp, \n" +
+                " ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.18060.0.4.2.3.14\n" +
+                "m-usage: dSAOperation\n\n";
+
+        assertEquals( expected, transform( "testATUsageDsaOp" ) );
+    }
+
+
+    @Test
+    public void testConvertMozillaATWithOidLen() throws ParserException, IOException
+    {
+        String expected =
+            HEADER +
+                "dn: m-oid=1.3.6.1.4.1.13769.3.2, ou=attributetypes, cn=testMozillaATWithOidLen, \n" +
+                " ou=schema\n" +
+                "objectclass: metaAttributeType\n" +
+                "objectclass: metaTop\n" +
+                "objectclass: top\n" +
+                "m-oid: 1.3.6.1.4.1.13769.3.2\n" +
+                "m-name: mozillaHomeStreet2\n" +
+                "m-equality: caseIgnoreMatch\n" +
+                "m-substr: caseIgnoreSubstringsMatch\n" +
+                "m-syntax: 1.3.6.1.4.1.1466.115.121.1.15\n" +
+                "m-length: 128\n" +
+                "m-singleValue: TRUE\n\n";
+
+        assertEquals( expected, transform( "testMozillaATWithOidLen" ) );
+    }
+
+
+    @Test(expected = ParserException.class)
+    public void testConvertWrongLdif() throws ParserException, IOException
+    {
+        transform( "testWrongLdif" );
+    }
+}
diff --git a/trunk/ldap/schema/converter/src/test/resources/log4j.properties b/trunk/ldap/schema/converter/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/test.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/test.schema
new file mode 100644
index 0000000..b1cbcd0
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/test.schema
@@ -0,0 +1,190 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.1 NAME 'apacheDnsClass'
+	DESC 'The class of a resource record'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.2 NAME 'apacheDnsTtl'
+	DESC 'An integer denoting time to live'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.3 NAME 'apacheDnsDomainName'
+	DESC 'A domain name represented as a sequence of labels'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.4 NAME 'apacheDnsCharacterString'
+	DESC 'A string up to 256 characters in length'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.5 NAME 'apacheDnsIpAddress'
+	DESC 'A 4 octet IP address'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.6 NAME 'apacheDnsSoaMName'
+	DESC 'The domain name of the name server that was the primary source of data for this zone'
+	SUP apacheDnsDomainName SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.7 NAME 'apacheDnsSoaRName'
+	DESC 'The domain name which specifies the mailbox of the person responsible for this zone'
+	SUP apacheDnsDomainName SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.8 NAME 'apacheDnsSoaSerial'
+	DESC 'The unsigned 32 bit version number of the original copy of the zone'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.9 NAME 'apacheDnsSoaRefresh'
+	DESC 'A 32 bit time interval before the zone should be refreshed'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.10 NAME 'apacheDnsSoaRetry'
+	DESC 'A 32 bit time interval that should elapse before a failed refresh should be retired'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.11 NAME 'apacheDnsSoaExpire'
+	DESC 'A 32 bit time value that specifies the upper limit on the time interval that can elapse before the zone is no longer authoritative'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.12 NAME 'apacheDnsSoaMinimum'
+	DESC 'The unsigned 32 bit minimum TTL field that should be exported with any RR from this zone.'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.13 NAME 'apacheDnsMxPreference'
+	DESC 'An integer denoting the mail exchange preference'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.14 NAME 'apacheDnsServicePriority'
+	DESC 'The unsigned 16 bit priority of this target host'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.15 NAME 'apacheDnsServiceWeight'
+	DESC 'The unsigned 16 bit weight specifying a relative weight for entries with the same priority'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.2.16 NAME 'apacheDnsServicePort'
+	DESC 'The unsigned 16 bit port on this target host of this service'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.1
+	NAME 'apacheDnsAbstractRecord'
+	DESC 'An abstract DNS record objectClass used to build other specific structural objectclasses for different record types'
+	SUP top
+	ABSTRACT
+	MUST cn
+	MAY ( apacheDnsTtl $ description ) )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.2 
+	NAME 'apacheDnsAddressRecord'
+	DESC 'An address A record'
+	SUP apacheDnsAbstractRecord 
+	MUST apacheDnsIpAddress )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.3 
+	NAME 'apacheDnsPointerRecord'
+	DESC 'A pointer PTR record'
+	SUP apacheDnsAbstractRecord 
+	MUST apacheDnsDomainName )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.4
+	NAME 'apacheDnsNameServerRecord'
+	DESC 'A name server NS record'
+	SUP apacheDnsAbstractRecord 
+	MUST apacheDnsDomainName )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.5
+	NAME 'apacheDnsStartOfAuthorityRecord'
+	DESC 'A start of authority SOA record'
+	SUP apacheDnsAbstractRecord
+	MUST ( apacheDnsSoaMName $ apacheDnsSoaRName $ apacheDnsSoaMinimum )
+	MAY ( apacheDnsClass $ apacheDnsSoaSerial $ apacheDnsSoaRefresh $ apacheDnsSoaRetry $ apacheDnsSoaExpire ) )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.6
+	NAME 'apacheDnsCanonicalNameRecord'
+	DESC 'A canonical name CNAME record'
+	SUP apacheDnsAbstractRecord 
+	MUST apacheDnsDomainName )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.7
+	NAME 'apacheDnsMailExchangeRecord'
+	DESC 'A mail exchange MX record'
+	SUP apacheDnsAbstractRecord 
+	MUST ( apacheDnsMxPreference $ apacheDnsDomainName ) )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.8
+	NAME 'apacheDnsTextRecord'
+	DESC 'A text TXT record'
+	SUP apacheDnsAbstractRecord 
+	MUST apacheDnsCharacterString )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.9
+	NAME 'apacheDnsServiceRecord'
+	DESC 'A service SRV record'
+	SUP apacheDnsAbstractRecord 
+	MUST ( apacheDnsServicePriority $ apacheDnsServiceWeight $ apacheDnsServicePort $ apacheDnsDomainName ) )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.10
+	NAME 'apacheDnsReferralNameServer'
+	DESC 'A non-authoritative referral or delegation name server'
+	SUP apacheDnsAbstractRecord 
+	MUST apacheDnsDomainName )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.11
+	NAME 'apacheDnsReferralAddress'
+	DESC 'A non-authoritative referral or glue address record'
+	SUP apacheDnsAbstractRecord 
+	MUST ( apacheDnsDomainName $ apacheDnsIpAddress ) )
+	
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.12
+	NAME 'lecharny'
+	DESC 'A non-authoritative referral or glue address record'
+	SUP apacheDnsAbstractRecord 
+	MUST ( apacheDnsDomainName $ apacheDnsIpAddress ) )
+	
+	
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.13
+	DESC 'An objectClass without name'
+	SUP apacheDnsAbstractRecord 
+	MUST ( apacheDnsDomainName $ apacheDnsIpAddress ) )
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME 'long-desc'
+	DESC 'An objectClass with a long description. This is lonnnnnnnnnnnnnnabnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng'
+	SUP apacheDnsAbstractRecord 
+	MUST ( apacheDnsDomainName $ apacheDnsIpAddress ) )
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/test2.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/test2.schema
new file mode 100644
index 0000000..a5336b8
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/test2.schema
@@ -0,0 +1,31 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME 'long-desc'
+	DESC 'An objectClass with a long description. This is lonnnnnnnnnnnnnnabnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng'
+	SUP apacheDnsAbstractRecord 
+	MUST ( apacheDnsDomainName $ apacheDnsIpAddress ) )
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATCollective.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATCollective.schema
new file mode 100644
index 0000000..f36bafa
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATCollective.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	COLLECTIVE 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATDesc.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATDesc.schema
new file mode 100644
index 0000000..8122a3f
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATDesc.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	DESC 'An attributeType'
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATDescWithEscaped.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATDescWithEscaped.schema
new file mode 100644
index 0000000..8116c6b
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATDescWithEscaped.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	DESC 'Some \27escaped\27 chars'
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATEquality.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATEquality.schema
new file mode 100644
index 0000000..f308dc2
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATEquality.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	EQUALITY booleanMatch
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATEqualityOID.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATEqualityOID.schema
new file mode 100644
index 0000000..67b8eb5
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATEqualityOID.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	EQUALITY 1.3.6.1.4.1.18060.0.4.2.3.15 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATMinimal.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATMinimal.schema
new file mode 100644
index 0000000..5a53b0a
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATMinimal.schema
@@ -0,0 +1,26 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14 )
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATName2.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATName2.schema
new file mode 100644
index 0000000..db90e10
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATName2.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME ( 'at' 'attribute' )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNameMany.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNameMany.schema
new file mode 100644
index 0000000..df93dbe
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNameMany.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME ( 'at' 'attribute' 'attribute2' )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNameOne.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNameOne.schema
new file mode 100644
index 0000000..114153f
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNameOne.schema
@@ -0,0 +1,26 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14 NAME 'attribute' )
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNoName.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNoName.schema
new file mode 100644
index 0000000..5a53b0a
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNoName.schema
@@ -0,0 +1,26 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14 )
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNoUserModification.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNoUserModification.schema
new file mode 100644
index 0000000..d7654c3
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATNoUserModification.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NO-USER-MODIFICATION 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATObsolete.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATObsolete.schema
new file mode 100644
index 0000000..8f0328c
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATObsolete.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	OBSOLETE
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATOrdering.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATOrdering.schema
new file mode 100644
index 0000000..f640e25
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATOrdering.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	ORDERING booleanMatch
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATOrderingOID.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATOrderingOID.schema
new file mode 100644
index 0000000..0e28b0f
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATOrderingOID.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	ORDERING 1.3.6.1.4.1.18060.0.4.2.3.15 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSingleValue.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSingleValue.schema
new file mode 100644
index 0000000..e1e78e7
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSingleValue.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SINGLE-VALUE 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSubstr.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSubstr.schema
new file mode 100644
index 0000000..725b82b
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSubstr.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SUBSTR booleanMatch
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSubstrOID.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSubstrOID.schema
new file mode 100644
index 0000000..667cd61
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSubstrOID.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SUBSTR 1.3.6.1.4.1.18060.0.4.2.3.15 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSup.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSup.schema
new file mode 100644
index 0000000..d23c171
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSup.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SUP anotherAttribute 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSupOID.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSupOID.schema
new file mode 100644
index 0000000..1168532
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSupOID.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SUP 1.3.6.1.4.1.18060.0.4.2.3.15 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSyntax.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSyntax.schema
new file mode 100644
index 0000000..8ea394f
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSyntax.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SYNTAX 1.3.6.1.4.1.18060.0.4.2.3.15 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSyntaxOidLen.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSyntaxOidLen.schema
new file mode 100644
index 0000000..8995fa9
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATSyntaxOidLen.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SYNTAX 1.3.6.1.4.1.18060.0.4.2.3.15{123}
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDirOp.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDirOp.schema
new file mode 100644
index 0000000..bb8386e
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDirOp.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	USAGE directoryOperation 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDistrOp.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDistrOp.schema
new file mode 100644
index 0000000..5d01739
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDistrOp.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	USAGE distributedOperation 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDsaOp.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDsaOp.schema
new file mode 100644
index 0000000..8179d04
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageDsaOp.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	USAGE dSAOperation 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageUserApp.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageUserApp.schema
new file mode 100644
index 0000000..d3b93cd
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testATUsageUserApp.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+attributetype ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	USAGE userApplications 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testMozillaATWithOidLen.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testMozillaATWithOidLen.schema
new file mode 100644
index 0000000..61b057d
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testMozillaATWithOidLen.schema
@@ -0,0 +1,20 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+attributetype ( 1.3.6.1.4.1.13769.3.2 NAME 'mozillaHomeStreet2'
+         EQUALITY caseIgnoreMatch
+         SUBSTR caseIgnoreSubstringsMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOC.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOC.schema
new file mode 100644
index 0000000..b65bb75
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOC.schema
@@ -0,0 +1,34 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME 'objectClass'
+	DESC 'An objectClass'
+	OBSOLETE
+	SUP top 
+	ABSTRACT
+	MUST ( attr1 $ attr2 ) 
+	MAY ( attr3 $ attr4 )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCAbstract.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCAbstract.schema
new file mode 100644
index 0000000..10f346a
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCAbstract.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	ABSTRACT
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCAuxiliary.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCAuxiliary.schema
new file mode 100644
index 0000000..eaa129a
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCAuxiliary.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	AUXILIARY
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCDesc.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCDesc.schema
new file mode 100644
index 0000000..8cf6c61
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCDesc.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	DESC 'An objectClass'
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMay2.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMay2.schema
new file mode 100644
index 0000000..9de91ce
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMay2.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	MAY ( attr1 $ attr2 )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMayMany.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMayMany.schema
new file mode 100644
index 0000000..a1186a1
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMayMany.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	MAY ( attr1 $ attr2 $ attr3 )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMayOne.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMayOne.schema
new file mode 100644
index 0000000..9d159f8
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMayOne.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	MAY attr1
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMinimal.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMinimal.schema
new file mode 100644
index 0000000..4b0259d
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMinimal.schema
@@ -0,0 +1,26 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14 )
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMust2.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMust2.schema
new file mode 100644
index 0000000..39dd4df
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMust2.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	MUST ( attr1 $ attr2 ) 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMustMany.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMustMany.schema
new file mode 100644
index 0000000..0ab587f
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMustMany.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	MUST ( attr1 $ attr2 $ attr3 ) 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMustOne.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMustOne.schema
new file mode 100644
index 0000000..dd35c66
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCMustOne.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	MUST attr1
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCName2.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCName2.schema
new file mode 100644
index 0000000..3839f8d
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCName2.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME ( 'oc' 'objectClass' )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNameMany.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNameMany.schema
new file mode 100644
index 0000000..c111675
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNameMany.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME ( 'oc' 'objectClass' 'object' )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNameOne.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNameOne.schema
new file mode 100644
index 0000000..019b24f
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNameOne.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	NAME 'objectClass'
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNoName.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNoName.schema
new file mode 100644
index 0000000..45c1a31
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCNoName.schema
@@ -0,0 +1,33 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	DESC 'An objectClass'
+	OBSOLETE
+	SUP top 
+	ABSTRACT
+	MUST ( attr1 $ attr2 ) 
+	MAY ( attr3 $ attr4 )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCObsolete.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCObsolete.schema
new file mode 100644
index 0000000..26aaa3b
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCObsolete.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	OBSOLETE
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSup2.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSup2.schema
new file mode 100644
index 0000000..dc53627
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSup2.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SUP ( top $ 1.3.6.1.4.1.18060.0.4.2.3.15 )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSupMany.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSupMany.schema
new file mode 100644
index 0000000..b0d0c31
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSupMany.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SUP ( top $ 1.3.6.1.4.1.18060.0.4.2.3.15 $ metaTop )
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSupOne.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSupOne.schema
new file mode 100644
index 0000000..028e68d
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testOCSupOne.schema
@@ -0,0 +1,28 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+# =============================================================================
+#                ApacheDS schema for storing DNS zones in LDAP
+# =============================================================================
+#               +---------------------------+-----------------+
+#               |         Apache OID        |   description   |
+#               +---------------------------+-----------------+
+#               +---------------------------+-----------------+
+# =============================================================================
+objectclass ( 1.3.6.1.4.1.18060.0.4.2.3.14
+	SUP top 
+	)
+	
\ No newline at end of file
diff --git a/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testWrongLdif.schema b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testWrongLdif.schema
new file mode 100644
index 0000000..20f111c
--- /dev/null
+++ b/trunk/ldap/schema/converter/src/test/resources/org/apache/directory/api/ldap/schema/converter/testWrongLdif.schema
@@ -0,0 +1,20 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+attributetype ( 1.3.6.1.4.1.13769.3.2 NAME 'mozillaHomeStreet2'
+         EQUALITY caseIgnoreMatch
+         SUBSTR caseIgnoreSubstringsMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/README.md b/trunk/ldap/schema/data/README.md
new file mode 100755
index 0000000..4fb9223
--- /dev/null
+++ b/trunk/ldap/schema/data/README.md
@@ -0,0 +1,299 @@
+# Schema Data

+

+## OID Allocation Policy (generated using /src/main/scripts/oid_allocation.pl)

+

+OID values are allocated as follows:

+

+### `ou=syntaxes` and `ou=syntaxCheckers`

+

+- 1.3.6.1.4.1.18060.0.4.1.0.0: Java Byte

+- 1.3.6.1.4.1.18060.0.4.1.0.2: Java Short

+- 1.3.6.1.4.1.18060.0.4.1.0.3: Java Long

+- 1.3.6.1.4.1.18060.0.4.1.0.4: Java Int

+- 1.3.6.1.4.1.18060.0.4.1.0.10: Search Scope

+- 1.3.6.1.4.1.18060.0.4.1.0.11: Deref Alias

+

+### `ou=comparators` and `ou=matchingRules` and `ou=normalizers`

+

+- 1.3.6.1.4.1.18060.0.4.1.1.1: exactDnAsStringMatch

+- 1.3.6.1.4.1.18060.0.4.1.1.2: bigIntegerMatch

+- 1.3.6.1.4.1.18060.0.4.1.1.3: jdbmStringMatch

+

+### `ou=attributeTypes`

+

+

+#### Base Bean

+

+- 1.3.6.1.4.1.18060.0.4.1.2.3: apachePresence

+- 1.3.6.1.4.1.18060.0.4.1.2.4: apacheOneLevel

+- 1.3.6.1.4.1.18060.0.4.1.2.5: apacheOneAlias

+- 1.3.6.1.4.1.18060.0.4.1.2.6: apacheSubAlias

+- 1.3.6.1.4.1.18060.0.4.1.2.7: apacheAlias

+- 1.3.6.1.4.1.18060.0.4.1.2.8: prefNodeName

+- 1.3.6.1.4.1.18060.0.4.1.2.9: apacheSamType

+- 1.3.6.1.4.1.18060.0.4.1.2.10: autonomousAreaSubentry

+- 1.3.6.1.4.1.18060.0.4.1.2.11: accessControlSubentries

+- 1.3.6.1.4.1.18060.0.4.1.2.15: apacheServicePid

+- 1.3.6.1.4.1.18060.0.4.1.2.16: apacheServiceFactoryPid

+- 1.3.6.1.4.1.18060.0.4.1.2.17: apacheCatalogEntryName

+- 1.3.6.1.4.1.18060.0.4.1.2.18: apacheCatalogEntryBaseDn

+- 1.3.6.1.4.1.18060.0.4.1.2.19: windowsFilePath

+- 1.3.6.1.4.1.18060.0.4.1.2.20: unixFilePath

+- 1.3.6.1.4.1.18060.0.4.1.2.21: fullyQualifiedJavaClassName

+- 1.3.6.1.4.1.18060.0.4.1.2.22: javaClassByteCode

+- 1.3.6.1.4.1.18060.0.4.1.2.23: classLoaderDefaultSearchContext

+- 1.3.6.1.4.1.18060.0.4.1.2.25: prescriptiveTriggerSpecification

+- 1.3.6.1.4.1.18060.0.4.1.2.26: entryTriggerSpecification

+- 1.3.6.1.4.1.18060.0.4.1.2.27: triggerExecutionSubentries

+- 1.3.6.1.4.1.18060.0.4.1.2.28: triggerExecutionSubentry

+- 1.3.6.1.4.1.18060.0.4.1.2.31: entryDeleted

+- 1.3.6.1.4.1.18060.0.4.1.2.32: comparators

+- 1.3.6.1.4.1.18060.0.4.1.2.33: normalizers

+- 1.3.6.1.4.1.18060.0.4.1.2.34: syntaxCheckers

+- 1.3.6.1.4.1.18060.0.4.1.2.35: schemaModifyTimestamp

+- 1.3.6.1.4.1.18060.0.4.1.2.36: schemaModifiersName

+- 1.3.6.1.4.1.18060.0.4.1.2.37: subschemaSubentryName

+- 1.3.6.1.4.1.18060.0.4.1.2.38: privateKeyFormat

+- 1.3.6.1.4.1.18060.0.4.1.2.39: keyAlgorithm

+- 1.3.6.1.4.1.18060.0.4.1.2.40: privateKey

+- 1.3.6.1.4.1.18060.0.4.1.2.41: publicKeyFormat

+- 1.3.6.1.4.1.18060.0.4.1.2.42: publicKey

+- 1.3.6.1.4.1.18060.0.4.1.2.43: apacheSubLevel

+- 1.3.6.1.4.1.18060.0.4.1.2.44: revisions

+- 1.3.6.1.4.1.18060.0.4.1.2.45: changeTime

+- 1.3.6.1.4.1.18060.0.4.1.2.46: changeType

+- 1.3.6.1.4.1.18060.0.4.1.2.47: rev

+- 1.3.6.1.4.1.18060.0.4.1.2.48: committer

+- 1.3.6.1.4.1.18060.0.4.1.2.49: changeLogContext

+- 1.3.6.1.4.1.18060.0.4.1.2.50: apacheRdn

+- 1.3.6.1.4.1.18060.0.4.1.2.51: entryParentId

+- 1.3.6.1.4.1.18060.0.4.1.2.61: ads-transportAddress

+- 1.3.6.1.4.1.18060.0.4.1.2.62: ads-transportBacklog

+- 1.3.6.1.4.1.18060.0.4.1.2.63: ads-transportEnableSSL

+- 1.3.6.1.4.1.18060.0.4.1.2.64: ads-transportNbThreads

+- 1.3.6.1.4.1.18060.0.4.1.2.65: ads-needClientAuth

+- 1.3.6.1.4.1.18060.0.4.1.2.66: ads-wantClientAuth

+- 1.3.6.1.4.1.18060.0.4.1.2.67: ads-enabledProtocols

+- 1.3.6.1.4.1.18060.0.4.1.2.68: ads-enabledCiphers

+

+#### Directory Service

+

+- 1.3.6.1.4.1.18060.0.4.1.2.100: ads-directoryServiceId

+- 1.3.6.1.4.1.18060.0.4.1.2.101: ads-dsAccessControlEnabled

+- 1.3.6.1.4.1.18060.0.4.1.2.102: ads-dsAllowAnonymousAccess

+- 1.3.6.1.4.1.18060.0.4.1.2.103: ads-dsDenormalizeOpAttrsEnabled

+- 1.3.6.1.4.1.18060.0.4.1.2.104: ads-dsPasswordHidden

+- 1.3.6.1.4.1.18060.0.4.1.2.110: ads-maxPDUSize

+- 1.3.6.1.4.1.18060.0.4.1.2.111: ads-dsSyncPeriodMillis

+- 1.3.6.1.4.1.18060.0.4.1.2.112: ads-dsReplicaId

+- 1.3.6.1.4.1.18060.0.4.1.2.113: ads-dsTestEntries

+- 1.3.6.1.4.1.18060.0.4.1.2.120: ads-changeLogId

+- 1.3.6.1.4.1.18060.0.4.1.2.121: ads-changeLogExposed

+- 1.3.6.1.4.1.18060.0.4.1.2.130: ads-interceptorId

+- 1.3.6.1.4.1.18060.0.4.1.2.131: ads-interceptorOrder

+- 1.3.6.1.4.1.18060.0.4.1.2.141: ads-journalRotation

+- 1.3.6.1.4.1.18060.0.4.1.2.142: ads-journalWorkingDir

+- 1.3.6.1.4.1.18060.0.4.1.2.143: ads-journalFileName

+- 1.3.6.1.4.1.18060.0.4.1.2.144: ads-journalId

+- 1.3.6.1.4.1.18060.0.4.1.2.150: ads-partitionId

+- 1.3.6.1.4.1.18060.0.4.1.2.151: ads-partitionSuffix

+- 1.3.6.1.4.1.18060.0.4.1.2.153: ads-partitionCacheSize

+- 1.3.6.1.4.1.18060.0.4.1.2.154: ads-contextEntry

+- 1.3.6.1.4.1.18060.0.4.1.2.160: ads-indexAttributeId

+- 1.3.6.1.4.1.18060.0.4.1.2.161: ads-indexFileName

+- 1.3.6.1.4.1.18060.0.4.1.2.162: ads-indexWorkingDir

+- 1.3.6.1.4.1.18060.0.4.1.2.163: ads-indexNumDupLimit

+- 1.3.6.1.4.1.18060.0.4.1.2.164: ads-indexCacheSize

+- 1.3.6.1.4.1.18060.0.4.1.2.165: ads-indexHasReverse

+- 1.3.6.1.4.1.18060.0.4.1.2.200: ads-transportId

+- 1.3.6.1.4.1.18060.0.4.1.2.250: ads-serverId

+- 1.3.6.1.4.1.18060.0.4.1.2.252: ads-Id

+- 1.3.6.1.4.1.18060.0.4.1.2.253: ads-extendedOpId

+

+#### LDAP Server

+

+- 1.3.6.1.4.1.18060.0.4.1.2.300: ads-confidentialityRequired

+- 1.3.6.1.4.1.18060.0.4.1.2.301: ads-allowAnonymousAccess

+- 1.3.6.1.4.1.18060.0.4.1.2.302: ads-maxSizeLimit

+- 1.3.6.1.4.1.18060.0.4.1.2.303: ads-maxTimeLimit

+- 1.3.6.1.4.1.18060.0.4.1.2.304: ads-saslHost

+- 1.3.6.1.4.1.18060.0.4.1.2.305: ads-saslPrincipal

+- 1.3.6.1.4.1.18060.0.4.1.2.306: ads-saslRealms

+- 1.3.6.1.4.1.18060.0.4.1.2.308: ads-keystoreFile

+- 1.3.6.1.4.1.18060.0.4.1.2.309: ads-certificatePassword

+- 1.3.6.1.4.1.18060.0.4.1.2.310: ads-replConsumerImpl

+

+#### Kerberos Server

+

+- 1.3.6.1.4.1.18060.0.4.1.2.400: ads-krbAllowableClockSkew

+- 1.3.6.1.4.1.18060.0.4.1.2.401: ads-krbEncryptionTypes

+- 1.3.6.1.4.1.18060.0.4.1.2.402: ads-krbEmptyAddressesAllowed

+- 1.3.6.1.4.1.18060.0.4.1.2.403: ads-krbForwardableAllowed

+- 1.3.6.1.4.1.18060.0.4.1.2.404: ads-krbPaEncTimestampRequired

+- 1.3.6.1.4.1.18060.0.4.1.2.405: ads-krbPostdatedAllowed

+- 1.3.6.1.4.1.18060.0.4.1.2.406: ads-krbProxiableAllowed

+- 1.3.6.1.4.1.18060.0.4.1.2.407: ads-krbRenewableAllowed

+- 1.3.6.1.4.1.18060.0.4.1.2.408: ads-krbKdcPrincipal

+- 1.3.6.1.4.1.18060.0.4.1.2.409: ads-krbMaximumRenewableLifetime

+- 1.3.6.1.4.1.18060.0.4.1.2.410: ads-krbMaximumTicketLifetime

+- 1.3.6.1.4.1.18060.0.4.1.2.411: ads-krbPrimaryRealm

+- 1.3.6.1.4.1.18060.0.4.1.2.412: ads-krbBodyChecksumVerified

+

+#### ChangePassword Server

+

+- 1.3.6.1.4.1.18060.0.4.1.2.800: ads-chgPwdPolicyCategoryCount

+- 1.3.6.1.4.1.18060.0.4.1.2.801: ads-chgPwdPolicyPasswordLength

+- 1.3.6.1.4.1.18060.0.4.1.2.802: ads-chgPwdPolicyTokenSize

+- 1.3.6.1.4.1.18060.0.4.1.2.803: ads-chgPwdServicePrincipal

+- 1.3.6.1.4.1.18060.0.4.1.2.804: ads-interceptorClassName

+- 1.3.6.1.4.1.18060.0.4.1.2.805: ads-enabled

+- 1.3.6.1.4.1.18060.0.4.1.2.806: ads-partitionSyncOnWrite

+- 1.3.6.1.4.1.18060.0.4.1.2.807: ads-jdbmPartitionOptimizerEnabled

+- 1.3.6.1.4.1.18060.0.4.1.2.808: ads-saslMechName

+- 1.3.6.1.4.1.18060.0.4.1.2.809: ads-ntlmMechProvider

+- 1.3.6.1.4.1.18060.0.4.1.2.810: ads-saslMechClassName

+- 1.3.6.1.4.1.18060.0.4.1.2.811: ads-extendedOpHandlerClass

+- 1.3.6.1.4.1.18060.0.4.1.2.812: ads-systemPort

+- 1.3.6.1.4.1.18060.0.4.1.2.813: ads-httpWarFile

+- 1.3.6.1.4.1.18060.0.4.1.2.814: ads-httpAppCtxPath

+- 1.3.6.1.4.1.18060.0.4.1.2.816: ads-httpConfFile

+- 1.3.6.1.4.1.18060.0.4.1.2.817: ads-replSearchFilter

+- 1.3.6.1.4.1.18060.0.4.1.2.818: ads-replLastSentCsn

+- 1.3.6.1.4.1.18060.0.4.1.2.819: ads-replAliasDerefMode

+- 1.3.6.1.4.1.18060.0.4.1.2.820: ads-searchBaseDN

+- 1.3.6.1.4.1.18060.0.4.1.2.821: ads-replSearchScope

+- 1.3.6.1.4.1.18060.0.4.1.2.822: ads-replRefreshNPersist

+- 1.3.6.1.4.1.18060.0.4.1.2.823: ads-replProvHostName

+- 1.3.6.1.4.1.18060.0.4.1.2.824: ads-replProvPort

+- 1.3.6.1.4.1.18060.0.4.1.2.825: ads-replUserDn

+- 1.3.6.1.4.1.18060.0.4.1.2.826: ads-replUserPassword

+- 1.3.6.1.4.1.18060.0.4.1.2.827: ads-replRefreshInterval

+- 1.3.6.1.4.1.18060.0.4.1.2.828: ads-replAttributes

+- 1.3.6.1.4.1.18060.0.4.1.2.829: ads-replSearchSizeLimit

+- 1.3.6.1.4.1.18060.0.4.1.2.830: ads-replSearchTimeOut

+- 1.3.6.1.4.1.18060.0.4.1.2.831: ads-replCookie

+- 1.3.6.1.4.1.18060.0.4.1.2.832: ads-replReqHandler

+- 1.3.6.1.4.1.18060.0.4.1.2.833: ads-replUseTls

+- 1.3.6.1.4.1.18060.0.4.1.2.834: ads-replStrictCertValidation

+- 1.3.6.1.4.1.18060.0.4.1.2.837: ads-replConsumerId

+- 1.3.6.1.4.1.18060.0.4.1.2.838: ads-replEnabled

+

+#### Password Policy

+

+- 1.3.6.1.4.1.18060.0.4.1.2.900: ads-pwdAttribute

+- 1.3.6.1.4.1.18060.0.4.1.2.901: ads-pwdMinAge

+- 1.3.6.1.4.1.18060.0.4.1.2.902: ads-pwdMaxAge

+- 1.3.6.1.4.1.18060.0.4.1.2.903: ads-pwdInHistory

+- 1.3.6.1.4.1.18060.0.4.1.2.904: ads-pwdCheckQuality

+- 1.3.6.1.4.1.18060.0.4.1.2.905: ads-pwdMinLength

+- 1.3.6.1.4.1.18060.0.4.1.2.906: ads-pwdMaxLength

+- 1.3.6.1.4.1.18060.0.4.1.2.907: ads-pwdExpireWarning

+- 1.3.6.1.4.1.18060.0.4.1.2.908: ads-pwdGraceAuthNLimit

+- 1.3.6.1.4.1.18060.0.4.1.2.909: ads-pwdGraceExpire

+- 1.3.6.1.4.1.18060.0.4.1.2.910: ads-pwdLockout

+- 1.3.6.1.4.1.18060.0.4.1.2.911: ads-pwdLockoutDuration

+- 1.3.6.1.4.1.18060.0.4.1.2.912: ads-pwdMaxFailure

+- 1.3.6.1.4.1.18060.0.4.1.2.913: ads-pwdFailureCountInterval

+- 1.3.6.1.4.1.18060.0.4.1.2.914: ads-pwdMustChange

+- 1.3.6.1.4.1.18060.0.4.1.2.915: ads-pwdAllowUserChange

+- 1.3.6.1.4.1.18060.0.4.1.2.916: ads-pwdSafeModify

+- 1.3.6.1.4.1.18060.0.4.1.2.917: ads-pwdMinDelay

+- 1.3.6.1.4.1.18060.0.4.1.2.918: ads-pwdMaxDelay

+- 1.3.6.1.4.1.18060.0.4.1.2.919: ads-pwdMaxIdle

+- 1.3.6.1.4.1.18060.0.4.1.2.920: ads-replLogMaxIdle

+- 1.3.6.1.4.1.18060.0.4.1.2.921: ads-pwdId

+- 1.3.6.1.4.1.18060.0.4.1.2.922: ads-replLogPurgeThresholdCount

+- 1.3.6.1.4.1.18060.0.4.1.2.923: ads-replPingerSleep

+- 1.3.6.1.4.1.18060.0.4.1.2.925: ads-pwdValidator

+- 1.3.6.1.4.1.18060.0.4.1.2.930: ads-authenticatorId

+- 1.3.6.1.4.1.18060.0.4.1.2.931: ads-delegateHost

+- 1.3.6.1.4.1.18060.0.4.1.2.932: ads-delegatePort

+- 1.3.6.1.4.1.18060.0.4.1.2.933: ads-delegateSsl

+- 1.3.6.1.4.1.18060.0.4.1.2.934: ads-authenticatorClass

+- 1.3.6.1.4.1.18060.0.4.1.2.935: ads-baseDn

+- 1.3.6.1.4.1.18060.0.4.1.2.936: ads-delegateTls

+- 1.3.6.1.4.1.18060.0.4.1.2.937: ads-delegateSslTrustManager

+- 1.3.6.1.4.1.18060.0.4.1.2.938: ads-delegateTlsTrustManager

+

+### `ou=objectClasses`

+

+

+#### Base Bean

+

+- 1.3.6.1.4.1.18060.0.4.1.3.0: ads-base

+- 1.3.6.1.4.1.18060.0.4.1.3.1: prefNode

+- 1.3.6.1.4.1.18060.0.4.1.3.3: apacheServiceConfiguration

+- 1.3.6.1.4.1.18060.0.4.1.3.4: apacheFactoryConfiguration

+- 1.3.6.1.4.1.18060.0.4.1.3.5: apacheCatalogEntry

+- 1.3.6.1.4.1.18060.0.4.1.3.6: windowsFile

+- 1.3.6.1.4.1.18060.0.4.1.3.7: unixFile

+- 1.3.6.1.4.1.18060.0.4.1.3.8: javaClass

+- 1.3.6.1.4.1.18060.0.4.1.3.9: apacheSubschema

+- 1.3.6.1.4.1.18060.0.4.1.3.10: schemaModificationAttributes

+- 1.3.6.1.4.1.18060.0.4.1.3.11: tlsKeyInfo

+- 1.3.6.1.4.1.18060.0.4.1.3.12: changeLogEvent

+- 1.3.6.1.4.1.18060.0.4.1.3.13: tag

+- 1.3.6.1.4.1.18060.0.4.1.3.18: ads-transport

+- 1.3.6.1.4.1.18060.0.4.1.3.19: ads-tcpTransport

+- 1.3.6.1.4.1.18060.0.4.1.3.20: ads-udpTransport

+

+#### Directory Service

+

+- 1.3.6.1.4.1.18060.0.4.1.3.100: ads-directoryService

+- 1.3.6.1.4.1.18060.0.4.1.3.120: ads-changeLog

+- 1.3.6.1.4.1.18060.0.4.1.3.130: ads-interceptor

+- 1.3.6.1.4.1.18060.0.4.1.3.131: ads-authenticationInterceptor

+- 1.3.6.1.4.1.18060.0.4.1.3.140: ads-journal

+- 1.3.6.1.4.1.18060.0.4.1.3.150: ads-partition

+- 1.3.6.1.4.1.18060.0.4.1.3.151: ads-jdbmPartition

+- 1.3.6.1.4.1.18060.0.4.1.3.160: ads-index

+- 1.3.6.1.4.1.18060.0.4.1.3.161: ads-jdbmIndex

+- 1.3.6.1.4.1.18060.0.4.1.3.250: ads-server

+- 1.3.6.1.4.1.18060.0.4.1.3.260: ads-dsBasedServer

+

+#### LDAP Server

+

+- 1.3.6.1.4.1.18060.0.4.1.3.300: ads-ldapServer

+

+#### Kerberos Server

+

+- 1.3.6.1.4.1.18060.0.4.1.3.400: ads-kdcServer

+

+#### DNS Server

+

+- 1.3.6.1.4.1.18060.0.4.1.3.500: ads-dnsServer

+

+#### DHCP Server

+

+- 1.3.6.1.4.1.18060.0.4.1.3.600: ads-dhcpServer

+

+#### NTP Server

+

+- 1.3.6.1.4.1.18060.0.4.1.3.700: ads-ntpServer

+

+#### ChangePassword Server

+

+- 1.3.6.1.4.1.18060.0.4.1.3.800: ads-changePasswordServer

+- 1.3.6.1.4.1.18060.0.4.1.3.801: ads-saslMechHandler

+- 1.3.6.1.4.1.18060.0.4.1.3.802: ads-extendedOpHandler

+- 1.3.6.1.4.1.18060.0.4.1.3.803: ads-httpWebApp

+- 1.3.6.1.4.1.18060.0.4.1.3.804: ads-httpServer

+- 1.3.6.1.4.1.18060.0.4.1.3.805: ads-replEventLog

+- 1.3.6.1.4.1.18060.0.4.1.3.806: ads-replConsumer

+

+#### Password Policy

+

+- 1.3.6.1.4.1.18060.0.4.1.3.900: ads-passwordPolicy

+- 1.3.6.1.4.1.18060.0.4.1.3.901: ads-authenticator

+- 1.3.6.1.4.1.18060.0.4.1.3.902: ads-authenticatorImpl

+- 1.3.6.1.4.1.18060.0.4.1.3.904: ads-delegatingAuthenticator

+- 1.3.6.1.4.1.18060.0.4.1.3.905: ads-mavibotIndex

+- 1.3.6.1.4.1.18060.0.4.1.3.906: ads-mavibotPartition

+- 1.3.6.1.4.1.18060.0.4.1.5.1: storedProcLangId

+- 1.3.6.1.4.1.18060.0.4.1.5.2: storedProcUnitName

+- 1.3.6.1.4.1.18060.0.4.1.5.3: storedProcUnit

+- 1.3.6.1.4.1.18060.0.4.1.5.4: javaByteCode

+- 1.3.6.1.4.1.18060.0.4.1.5.5: javaStoredProcUnit

+- 1.3.6.1.4.1.18060.0.4.1.5.6: javaxScriptLangId

+- 1.3.6.1.4.1.18060.0.4.1.5.7: javaxScriptCode

+- 1.3.6.1.4.1.18060.0.4.1.5.8: javaxScriptStoredProcUnit

diff --git a/trunk/ldap/schema/data/pom.xml b/trunk/ldap/schema/data/pom.xml
new file mode 100644
index 0000000..547e3b8
--- /dev/null
+++ b/trunk/ldap/schema/data/pom.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-schema-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-schema-data</artifactId>
+  <name>Apache Directory LDAP API Schema Data</name>
+
+  <description>
+    Jar bundled LDIF files containing schema data using the Apache Directory
+    specific meta schema for describing schema information using LDAP.  This
+    jar can be used by clients as well as by ApacheDS' schema partition.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-ldap-extras-aci</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <groupId>org.apache.maven.plugins</groupId>
+        <configuration>
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target</workingDirectory>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>generate-resources</phase>
+            <configuration>
+              <target>
+                <!-- Various properties -->
+                <property name="schema.index" value="target/generated-resources/apacheds/META-INF/apacheds-schema.index" />
+                <property name="schema.location" value="src${file.separator}main${file.separator}resources${file.separator}" />
+              
+                <!-- Listing all LDIF files under schema location -->
+                <path id="schema.files.path">
+                  <fileset dir="${schema.location}">
+                    <include name="**/*.ldif" />
+                    <exclude name="schema-all.ldif" />
+                  </fileset>
+                </path>
+                <property name="schema.files" refid="schema.files.path" />
+                
+                <!-- Creating the schema index file -->
+                <echo message="${schema.files}" file="${schema.index}" />
+                <replace file="${schema.index}">
+                  <!-- Replace the path separator (':' on Unix, ';' on Windows) by a new line -->
+                  <replacefilter token="${path.separator}" value="${line.separator}" />
+                  <!-- Remove the full path of the schema location to get relative paths for files -->
+                  <replacefilter token="${basedir}${file.separator}${schema.location}" value="" />
+                  <!-- Replace the file separator ('/' on Unix, '\' on Windows) by a '/' - Useful on Windows -->
+                  <replacefilter token="${file.separator}" value="/" />
+                </replace>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <executions>
+          <execution>
+            <id>bundle-manifest</id>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>manifest</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.ldap.schema</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.ldap.schema.extractor;version="${project.version}";-noimport:=true,
+              org.apache.directory.api.ldap.schema.extractor.impl;version="${project.version}";-noimport:=true,
+              org.apache.directory.api.ldap.schema.loader;version="${project.version}";-noimport:=true,
+              org.apache.directory.api.ldap.schema.manager.impl;version="${project.version}";-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.asn1.util;version=${project.version},
+              org.apache.directory.api.i18n;version=${project.version},
+              org.apache.directory.api.ldap.aci;version=${project.version},
+              org.apache.directory.api.ldap.model.constants;version=${project.version},
+              org.apache.directory.api.ldap.model.entry;version=${project.version},
+              org.apache.directory.api.ldap.model.exception;version=${project.version},
+              org.apache.directory.api.ldap.model.ldif;version=${project.version},
+              org.apache.directory.api.ldap.model.message;version=${project.version},
+              org.apache.directory.api.ldap.model.name;version=${project.version},
+              org.apache.directory.api.ldap.model.schema;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.comparators;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.syntaxCheckers;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.normalizers;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.parsers;version=${project.version},
+              org.apache.directory.api.ldap.model.schema.registries;version=${project.version},
+              org.apache.directory.api.util;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion}
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+
+    </plugins>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+      </resource>
+      <resource>
+        <directory>target/generated-resources/apacheds</directory>
+      </resource>
+    </resources>
+  </build>
+</project>
diff --git a/trunk/ldap/schema/data/src/checkstyle/suppressions.xml b/trunk/ldap/schema/data/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..0dad3dc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/checkstyle/suppressions.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <!-- We have some long files -->
+    <suppress files="org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager" checks="FileLength" />
+</suppressions>
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/SchemaLdifExtractor.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/SchemaLdifExtractor.java
new file mode 100644
index 0000000..064a21f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/SchemaLdifExtractor.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.extractor;
+
+
+import java.io.IOException;
+
+
+/**
+ * Extracts LDIF files for the schema repository.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface SchemaLdifExtractor
+{
+    /**
+     * Gets whether or not the content has been extracted previously by this
+     * extractor or another into the directory file structure.
+     *
+     * @return true if extracted at least once, false otherwise
+     */
+    boolean isExtracted();
+
+
+    /**
+     * Extracts the LDIF files from a Jar file or copies exploded LDIF resources.
+     *
+     * @param overwrite over write extracted structure if true, false otherwise
+     * @throws java.io.IOException if schema already extracted and on IO errors
+     */
+    void extractOrCopy( boolean overwrite ) throws IOException;
+
+
+    /**
+     * Extracts the LDIF files from a Jar file or copies exploded LDIF
+     * resources without overwriting the resources if the schema has
+     * already been extracted.
+     *
+     * @throws java.io.IOException if schema already extracted and on IO errors
+     */
+    void extractOrCopy() throws IOException;
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/UniqueResourceException.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/UniqueResourceException.java
new file mode 100644
index 0000000..052bb2d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/UniqueResourceException.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.ldap.schema.extractor;
+
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+
+/**
+ * Exception for when we detect more than one unqiue schema LDIF file resource
+ * on the classpath.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UniqueResourceException extends RuntimeException
+{
+
+    /** The serialVersionUID. */
+    private static final long serialVersionUID = 1L;
+
+    /** The resource name. */
+    private final String resourceName;
+
+    /** The urls. */
+    private final List<URL> urls;
+
+    /** The resource description. */
+    private final String resourceDescription;
+
+
+    /**
+     * Instantiates a new unique resource exception.
+     *
+     * @param resourceName the resource name
+     * @param resourceDescription the resource description
+     */
+    public UniqueResourceException( String resourceName, String resourceDescription )
+    {
+        this( resourceName, null, resourceDescription );
+    }
+
+
+    /**
+     * Instantiates a new unique resource exception.
+     *
+     * @param resourceName the resource name
+     * @param urls the URLs
+     * @param resourceDescription the resource description
+     */
+    public UniqueResourceException( String resourceName, List<URL> urls, String resourceDescription )
+    {
+        this.resourceName = resourceName;
+        this.urls = urls;
+        this.resourceDescription = resourceDescription;
+    }
+
+
+    /**
+     * Instantiates a new unique resource exception.
+     *
+     * @param resourceName the resource name
+     * @param first the first
+     * @param urlEnum the enum with URLs
+     * @param resourceDescription the resource description
+     */
+    public UniqueResourceException( String resourceName, URL first, Enumeration<URL> urlEnum, String resourceDescription )
+    {
+        this( resourceName, toList( first, urlEnum ), resourceDescription );
+    }
+
+
+    private static List<URL> toList( URL first, Enumeration<URL> urlEnum )
+    {
+        ArrayList<URL> urls = new ArrayList<URL>();
+        urls.add( first );
+        while ( urlEnum.hasMoreElements() )
+        {
+            urls.add( urlEnum.nextElement() );
+        }
+        return urls;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getMessage()
+    {
+        StringBuffer buf = new StringBuffer( "Problem locating " ).append( resourceDescription ).append( "\n" );
+        if ( urls == null )
+        {
+            buf.append( "No resources named '" ).append( resourceName ).append( "' located on classpath" );
+        }
+        else
+        {
+            buf.append( "Multiple copies of resource named '" ).append( resourceName ).append(
+                "' located on classpath at urls" );
+            for ( URL url : urls )
+            {
+                buf.append( "\n    " ).append( url );
+            }
+        }
+        return buf.toString();
+    }
+
+
+    /**
+     * Gets the resource name.
+     *
+     * @return the resource name
+     */
+    public String getResourceName()
+    {
+        return resourceName;
+    }
+
+
+    /**
+     * Gets the URLs.
+     *
+     * @return the URLs
+     */
+    public List<URL> getUrls()
+    {
+        return Collections.unmodifiableList( urls );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/impl/DefaultSchemaLdifExtractor.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/impl/DefaultSchemaLdifExtractor.java
new file mode 100644
index 0000000..3c9aa3a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/impl/DefaultSchemaLdifExtractor.java
@@ -0,0 +1,428 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.extractor.impl;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Stack;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdapLdifException;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.UniqueResourceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Extracts LDIF files for the schema repository onto a destination directory.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultSchemaLdifExtractor implements SchemaLdifExtractor
+{
+    /** The base path. */
+    private static final String BASE_PATH = "";
+
+    /** The schema sub-directory. */
+    private static final String SCHEMA_SUBDIR = "schema";
+
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaLdifExtractor.class );
+
+    /**
+     * The pattern to extract the schema from LDIF files.
+     * java.util.regex.Pattern is immutable so only one instance is needed for all uses.
+     */
+    private static final Pattern EXTRACT_PATTERN = Pattern.compile( ".*schema" + "[/\\Q\\\\E]" + "ou=schema.*\\.ldif" );
+
+    /** The extracted flag. */
+    private boolean extracted;
+
+    /** The output directory. */
+    private File outputDirectory;
+
+
+    /**
+     * Creates an extractor which deposits files into the specified output
+     * directory.
+     *
+     * @param outputDirectory the directory where the schema root is extracted
+     */
+    public DefaultSchemaLdifExtractor( File outputDirectory )
+    {
+        LOG.debug( "BASE_PATH set to {}, outputDirectory set to {}", BASE_PATH, outputDirectory );
+        this.outputDirectory = outputDirectory;
+        File schemaDirectory = new File( outputDirectory, SCHEMA_SUBDIR );
+
+        if ( !outputDirectory.exists() )
+        {
+            LOG.debug( "Creating output directory: {}", outputDirectory );
+            if ( !outputDirectory.mkdir() )
+            {
+                LOG.error( "Failed to create outputDirectory: {}", outputDirectory );
+            }
+        }
+        else
+        {
+            LOG.debug( "Output directory exists: no need to create." );
+        }
+
+        if ( !schemaDirectory.exists() )
+        {
+            LOG.info( "Schema directory '{}' does NOT exist: extracted state set to false.", schemaDirectory );
+            extracted = false;
+        }
+        else
+        {
+            LOG.info( "Schema directory '{}' does exist: extracted state set to true.", schemaDirectory );
+            extracted = true;
+        }
+    }
+
+
+    /**
+     * Gets whether or not schema folder has been created or not.
+     *
+     * @return true if schema folder has already been extracted.
+     */
+    public boolean isExtracted()
+    {
+        return extracted;
+    }
+
+
+    /**
+     * Extracts the LDIF files from a Jar file or copies exploded LDIF resources.
+     *
+     * @param overwrite over write extracted structure if true, false otherwise
+     * @throws IOException if schema already extracted and on IO errors
+     */
+    public void extractOrCopy( boolean overwrite ) throws IOException
+    {
+        if ( !outputDirectory.exists() && !outputDirectory.mkdirs() )
+        {
+            throw new IOException( I18n.err( I18n.ERR_09001_DIRECTORY_CREATION_FAILED, outputDirectory
+                .getAbsolutePath() ) );
+        }
+
+        File schemaDirectory = new File( outputDirectory, SCHEMA_SUBDIR );
+
+        if ( !schemaDirectory.exists() )
+        {
+            if ( !schemaDirectory.mkdirs() )
+            {
+                throw new IOException( I18n.err( I18n.ERR_09001_DIRECTORY_CREATION_FAILED, schemaDirectory
+                    .getAbsolutePath() ) );
+            }
+        }
+        else if ( !overwrite )
+        {
+            throw new IOException( I18n.err( I18n.ERR_08001, schemaDirectory.getAbsolutePath() ) );
+        }
+
+        Map<String, Boolean> list = ResourceMap.getResources( EXTRACT_PATTERN );
+
+        for ( Entry<String, Boolean> entry : list.entrySet() )
+        {
+            if ( entry.getValue() )
+            {
+                extractFromClassLoader( entry.getKey() );
+            }
+            else
+            {
+                File resource = new File( entry.getKey() );
+                copyFile( resource, getDestinationFile( resource ) );
+            }
+        }
+    }
+
+
+    /**
+     * Extracts the LDIF files from a Jar file or copies exploded LDIF
+     * resources without overwriting the resources if the schema has
+     * already been extracted.
+     *
+     * @throws IOException if schema already extracted and on IO errors
+     */
+    public void extractOrCopy() throws IOException
+    {
+        extractOrCopy( false );
+    }
+
+
+    /**
+     * Copies a file line by line from the source file argument to the 
+     * destination file argument.
+     *
+     * @param source the source file to copy
+     * @param destination the destination to copy the source to
+     * @throws IOException if there are IO errors or the source does not exist
+     */
+    private void copyFile( File source, File destination ) throws IOException
+    {
+        LOG.debug( "copyFile(): source = {}, destination = {}", source, destination );
+
+        if ( !destination.getParentFile().exists() && !destination.getParentFile().mkdirs() )
+        {
+            throw new IOException( I18n.err( I18n.ERR_09001_DIRECTORY_CREATION_FAILED, destination.getParentFile()
+                .getAbsolutePath() ) );
+        }
+
+        if ( !source.getParentFile().exists() )
+        {
+            throw new FileNotFoundException( I18n.err( I18n.ERR_08002, source.getAbsolutePath() ) );
+        }
+
+        FileWriter out = new FileWriter( destination );
+
+        LdifReader ldifReader = null;
+
+        try
+        {
+            ldifReader = new LdifReader( source );
+            boolean first = true;
+            LdifEntry ldifEntry = null;
+
+            while ( ldifReader.hasNext() )
+            {
+                if ( first )
+                {
+                    ldifEntry = ldifReader.next();
+
+                    if ( ldifEntry.get( SchemaConstants.ENTRY_UUID_AT ) == null )
+                    {
+                        // No UUID, let's create one
+                        UUID entryUuid = UUID.randomUUID();
+                        ldifEntry.addAttribute( SchemaConstants.ENTRY_UUID_AT, entryUuid.toString() );
+                    }
+
+                    first = false;
+                }
+                else
+                {
+                    // throw an exception : we should not have more than one entry per schema ldif file
+                    String msg = I18n.err( I18n.ERR_08003, source );
+                    LOG.error( msg );
+                    throw new InvalidObjectException( msg );
+                }
+            }
+
+            // Add the version at the first line, to avoid a warning
+            String ldifString = "version: 1\n" + ldifEntry.toString();
+
+            out.write( ldifString );
+            out.flush();
+        }
+        catch ( LdapLdifException ne )
+        {
+            String msg = I18n.err( I18n.ERR_08004, source, ne.getLocalizedMessage() );
+            LOG.error( msg );
+            throw new InvalidObjectException( msg );
+        }
+        catch ( LdapException ne )
+        {
+            String msg = I18n.err( I18n.ERR_08004, source, ne.getLocalizedMessage() );
+            LOG.error( msg );
+            throw new InvalidObjectException( msg );
+        }
+        finally
+        {
+            if ( ldifReader != null )
+            {
+                ldifReader.close();
+            }
+
+            if ( out != null )
+            {
+                out.close();
+            }
+        }
+    }
+
+
+    /**
+     * Assembles the destination file by appending file components previously
+     * pushed on the fileComponentStack argument.
+     *
+     * @param fileComponentStack stack containing pushed file components
+     * @return the assembled destination file
+     */
+    private File assembleDestinationFile( Stack<String> fileComponentStack )
+    {
+        File destinationFile = outputDirectory.getAbsoluteFile();
+
+        while ( !fileComponentStack.isEmpty() )
+        {
+            destinationFile = new File( destinationFile, fileComponentStack.pop() );
+        }
+
+        return destinationFile;
+    }
+
+
+    /**
+     * Calculates the destination file.
+     *
+     * @param resource the source file
+     * @return the destination file's parent directory
+     */
+    private File getDestinationFile( File resource )
+    {
+        File parent = resource.getParentFile();
+        Stack<String> fileComponentStack = new Stack<String>();
+        fileComponentStack.push( resource.getName() );
+
+        while ( parent != null )
+        {
+            if ( parent.getName().equals( "schema" ) )
+            {
+                // All LDIF files besides the schema.ldif are under the 
+                // schema/schema base path. So we need to add one more 
+                // schema component to all LDIF files minus this schema.ldif
+                fileComponentStack.push( "schema" );
+
+                return assembleDestinationFile( fileComponentStack );
+            }
+
+            fileComponentStack.push( parent.getName() );
+
+            if ( parent.equals( parent.getParentFile() ) || parent.getParentFile() == null )
+            {
+                throw new IllegalStateException( I18n.err( I18n.ERR_08005 ) );
+            }
+
+            parent = parent.getParentFile();
+        }
+
+        throw new IllegalStateException( I18n.err( I18n.ERR_08006 ) );
+    }
+
+
+    /**
+     * Gets the unique schema file resource from the class loader off the base path.  If 
+     * the same resource exists multiple times then an error will result since the resource
+     * is not unique.
+     *
+     * @param resourceName the file name of the resource to load
+     * @param resourceDescription human description of the resource
+     * @return the InputStream to read the contents of the resource
+     * @throws IOException if there are problems reading or finding a unique copy of the resource
+     */
+    public static InputStream getUniqueResourceAsStream( String resourceName, String resourceDescription )
+        throws IOException
+    {
+        resourceName = BASE_PATH + resourceName;
+        URL result = getUniqueResource( resourceName, resourceDescription );
+        return result.openStream();
+    }
+
+
+    /**
+     * Gets a unique resource from the class loader.
+     * 
+     * @param resourceName the name of the resource
+     * @param resourceDescription the description of the resource
+     * @return the URL to the resource in the class loader
+     * @throws IOException if there is an IO error
+     */
+    public static URL getUniqueResource( String resourceName, String resourceDescription ) throws IOException
+    {
+        Enumeration<URL> resources = DefaultSchemaLdifExtractor.class.getClassLoader().getResources( resourceName );
+        if ( !resources.hasMoreElements() )
+        {
+            throw new UniqueResourceException( resourceName, resourceDescription );
+        }
+        URL result = resources.nextElement();
+        if ( resources.hasMoreElements() )
+        {
+            throw new UniqueResourceException( resourceName, result, resources, resourceDescription );
+        }
+        return result;
+    }
+
+
+    /**
+     * Extracts the LDIF schema resource from class loader.
+     *
+     * @param resource the LDIF schema resource
+     * @throws IOException if there are IO errors
+     */
+    private void extractFromClassLoader( String resource ) throws IOException
+    {
+        byte[] buf = new byte[512];
+        InputStream in = DefaultSchemaLdifExtractor.getUniqueResourceAsStream( resource,
+            "LDIF file in schema repository" );
+
+        try
+        {
+            File destination = new File( outputDirectory, resource );
+
+            /*
+             * Do not overwrite an LDIF file if it has already been extracted.
+             */
+            if ( destination.exists() )
+            {
+                return;
+            }
+
+            if ( !destination.getParentFile().exists() && !destination.getParentFile().mkdirs() )
+            {
+                throw new IOException( I18n.err( I18n.ERR_09001_DIRECTORY_CREATION_FAILED, destination
+                    .getParentFile().getAbsolutePath() ) );
+            }
+
+            FileOutputStream out = new FileOutputStream( destination );
+            try
+            {
+                while ( in.available() > 0 )
+                {
+                    int readCount = in.read( buf );
+                    out.write( buf, 0, readCount );
+                }
+                out.flush();
+            }
+            finally
+            {
+                out.close();
+            }
+        }
+        finally
+        {
+            in.close();
+        }
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/impl/ResourceMap.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/impl/ResourceMap.java
new file mode 100644
index 0000000..8ca092a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/extractor/impl/ResourceMap.java
@@ -0,0 +1,258 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.extractor.impl;
+
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Lists LDIF resources available from the classpath.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class ResourceMap
+{
+    /** the system property which can be used to load schema from a user specified
+     *  resource like a absolute path to a directory or jar file.
+     *  This is useful to start embedded DirectoryService in a servlet container environment
+     *
+     *  usage: -Dschema.resource.location=/tmp/schema
+     *                OR
+     *         -Dschema.resource.location=/tmp/api-ldap-schema-1.0.0-M13.jar
+     *  */
+    private static final String SCHEMA_RESOURCE_LOCATION = "schema.resource.location";
+
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( ResourceMap.class );
+
+
+    /**
+     * Private constructor.
+     */
+    private ResourceMap()
+    {
+    }
+
+
+    /**
+     * For all elements of java.class.path OR from the resource name set in the
+     * system property 'schema.resource.location' get a Map of resources
+     * Pattern pattern = Pattern.compile(".*").
+     * The keys represent resource names and the boolean parameter indicates
+     * whether or not the resource is in a Jar file.
+     *
+     * @param pattern the pattern to match
+     * @return the resources with markers - true if resource is in Jar
+     */
+    public static Map<String, Boolean> getResources( Pattern pattern )
+    {
+        HashMap<String, Boolean> retval = new HashMap<String, Boolean>();
+
+        String schemaResourceLoc = System.getProperty( SCHEMA_RESOURCE_LOCATION, "" );
+
+        if ( schemaResourceLoc.trim().length() > 0 )
+        {
+            LOG.debug( "loading from the user provider schema resource {}", schemaResourceLoc );
+
+            File file = new File( schemaResourceLoc );
+
+            if ( file.exists() )
+            {
+                getResources( retval, schemaResourceLoc, pattern );
+            }
+            else
+            {
+                LOG.error( "unable to load schema from the given resource value {}", schemaResourceLoc );
+            }
+        }
+        else
+        {
+            getResourcesFromClassloader( retval, pattern );
+        }
+
+        return retval;
+    }
+
+
+    private static void getResources( HashMap<String, Boolean> map,
+        String element, Pattern pattern )
+    {
+        File file = new File( element );
+
+        if ( !file.exists() )
+        {
+            // this may happen if the class path contains an element that doesn't exist
+            LOG.debug( "element {} does not exist", element );
+
+            return;
+        }
+
+        if ( file.isDirectory() )
+        {
+            getResourcesFromDirectory( map, file, pattern );
+        }
+        else
+        {
+            getResourcesFromJarFile( map, file, pattern );
+        }
+    }
+
+
+    private static void getResourcesFromJarFile( HashMap<String, Boolean> map,
+        File file, Pattern pattern )
+    {
+        ZipFile zf;
+
+        try
+        {
+            zf = new ZipFile( file );
+        }
+        catch ( ZipException e )
+        {
+            throw new Error( e );
+        }
+        catch ( IOException e )
+        {
+            throw new Error( e );
+        }
+
+        Enumeration<? extends ZipEntry> e = zf.entries();
+
+        while ( e.hasMoreElements() )
+        {
+            ZipEntry ze = e.nextElement();
+            String fileName = ze.getName();
+            boolean accept = pattern.matcher( fileName ).matches();
+
+            if ( accept )
+            {
+                map.put( fileName, Boolean.TRUE );
+            }
+        }
+        try
+        {
+            zf.close();
+        }
+        catch ( IOException e1 )
+        {
+            throw new Error( e1 );
+        }
+    }
+
+
+    private static void getResourcesFromDirectory(
+        HashMap<String, Boolean> map, File directory, Pattern pattern )
+    {
+        File[] fileList = directory.listFiles();
+
+        if ( fileList != null )
+        {
+            for ( File file : fileList )
+            {
+                if ( file.isDirectory() )
+                {
+                    getResourcesFromDirectory( map, file, pattern );
+                }
+                else
+                {
+                    try
+                    {
+                        String fileName = file.getCanonicalPath();
+                        boolean accept = pattern.matcher( fileName ).matches();
+    
+                        if ( accept )
+                        {
+                            map.put( fileName, Boolean.FALSE );
+                        }
+                    }
+                    catch ( IOException e )
+                    {
+                        LOG.error( "Cannot load file {} : {}", file.getAbsolutePath(), e.getMessage() );
+    
+                        // Continue...
+                    }
+                }
+            }
+        }
+    }
+
+
+    private static void getResourcesFromClassloader( HashMap<String, Boolean> map, Pattern pattern )
+    {
+        try
+        {
+            ClassLoader cl = ResourceMap.class.getClassLoader();
+            Enumeration<URL> indexes = cl.getResources( "META-INF/apacheds-schema.index" );
+
+            while ( indexes.hasMoreElements() )
+            {
+                URL index = null;
+
+                try
+                {
+                    index = indexes.nextElement();
+                    InputStream in = index.openStream();
+                    BufferedReader reader = new BufferedReader( new InputStreamReader( in, "UTF-8" ) );
+                    String line = reader.readLine();
+
+                    while ( line != null )
+                    {
+                        boolean accept = pattern.matcher( line ).matches();
+
+                        if ( accept )
+                        {
+                            map.put( line, Boolean.TRUE );
+                        }
+
+                        line = reader.readLine();
+                    }
+
+                    reader.close();
+                }
+                catch ( IOException ioe )
+                {
+                    LOG.debug( "Cannot load resource {} : {}", index, ioe.getMessage() );
+                    // Continue...
+                }
+            }
+        }
+        catch ( IOException e )
+        {
+            LOG.debug( "Error while loading  resuce from class loaded : {}", e.getMessage() );
+            throw new Error( e );
+        }
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/AttributeClassLoader.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/AttributeClassLoader.java
new file mode 100644
index 0000000..c510c04
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/AttributeClassLoader.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+
+
+/**
+ * A class loader that loads classes from an attribute within an entry.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributeClassLoader extends ClassLoader
+{
+
+    /** The attribute. */
+    private Attribute attribute;
+
+
+    /**
+     * Instantiates a new attribute class loader.
+     */
+    public AttributeClassLoader()
+    {
+        super( AttributeClassLoader.class.getClassLoader() );
+    }
+
+
+    /**
+     * Sets the attribute.
+     *
+     * @param attribute the new attribute
+     * @throws LdapException if the attribute is not binary.
+     */
+    public void setAttribute( Attribute attribute ) throws LdapException
+    {
+        if ( attribute.isHumanReadable() )
+        {
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.CONSTRAINT_VIOLATION,
+                I18n.err( I18n.ERR_10001 ) );
+        }
+
+        this.attribute = attribute;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Class<?> findClass( String name ) throws ClassNotFoundException
+    {
+        byte[] classBytes = null;
+
+        Value<?> value = attribute.get();
+
+        if ( value.isHumanReadable() )
+        {
+            throw new ClassNotFoundException( I18n.err( I18n.ERR_10002 ) );
+        }
+
+        classBytes = value.getBytes();
+
+        return defineClass( name, classBytes, 0, classBytes.length );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/EntityFactory.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/EntityFactory.java
new file mode 100644
index 0000000..745f337
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/EntityFactory.java
@@ -0,0 +1,189 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+
+
+public interface EntityFactory
+{
+    /**
+     * Return an instance of the Schema associated to the entry
+     *
+     * @param entry The Schema entry
+     * @return An instance of a Schema
+     * @throws Exception If the instance can't be created
+     */
+    Schema getSchema( Entry entry ) throws Exception;
+
+
+    /**
+     * Construct an AttributeType from an entry representing an AttributeType.
+     *
+     * @param schemaManager The Schema Manager
+     * @param entry The entry containing all the informations to build an AttributeType
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return An AttributeType SchemaObject
+     * @throws LdapException If the AttributeType is invalid
+     */
+    AttributeType getAttributeType( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapException;
+
+
+    /**
+     * Construct a LdapComparator from a description of a comparator.
+     *
+     * @param schemaManager The Schema Manager
+     * @param comparatorDescription The LdapComparator description object 
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return A new instance of a LdapComparator
+     * @throws Exception If the creation has failed
+     */
+    LdapComparator<?> getLdapComparator( SchemaManager schemaManager,
+        LdapComparatorDescription comparatorDescription,
+        Registries targetRegistries, String schemaName ) throws Exception;
+
+
+    /**
+     * Retrieve and load a Comparator class from the DIT.
+     * 
+     * @param schemaManager The Schema Manager
+     * @param entry The entry containing all the informations to build a LdapComparator
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return the loaded Comparator
+     * @throws LdapException if anything fails during loading
+     */
+    LdapComparator<?> getLdapComparator( SchemaManager schemaManager, Entry entry,
+        Registries targetRegistries, String schemaName ) throws LdapException;
+
+
+    /**
+     * Construct an MatchingRule from an entry get from the Dit
+     *
+     * @param schemaManager The Schema Manager
+     * @param entry The entry containing all the informations to build a MatchingRule
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return A MatchingRule SchemaObject
+     * @throws LdapException If the MatchingRule is invalid
+     */
+    MatchingRule getMatchingRule( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapException;
+
+
+    /**
+     * Create a new instance of a Normalizer 
+     *
+     * @param schemaManager The Schema Manager
+     * @param normalizerDescription The Normalizer description object 
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return A new instance of a normalizer
+     * @throws Exception If the creation has failed
+     */
+    Normalizer getNormalizer( SchemaManager schemaManager, NormalizerDescription normalizerDescription,
+        Registries targetRegistries, String schemaName ) throws Exception;
+
+
+    /**
+     * Retrieve and load a Normalizer class from the DIT.
+     * 
+     * @param schemaManager The Schema Manager
+     * @param entry The entry containing all the informations to build a Normalizer
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return the loaded Normalizer
+     * @throws LdapException if anything fails during loading
+     */
+    Normalizer getNormalizer( SchemaManager schemaManager, Entry entry, Registries targetRegistries, String schemaName )
+        throws LdapException;
+
+
+    /**
+     * 
+     * @param schemaManager The Schema Manager
+     * @param entry The entry containing all the informations to build an ObjectClass
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return
+     * @throws Exception
+     */
+    ObjectClass getObjectClass( SchemaManager schemaManager, Entry entry, Registries targetRegistries, String schemaName )
+        throws LdapException;
+
+
+    /**
+     * 
+     * @param schemaManager The Schema Manager
+     * @param entry The entry containing all the informations to build a LdapSyntax
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return
+     * @throws LdapException
+     */
+    LdapSyntax getSyntax( SchemaManager schemaManager, Entry entry, Registries targetRegistries, String schemaName )
+        throws LdapException;
+
+
+    /**
+     * Retrieve and load a syntaxChecker class from the DIT.
+     * 
+     * @param schemaManager The Schema Manager
+     * @param entry The entry containing all the informations to build a SyntaxChecker
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return the loaded SyntaxChecker
+     * @throws LdapException if anything fails during loading
+     */
+    SyntaxChecker getSyntaxChecker( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapException;
+
+
+    /**
+     * Create a new instance of a SyntaxChecker 
+     *
+     * @param schemaManager The Schema Manager
+     * @param syntaxCheckerDescription The SyntaxChecker description object 
+     * @param targetRegistries The registries containing all the enabled SchemaObjects
+     * @param schemaName The schema this SchemaObject will be part of
+     * @return A new instance of a syntaxChecker
+     * @throws Exception If the creation has failed
+     */
+    SyntaxChecker getSyntaxChecker( SchemaManager schemaManager, SyntaxCheckerDescription syntaxCheckerDescription,
+        Registries targetRegistries, String schemaName ) throws Exception;
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/JarLdifSchemaLoader.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/JarLdifSchemaLoader.java
new file mode 100644
index 0000000..75da3d7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/JarLdifSchemaLoader.java
@@ -0,0 +1,564 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.ResourceMap;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Loads schema data from LDIF files containing entries representing schema
+ * objects, using the meta schema format.
+ * 
+ * This class is used only for tests.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class JarLdifSchemaLoader extends AbstractSchemaLoader
+{
+    /**
+     * Filesystem path separator pattern, either forward slash or backslash.
+     * java.util.regex.Pattern is immutable so only one instance is needed for all uses.
+     */
+    private static final String SEPARATOR_PATTERN = "[/\\Q\\\\E]";
+
+    /** ldif file extension used */
+    private static final String LDIF_EXT = "ldif";
+
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( JarLdifSchemaLoader.class );
+
+    /** Speedup for DEBUG mode */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** a map of all the resources in this jar */
+    private static final Map<String, Boolean> RESOURCE_MAP = ResourceMap.getResources( Pattern
+        .compile( "schema" + SEPARATOR_PATTERN + "ou=schema.*" ) );
+
+
+    /**
+     * Creates a new LDIF based SchemaLoader. The constructor checks to make
+     * sure the supplied base directory exists and contains a schema.ldif file
+     * and if not complains about it.
+     *
+     * @throws Exception if the base directory does not exist or does not
+     * a valid schema.ldif file
+     */
+    public JarLdifSchemaLoader() throws Exception
+    {
+        initializeSchemas();
+    }
+
+
+    private URL getResource( String resource, String msg ) throws IOException
+    {
+        if ( RESOURCE_MAP.get( resource ) )
+        {
+            return DefaultSchemaLdifExtractor.getUniqueResource( resource, msg );
+        }
+        else
+        {
+            return new File( resource ).toURI().toURL();
+        }
+    }
+
+
+    /**
+     * Scans for LDIF files just describing the various schema contained in
+     * the schema repository.
+     *
+     * @throws Exception
+     */
+    private void initializeSchemas() throws Exception
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initializing schema" );
+        }
+
+        Pattern pat = Pattern.compile( "schema" + SEPARATOR_PATTERN + "ou=schema"
+            + SEPARATOR_PATTERN + "cn=[a-z0-9-_]*\\." + LDIF_EXT );
+
+        for ( String file : RESOURCE_MAP.keySet() )
+        {
+            if ( pat.matcher( file ).matches() )
+            {
+                URL resource = getResource( file, "schema LDIF file" );
+                InputStream in = resource.openStream();
+
+                try
+                {
+                    LdifReader reader = new LdifReader( in );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+                    Schema schema = getSchema( entry.getEntry() );
+                    schemaMap.put( schema.getSchemaName(), schema );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Schema Initialized ... \n{}", schema );
+                    }
+                }
+                catch ( Exception e )
+                {
+                    LOG.error( I18n.err( I18n.ERR_10003, file ), e );
+                    throw e;
+                }
+                finally
+                {
+                    in.close();
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Utility method to get a regex.Pattern fragment for the path for a schema directory.
+     *
+     * @param schema the schema to get the path for
+     * @return the regex.Pattern fragment for the path for the specified schema directory
+     */
+    private String getSchemaDirectoryString( Schema schema )
+    {
+        return "schema" + "/" + "ou=schema" + "/"
+            + "cn=" + Strings.lowerCase( schema.getSchemaName() ) + "/";
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> comparatorList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return comparatorList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.COMPARATORS_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "comparator LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    comparatorList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return comparatorList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> syntaxCheckerList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return syntaxCheckerList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.SYNTAX_CHECKERS_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "syntaxChecker LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    syntaxCheckerList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return syntaxCheckerList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> normalizerList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return normalizerList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.NORMALIZERS_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "normalizer LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    normalizerList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return normalizerList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> matchingRuleList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return matchingRuleList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.MATCHING_RULES_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "matchingRules LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    matchingRuleList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return matchingRuleList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> syntaxList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return syntaxList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.SYNTAXES_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "syntax LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    syntaxList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return syntaxList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> attributeTypeList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return attributeTypeList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            // check that the attributeTypes directory exists for the schema
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.ATTRIBUTE_TYPES_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            // get list of attributeType LDIF schema files in attributeTypes
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "attributeType LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    attributeTypeList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return attributeTypeList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> matchingRuleUseList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return matchingRuleUseList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.MATCHING_RULE_USE_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "matchingRuleUse LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    matchingRuleUseList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return matchingRuleUseList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> nameFormList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return nameFormList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.NAME_FORMS_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "nameForm LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    nameFormList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return nameFormList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> ditContentRulesList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return ditContentRulesList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.DIT_CONTENT_RULES_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "ditContentRule LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    ditContentRulesList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return ditContentRulesList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> ditStructureRuleList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return ditStructureRuleList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.DIT_STRUCTURE_RULES_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "ditStructureRule LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    ditStructureRuleList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return ditStructureRuleList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> objectClassList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return objectClassList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            // get objectClasses directory, check if exists, return if not
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.OBJECT_CLASSES_PATH + "/" + "m-oid=";
+            String end = "." + LDIF_EXT;
+
+            for ( String resourcePath : RESOURCE_MAP.keySet() )
+            {
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
+                {
+                    URL resource = getResource( resourcePath, "objectClass LDIF file" );
+                    LdifReader reader = new LdifReader( resource.openStream() );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    objectClassList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return objectClassList;
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/LdifSchemaLoader.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/LdifSchemaLoader.java
new file mode 100644
index 0000000..62de06a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/LdifSchemaLoader.java
@@ -0,0 +1,626 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Loads schema data from LDIF files containing entries representing schema
+ * objects, using the meta schema format.
+ *
+ * This class is used only for tests.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifSchemaLoader extends AbstractSchemaLoader
+{
+    /** ldif file extension used */
+    private static final String LDIF_EXT = "ldif";
+
+    /** ou=schema LDIF file name */
+    private static final String OU_SCHEMA_LDIF = "ou=schema." + LDIF_EXT;
+
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( LdifSchemaLoader.class );
+
+    /** Speedup for DEBUG mode */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** directory containing the schema LDIF file for ou=schema */
+    private final File baseDirectory;
+
+    /** a filter for listing all the LDIF files within a directory */
+    private final FilenameFilter ldifFilter = new FilenameFilter()
+    {
+        public boolean accept( File file, String name )
+        {
+            return name.endsWith( LDIF_EXT );
+        }
+    };
+
+
+    /**
+     * Creates a new LDIF based SchemaLoader. The constructor checks to make
+     * sure the supplied base directory exists and contains a schema.ldif file
+     * and if not complains about it.
+     *
+     * @param baseDirectory the schema LDIF base directory
+     * @throws Exception if the base directory does not exist or does not
+     * a valid schema.ldif file
+     */
+    public LdifSchemaLoader( File baseDirectory ) throws Exception
+    {
+        this.baseDirectory = baseDirectory;
+
+        if ( !baseDirectory.exists() )
+        {
+            String msg = "Provided baseDirectory '" + baseDirectory.getAbsolutePath() + "' does not exist.";
+            LOG.error( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        File schemaLdif = new File( baseDirectory, OU_SCHEMA_LDIF );
+
+        if ( !schemaLdif.exists() )
+        {
+            String msg = I18n.err( I18n.ERR_10004, schemaLdif.getAbsolutePath() );
+            LOG.error( msg );
+            throw new FileNotFoundException( msg );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Using '{}' as the base schema load directory.", baseDirectory );
+        }
+
+        initializeSchemas();
+    }
+
+
+    /**
+     * Scans for LDIF files just describing the various schema contained in
+     * the schema repository.
+     *
+     * @throws Exception
+     */
+    private void initializeSchemas() throws Exception
+    {
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Initializing schema" );
+        }
+
+        File schemaDirectory = new File( baseDirectory, SchemaConstants.OU_SCHEMA );
+        String[] ldifFiles = schemaDirectory.list( ldifFilter );
+
+        if ( ldifFiles != null )
+        {
+            for ( String ldifFile : ldifFiles )
+            {
+                File file = new File( schemaDirectory, ldifFile );
+
+                try
+                {
+                    LdifReader reader = new LdifReader( file );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+                    Schema schema = getSchema( entry.getEntry() );
+
+                    if ( schema == null )
+                    {
+                        // The entry was not a schema, skip it
+                        continue;
+                    }
+
+                    schemaMap.put( schema.getSchemaName(), schema );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( "Schema Initialized ... \n{}", schema );
+                    }
+                }
+                catch ( Exception e )
+                {
+                    LOG.error( I18n.err( I18n.ERR_10003, ldifFile ), e );
+                    throw e;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Utility method to get the file for a schema directory.
+     *
+     * @param schema the schema to get the file for
+     * @return the file for the specific schema directory
+     */
+    private File getSchemaDirectory( Schema schema )
+    {
+        return new File( new File( baseDirectory, SchemaConstants.OU_SCHEMA ), "cn="
+            + Strings.lowerCase( schema.getSchemaName() ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> comparatorList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return comparatorList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File comparatorsDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.COMPARATORS_PATH );
+
+            if ( !comparatorsDirectory.exists() )
+            {
+                return comparatorList;
+            }
+
+            File[] comparators = comparatorsDirectory.listFiles( ldifFilter );
+
+            if ( comparators != null )
+            {
+                for ( File ldifFile : comparators )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    comparatorList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return comparatorList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> syntaxCheckerList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return syntaxCheckerList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File syntaxCheckersDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.SYNTAX_CHECKERS_PATH );
+
+            if ( !syntaxCheckersDirectory.exists() )
+            {
+                return syntaxCheckerList;
+            }
+
+            File[] syntaxCheckerFiles = syntaxCheckersDirectory.listFiles( ldifFilter );
+
+            if ( syntaxCheckerFiles != null )
+            {
+                for ( File ldifFile : syntaxCheckerFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    syntaxCheckerList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return syntaxCheckerList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> normalizerList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return normalizerList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File normalizersDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.NORMALIZERS_PATH );
+
+            if ( !normalizersDirectory.exists() )
+            {
+                return normalizerList;
+            }
+
+            File[] normalizerFiles = normalizersDirectory.listFiles( ldifFilter );
+
+            if ( normalizerFiles != null )
+            {
+                for ( File ldifFile : normalizerFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    normalizerList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return normalizerList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> matchingRuleList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return matchingRuleList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File matchingRulesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.MATCHING_RULES_PATH );
+
+            if ( !matchingRulesDirectory.exists() )
+            {
+                return matchingRuleList;
+            }
+
+            File[] matchingRuleFiles = matchingRulesDirectory.listFiles( ldifFilter );
+
+            if ( matchingRuleFiles != null )
+            {
+                for ( File ldifFile : matchingRuleFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    matchingRuleList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return matchingRuleList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> syntaxList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return syntaxList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File syntaxesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.SYNTAXES_PATH );
+
+            if ( !syntaxesDirectory.exists() )
+            {
+                return syntaxList;
+            }
+
+            File[] syntaxFiles = syntaxesDirectory.listFiles( ldifFilter );
+
+            if ( syntaxFiles != null )
+            {
+                for ( File ldifFile : syntaxFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    syntaxList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return syntaxList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> attributeTypeList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return attributeTypeList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            // check that the attributeTypes directory exists for the schema
+            File attributeTypesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.ATTRIBUTE_TYPES_PATH );
+
+            if ( !attributeTypesDirectory.exists() )
+            {
+                return attributeTypeList;
+            }
+
+            // get list of attributeType LDIF schema files in attributeTypes
+            File[] attributeTypeFiles = attributeTypesDirectory.listFiles( ldifFilter );
+
+            if ( attributeTypeFiles != null )
+            {
+                for ( File ldifFile : attributeTypeFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    attributeTypeList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return attributeTypeList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> matchingRuleUseList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return matchingRuleUseList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File matchingRuleUsesDirectory = new File( getSchemaDirectory( schema ),
+                SchemaConstants.MATCHING_RULE_USE_PATH );
+
+            if ( !matchingRuleUsesDirectory.exists() )
+            {
+                return matchingRuleUseList;
+            }
+
+            File[] matchingRuleUseFiles = matchingRuleUsesDirectory.listFiles( ldifFilter );
+
+            if ( matchingRuleUseFiles != null )
+            {
+                for ( File ldifFile : matchingRuleUseFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    matchingRuleUseList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return matchingRuleUseList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> nameFormList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return nameFormList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File nameFormsDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.NAME_FORMS_PATH );
+
+            if ( !nameFormsDirectory.exists() )
+            {
+                return nameFormList;
+            }
+
+            File[] nameFormFiles = nameFormsDirectory.listFiles( ldifFilter );
+
+            if ( nameFormFiles != null )
+            {
+                for ( File ldifFile : nameFormFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    nameFormList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return nameFormList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> ditContentRuleList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return ditContentRuleList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File ditContentRulesDirectory = new File( getSchemaDirectory( schema ),
+                SchemaConstants.DIT_CONTENT_RULES_PATH );
+
+            if ( !ditContentRulesDirectory.exists() )
+            {
+                return ditContentRuleList;
+            }
+
+            File[] ditContentRuleFiles = ditContentRulesDirectory.listFiles( ldifFilter );
+
+            if ( ditContentRuleFiles != null )
+            {
+                for ( File ldifFile : ditContentRuleFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    ditContentRuleList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return ditContentRuleList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> ditStructureRuleList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return ditStructureRuleList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            File ditStructureRulesDirectory = new File( getSchemaDirectory( schema ),
+                SchemaConstants.DIT_STRUCTURE_RULES_PATH );
+
+            if ( !ditStructureRulesDirectory.exists() )
+            {
+                return ditStructureRuleList;
+            }
+
+            File[] ditStructureRuleFiles = ditStructureRulesDirectory.listFiles( ldifFilter );
+
+            if ( ditStructureRuleFiles != null )
+            {
+                for ( File ldifFile : ditStructureRuleFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    ditStructureRuleList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return ditStructureRuleList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException
+    {
+        List<Entry> objectClassList = new ArrayList<Entry>();
+
+        if ( schemas == null )
+        {
+            return objectClassList;
+        }
+
+        for ( Schema schema : schemas )
+        {
+            // get objectClasses directory, check if exists, return if not
+            File objectClassesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.OBJECT_CLASSES_PATH );
+
+            if ( !objectClassesDirectory.exists() )
+            {
+                return objectClassList;
+            }
+
+            // get list of objectClass LDIF files from directory and load
+            File[] objectClassFiles = objectClassesDirectory.listFiles( ldifFilter );
+
+            if ( objectClassFiles != null )
+            {
+                for ( File ldifFile : objectClassFiles )
+                {
+                    LdifReader reader = new LdifReader( ldifFile );
+                    LdifEntry entry = reader.next();
+                    reader.close();
+
+                    objectClassList.add( entry.getEntry() );
+                }
+            }
+        }
+
+        return objectClassList;
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/SchemaEntityFactory.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/SchemaEntityFactory.java
new file mode 100644
index 0000000..62f5b98
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/SchemaEntityFactory.java
@@ -0,0 +1,1229 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import java.lang.reflect.Constructor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.directory.api.asn1.util.Oid;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableObjectClass;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+import org.apache.directory.api.ldap.model.schema.parsers.LdapComparatorDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.NormalizerDescription;
+import org.apache.directory.api.ldap.model.schema.parsers.SyntaxCheckerDescription;
+import org.apache.directory.api.ldap.model.schema.registries.DefaultSchema;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.util.Base64;
+import org.apache.directory.api.util.StringConstants;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Showing how it's done ...
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaEntityFactory implements EntityFactory
+{
+    /** Slf4j logger */
+    private static final Logger LOG = LoggerFactory.getLogger( SchemaEntityFactory.class );
+
+    /** The empty string list. */
+    private static final List<String> EMPTY_LIST = new ArrayList<String>();
+
+    /** The empty string array. */
+    private static final String[] EMPTY_ARRAY = new String[]
+        {};
+
+    /** A special ClassLoader that loads a class from the bytecode attribute */
+    private final AttributeClassLoader classLoader;
+
+
+    /**
+     * Instantiates a new schema entity factory.
+     */
+    public SchemaEntityFactory()
+    {
+        this.classLoader = AccessController.doPrivileged( new PrivilegedAction<AttributeClassLoader>()
+        {
+            public AttributeClassLoader run() 
+            {
+                return new AttributeClassLoader();
+            }
+        } );
+    }
+
+
+    /**
+     * Get an OID from an entry. Handles the bad cases (null OID,
+     * not a valid OID, ...)
+     */
+    private String getOid( Entry entry, String objectType, boolean strict ) throws LdapInvalidAttributeValueException
+    {
+        // The OID
+        Attribute mOid = entry.get( MetaSchemaConstants.M_OID_AT );
+
+        if ( mOid == null )
+        {
+            String msg = I18n.err( I18n.ERR_10005, objectType, MetaSchemaConstants.M_OID_AT );
+            LOG.warn( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        String oid = mOid.getString();
+
+        if ( strict && !Oid.isOid( oid ) )
+        {
+            String msg = I18n.err( I18n.ERR_10006, oid );
+            LOG.warn( msg );
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
+        }
+
+        return oid;
+    }
+
+
+    /**
+     * Get an OID from an entry. Handles the bad cases (null OID,
+     * not a valid OID, ...)
+     */
+    private String getOid( SchemaObject description, String objectType ) throws LdapInvalidAttributeValueException
+    {
+        // The OID
+        String oid = description.getOid();
+
+        if ( oid == null )
+        {
+            String msg = I18n.err( I18n.ERR_10005, objectType, MetaSchemaConstants.M_OID_AT );
+            LOG.warn( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        if ( !Oid.isOid( oid ) )
+        {
+            String msg = I18n.err( I18n.ERR_10006, oid );
+            LOG.warn( msg );
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
+        }
+
+        return oid;
+    }
+
+
+    /**
+     * Check that the Entry is not null
+     */
+    private void checkEntry( Entry entry, String schemaEntity )
+    {
+        if ( entry == null )
+        {
+            String msg = I18n.err( I18n.ERR_10007, schemaEntity );
+            LOG.warn( msg );
+            throw new IllegalArgumentException( msg );
+        }
+    }
+
+
+    /**
+     * Check that the Description is not null
+     */
+    private void checkDescription( SchemaObject description, String schemaEntity )
+    {
+        if ( description == null )
+        {
+            String msg = I18n.err( I18n.ERR_10008, schemaEntity );
+            LOG.warn( msg );
+            throw new IllegalArgumentException( msg );
+        }
+    }
+
+
+    /**
+     * Get the schema from its name. Return the Other reference if there
+     * is no schema name. Throws a NPE if the schema is not loaded.
+     */
+    private Schema getSchema( String schemaName, Registries registries )
+    {
+        if ( Strings.isEmpty( schemaName ) )
+        {
+            schemaName = MetaSchemaConstants.SCHEMA_OTHER;
+        }
+
+        Schema schema = registries.getLoadedSchema( schemaName );
+
+        if ( schema == null )
+        {
+            String msg = I18n.err( I18n.ERR_10009, schemaName );
+            LOG.error( msg );
+        }
+
+        return schema;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Schema getSchema( Entry entry ) throws LdapException
+    {
+        String name;
+        String owner;
+        String[] dependencies = EMPTY_ARRAY;
+        boolean isDisabled = false;
+
+        if ( entry == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_10010 ) );
+        }
+
+        if ( entry.get( SchemaConstants.CN_AT ) == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_10011 ) );
+        }
+
+        name = entry.get( SchemaConstants.CN_AT ).getString();
+
+        if ( entry.get( SchemaConstants.CREATORS_NAME_AT ) == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_10012, SchemaConstants.CREATORS_NAME_AT ) );
+        }
+
+        owner = entry.get( SchemaConstants.CREATORS_NAME_AT ).getString();
+
+        if ( entry.get( MetaSchemaConstants.M_DISABLED_AT ) != null )
+        {
+            String value = entry.get( MetaSchemaConstants.M_DISABLED_AT ).getString();
+            value = value.toUpperCase();
+            isDisabled = value.equals( "TRUE" );
+        }
+
+        if ( entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT ) != null )
+        {
+            Set<String> depsSet = new HashSet<String>();
+            Attribute depsAttr = entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT );
+
+            for ( Value<?> value : depsAttr )
+            {
+                depsSet.add( value.getString() );
+            }
+
+            dependencies = depsSet.toArray( EMPTY_ARRAY );
+        }
+
+        return new DefaultSchema( name, owner, dependencies, isDisabled );
+    }
+
+
+    /**
+     * Class load a syntaxChecker instance
+     */
+    private SyntaxChecker classLoadSyntaxChecker( SchemaManager schemaManager, String oid, String className,
+        Attribute byteCode )
+        throws Exception
+    {
+        // Try to class load the syntaxChecker
+        Class<?> clazz = null;
+        SyntaxChecker syntaxChecker = null;
+        String byteCodeStr = StringConstants.EMPTY;
+
+        if ( byteCode == null )
+        {
+            clazz = Class.forName( className );
+        }
+        else
+        {
+            classLoader.setAttribute( byteCode );
+            clazz = classLoader.loadClass( className );
+            byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
+        }
+
+        // Create the syntaxChecker instance
+        syntaxChecker = ( SyntaxChecker ) clazz.newInstance();
+
+        // Update the common fields
+        syntaxChecker.setBytecode( byteCodeStr );
+        syntaxChecker.setFqcn( className );
+
+        // Inject the new OID, as the loaded syntaxChecker might have its own
+        syntaxChecker.setOid( oid );
+
+        // Inject the SchemaManager for the comparator who needs it
+        syntaxChecker.setSchemaManager( schemaManager );
+
+        return syntaxChecker;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxChecker getSyntaxChecker( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapException
+    {
+        checkEntry( entry, SchemaConstants.SYNTAX_CHECKER );
+
+        // The SyntaxChecker OID
+        String oid = getOid( entry, SchemaConstants.SYNTAX_CHECKER, schemaManager.isStrict() );
+
+        // Get the schema
+        if ( !schemaManager.isSchemaLoaded( schemaName ) )
+        {
+            // The schema is not loaded. We can't create the requested Normalizer
+            String msg = I18n.err( I18n.ERR_10013, entry.getDn().getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is disabled. We still have to update the backend
+            String msg = I18n.err( I18n.ERR_10014, entry.getDn().getName(), schemaName );
+            LOG.info( msg );
+            schema = schemaManager.getLoadedSchema( schemaName );
+        }
+
+        // The FQCN
+        String className = getFqcn( entry, SchemaConstants.SYNTAX_CHECKER );
+
+        // The ByteCode
+        Attribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
+
+        try
+        {
+            // Class load the syntaxChecker
+            SyntaxChecker syntaxChecker = classLoadSyntaxChecker( schemaManager, oid, className, byteCode );
+
+            // Update the common fields
+            setSchemaObjectProperties( syntaxChecker, entry, schema );
+
+            // return the resulting syntaxChecker
+            return syntaxChecker;
+        }
+        catch ( Exception e )
+        {
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxChecker getSyntaxChecker( SchemaManager schemaManager,
+        SyntaxCheckerDescription syntaxCheckerDescription, Registries targetRegistries, String schemaName )
+        throws Exception
+    {
+        checkDescription( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
+
+        // The Comparator OID
+        String oid = getOid( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
+
+        // Get the schema
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is not loaded. We can't create the requested SyntaxChecker
+            String msg = I18n.err( I18n.ERR_10013, syntaxCheckerDescription.getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        // The FQCN
+        String fqcn = getFqcn( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
+
+        // get the byteCode
+        Attribute byteCode = getByteCode( syntaxCheckerDescription, SchemaConstants.SYNTAX_CHECKER );
+
+        // Class load the SyntaxChecker
+        SyntaxChecker syntaxChecker = classLoadSyntaxChecker( schemaManager, oid, fqcn, byteCode );
+
+        // Update the common fields
+        setSchemaObjectProperties( syntaxChecker, syntaxCheckerDescription, schema );
+
+        return syntaxChecker;
+    }
+
+
+    /**
+     * Class load a comparator instances
+     */
+    private LdapComparator<?> classLoadComparator( SchemaManager schemaManager, String oid, String className,
+        Attribute byteCode ) throws Exception
+    {
+        // Try to class load the comparator
+        LdapComparator<?> comparator = null;
+        Class<?> clazz = null;
+        String byteCodeStr = StringConstants.EMPTY;
+
+        if ( byteCode == null )
+        {
+            clazz = Class.forName( className );
+        }
+        else
+        {
+            classLoader.setAttribute( byteCode );
+            clazz = classLoader.loadClass( className );
+            byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
+        }
+
+        // Create the comparator instance. Either we have a no argument constructor,
+        // or we have one which takes an OID. Lets try the one with an OID argument first
+        try
+        {
+            Constructor<?> constructor = clazz.getConstructor( new Class[]
+                { String.class } );
+            comparator = ( LdapComparator<?> ) constructor.newInstance( new Object[]
+                { oid } );
+        }
+        catch ( NoSuchMethodException nsme )
+        {
+            // Ok, let's try with the constructor without argument.
+            // In this case, we will have to check that the OID is the same than
+            // the one we got in the Comparator entry
+            clazz.getConstructor();
+            comparator = ( LdapComparator<?> ) clazz.newInstance();
+
+            if ( !comparator.getOid().equals( oid ) )
+            {
+                String msg = I18n.err( I18n.ERR_10015, oid, comparator.getOid() );
+                throw new LdapInvalidAttributeValueException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg, nsme );
+            }
+        }
+
+        // Update the loadable fields
+        comparator.setBytecode( byteCodeStr );
+        comparator.setFqcn( className );
+
+        // Inject the SchemaManager for the comparator who needs it
+        comparator.setSchemaManager( schemaManager );
+
+        return comparator;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapComparator<?> getLdapComparator( SchemaManager schemaManager,
+        LdapComparatorDescription comparatorDescription, Registries targetRegistries, String schemaName )
+        throws Exception
+    {
+        checkDescription( comparatorDescription, SchemaConstants.COMPARATOR );
+
+        // The Comparator OID
+        String oid = getOid( comparatorDescription, SchemaConstants.COMPARATOR );
+
+        // Get the schema
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is not loaded. We can't create the requested Comparator
+            String msg = I18n.err( I18n.ERR_10016, comparatorDescription.getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        // The FQCN
+        String fqcn = getFqcn( comparatorDescription, SchemaConstants.COMPARATOR );
+
+        // get the byteCode
+        Attribute byteCode = getByteCode( comparatorDescription, SchemaConstants.COMPARATOR );
+
+        // Class load the comparator
+        LdapComparator<?> comparator = classLoadComparator( schemaManager, oid, fqcn, byteCode );
+
+        // Update the common fields
+        setSchemaObjectProperties( comparator, comparatorDescription, schema );
+
+        return comparator;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapComparator<?> getLdapComparator( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapException
+    {
+        checkEntry( entry, SchemaConstants.COMPARATOR );
+
+        // The Comparator OID
+        String oid = getOid( entry, SchemaConstants.COMPARATOR, schemaManager.isStrict() );
+
+        // Get the schema
+        if ( !schemaManager.isSchemaLoaded( schemaName ) )
+        {
+            // The schema is not loaded. We can't create the requested Comparator
+            String msg = I18n.err( I18n.ERR_10016, entry.getDn().getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is disabled. We still have to update the backend
+            String msg = I18n.err( I18n.ERR_10017, entry.getDn().getName(), schemaName );
+            LOG.info( msg );
+            schema = schemaManager.getLoadedSchema( schemaName );
+        }
+
+        // The FQCN
+        String fqcn = getFqcn( entry, SchemaConstants.COMPARATOR );
+
+        // The ByteCode
+        Attribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
+
+        try
+        {
+            // Class load the comparator
+            LdapComparator<?> comparator = classLoadComparator( schemaManager, oid, fqcn, byteCode );
+
+            // Update the common fields
+            setSchemaObjectProperties( comparator, entry, schema );
+
+            // return the resulting comparator
+            return comparator;
+        }
+        catch ( Exception e )
+        {
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * Class load a normalizer instances
+     */
+    private Normalizer classLoadNormalizer( SchemaManager schemaManager, String oid, String className,
+        Attribute byteCode ) throws Exception
+    {
+        // Try to class load the normalizer
+        Class<?> clazz = null;
+        Normalizer normalizer = null;
+        String byteCodeStr = StringConstants.EMPTY;
+
+        if ( byteCode == null )
+        {
+            clazz = Class.forName( className );
+        }
+        else
+        {
+            classLoader.setAttribute( byteCode );
+            clazz = classLoader.loadClass( className );
+            byteCodeStr = new String( Base64.encode( byteCode.getBytes() ) );
+        }
+
+        // Create the normalizer instance
+        normalizer = ( Normalizer ) clazz.newInstance();
+
+        // Update the common fields
+        normalizer.setBytecode( byteCodeStr );
+        normalizer.setFqcn( className );
+
+        // Inject the new OID, as the loaded normalizer might have its own
+        normalizer.setOid( oid );
+
+        // Inject the SchemaManager for the normalizer who needs it
+        normalizer.setSchemaManager( schemaManager );
+
+        return normalizer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Normalizer getNormalizer( SchemaManager schemaManager, NormalizerDescription normalizerDescription,
+        Registries targetRegistries, String schemaName ) throws Exception
+    {
+        checkDescription( normalizerDescription, SchemaConstants.NORMALIZER );
+
+        // The Comparator OID
+        String oid = getOid( normalizerDescription, SchemaConstants.NORMALIZER );
+
+        // Get the schema
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is not loaded. We can't create the requested Normalizer
+            String msg = I18n.err( I18n.ERR_10018, normalizerDescription.getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        // The FQCN
+        String fqcn = getFqcn( normalizerDescription, SchemaConstants.NORMALIZER );
+
+        // get the byteCode
+        Attribute byteCode = getByteCode( normalizerDescription, SchemaConstants.NORMALIZER );
+
+        // Class load the normalizer
+        Normalizer normalizer = classLoadNormalizer( schemaManager, oid, fqcn, byteCode );
+
+        // Update the common fields
+        setSchemaObjectProperties( normalizer, normalizerDescription, schema );
+
+        return normalizer;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Normalizer getNormalizer( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapException
+    {
+        checkEntry( entry, SchemaConstants.NORMALIZER );
+
+        // The Normalizer OID
+        String oid = getOid( entry, SchemaConstants.NORMALIZER, schemaManager.isStrict() );
+
+        // Get the schema
+        if ( !schemaManager.isSchemaLoaded( schemaName ) )
+        {
+            // The schema is not loaded. We can't create the requested Normalizer
+            String msg = I18n.err( I18n.ERR_10018, entry.getDn().getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is disabled. We still have to update the backend
+            String msg = I18n.err( I18n.ERR_10019, entry.getDn().getName(), schemaName );
+            LOG.info( msg );
+            schema = schemaManager.getLoadedSchema( schemaName );
+        }
+
+        // The FQCN
+        String className = getFqcn( entry, SchemaConstants.NORMALIZER );
+
+        // The ByteCode
+        Attribute byteCode = entry.get( MetaSchemaConstants.M_BYTECODE_AT );
+
+        try
+        {
+            // Class load the Normalizer
+            Normalizer normalizer = classLoadNormalizer( schemaManager, oid, className, byteCode );
+
+            // Update the common fields
+            setSchemaObjectProperties( normalizer, entry, schema );
+
+            // return the resulting Normalizer
+            return normalizer;
+        }
+        catch ( Exception e )
+        {
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws LdapInvalidAttributeValueException
+     * @throws LdapUnwillingToPerformException
+     */
+    public LdapSyntax getSyntax( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapInvalidAttributeValueException, LdapUnwillingToPerformException
+    {
+        checkEntry( entry, SchemaConstants.SYNTAX );
+
+        // The Syntax OID
+        String oid = getOid( entry, SchemaConstants.SYNTAX, schemaManager.isStrict() );
+
+        // Get the schema
+        if ( !schemaManager.isSchemaLoaded( schemaName ) )
+        {
+            // The schema is not loaded. We can't create the requested Syntax
+            String msg = I18n.err( I18n.ERR_10020, entry.getDn().getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is disabled. We still have to update the backend
+            String msg = I18n.err( I18n.ERR_10021, entry.getDn().getName(), schemaName );
+            LOG.info( msg );
+            schema = schemaManager.getLoadedSchema( schemaName );
+        }
+
+        // Create the new LdapSyntax instance
+        LdapSyntax syntax = new LdapSyntax( oid );
+
+        // Common properties
+        setSchemaObjectProperties( syntax, entry, schema );
+
+        return syntax;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws LdapUnwillingToPerformException
+     * @throws LdapInvalidAttributeValueException
+     */
+    public MatchingRule getMatchingRule( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapUnwillingToPerformException, LdapInvalidAttributeValueException
+    {
+        checkEntry( entry, SchemaConstants.MATCHING_RULE );
+
+        // The MatchingRule OID
+        String oid = getOid( entry, SchemaConstants.MATCHING_RULE, schemaManager.isStrict() );
+
+        // Get the schema
+        if ( !schemaManager.isSchemaLoaded( schemaName ) )
+        {
+            // The schema is not loaded. We can't create the requested MatchingRule
+            String msg = I18n.err( I18n.ERR_10022, entry.getDn().getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is disabled. We still have to update the backend
+            String msg = I18n.err( I18n.ERR_10023, entry.getDn().getName(), schemaName );
+            LOG.info( msg );
+            schema = schemaManager.getLoadedSchema( schemaName );
+        }
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( oid );
+
+        // The syntax field
+        Attribute mSyntax = entry.get( MetaSchemaConstants.M_SYNTAX_AT );
+
+        if ( mSyntax != null )
+        {
+            matchingRule.setSyntaxOid( mSyntax.getString() );
+        }
+
+        // The normalizer and comparator fields will be updated when we will
+        // apply the registry
+
+        // Common properties
+        setSchemaObjectProperties( matchingRule, entry, schema );
+
+        return matchingRule;
+    }
+
+
+    /**
+     * Create a list of string from a multivalued attribute's values
+     */
+    private List<String> getStrings( Attribute attr )
+    {
+        if ( attr == null )
+        {
+            return EMPTY_LIST;
+        }
+
+        List<String> strings = new ArrayList<String>( attr.size() );
+
+        for ( Value<?> value : attr )
+        {
+            strings.add( value.getString() );
+        }
+
+        return strings;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClass getObjectClass( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapException
+    {
+        checkEntry( entry, SchemaConstants.OBJECT_CLASS );
+
+        // The ObjectClass OID
+        String oid = getOid( entry, SchemaConstants.OBJECT_CLASS, schemaManager.isStrict() );
+
+        // Get the schema
+        if ( !schemaManager.isSchemaLoaded( schemaName ) )
+        {
+            // The schema is not loaded. We can't create the requested ObjectClass
+            String msg = I18n.err( I18n.ERR_10024, entry.getDn().getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is disabled. We still have to update the backend
+            String msg = I18n.err( I18n.ERR_10025, entry.getDn().getName(), schemaName );
+            LOG.info( msg );
+            schema = schemaManager.getLoadedSchema( schemaName );
+        }
+
+        // Create the ObjectClass instance
+        MutableObjectClass oc = new MutableObjectClass( oid );
+
+        // The Sup field
+        Attribute mSuperiors = entry.get( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT );
+
+        if ( mSuperiors != null )
+        {
+            oc.setSuperiorOids( getStrings( mSuperiors ) );
+        }
+
+        // The May field
+        Attribute mMay = entry.get( MetaSchemaConstants.M_MAY_AT );
+
+        if ( mMay != null )
+        {
+            oc.setMayAttributeTypeOids( getStrings( mMay ) );
+        }
+
+        // The Must field
+        Attribute mMust = entry.get( MetaSchemaConstants.M_MUST_AT );
+
+        if ( mMust != null )
+        {
+            oc.setMustAttributeTypeOids( getStrings( mMust ) );
+        }
+
+        // The objectClassType field
+        Attribute mTypeObjectClass = entry.get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT );
+
+        if ( mTypeObjectClass != null )
+        {
+            String type = mTypeObjectClass.getString();
+            oc.setType( ObjectClassTypeEnum.getClassType( type ) );
+        }
+
+        // Common properties
+        setSchemaObjectProperties( oc, entry, schema );
+
+        return oc;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws LdapInvalidAttributeValueException
+     * @throws LdapUnwillingToPerformException
+     */
+    public AttributeType getAttributeType( SchemaManager schemaManager, Entry entry, Registries targetRegistries,
+        String schemaName ) throws LdapInvalidAttributeValueException, LdapUnwillingToPerformException
+    {
+        checkEntry( entry, SchemaConstants.ATTRIBUTE_TYPE );
+
+        // The AttributeType OID
+        String oid = getOid( entry, SchemaConstants.ATTRIBUTE_TYPE, schemaManager.isStrict() );
+
+        // Get the schema
+        if ( !schemaManager.isSchemaLoaded( schemaName ) )
+        {
+            // The schema is not loaded, this is an error
+            String msg = I18n.err( I18n.ERR_10026, entry.getDn().getName(), schemaName );
+            LOG.warn( msg );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
+        }
+
+        Schema schema = getSchema( schemaName, targetRegistries );
+
+        if ( schema == null )
+        {
+            // The schema is disabled. We still have to update the backend
+            String msg = I18n.err( I18n.ERR_10027, entry.getDn().getName(), schemaName );
+            LOG.info( msg );
+            schema = schemaManager.getLoadedSchema( schemaName );
+        }
+
+        // Create the new AttributeType
+        MutableAttributeType attributeType = new MutableAttributeType( oid );
+
+        // Syntax
+        Attribute mSyntax = entry.get( MetaSchemaConstants.M_SYNTAX_AT );
+
+        if ( ( mSyntax != null ) && ( mSyntax.get() != null ) )
+        {
+            attributeType.setSyntaxOid( mSyntax.getString() );
+        }
+
+        // Syntax Length
+        Attribute mSyntaxLength = entry.get( MetaSchemaConstants.M_LENGTH_AT );
+
+        if ( mSyntaxLength != null )
+        {
+            attributeType.setSyntaxLength( Integer.parseInt( mSyntaxLength.getString() ) );
+        }
+
+        // Equality
+        Attribute mEquality = entry.get( MetaSchemaConstants.M_EQUALITY_AT );
+
+        if ( mEquality != null )
+        {
+            attributeType.setEqualityOid( mEquality.getString() );
+        }
+
+        // Ordering
+        Attribute mOrdering = entry.get( MetaSchemaConstants.M_ORDERING_AT );
+
+        if ( mOrdering != null )
+        {
+            attributeType.setOrderingOid( mOrdering.getString() );
+        }
+
+        // Substr
+        Attribute mSubstr = entry.get( MetaSchemaConstants.M_SUBSTR_AT );
+
+        if ( mSubstr != null )
+        {
+            attributeType.setSubstringOid( mSubstr.getString() );
+        }
+
+        Attribute mSupAttributeType = entry.get( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT );
+
+        // Sup
+        if ( mSupAttributeType != null )
+        {
+            attributeType.setSuperiorOid( mSupAttributeType.getString() );
+        }
+
+        // isCollective
+        Attribute mCollective = entry.get( MetaSchemaConstants.M_COLLECTIVE_AT );
+
+        if ( mCollective != null )
+        {
+            String val = mCollective.getString();
+            attributeType.setCollective( val.equalsIgnoreCase( "TRUE" ) );
+        }
+
+        // isSingleValued
+        Attribute mSingleValued = entry.get( MetaSchemaConstants.M_SINGLE_VALUE_AT );
+
+        if ( mSingleValued != null )
+        {
+            String val = mSingleValued.getString();
+            attributeType.setSingleValued( val.equalsIgnoreCase( "TRUE" ) );
+        }
+
+        // isReadOnly
+        Attribute mNoUserModification = entry.get( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT );
+
+        if ( mNoUserModification != null )
+        {
+            String val = mNoUserModification.getString();
+            attributeType.setUserModifiable( !val.equalsIgnoreCase( "TRUE" ) );
+        }
+
+        // Usage
+        Attribute mUsage = entry.get( MetaSchemaConstants.M_USAGE_AT );
+
+        if ( mUsage != null )
+        {
+            attributeType.setUsage( UsageEnum.getUsage( mUsage.getString() ) );
+        }
+
+        // Common properties
+        setSchemaObjectProperties( attributeType, entry, schema );
+
+        return attributeType;
+    }
+
+
+    /**
+     * Process the FQCN attribute
+     * @throws LdapInvalidAttributeValueException
+     */
+    private String getFqcn( Entry entry, String objectType ) throws LdapInvalidAttributeValueException
+    {
+        // The FQCN
+        Attribute mFqcn = entry.get( MetaSchemaConstants.M_FQCN_AT );
+
+        if ( mFqcn == null )
+        {
+            String msg = I18n.err( I18n.ERR_10028, objectType, MetaSchemaConstants.M_FQCN_AT );
+            LOG.warn( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        return mFqcn.getString();
+    }
+
+
+    /**
+     * Process the FQCN attribute
+     */
+    private String getFqcn( LoadableSchemaObject description, String objectType )
+    {
+        // The FQCN
+        String mFqcn = description.getFqcn();
+
+        if ( mFqcn == null )
+        {
+            String msg = I18n.err( I18n.ERR_10028, objectType, MetaSchemaConstants.M_FQCN_AT );
+            LOG.warn( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        return mFqcn;
+    }
+
+
+    /**
+     * Process the ByteCode attribute
+     */
+    private Attribute getByteCode( LoadableSchemaObject description, String objectType )
+    {
+        String byteCodeString = description.getBytecode();
+
+        if ( byteCodeString == null )
+        {
+            String msg = I18n.err( I18n.ERR_10028, objectType, MetaSchemaConstants.M_BYTECODE_AT );
+            LOG.warn( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        byte[] bytecode = Base64.decode( byteCodeString.toCharArray() );
+        Attribute attr = new DefaultAttribute( MetaSchemaConstants.M_BYTECODE_AT, bytecode );
+
+        return attr;
+    }
+
+
+    /**
+     * Return a String value, from teh given Valu, even if it's a binary value
+     */
+    private String getStringValue( Attribute attribute )
+    {
+        Value<?> value = attribute.get();
+
+        if ( value instanceof BinaryValue )
+        {
+            // We have to transform the value to a String
+            return Strings.utf8ToString( value.getBytes() );
+        }
+        else
+        {
+            return value.getString();
+        }
+    }
+
+
+    /**
+     * Process the common attributes to all SchemaObjects :
+     *  - obsolete
+     *  - description
+     *  - names
+     *  - schemaName
+     *  - specification (if any)
+     *  - extensions
+     *  - isReadOnly
+     *  - isEnabled
+     * @throws org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException
+     */
+    private void setSchemaObjectProperties( SchemaObject schemaObject, Entry entry, Schema schema )
+        throws LdapInvalidAttributeValueException
+    {
+        // The isObsolete field
+        Attribute mObsolete = entry.get( MetaSchemaConstants.M_OBSOLETE_AT );
+
+        if ( mObsolete != null )
+        {
+            String val = mObsolete.getString();
+            schemaObject.setObsolete( val.equalsIgnoreCase( "TRUE" ) );
+        }
+
+        // The description field
+        Attribute mDescription = entry.get( MetaSchemaConstants.M_DESCRIPTION_AT );
+
+        if ( mDescription != null )
+        {
+            schemaObject.setDescription( getStringValue( mDescription ) );
+        }
+
+        // The names field
+        Attribute names = entry.get( MetaSchemaConstants.M_NAME_AT );
+
+        if ( names != null )
+        {
+            List<String> values = new ArrayList<String>();
+
+            for ( Value<?> name : names )
+            {
+                values.add( name.getString() );
+            }
+
+            schemaObject.setNames( values );
+        }
+
+        // The isEnabled field
+        Attribute mDisabled = entry.get( MetaSchemaConstants.M_DISABLED_AT );
+
+        // If the SchemaObject has an explicit m-disabled attribute, then use it.
+        // Otherwise, inherit it from the schema
+        if ( mDisabled != null )
+        {
+            String val = mDisabled.getString();
+            schemaObject.setEnabled( !val.equalsIgnoreCase( "TRUE" ) );
+        }
+        else
+        {
+            schemaObject.setEnabled( schema.isEnabled() );
+        }
+
+        // The specification field
+        /*
+         * TODO : create the M_SPECIFICATION_AT
+        EntryAttribute mSpecification = entry.get( MetaSchemaConstants.M_SPECIFICATION_AT );
+        
+        if ( mSpecification != null )
+        {
+            so.setSpecification( mSpecification.getString() );
+        }
+        */
+
+        // The schemaName field
+        schemaObject.setSchemaName( schema.getSchemaName() );
+
+        // The extensions fields
+        // X-SCHEMA
+        Attribute xSchema = entry.get( MetaSchemaConstants.X_SCHEMA_AT );
+
+        if ( xSchema != null )
+        {
+            String schemaName = xSchema.getString();
+
+            if ( !schema.getSchemaName().equalsIgnoreCase( schemaName ) )
+            {
+                LOG.warn( "Schema (" + schema.getSchemaName() + ") and X-SCHEMA ("
+                    + schemaName + ") are different : " + entry );
+            }
+
+            schemaObject.addExtension( MetaSchemaConstants.X_SCHEMA_AT, schemaName );
+        }
+
+        // X-NOT-HUMAN-READABLE
+        Attribute xNotHumanReadable = entry.get( MetaSchemaConstants.X_NOT_HUMAN_READABLE_AT );
+
+        if ( xNotHumanReadable != null )
+        {
+            String value = xNotHumanReadable.getString();
+
+            schemaObject.addExtension( MetaSchemaConstants.X_NOT_HUMAN_READABLE_AT, value );
+        }
+
+        // X-READ-ONLY
+        Attribute xReadOnly = entry.get( MetaSchemaConstants.X_READ_ONLY_AT );
+
+        if ( xReadOnly != null )
+        {
+            String value = xReadOnly.getString();
+
+            schemaObject.addExtension( MetaSchemaConstants.X_READ_ONLY_AT, value );
+        }
+    }
+
+
+    /**
+     * Process the common attributes to all SchemaObjects :
+     *  - obsolete
+     *  - description
+     *  - names
+     *  - schemaName
+     *  - specification (if any)
+     *  - extensions
+     *  - isReadOnly
+     *  - isEnabled
+     */
+    private void setSchemaObjectProperties( SchemaObject schemaObject, SchemaObject description, Schema schema )
+    {
+        // The isObsolete field
+        schemaObject.setObsolete( description.isObsolete() );
+
+        // The description field
+        schemaObject.setDescription( description.getDescription() );
+
+        // The names field
+        schemaObject.setNames( description.getNames() );
+
+        // The isEnabled field. Has the description does not hold a
+        // Disable field, we will inherit from the schema enable field
+        schemaObject.setEnabled( schema.isEnabled() );
+
+        // The isReadOnly field. We don't have this data in the description,
+        // so set it to false
+        // TODO : should it be a X-READONLY extension ?
+        schemaObject.setReadOnly( false );
+
+        // The specification field
+        schemaObject.setSpecification( description.getSpecification() );
+
+        // The schemaName field
+        schemaObject.setSchemaName( schema.getSchemaName() );
+
+        // The extensions field
+        schemaObject.setExtensions( description.getExtensions() );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/SingleLdifSchemaLoader.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/SingleLdifSchemaLoader.java
new file mode 100644
index 0000000..d39bf60
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/loader/SingleLdifSchemaLoader.java
@@ -0,0 +1,306 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.schema.registries.AbstractSchemaLoader;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A schema loader based on a single monolithic ldif file containing all the schema partition elements
+ * 
+ * Performs better than any other existing LDIF schema loaders. NOT DOCUMENTED atm
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SingleLdifSchemaLoader extends AbstractSchemaLoader
+{
+    /** 
+     * Pattern for start of schema Dn.
+     * java.util.regex.Pattern is immutable so only one instance is needed for all uses.
+     */
+    private static final Pattern SCHEMA_START_PATTERN = Pattern
+        .compile( "cn\\s*=\\s*[a-z0-9-_]*\\s*,\\s*ou\\s*=\\s*schema" );
+
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( SingleLdifSchemaLoader.class );
+
+    /** The schema object Rdn attribute types. */
+    private String[] schemaObjectTypeRdns = new String[]
+        { "attributetypes", "comparators", "ditContentRules", "ditStructureRules", "matchingRules", "matchingRuleUse",
+            "nameForms", "normalizers", "objectClasses", "syntaxes", "syntaxCheckers" };
+
+    /** The map containing ... */
+    private Map<String, Map<String, List<Entry>>> scObjEntryMap = new HashMap<String, Map<String, List<Entry>>>();
+
+
+    /**
+     * Instantiates a new single LDIF schema loader.
+     */
+    public SingleLdifSchemaLoader()
+    {
+        try
+        {
+            URL resource = getClass().getClassLoader().getResource( "schema-all.ldif" );
+
+            LOG.debug( "URL of the all schema ldif file {}", resource );
+
+            for ( String s : schemaObjectTypeRdns )
+            {
+                scObjEntryMap.put( s, new HashMap<String, List<Entry>>() );
+            }
+
+            InputStream in = resource.openStream();
+
+            initializeSchemas( in );
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    private void initializeSchemas( InputStream in ) throws Exception
+    {
+        LdifReader ldifReader = new LdifReader( in );
+
+        Schema currentSchema = null;
+
+        while ( ldifReader.hasNext() )
+        {
+            LdifEntry ldifEntry = ldifReader.next();
+            String dn = ldifEntry.getDn().getName();
+
+            if ( SCHEMA_START_PATTERN.matcher( dn ).matches() )
+            {
+                Schema schema = getSchema( ldifEntry.getEntry() );
+                schemaMap.put( schema.getSchemaName(), schema );
+                currentSchema = schema;
+            }
+            else
+            {
+                loadSchemaObject( currentSchema.getSchemaName(), ldifEntry );
+            }
+        }
+
+        ldifReader.close();
+    }
+
+
+    private void loadSchemaObject( String schemaName, LdifEntry ldifEntry ) throws Exception
+    {
+        for ( String scObjTypeRdn : schemaObjectTypeRdns )
+        {
+            Pattern regex = Pattern.compile( "m-oid\\s*=\\s*[0-9\\.]*\\s*" + ",\\s*ou\\s*=\\s*" + scObjTypeRdn
+                + "\\s*,\\s*cn\\s*=\\s*" + schemaName
+                + "\\s*,\\s*ou=schema\\s*", Pattern.CASE_INSENSITIVE );
+
+            String dn = ldifEntry.getDn().getName();
+
+            if ( regex.matcher( dn ).matches() )
+            {
+                Map<String, List<Entry>> m = scObjEntryMap.get( scObjTypeRdn );
+                List<Entry> entryList = m.get( schemaName );
+                if ( entryList == null )
+                {
+                    entryList = new ArrayList<Entry>();
+                    entryList.add( ldifEntry.getEntry() );
+                    m.put( schemaName, entryList );
+                }
+                else
+                {
+                    entryList.add( ldifEntry.getEntry() );
+                }
+
+                break;
+            }
+        }
+    }
+
+
+    private List<Entry> loadSchemaObjects( String schemaObjectType, Schema... schemas ) throws LdapException,
+        IOException
+    {
+        Map<String, List<Entry>> m = scObjEntryMap.get( schemaObjectType );
+        List<Entry> atList = new ArrayList<Entry>();
+
+        for ( Schema s : schemas )
+        {
+            List<Entry> preLoaded = m.get( s.getSchemaName() );
+            if ( preLoaded != null )
+            {
+                atList.addAll( preLoaded );
+            }
+        }
+
+        return atList;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadAttributeTypes( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "attributetypes", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadComparators( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "comparators", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitContentRules( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "ditContentRules", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadDitStructureRules( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "ditStructureRules", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRules( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "matchingRules", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "matchingRuleUse", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNameForms( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "nameForms", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadNormalizers( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "normalizers", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadObjectClasses( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "objectClasses", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxes( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "syntaxes", schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws LdapException, IOException
+    {
+        return loadSchemaObjects( "syntaxCheckers", schemas );
+    }
+
+}
+
+class SchemaMarker
+{
+    /** The start marker. */
+    private int start;
+
+    /** The end marker. */
+    private int end;
+
+
+    public SchemaMarker( int start )
+    {
+        this.start = start;
+    }
+
+
+    public void setEnd( int end )
+    {
+        this.end = end;
+    }
+
+
+    public int getStart()
+    {
+        return start;
+    }
+
+
+    public int getEnd()
+    {
+        return end;
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/manager/impl/DefaultSchemaManager.java b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/manager/impl/DefaultSchemaManager.java
new file mode 100644
index 0000000..0e2c26c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/java/org/apache/directory/api/ldap/schema/manager/impl/DefaultSchemaManager.java
@@ -0,0 +1,2246 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.manager.impl;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapOtherException;
+import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SchemaObject;
+import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ComparatorRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.DitContentRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.DitStructureRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableAttributeTypeRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableComparatorRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableDitContentRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableDitStructureRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableLdapSyntaxRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableMatchingRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableMatchingRuleUseRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableNameFormRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableNormalizerRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableObjectClassRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ImmutableSyntaxCheckerRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.LdapSyntaxRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleUseRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.NameFormRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.NormalizerRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.OidRegistry;
+import org.apache.directory.api.ldap.model.schema.registries.Registries;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
+import org.apache.directory.api.ldap.model.schema.registries.SyntaxCheckerRegistry;
+import org.apache.directory.api.ldap.schema.loader.EntityFactory;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.loader.SchemaEntityFactory;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The SchemaManager class : it handles all the schema operations (addition, removal,
+ * modification).
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DefaultSchemaManager implements SchemaManager
+{
+    /** static class logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaManager.class );
+
+    /** The NamingContext this SchemaManager is associated with */
+    private Dn namingContext;
+
+    /** The global registries for this namingContext */
+    private volatile Registries registries;
+
+    /** The list of errors produced when loading some schema elements */
+    private List<Throwable> errors;
+
+    /** The Schema schemaLoader used by this SchemaManager */
+    private SchemaLoader schemaLoader;
+
+    /** the factory that generates respective SchemaObjects from LDIF entries */
+    private final EntityFactory factory;
+
+    /** A Map containing all the schema being dependent from a schema */
+    private Map<String, Set<String>> schemaDependences = new HashMap<String, Set<String>>();
+
+    /** A flag indicating that the SchemaManager is relaxed or not */
+    private boolean isRelaxed = STRICT;
+
+    /**
+     * Creates a new instance of DefaultSchemaManager with the default schema schemaLoader
+     *
+     * @param loader The schema loader to use
+     */
+    public DefaultSchemaManager() throws Exception
+    {
+        // Default to the the root (one schemaManager for all the entries
+        namingContext = Dn.ROOT_DSE;
+        this.schemaLoader = new JarLdifSchemaLoader();
+        errors = new ArrayList<Throwable>();
+        registries = new Registries();
+        factory = new SchemaEntityFactory();
+        isRelaxed = STRICT;
+        loadAllEnabled();
+    }
+
+
+    /**
+     * Creates a new instance of DefaultSchemaManager with the default schema schemaLoader
+     *
+     * @param loader The schema loader to use
+     */
+    public DefaultSchemaManager( SchemaLoader loader )
+    {
+        // Default to the the root (one schemaManager for all the entries
+        namingContext = Dn.ROOT_DSE;
+        this.schemaLoader = loader;
+        errors = new ArrayList<Throwable>();
+        registries = new Registries();
+        factory = new SchemaEntityFactory();
+        isRelaxed = loader.isRelaxed();
+    }
+
+
+    /**
+     * Creates a new instance of DefaultSchemaManager, for a specific
+     * naming context
+     *
+     * @param loader The schema loader to use
+     * @param namingContext The associated NamingContext
+     */
+    public DefaultSchemaManager( SchemaLoader loader, Dn namingContext )
+    {
+        this.namingContext = namingContext;
+        this.schemaLoader = loader;
+        errors = new ArrayList<Throwable>();
+        registries = new Registries();
+        factory = new SchemaEntityFactory();
+        isRelaxed = loader.isRelaxed();
+    }
+
+
+    //-----------------------------------------------------------------------
+    // Helper methods
+    //-----------------------------------------------------------------------
+    /**
+     * Clone the registries before doing any modification on it. Relax it
+     * too so that we can update it.
+     */
+    private Registries cloneRegistries() throws LdapException
+    {
+        try
+        {
+            // Relax the controls at first
+            errors = new ArrayList<Throwable>();
+
+            // Clone the Registries
+            Registries clonedRegistries = registries.clone();
+
+            // And update references. We may have errors, that may be fixed
+            // by the new loaded schemas.
+            errors = clonedRegistries.checkRefInteg();
+
+            // Now, relax the cloned Registries if there is no error
+            clonedRegistries.setRelaxed();
+
+            return clonedRegistries;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            throw new LdapOtherException( cnse.getMessage(), cnse );
+        }
+    }
+
+
+    /**
+     * Transform a String[] array of schema to a Schema[]
+     */
+    private Schema[] toArray( String... schemas ) throws LdapException
+    {
+        Schema[] schemaArray = new Schema[schemas.length];
+        int n = 0;
+
+        for ( String schemaName : schemas )
+        {
+            Schema schema = schemaLoader.getSchema( schemaName );
+
+            if ( schema != null )
+            {
+                schemaArray[n++] = schema;
+            }
+            else
+            {
+                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err(
+                    I18n.ERR_11001, schemaName ) );
+            }
+        }
+
+        return schemaArray;
+    }
+
+
+    private void addSchemaObjects( Schema schema, Registries registries ) throws LdapException
+    {
+        // Create a content container for this schema
+        registries.addSchema( schema.getSchemaName() );
+
+        // And inject any existing SchemaObject into the registries
+        try
+        {
+            addComparators( schema, registries );
+            addNormalizers( schema, registries );
+            addSyntaxCheckers( schema, registries );
+            addSyntaxes( schema, registries );
+            addMatchingRules( schema, registries );
+            addAttributeTypes( schema, registries );
+            addObjectClasses( schema, registries );
+            //addMatchingRuleUses( schema, registries );
+            //addDitContentRules( schema, registries );
+            //addNameForms( schema, registries );
+            //addDitStructureRules( schema, registries );
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapOtherException( ioe.getMessage(), ioe );
+        }
+    }
+
+
+    /**
+     * Delete all the schemaObjects for a given schema from the registries
+     */
+    private void deleteSchemaObjects( Schema schema, Registries registries ) throws LdapException
+    {
+        Map<String, Set<SchemaObjectWrapper>> schemaObjects = registries.getObjectBySchemaName();
+        Set<SchemaObjectWrapper> content = schemaObjects.get( Strings.toLowerCaseAscii( schema.getSchemaName() ) );
+
+        List<SchemaObject> toBeDeleted = new ArrayList<SchemaObject>();
+
+        if ( content != null )
+        {
+            // Build an intermediate list to avoid concurrent modifications
+            for ( SchemaObjectWrapper schemaObjectWrapper : content )
+            {
+                toBeDeleted.add( schemaObjectWrapper.get() );
+            }
+
+            for ( SchemaObject schemaObject : toBeDeleted )
+            {
+                registries.delete( errors, schemaObject );
+            }
+        }
+    }
+
+
+    //-----------------------------------------------------------------------
+    // API methods
+    //-----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public boolean disable( Schema... schemas ) throws LdapException
+    {
+        boolean disabled = false;
+
+        // Reset the errors if not null
+        if ( errors != null )
+        {
+            errors.clear();
+        }
+
+        // Work on a cloned and relaxed registries
+        Registries clonedRegistries = cloneRegistries();
+        clonedRegistries.setRelaxed();
+
+        for ( Schema schema : schemas )
+        {
+            unload( clonedRegistries, schema );
+        }
+
+        // Build the cross references
+        errors = clonedRegistries.buildReferences();
+
+        // Destroy the clonedRegistry
+        clonedRegistries.clear();
+
+        if ( errors.isEmpty() )
+        {
+            // Ok no errors. Check the registries now
+            errors = clonedRegistries.checkRefInteg();
+
+            if ( errors.isEmpty() )
+            {
+                // We are golden : let's apply the schemas in the real registries
+                for ( Schema schema : schemas )
+                {
+                    unload( registries, schema );
+                    schema.disable();
+                }
+
+                // Build the cross references
+                errors = registries.buildReferences();
+                registries.setStrict();
+
+                disabled = true;
+            }
+        }
+
+        // clear the cloned registries
+        clonedRegistries.clear();
+
+        return disabled;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean disable( String... schemaNames ) throws LdapException
+    {
+        Schema[] schemas = toArray( schemaNames );
+
+        return disable( schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean disabledRelaxed( Schema... schemas )
+    {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean disabledRelaxed( String... schemas )
+    {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Schema> getDisabled()
+    {
+        List<Schema> disabled = new ArrayList<Schema>();
+
+        for ( Schema schema : registries.getLoadedSchemas().values() )
+        {
+            if ( schema.isDisabled() )
+            {
+                disabled.add( schema );
+            }
+        }
+
+        return disabled;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean enable( Schema... schemas ) throws LdapException
+    {
+        boolean enabled = false;
+
+        // Reset the errors if not null
+        if ( errors != null )
+        {
+            errors.clear();
+        }
+
+        // Work on a cloned and relaxed registries
+        Registries clonedRegistries = cloneRegistries();
+        clonedRegistries.setRelaxed();
+
+        Set<Schema> disabledSchemas = new HashSet<Schema>();
+
+        for ( Schema schema : schemas )
+        {
+            if ( schema.getDependencies() != null )
+            {
+                for ( String dependency : schema.getDependencies() )
+                {
+                    Schema dependencySchema = schemaLoader.getSchema( dependency );
+
+                    if ( dependencySchema.isDisabled() )
+                    {
+                        disabledSchemas.add( dependencySchema );
+                    }
+                }
+            }
+
+            schema.enable();
+            load( clonedRegistries, schema );
+        }
+
+        // Revert back the disabled schema to disabled
+        for ( Schema disabledSchema : disabledSchemas )
+        {
+            if ( disabledSchema.isEnabled() )
+            {
+                disabledSchema.disable();
+            }
+        }
+
+        // Build the cross references
+        errors = clonedRegistries.buildReferences();
+
+        // Destroy the clonedRegistry
+        clonedRegistries.clear();
+
+        if ( errors.isEmpty() )
+        {
+            // Ok no errors. Check the registries now
+            errors = clonedRegistries.checkRefInteg();
+
+            if ( errors.isEmpty() )
+            {
+                // We are golden : let's apply the schemas in the real registries
+                for ( Schema schema : schemas )
+                {
+                    schema.enable();
+                    load( registries, schema );
+                }
+
+                // Build the cross references
+                errors = registries.buildReferences();
+                registries.setStrict();
+
+                enabled = true;
+            }
+        }
+
+        // clear the cloned registries
+        clonedRegistries.clear();
+
+        return enabled;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean enable( String... schemaNames ) throws LdapException
+    {
+        Schema[] schemas = toArray( schemaNames );
+        return enable( schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean enableRelaxed( Schema... schemas )
+    {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean enableRelaxed( String... schemas )
+    {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Schema> getEnabled()
+    {
+        List<Schema> enabled = new ArrayList<Schema>();
+
+        for ( Schema schema : registries.getLoadedSchemas().values() )
+        {
+            if ( schema.isEnabled() )
+            {
+                enabled.add( schema );
+            }
+        }
+
+        return enabled;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<Throwable> getErrors()
+    {
+        return errors;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Registries getRegistries()
+    {
+        return registries;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDisabledAccepted()
+    {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean load( Schema... schemas ) throws LdapException
+    {
+        if ( schemas.length == 0 )
+        {
+            return true;
+        }
+
+        boolean loaded = false;
+
+        // Reset the errors if not null
+        if ( errors != null )
+        {
+            errors.clear();
+        }
+
+        // Work on a cloned and relaxed registries
+        Registries clonedRegistries = cloneRegistries();
+        clonedRegistries.setRelaxed();
+
+        // Load the schemas
+        for ( Schema schema : schemas )
+        {
+            boolean singleSchemaLoaded = load( clonedRegistries, schema );
+
+            // return false if the schema was not loaded in the first place
+            if ( !singleSchemaLoaded )
+            {
+                return false;
+            }
+        }
+
+        // Build the cross references
+        errors = clonedRegistries.buildReferences();
+
+        if ( errors.isEmpty() )
+        {
+            // Ok no errors. Check the registries now
+            errors = clonedRegistries.checkRefInteg();
+
+            if ( errors.isEmpty() )
+            {
+                // We are golden : let's apply the schema in the real registries
+                registries.setRelaxed();
+
+                // Load the schemas
+                for ( Schema schema : schemas )
+                {
+                    load( registries, schema );
+
+                    // Update the schema dependences if needed
+
+                    if ( schema.getDependencies() != null )
+                    {
+                        for ( String dep : schema.getDependencies() )
+                        {
+                            Set<String> deps = schemaDependences.get( dep );
+
+                            if ( deps == null )
+                            {
+                                deps = new HashSet<String>();
+                                deps.add( schema.getSchemaName() );
+                            }
+
+                            // Replace the dependences
+                            schemaDependences.put( dep, deps );
+                        }
+                    }
+
+                    // add the schema to the schemaLoader
+                    schemaLoader.addSchema( schema );
+                }
+
+                // Build the cross references
+                errors = registries.buildReferences();
+                registries.setStrict();
+
+                loaded = true;
+            }
+        }
+
+        // clear the cloned registries
+        clonedRegistries.clear();
+
+        return loaded;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean load( String... schemaNames ) throws Exception
+    {
+        if ( schemaNames.length == 0 )
+        {
+            return true;
+        }
+
+        Schema[] schemas = toArray( schemaNames );
+
+        return load( schemas );
+    }
+
+
+    /**
+     * Load the schema in the registries. We will load everything accordingly to the two flags :
+     * - isRelaxed
+     * - disabledAccepted
+     */
+    private boolean load( Registries registries, Schema schema ) throws LdapException
+    {
+        if ( schema == null )
+        {
+            LOG.info( "The schema is null" );
+            return false;
+        }
+
+        // First avoid loading twice the same schema
+        if ( registries.isSchemaLoaded( schema.getSchemaName() ) )
+        {
+            return true;
+        }
+
+        if ( schema.isDisabled() )
+        {
+            if ( registries.isDisabledAccepted() )
+            {
+                LOG.info( "Loading {} disabled schema: \n{}", schema.getSchemaName(), schema );
+
+                registries.schemaLoaded( schema );
+                addSchemaObjects( schema, registries );
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            LOG.info( "Loading {} enabled schema: \n{}", schema.getSchemaName(), schema );
+
+            // Check that the dependencies, if any, are correct
+            if ( schema.getDependencies() != null )
+            {
+                for ( String dependency : schema.getDependencies() )
+                {
+                    Schema dependencySchema = schemaLoader.getSchema( dependency );
+
+                    if ( dependencySchema == null )
+                    {
+                        // The dependency has not been loaded.
+                        String msg = I18n.err( I18n.ERR_11002, schema.getSchemaName() );
+                        LOG.info( msg );
+                        Throwable error = new LdapProtocolErrorException( msg );
+                        errors.add( error );
+
+                        return false;
+                    }
+
+                    // If the dependency is disabled, then enable it
+                    if ( dependencySchema.isDisabled() )
+                    {
+                        dependencySchema.enable();
+
+                        if ( !load( registries, dependencySchema ) )
+                        {
+                            dependencySchema.disable();
+
+                            return false;
+                        }
+                    }
+                }
+            }
+
+            registries.schemaLoaded( schema );
+            addSchemaObjects( schema, registries );
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Unload the schema from the registries. We will unload everything accordingly to the two flags :
+     * - isRelaxed
+     * - disabledAccepted
+     */
+    private boolean unload( Registries registries, Schema schema ) throws LdapException
+    {
+        if ( schema == null )
+        {
+            LOG.info( "The schema is null" );
+            return false;
+        }
+
+        // First avoid unloading twice the same schema
+        if ( !registries.isSchemaLoaded( schema.getSchemaName() ) )
+        {
+            return true;
+        }
+
+        if ( schema.isEnabled() )
+        {
+            LOG.info( "Unloading {} schema: \n{}", schema.getSchemaName(), schema );
+
+            deleteSchemaObjects( schema, registries );
+            registries.schemaUnloaded( schema );
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Add all the Schema's AttributeTypes
+     */
+    private void addAttributeTypes( Schema schema, Registries registries ) throws LdapException, IOException
+    {
+        for ( Entry entry : schemaLoader.loadAttributeTypes( schema ) )
+        {
+            AttributeType attributeType = factory.getAttributeType( this, entry, registries, schema.getSchemaName() );
+
+            addSchemaObject( registries, attributeType, schema );
+        }
+    }
+
+
+    /**
+     * Add all the Schema's comparators
+     */
+    private void addComparators( Schema schema, Registries registries ) throws LdapException, IOException
+    {
+        for ( Entry entry : schemaLoader.loadComparators( schema ) )
+        {
+            LdapComparator<?> comparator = factory.getLdapComparator( this, entry, registries, schema.getSchemaName() );
+
+            addSchemaObject( registries, comparator, schema );
+        }
+    }
+
+
+    /**
+     * Add all the Schema's DitContentRules
+     */
+    // Not yet implemented, but may be used
+    //    @SuppressWarnings("PMD.UnusedFormalParameter")
+    //    private void addDitContentRules( Schema schema, Registries registries ) throws LdapException, IOException
+    //    {
+    //        if ( !schemaLoader.loadDitContentRules( schema ).isEmpty() )
+    //        {
+    //            throw new NotImplementedException( I18n.err( I18n.ERR_11003 ) );
+    //        }
+    //    }
+
+    /**
+     * Add all the Schema's DitStructureRules
+     */
+    // Not yet implemented, but may be used
+    //    @SuppressWarnings("PMD.UnusedFormalParameter")
+    //    private void addDitStructureRules( Schema schema, Registries registries ) throws LdapException, IOException
+    //    {
+    //        if ( !schemaLoader.loadDitStructureRules( schema ).isEmpty() )
+    //        {
+    //            throw new NotImplementedException( I18n.err( I18n.ERR_11004 ) );
+    //        }
+    //    }
+
+    /**
+     * Add all the Schema's MatchingRules
+     */
+    private void addMatchingRules( Schema schema, Registries registries ) throws LdapException, IOException
+    {
+        for ( Entry entry : schemaLoader.loadMatchingRules( schema ) )
+        {
+            MatchingRule matchingRule = factory.getMatchingRule( this, entry, registries, schema.getSchemaName() );
+
+            addSchemaObject( registries, matchingRule, schema );
+        }
+    }
+
+
+    /**
+     * Add all the Schema's MatchingRuleUses
+     */
+    // Not yet implemented, but may be used
+    //    @SuppressWarnings("PMD.UnusedFormalParameter")
+    //    private void addMatchingRuleUses( Schema schema, Registries registries ) throws LdapException, IOException
+    //    {
+    //        if ( !schemaLoader.loadMatchingRuleUses( schema ).isEmpty() )
+    //        {
+    //            throw new NotImplementedException( I18n.err( I18n.ERR_11005 ) );
+    //        }
+    //        // for ( Entry entry : schemaLoader.loadMatchingRuleUses( schema ) )
+    //        // {
+    //        //     throw new NotImplementedException( I18n.err( I18n.ERR_11005 ) );
+    //        // }
+    //    }
+
+    /**
+     * Add all the Schema's NameForms
+     */
+    // Not yet implemented, but may be used
+    //    @SuppressWarnings("PMD.UnusedFormalParameter")
+    //    private void addNameForms( Schema schema, Registries registries ) throws LdapException, IOException
+    //    {
+    //        if ( !schemaLoader.loadNameForms( schema ).isEmpty() )
+    //        {
+    //            throw new NotImplementedException( I18n.err( I18n.ERR_11006 ) );
+    //        }
+    //    }
+
+    /**
+     * Add all the Schema's Normalizers
+     */
+    private void addNormalizers( Schema schema, Registries registries ) throws LdapException, IOException
+    {
+        for ( Entry entry : schemaLoader.loadNormalizers( schema ) )
+        {
+            Normalizer normalizer = factory.getNormalizer( this, entry, registries, schema.getSchemaName() );
+
+            addSchemaObject( registries, normalizer, schema );
+        }
+    }
+
+
+    /**
+     * Add all the Schema's ObjectClasses
+     */
+    private void addObjectClasses( Schema schema, Registries registries ) throws LdapException, IOException
+    {
+        for ( Entry entry : schemaLoader.loadObjectClasses( schema ) )
+        {
+            ObjectClass objectClass = factory.getObjectClass( this, entry, registries, schema.getSchemaName() );
+
+            addSchemaObject( registries, objectClass, schema );
+        }
+    }
+
+
+    /**
+     * Add all the Schema's Syntaxes
+     */
+    private void addSyntaxes( Schema schema, Registries registries ) throws LdapException, IOException
+    {
+        for ( Entry entry : schemaLoader.loadSyntaxes( schema ) )
+        {
+            LdapSyntax syntax = factory.getSyntax( this, entry, registries, schema.getSchemaName() );
+
+            addSchemaObject( registries, syntax, schema );
+        }
+    }
+
+
+    /**Add
+     * Register all the Schema's SyntaxCheckers
+     */
+    private void addSyntaxCheckers( Schema schema, Registries registries ) throws LdapException, IOException
+    {
+        for ( Entry entry : schemaLoader.loadSyntaxCheckers( schema ) )
+        {
+            SyntaxChecker syntaxChecker = factory.getSyntaxChecker( this, entry, registries, schema.getSchemaName() );
+
+            addSchemaObject( registries, syntaxChecker, schema );
+        }
+    }
+
+
+    /**
+     * Add the schemaObject into the registries.
+     *
+     * @param registries The Registries
+     * @param schemaObject The SchemaObject containing the SchemaObject description
+     * @param schema The associated schema
+     * @return the created schemaObject instance
+     * @throws LdapException If the registering failed
+     */
+    private SchemaObject addSchemaObject( Registries registries, SchemaObject schemaObject, Schema schema )
+        throws LdapException
+    {
+        if ( registries.isRelaxed() )
+        {
+            if ( registries.isDisabledAccepted() || ( schema.isEnabled() && schemaObject.isEnabled() ) )
+            {
+                registries.add( errors, schemaObject, false );
+            }
+            else
+            {
+                errors.add( new Throwable() );
+            }
+        }
+        else
+        {
+            if ( schema.isEnabled() && schemaObject.isEnabled() )
+            {
+                registries.add( errors, schemaObject, false );
+            }
+            else
+            {
+                errors.add( new Throwable() );
+            }
+        }
+
+        return schemaObject;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadAllEnabled() throws Exception
+    {
+        Schema[] schemas = schemaLoader.getAllEnabled().toArray( new Schema[0] );
+
+        return loadWithDeps( schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadAllEnabledRelaxed() throws Exception
+    {
+        Schema[] schemas = schemaLoader.getAllEnabled().toArray( new Schema[0] );
+
+        return loadWithDepsRelaxed( schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadDisabled( Schema... schemas ) throws LdapException
+    {
+        // Work on a cloned and relaxed registries
+        Registries clonedRegistries = cloneRegistries();
+
+        // Accept the disabled schemas
+        clonedRegistries.setDisabledAccepted( true );
+
+        // Load the schemas
+        for ( Schema schema : schemas )
+        {
+            // Enable the Schema object before loading it
+            schema.enable();
+            load( clonedRegistries, schema );
+        }
+
+        clonedRegistries.clear();
+
+        // Apply the change to the correct registries if no errors
+        if ( errors.size() == 0 )
+        {
+            // No error, we can enable the schema in the real registries
+            for ( Schema schema : schemas )
+            {
+                load( registries, schema );
+            }
+
+            return true;
+        }
+        else
+        {
+            for ( Schema schema : schemas )
+            {
+                schema.disable();
+            }
+
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadDisabled( String... schemaNames ) throws LdapException
+    {
+        Schema[] schemas = toArray( schemaNames );
+
+        return loadDisabled( schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadRelaxed( Schema... schemas ) throws Exception
+    {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadRelaxed( String... schemaNames ) throws Exception
+    {
+        Schema[] schemas = toArray( schemaNames );
+        return loadRelaxed( schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadWithDeps( Schema... schemas ) throws Exception
+    {
+        boolean loaded = false;
+
+        // Reset the errors if not null
+        if ( errors != null )
+        {
+            errors.clear();
+        }
+
+        // Work on a cloned and relaxed registries
+        Registries clonedRegistries = cloneRegistries();
+        clonedRegistries.setRelaxed();
+
+        // Load the schemas
+        for ( Schema schema : schemas )
+        {
+            loadDepsFirst( clonedRegistries, schema );
+        }
+
+        // Build the cross references
+        errors = clonedRegistries.buildReferences();
+
+        if ( errors.isEmpty() )
+        {
+            // Ok no errors. Check the registries now
+            errors = clonedRegistries.checkRefInteg();
+
+            if ( errors.isEmpty() )
+            {
+                // We are golden : let's apply the schema in the real registries
+                registries = clonedRegistries;
+                registries.setStrict();
+                loaded = true;
+            }
+        }
+        else if ( isStrict() )
+        {
+            // clear the cloned registries
+            clonedRegistries.clear();
+        }
+        else
+        {
+            // Relaxed mode
+            registries = clonedRegistries;
+            registries.setRelaxed();
+            loaded = true;
+        }
+
+        return loaded;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadWithDeps( String... schemas ) throws Exception
+    {
+        return loadWithDeps( toArray( schemas ) );
+    }
+
+
+    /**
+     * Recursive method which loads schema's with their dependent schemas first
+     * and tracks what schemas it has seen so the recursion does not go out of
+     * control with dependency cycle detection.
+     *
+     * @param registries The Registries in which the schemas will be loaded
+     * @param schema the current schema we are attempting to load
+     * @throws Exception if there is a cycle detected and/or another
+     * failure results while loading, producing and or registering schema objects
+     */
+    private void loadDepsFirst( Registries registries, Schema schema ) throws Exception
+    {
+        if ( schema == null )
+        {
+            LOG.info( "The schema is null" );
+            return;
+        }
+
+        if ( schema.isDisabled() && !registries.isDisabledAccepted() )
+        {
+            LOG.info( "The schema is disabled and the registries does not accepted disabled schema" );
+            return;
+        }
+
+        String schemaName = schema.getSchemaName();
+
+        if ( registries.isSchemaLoaded( schemaName ) )
+        {
+            LOG.info( "{} schema has already been loaded", schema.getSchemaName() );
+            return;
+        }
+
+        String[] deps = schema.getDependencies();
+
+        // if no deps then load this guy and return
+        if ( ( deps == null ) || ( deps.length == 0 ) )
+        {
+            load( registries, schema );
+
+            return;
+        }
+
+        /*
+         * We got deps and need to load them before this schema.  We go through
+         * all deps loading them with their deps first if they have not been
+         * loaded.
+         */
+        for ( String depName : deps )
+        {
+            if ( registries.isSchemaLoaded( schemaName ) )
+            {
+                // The schema is already loaded. Loop on the next schema
+                continue;
+            }
+            else
+            {
+                // Call recursively this method
+                Schema schemaDep = schemaLoader.getSchema( depName );
+                loadDepsFirst( registries, schemaDep );
+            }
+        }
+
+        // Now load the current schema
+        load( registries, schema );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadWithDepsRelaxed( Schema... schemas ) throws Exception
+    {
+        registries.setRelaxed();
+
+        // Load the schemas
+        for ( Schema schema : schemas )
+        {
+            loadDepsFirstRelaxed( schema );
+        }
+
+        // Build the cross references
+        errors = registries.buildReferences();
+
+        // Check the registries now
+        errors = registries.checkRefInteg();
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean loadWithDepsRelaxed( String... schemas ) throws Exception
+    {
+        return loadWithDepsRelaxed( toArray( schemas ) );
+    }
+
+
+    /**
+     * Recursive method which loads schema's with their dependent schemas first
+     * and tracks what schemas it has seen so the recursion does not go out of
+     * control with dependency cycle detection.
+     *
+     * @param schema the current schema we are attempting to load
+     * @throws Exception if there is a cycle detected and/or another
+     * failure results while loading, producing and or registering schema objects
+     */
+    private void loadDepsFirstRelaxed( Schema schema ) throws Exception
+    {
+        if ( schema == null )
+        {
+            LOG.info( "The schema is null" );
+            return;
+        }
+
+        if ( schema.isDisabled() && !registries.isDisabledAccepted() )
+        {
+            LOG.info( "The schema is disabled and the registries does not accepted disabled schema" );
+            return;
+        }
+
+        String schemaName = schema.getSchemaName();
+
+        if ( registries.isSchemaLoaded( schemaName ) )
+        {
+            LOG.info( "{} schema has already been loaded", schema.getSchemaName() );
+            return;
+        }
+
+        String[] deps = schema.getDependencies();
+
+        // if no deps then load this guy and return
+        if ( ( deps == null ) || ( deps.length == 0 ) )
+        {
+            load( registries, schema );
+
+            return;
+        }
+
+        /*
+         * We got deps and need to load them before this schema.  We go through
+         * all deps loading them with their deps first if they have not been
+         * loaded.
+         */
+        for ( String depName : deps )
+        {
+            if ( registries.isSchemaLoaded( schemaName ) )
+            {
+                // The schema is already loaded. Loop on the next schema
+                continue;
+            }
+            else
+            {
+                // Call recursively this method
+                Schema schemaDep = schemaLoader.getSchema( depName );
+                loadDepsFirstRelaxed( schemaDep );
+            }
+        }
+
+        // Now load the current schema
+        load( registries, schema );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRegistries( Registries registries )
+    {
+        // TODO Auto-generated method stub
+
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean unload( Schema... schemas ) throws LdapException
+    {
+        boolean unloaded = false;
+
+        // Reset the errors if not null
+        if ( errors != null )
+        {
+            errors.clear();
+        }
+
+        // Work on a cloned and relaxed registries
+        Registries clonedRegistries = cloneRegistries();
+        clonedRegistries.setRelaxed();
+
+        // Load the schemas
+        for ( Schema schema : schemas )
+        {
+            unload( clonedRegistries, schema );
+        }
+
+        // Build the cross references
+        errors = clonedRegistries.buildReferences();
+
+        if ( errors.isEmpty() )
+        {
+            // Ok no errors. Check the registries now
+            errors = clonedRegistries.checkRefInteg();
+
+            if ( errors.isEmpty() )
+            {
+                // We are golden : let's apply the schema in the real registries
+                registries.setRelaxed();
+
+                // Load the schemas
+                for ( Schema schema : schemas )
+                {
+                    unload( registries, schema );
+
+                    // Update the schema dependences
+                    for ( String dep : schema.getDependencies() )
+                    {
+                        Set<String> deps = schemaDependences.get( dep );
+
+                        if ( deps != null )
+                        {
+                            deps.remove( schema.getSchemaName() );
+                        }
+                    }
+
+                    schemaLoader.removeSchema( schema );
+                }
+
+                // Build the cross references
+                errors = registries.buildReferences();
+                registries.setStrict();
+
+                unloaded = true;
+            }
+        }
+
+        // clear the cloned registries
+        clonedRegistries.clear();
+
+        return unloaded;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean unload( String... schemaNames ) throws LdapException
+    {
+        Schema[] schemas = toArray( schemaNames );
+
+        return unload( schemas );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean verify( Schema... schemas ) throws Exception
+    {
+        // Work on a cloned registries
+        Registries clonedRegistries = cloneRegistries();
+
+        // Loop on all the schemas
+        for ( Schema schema : schemas )
+        {
+            try
+            {
+                // Inject the schema
+                boolean loaded = load( clonedRegistries, schema );
+
+                if ( !loaded )
+                {
+                    // We got an error : exit
+                    clonedRegistries.clear();
+                    return false;
+                }
+
+                // Now, check the registries
+                List<Throwable> errorList = clonedRegistries.checkRefInteg();
+
+                if ( errorList.size() != 0 )
+                {
+                    // We got an error : exit
+                    clonedRegistries.clear();
+                    return false;
+                }
+            }
+            catch ( Exception e )
+            {
+                // We got an error : exit
+                clonedRegistries.clear();
+                return false;
+            }
+        }
+
+        // We can now delete the cloned registries before exiting
+        clonedRegistries.clear();
+
+        return true;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean verify( String... schemas ) throws Exception
+    {
+        return verify( toArray( schemas ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setSchemaLoader( SchemaLoader schemaLoader )
+    {
+        this.schemaLoader = schemaLoader;
+    }
+
+
+    /**
+     * @return the namingContext
+     */
+    public Dn getNamingContext()
+    {
+        return namingContext;
+    }
+
+
+    /**
+     * Initializes the SchemaService
+     *
+     * @throws Exception If the initialization fails
+     */
+    public void initialize() throws Exception
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaLoader getLoader()
+    {
+        return schemaLoader;
+    }
+
+
+    //-----------------------------------------------------------------------------------
+    // Immutable accessors
+    //-----------------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeTypeRegistry getAttributeTypeRegistry()
+    {
+        return new ImmutableAttributeTypeRegistry( registries.getAttributeTypeRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ComparatorRegistry getComparatorRegistry()
+    {
+        return new ImmutableComparatorRegistry( registries.getComparatorRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitContentRuleRegistry getDITContentRuleRegistry()
+    {
+        return new ImmutableDitContentRuleRegistry( registries.getDitContentRuleRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public DitStructureRuleRegistry getDITStructureRuleRegistry()
+    {
+        return new ImmutableDitStructureRuleRegistry( registries.getDitStructureRuleRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRuleRegistry getMatchingRuleRegistry()
+    {
+        return new ImmutableMatchingRuleRegistry( registries.getMatchingRuleRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRuleUseRegistry getMatchingRuleUseRegistry()
+    {
+        return new ImmutableMatchingRuleUseRegistry( registries.getMatchingRuleUseRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public NameFormRegistry getNameFormRegistry()
+    {
+        return new ImmutableNameFormRegistry( registries.getNameFormRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public NormalizerRegistry getNormalizerRegistry()
+    {
+        return new ImmutableNormalizerRegistry( registries.getNormalizerRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClassRegistry getObjectClassRegistry()
+    {
+        return new ImmutableObjectClassRegistry( registries.getObjectClassRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapSyntaxRegistry getLdapSyntaxRegistry()
+    {
+        return new ImmutableLdapSyntaxRegistry( registries.getLdapSyntaxRegistry() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxCheckerRegistry getSyntaxCheckerRegistry()
+    {
+        return new ImmutableSyntaxCheckerRegistry( registries.getSyntaxCheckerRegistry() );
+    }
+
+
+    /**
+     * Get rid of AT's options (everything after the ';'
+     * @param oid
+     * @return
+     */
+    private String stripOptions( String oid )
+    {
+        int semiColonPos = oid.indexOf( ';' );
+
+        if ( semiColonPos != -1 )
+        {
+            return oid.substring( 0, semiColonPos );
+        }
+        else
+        {
+            return oid;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType lookupAttributeTypeRegistry( String oid ) throws LdapException
+    {
+        String oidTrimmed = Strings.toLowerCaseAscii( oid ).trim();
+        String oidNoOption = stripOptions( oidTrimmed );
+        return registries.getAttributeTypeRegistry().lookup( oidNoOption );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public AttributeType getAttributeType( String oid )
+    {
+        try
+        {
+            return registries.getAttributeTypeRegistry().lookup( Strings.toLowerCaseAscii( oid ).trim() );
+        }
+        catch ( LdapException lnsae )
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapComparator<?> lookupComparatorRegistry( String oid ) throws LdapException
+    {
+        return registries.getComparatorRegistry().lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public MatchingRule lookupMatchingRuleRegistry( String oid ) throws LdapException
+    {
+        return registries.getMatchingRuleRegistry().lookup( Strings.toLowerCaseAscii( oid ).trim() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Normalizer lookupNormalizerRegistry( String oid ) throws LdapException
+    {
+        return registries.getNormalizerRegistry().lookup( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ObjectClass lookupObjectClassRegistry( String oid ) throws LdapException
+    {
+        return registries.getObjectClassRegistry().lookup( Strings.toLowerCaseAscii( oid ).trim() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public LdapSyntax lookupLdapSyntaxRegistry( String oid ) throws LdapException
+    {
+        return registries.getLdapSyntaxRegistry().lookup( Strings.toLowerCaseAscii( oid ).trim() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SyntaxChecker lookupSyntaxCheckerRegistry( String oid ) throws LdapException
+    {
+        return registries.getSyntaxCheckerRegistry().lookup( oid );
+    }
+
+
+    /**
+     * Check that the given OID exists in the globalOidRegistry.
+     */
+    private boolean checkOidExist( SchemaObject schemaObject )
+    {
+        if ( !( schemaObject instanceof LoadableSchemaObject ) )
+        {
+            return registries.getGlobalOidRegistry().contains( schemaObject.getOid() );
+        }
+
+        if ( schemaObject instanceof LdapComparator<?> )
+        {
+            return registries.getComparatorRegistry().contains( schemaObject.getOid() );
+        }
+
+        if ( schemaObject instanceof SyntaxChecker )
+        {
+            return registries.getSyntaxCheckerRegistry().contains( schemaObject.getOid() );
+        }
+
+        if ( schemaObject instanceof Normalizer )
+        {
+            return registries.getNormalizerRegistry().contains( schemaObject.getOid() );
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Get the inner SchemaObject if it's not a C/N/SC
+     */
+    private SchemaObject getSchemaObject( SchemaObject schemaObject ) throws LdapException
+    {
+        if ( schemaObject instanceof LoadableSchemaObject )
+        {
+            return schemaObject;
+        }
+        else
+        {
+            return registries.getGlobalOidRegistry().getSchemaObject( schemaObject.getOid() );
+        }
+    }
+
+
+    /**
+     * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found.
+     */
+    private String getSchemaName( SchemaObject schemaObject )
+    {
+        String schemaName = Strings.toLowerCaseAscii( schemaObject.getSchemaName() );
+
+        if ( Strings.isEmpty( schemaName ) )
+        {
+            return MetaSchemaConstants.SCHEMA_OTHER;
+        }
+
+        if ( schemaLoader.getSchema( schemaName ) == null )
+        {
+            return null;
+        }
+        else
+        {
+            return schemaName;
+        }
+    }
+
+
+    private SchemaObject copy( SchemaObject schemaObject )
+    {
+        SchemaObject copy = null;
+
+        if ( !( schemaObject instanceof LoadableSchemaObject ) )
+        {
+            copy = schemaObject.copy();
+        }
+        else
+        {
+            // Check the schemaObject here.
+            if ( ( ( LoadableSchemaObject ) schemaObject ).isValid() )
+            {
+                copy = schemaObject;
+            }
+            else
+            {
+                // We have an invalid SchemaObject, no need to go any further
+                Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err(
+                    I18n.ERR_11007, schemaObject.getOid() ) );
+                errors.add( error );
+            }
+        }
+
+        return copy;
+    }
+
+
+    //-----------------------------------------------------------------------------------
+    // SchemaObject operations
+    //-----------------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public boolean add( SchemaObject schemaObject ) throws LdapException
+    {
+        // First, clear the errors
+        errors.clear();
+
+        // Clone the schemaObject
+        SchemaObject copy = copy( schemaObject );
+
+        if ( copy == null )
+        {
+            return false;
+        }
+
+        if ( registries.isRelaxed() )
+        {
+            // Apply the addition right away
+            registries.add( errors, copy, true );
+
+            return errors.isEmpty();
+        }
+        else
+        {
+            // Clone, apply, check, then apply again if ok
+            // The new schemaObject's OID must not already exist
+            if ( checkOidExist( copy ) )
+            {
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_11008, schemaObject.getOid() ) );
+                ldapSchemaException.setSourceObject( schemaObject );
+                errors.add( ldapSchemaException );
+
+                return false;
+            }
+
+            // Build the new AttributeType from the given entry
+            String schemaName = getSchemaName( copy );
+
+            if ( schemaName == null )
+            {
+                // The schema associated with the SchemaaObject does not exist. This is not valid.
+
+                LdapSchemaException ldapSchemaException = new LdapSchemaException(
+                    LdapSchemaExceptionCodes.NONEXISTENT_SCHEMA, I18n.err( I18n.ERR_11009, schemaObject.getOid(),
+                        copy.getSchemaName() ) );
+                ldapSchemaException.setSourceObject( schemaObject );
+                ldapSchemaException.setRelatedId( copy.getSchemaName() );
+                errors.add( ldapSchemaException );
+
+                return false;
+            }
+
+            // At this point, the constructed AttributeType has not been checked against the
+            // existing Registries. It may be broken (missing SUP, or such), it will be checked
+            // there, if the schema and the AttributeType are both enabled.
+            Schema schema = getLoadedSchema( schemaName );
+
+            if ( schema == null )
+            {
+                // The SchemaObject must be associated with an existing schema
+                String msg = I18n.err( I18n.ERR_11010, copy.getOid() );
+                LOG.info( msg );
+                Throwable error = new LdapProtocolErrorException( msg );
+                errors.add( error );
+                return false;
+            }
+
+            if ( schema.isEnabled() && copy.isEnabled() )
+            {
+                // As we may break the registries, work on a cloned registries
+                Registries clonedRegistries = null;
+
+                try
+                {
+                    clonedRegistries = registries.clone();
+                }
+                catch ( CloneNotSupportedException cnse )
+                {
+                    throw new LdapOtherException( cnse.getMessage(), cnse );
+                }
+
+                // Inject the new SchemaObject in the cloned registries
+                clonedRegistries.add( errors, copy, true );
+
+                // Remove the cloned registries
+                clonedRegistries.clear();
+
+                // If we didn't get any error, apply the addition to the real retistries
+                if ( errors.isEmpty() )
+                {
+                    // Copy again as the clonedRegistries clear has removed the previous copy
+                    copy = copy( schemaObject );
+
+                    // Apply the addition to the real registries
+                    registries.add( errors, copy, true );
+
+                    LOG.debug( "Added {} into the enabled schema {}", copy.getName(), schemaName );
+
+                    return true;
+                }
+                else
+                {
+                    // We have some error : reject the addition and get out
+                    String msg = "Cannot add the SchemaObject " + copy.getOid() + " into the registries, "
+                        + "the resulting registries would be inconsistent :" + Strings.listToString( errors );
+                    LOG.info( msg );
+
+                    return false;
+                }
+            }
+            else
+            {
+                // At least, we register the OID in the globalOidRegistry, and associates it with the
+                // schema
+                registries.associateWithSchema( errors, copy );
+
+                LOG.debug( "Added {} into the disabled schema {}", copy.getName(), schemaName );
+                return errors.isEmpty();
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean delete( SchemaObject schemaObject ) throws LdapException
+    {
+        // First, clear the errors
+        errors.clear();
+
+        if ( registries.isRelaxed() )
+        {
+            // Apply the addition right away
+            registries.delete( errors, schemaObject );
+
+            return errors.isEmpty();
+        }
+        else
+        {
+            // Clone, apply, check, then apply again if ok
+            // The new schemaObject's OID must exist
+            if ( !checkOidExist( schemaObject ) )
+            {
+                Throwable error = new LdapProtocolErrorException( I18n.err( I18n.ERR_11011, schemaObject.getOid() ) );
+                errors.add( error );
+                return false;
+            }
+
+            // Get the SchemaObject to delete if it's not a LoadableSchemaObject
+            SchemaObject toDelete = getSchemaObject( schemaObject );
+
+            // First check that this SchemaObject does not have any referencing SchemaObjects
+            Set<SchemaObjectWrapper> referencing = registries.getReferencing( toDelete );
+
+            if ( ( referencing != null ) && !referencing.isEmpty() )
+            {
+                String msg = I18n.err( I18n.ERR_11012, schemaObject.getOid(), Strings.setToString( referencing ) );
+
+                Throwable error = new LdapProtocolErrorException( msg );
+                errors.add( error );
+                return false;
+            }
+
+            String schemaName = getSchemaName( toDelete );
+
+            // At this point, the deleted AttributeType may be referenced, it will be checked
+            // there, if the schema and the AttributeType are both enabled.
+            Schema schema = getLoadedSchema( schemaName );
+
+            if ( schema == null )
+            {
+                // The SchemaObject must be associated with an existing schema
+                String msg = I18n.err( I18n.ERR_11013, schemaObject.getOid() );
+                LOG.info( msg );
+                Throwable error = new LdapProtocolErrorException( msg );
+                errors.add( error );
+                return false;
+            }
+
+            if ( schema.isEnabled() && schemaObject.isEnabled() )
+            {
+                // As we may break the registries, work on a cloned registries
+                Registries clonedRegistries = null;
+
+                try
+                {
+                    clonedRegistries = registries.clone();
+                }
+                catch ( CloneNotSupportedException cnse )
+                {
+                    throw new LdapOtherException( cnse.getMessage(), cnse );
+                }
+
+                // Delete the SchemaObject from the cloned registries
+                clonedRegistries.delete( errors, toDelete );
+
+                // Remove the cloned registries
+                clonedRegistries.clear();
+
+                // If we didn't get any error, apply the deletion to the real retistries
+                if ( errors.isEmpty() )
+                {
+                    // Apply the deletion to the real registries
+                    registries.delete( errors, toDelete );
+
+                    LOG.debug( "Removed {} from the enabled schema {}", toDelete.getName(), schemaName );
+
+                    return true;
+                }
+                else
+                {
+                    // We have some error : reject the deletion and get out
+                    String msg = "Cannot delete the SchemaObject " + schemaObject.getOid() + " from the registries, "
+                        + "the resulting registries would be inconsistent :" + Strings.listToString( errors );
+                    LOG.info( msg );
+
+                    return false;
+                }
+            }
+            else
+            {
+                // At least, we register the OID in the globalOidRegistry, and associates it with the
+                // schema
+                registries.associateWithSchema( errors, schemaObject );
+
+                LOG.debug( "Removed {} from the disabled schema {}", schemaObject.getName(), schemaName );
+                return errors.isEmpty();
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, OidNormalizer> getNormalizerMapping()
+    {
+        return registries.getAttributeTypeRegistry().getNormalizerMapping();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("rawtypes")
+    public OidRegistry getGlobalOidRegistry()
+    {
+        return registries.getGlobalOidRegistry();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Schema getLoadedSchema( String schemaName )
+    {
+        return schemaLoader.getSchema( schemaName );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isSchemaLoaded( String schemaName )
+    {
+        try
+        {
+            Schema schema = schemaLoader.getSchema( schemaName );
+            return schema != null;
+        }
+        catch ( Exception e )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterAttributeType( String attributeTypeOid ) throws LdapException
+    {
+        return registries.getAttributeTypeRegistry().unregister( attributeTypeOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterComparator( String comparatorOid ) throws LdapException
+    {
+        return registries.getComparatorRegistry().unregister( comparatorOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterDitControlRule( String ditControlRuleOid ) throws LdapException
+    {
+        return registries.getDitContentRuleRegistry().unregister( ditControlRuleOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterDitStructureRule( String ditStructureRuleOid ) throws LdapException
+    {
+        return registries.getDitStructureRuleRegistry().unregister( ditStructureRuleOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterLdapSyntax( String ldapSyntaxOid ) throws LdapException
+    {
+        return registries.getLdapSyntaxRegistry().unregister( ldapSyntaxOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterMatchingRule( String matchingRuleOid ) throws LdapException
+    {
+        return registries.getMatchingRuleRegistry().unregister( matchingRuleOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterMatchingRuleUse( String matchingRuleUseOid ) throws LdapException
+    {
+        return registries.getMatchingRuleUseRegistry().unregister( matchingRuleUseOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterNameForm( String nameFormOid ) throws LdapException
+    {
+        return registries.getNameFormRegistry().unregister( nameFormOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterNormalizer( String normalizerOid ) throws LdapException
+    {
+        return registries.getNormalizerRegistry().unregister( normalizerOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterObjectClass( String objectClassOid ) throws LdapException
+    {
+        return registries.getObjectClassRegistry().unregister( objectClassOid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public SchemaObject unregisterSyntaxChecker( String syntaxCheckerOid ) throws LdapException
+    {
+        return registries.getSyntaxCheckerRegistry().unregister( syntaxCheckerOid );
+    }
+
+
+    /**
+     * Tells if the SchemaManager is permissive or if it must be checked
+     * against inconsistencies.
+     *
+     * @return True if SchemaObjects can be added even if they break the consistency
+     */
+    public boolean isRelaxed()
+    {
+        return isRelaxed;
+    }
+
+    
+    /**
+     * Tells if the SchemaManager is strict.
+     *
+     * @return True if SchemaObjects cannot be added if they break the consistency
+     */
+    public boolean isStrict()
+    {
+        return !isRelaxed;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<String> listDependentSchemaNames( String schemaName )
+    {
+        return schemaDependences.get( schemaName );
+    }
+
+
+    /**
+     * Change the SchemaManager to a relaxed mode, where invalid SchemaObjects
+     * can be registered.
+     */
+    public void setRelaxed()
+    {
+        isRelaxed = RELAXED;
+    }
+
+
+    /**
+     * Change the SchemaManager to a strict mode, where invalid SchemaObjects
+     * cannot be registered.
+     */
+    public void setStrict()
+    {
+        isRelaxed = STRICT;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDisabled( String schemaName )
+    {
+        Schema schema = registries.getLoadedSchema( schemaName );
+
+        return ( schema != null ) && schema.isDisabled();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDisabled( Schema schema )
+    {
+        return ( schema != null ) && schema.isDisabled();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEnabled( String schemaName )
+    {
+        Schema schema = registries.getLoadedSchema( schemaName );
+
+        return ( schema != null ) && schema.isEnabled();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEnabled( Schema schema )
+    {
+        return ( schema != null ) && schema.isEnabled();
+    }
+}
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema.ldif
new file mode 100644
index 0000000..b90a9bd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=schema
+ou: schema
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig.ldif
new file mode 100644
index 0000000..713bdb8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig.ldif
@@ -0,0 +1,9 @@
+version: 1
+dn: cn=adsconfig,ou=schema
+cn: adsconfig
+objectclass: metaSchema
+objectclass: top
+m-dependencies: apache
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes.ldif
new file mode 100644
index 0000000..318958e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=adsconfig,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.100.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.100.ldif
new file mode 100644
index 0000000..d2603db
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.100.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.100,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-directoryServiceId
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.100
+m-description: The DirectoryService ID
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.101.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.101.ldif
new file mode 100644
index 0000000..b1e6f8c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.101.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.101,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-dsAccessControlEnabled
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.101
+m-description: Tells if access control is activated or not
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.102.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.102.ldif
new file mode 100644
index 0000000..b12fc3c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.102.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.102,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-dsAllowAnonymousAccess
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.102
+m-description: Tells if anonymous access are allowed or not
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.103.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.103.ldif
new file mode 100644
index 0000000..04257ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.103.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.103,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-dsDenormalizeOpAttrsEnabled
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.103
+m-description: Tells if the operational attributes are denormalized or not
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.104.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.104.ldif
new file mode 100644
index 0000000..70e2b64
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.104.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.104,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-dsPasswordHidden
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.104
+m-description: Tells if the password is stored encrypted even for PLAIN authentication
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.110.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.110.ldif
new file mode 100644
index 0000000..d47e5a3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.110.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.110,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-maxPDUSize
+m-description: Gives the maximum size of a PDU
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.110
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.111.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.111.ldif
new file mode 100644
index 0000000..3ec0bda
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.111.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.111,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-dsSyncPeriodMillis
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.111
+m-description: Define the duration between two flushes on disk
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.112.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.112.ldif
new file mode 100644
index 0000000..6c307ad
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.112.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.112,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-dsReplicaId
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.112
+m-description: The server identifier, used for replication
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.113.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.113.ldif
new file mode 100644
index 0000000..db52060
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.113.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.113,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-dsTestEntries
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.113
+m-description: The set of entries to inject at startup (may be obsolete)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.120.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.120.ldif
new file mode 100644
index 0000000..041da737
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.120.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.120,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-changeLogId
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.120
+m-description: The ChangeLog identifier
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.121.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.121.ldif
new file mode 100644
index 0000000..af93d5c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.121.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.121,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-changeLogExposed
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.121
+m-description: Tells if the changeLog system is visible by the clients
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.130.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.130.ldif
new file mode 100644
index 0000000..724298b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.130.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.130,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-interceptorId
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.130
+m-description: The Interceptor identifier
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.131.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.131.ldif
new file mode 100644
index 0000000..d8483c5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.131.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.131,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-interceptorOrder
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.131
+m-description: The Interceptor order number
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.0.ldif
new file mode 100755
index 0000000..1621578
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.0.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.0,ou=attributeTypes,cn=adsconfig,ou=schema
+creatorsname: uid=admin,ou=system
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-description: The hash algorithm
+m-equality: caseIgnoreMatch
+m-length: 0
+m-name: ads-hashAlgorithm
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.132.0
+m-ordering: caseIgnoreOrderingMatch
+m-singlevalue: TRUE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.1.ldif
new file mode 100755
index 0000000..33cdc92
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.132.1,ou=attributeTypes,cn=adsconfig,ou=schema
+creatorsname: uid=admin,ou=system
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-description: An OID of an attributeType that should be hashed
+m-equality: objectIdentifierMatch
+m-name: ads-hashAttribute
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.132.1
+m-singlevalue: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.141.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.141.ldif
new file mode 100644
index 0000000..d1dc6a0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.141.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.141,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-journalRotation
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.141
+m-description: The size before a journal rotation occurs.
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.142.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.142.ldif
new file mode 100644
index 0000000..f373c2e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.142.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.142,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-journalWorkingDir
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.142
+m-description: The place on disk where the journal is stored.
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.143.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.143.ldif
new file mode 100644
index 0000000..419153b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.143.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.143,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-journalFileName
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.143
+m-description: The journal file name.
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.144.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.144.ldif
new file mode 100644
index 0000000..67f1b73
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.144.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.144,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-journalId
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.144
+m-description: The Journal ID
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.150.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.150.ldif
new file mode 100644
index 0000000..a46924c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.150.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.150,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-partitionId
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.150
+m-description: The Partition identifier
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.151.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.151.ldif
new file mode 100644
index 0000000..ddea4e0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.151.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.151,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-partitionSuffix
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.151
+m-description: The partition suffix
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-equality: distinguishedNameMatch
+m-ordering: distinguishedNameMatch
+m-singlevalue: TRUE
+m-supattributetype: distinguishedName
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.153.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.153.ldif
new file mode 100644
index 0000000..2e1a358
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.153.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.153,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-partitionCacheSize
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.153
+m-description: The number of entries in the cache for this partition
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.154.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.154.ldif
new file mode 100644
index 0000000..9e45bc7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.154.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.154,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-contextEntry
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.154
+m-description: The Partition context entry
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.160.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.160.ldif
new file mode 100644
index 0000000..c8fc205
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.160.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.160,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.160
+m-description: The attributeType name or OID
+m-supattributetype: name
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-name: ads-indexAttributeId
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.161.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.161.ldif
new file mode 100644
index 0000000..1c1bc1a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.161.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.161,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.161
+m-description: The index file name
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-indexFileName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.162.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.162.ldif
new file mode 100644
index 0000000..aec783b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.162.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.162,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.162
+m-description: The place on disk where the index file is stored
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-indexWorkingDir
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.163.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.163.ldif
new file mode 100644
index 0000000..1c0c924
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.163.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.163,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.163
+m-description: The number of duplicated element we allow before switching to a secondary tree
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-indexNumDupLimit
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.164.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.164.ldif
new file mode 100644
index 0000000..083bde3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.164.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.164,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.164
+m-description: The number of key we store in the cache for this index
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-indexCacheSize
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.165.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.165.ldif
new file mode 100644
index 0000000..beaeb59
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.165.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.165,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.165
+m-description: A flag telling if the index has a reverse table
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-name: ads-indexHasReverse
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.200.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.200.ldif
new file mode 100644
index 0000000..2ab61a8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.200.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.200,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.200
+m-description: The transport ID
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-transportId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.250.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.250.ldif
new file mode 100644
index 0000000..07387a5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.250.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.250,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.250
+m-description: The server ID
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-serverId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.252.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.252.ldif
new file mode 100644
index 0000000..59fc21c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.252.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.252,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.252
+m-description: a generic ID which can be used in any configuration entry DN
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-Id
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.253.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.253.ldif
new file mode 100644
index 0000000..3854d99
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.253.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.253,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.253
+m-description: an ID used for ExtendeOpertion names
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-extendedOpId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.300.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.300.ldif
new file mode 100644
index 0000000..23df36a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.300.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.300,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.300
+m-description: Tells the server to accept requests using startTLS or LDAPS
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-confidentialityRequired
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.301.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.301.ldif
new file mode 100644
index 0000000..3d67aff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.301.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.301,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.301
+m-description: Tells the server to accept Anynymous requests or not
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-allowAnonymousAccess
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.302.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.302.ldif
new file mode 100644
index 0000000..b5f2242
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.302.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.302,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.302
+m-description: The maximum number of entries to return
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-maxSizeLimit
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.303.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.303.ldif
new file mode 100644
index 0000000..d0e47b4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.303.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.303,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.303
+m-description: The maximum time before an operation is aborted (in seconds)
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-maxTimeLimit
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.304.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.304.ldif
new file mode 100644
index 0000000..3e26442
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.304.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.304,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.304
+m-description: The name of this host, validated during SASL negotiation
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-saslHost
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.305.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.305.ldif
new file mode 100644
index 0000000..2c77e65
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.305.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.305,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.305
+m-description: The service principal, used by GSSAPI
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-name: ads-saslPrincipal
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.306.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.306.ldif
new file mode 100644
index 0000000..276b238
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.306.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.306,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.306
+m-description: The realms serviced by this SASL host
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-saslRealms
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.308.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.308.ldif
new file mode 100644
index 0000000..2458602
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.308.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.308,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.308
+m-description: The keystore file to use to store certificates
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-name: ads-keystoreFile
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.309.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.309.ldif
new file mode 100644
index 0000000..f510308
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.309.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.309,ou=attributeTypes,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.309
+m-description: The certificate passord
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-supattributetype: userPassword
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-name: ads-certificatePassword
+creatorsname: uid=admin,ou=system
+m-equality: octetStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.310.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.310.ldif
new file mode 100644
index 0000000..2538f9c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.310.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.310,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.310
+m-description: The FQCN of the replication consumer/client handler
+m-substr: caseExactSubstringsMatch
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-replConsumerImpl
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.400.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.400.ldif
new file mode 100644
index 0000000..c622152
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.400.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.400,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.400
+m-description: The allowable clock skew
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-krbAllowableClockSkew
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.401.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.401.ldif
new file mode 100644
index 0000000..07c9987
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.401.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.401,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.401
+m-description: The encryption types
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-krbEncryptionTypes
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.402.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.402.ldif
new file mode 100644
index 0000000..33c9a3c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.402.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.402,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.402
+m-description: Whether empty addresses are allowed
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-krbEmptyAddressesAllowed
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.403.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.403.ldif
new file mode 100644
index 0000000..aa31c1c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.403.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.403,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.403
+m-description: Whether forwardable addresses are allowed
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-krbForwardableAllowed
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.404.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.404.ldif
new file mode 100644
index 0000000..ab3c79e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.404.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.404,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.404
+m-description: Whether pre-authentication by encrypted timestamp is required
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-krbPaEncTimestampRequired
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.405.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.405.ldif
new file mode 100644
index 0000000..04c7876
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.405.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.405,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.405
+m-description: Whether postdated tickets are allowed
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-krbPostdatedAllowed
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.406.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.406.ldif
new file mode 100644
index 0000000..04aca13
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.406.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.406,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.406
+m-description: Whether proxiable addresses are allowed
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-krbProxiableAllowed
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.407.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.407.ldif
new file mode 100644
index 0000000..d53514a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.407.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.407,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.407
+m-description: Whether renewable tickets are allowed
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-krbRenewableAllowed
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.408.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.408.ldif
new file mode 100644
index 0000000..abd2762
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.408.ldif
@@ -0,0 +1,16 @@
+#this AT is not used in ads-kdcServer OC anymore, can be reused for a new AT definition
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.408,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.408
+m-description: The service principal name
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-name: ads-krbKdcPrincipal
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.409.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.409.ldif
new file mode 100644
index 0000000..12fd3a1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.409.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.409,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.409
+m-description: The maximum renewable lifetime
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-krbMaximumRenewableLifetime
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.410.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.410.ldif
new file mode 100644
index 0000000..72b1471
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.410.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.410,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.410
+m-description: The maximum ticket lifetime
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-krbMaximumTicketLifetime
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.411.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.411.ldif
new file mode 100644
index 0000000..a2079df
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.411.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.411,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.411
+m-description: The primary realm
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-krbPrimaryRealm
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.412.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.412.ldif
new file mode 100644
index 0000000..c95cca0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.412.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.412,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.412
+m-description: Whether to verify the body checksum
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-krbBodyChecksumVerified
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.61.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.61.ldif
new file mode 100644
index 0000000..e5f3692
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.61.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.61,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.61
+m-description: The Address to listen on.
+m-substr: caseIgnoreIA5SubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-name: ads-transportAddress
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreOrderingMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.62.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.62.ldif
new file mode 100644
index 0000000..c0ebad2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.62.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.62,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.62
+m-description: The number of messages waiting to be processed.
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-transportBacklog
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.63.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.63.ldif
new file mode 100644
index 0000000..754ba47
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.63.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.63,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.63
+m-description: Tells if this transport support SSL.
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-transportEnableSSL
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.64.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.64.ldif
new file mode 100644
index 0000000..d837628
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.64.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.64,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.64
+m-description: The number of threads to use for the Acceptor
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-transportNbThreads
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.65.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.65.ldif
new file mode 100644
index 0000000..654a9e4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.65.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.65,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.65
+m-name: ads-needClientAuth
+m-description: Tells if the client auth is needed
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-singlevalue: TRUE
+m-equality: booleanMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.66.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.66.ldif
new file mode 100644
index 0000000..a1284ce
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.66.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.66,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.66
+m-name: ads-wantClientAuth
+m-description: Tells if the client auth is wanted
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.67.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.67.ldif
new file mode 100644
index 0000000..3800a1a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.67.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.67,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.67
+m-name: ads-enabledProtocols
+m-description: Enabled SSL protocol
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreOrderingMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseIgnoreIA5SubstringsMatch
+m-singlevalue: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.68.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.68.ldif
new file mode 100644
index 0000000..f26144e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.68.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.68,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.68
+m-name: ads-enabledCiphers
+m-description: Enabled ciphers
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreOrderingMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseIgnoreIA5SubstringsMatch
+m-singlevalue: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.800.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.800.ldif
new file mode 100644
index 0000000..156c745
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.800.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.800,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.800
+m-description: The policy category count
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-chgPwdPolicyCategoryCount
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.801.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.801.ldif
new file mode 100644
index 0000000..b37a239
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.801.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.801,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.801
+m-description: The policy minimum password length
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-chgPwdPolicyPasswordLength
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.802.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.802.ldif
new file mode 100644
index 0000000..404778a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.802.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.802,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.802
+m-description: The policy token size
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-chgPwdPolicyTokenSize
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.803.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.803.ldif
new file mode 100644
index 0000000..d335836
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.803.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.803,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.803
+m-description: The Change Password service principal
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-name: ads-chgPwdServicePrincipal
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.804.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.804.ldif
new file mode 100644
index 0000000..5de7d28
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.804.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.804,ou=attributeTypes,cn=adsconfig,ou=schema
+m-name: ads-interceptorClassName
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.804
+m-description: Fully qualified class name of the interceptor
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.805.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.805.ldif
new file mode 100644
index 0000000..380c400
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.805.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.805,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.805
+m-description: specifies whether a config element is enabled or not, default is true
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-enabled
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.806.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.806.ldif
new file mode 100644
index 0000000..21b0485
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.806.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.806,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.806
+m-description: directs a partition to synchronize the underlying storage upon a write operation
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-partitionSyncOnWrite
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.807.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.807.ldif
new file mode 100644
index 0000000..3b542c0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.807.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.807,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.807
+m-description: Enables JDBM partition optimizer
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: ads-jdbmPartitionOptimizerEnabled
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.808.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.808.ldif
new file mode 100644
index 0000000..0710aff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.808.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.808,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.808
+m-description: SASL mechanism name
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-saslMechName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.809.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.809.ldif
new file mode 100644
index 0000000..8b22501
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.809.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.809,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.809
+m-description: Fully qualified class name of SASL NTLM provider
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-ntlmMechProvider
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.810.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.810.ldif
new file mode 100644
index 0000000..a150caa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.810.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.810,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.810
+m-description: Fully qualified class name of SASL mechanism implementation
+m-substr: caseExactSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-saslMechClassName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.811.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.811.ldif
new file mode 100644
index 0000000..17584f8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.811.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.811,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.811
+m-description: Fully qualified class name of the extended operation handler
+m-substr: caseExactSubstringsMatch
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-extendedOpHandlerClass
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.812.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.812.ldif
new file mode 100644
index 0000000..4b85890
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.812.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.812,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.812
+m-description: Port number on system
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-systemPort
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.813.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.813.ldif
new file mode 100644
index 0000000..6fae1c7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.813.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.813,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseIgnoreOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.813
+m-description: a web app archive
+m-substr: caseIgnoreSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-httpWarFile
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.814.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.814.ldif
new file mode 100644
index 0000000..e94d138
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.814.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.814,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseIgnoreOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.814
+m-description: A web app context path
+m-substr: caseIgnoreSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-httpAppCtxPath
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.816.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.816.ldif
new file mode 100644
index 0000000..4329e81
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.816.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.816,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseIgnoreOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.816
+m-description: Jetty web server config file path
+m-substr: caseIgnoreSubstringsMatch
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-httpConfFile
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.817.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.817.ldif
new file mode 100644
index 0000000..d16d2d8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.817.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.817,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseIgnoreOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.817
+m-description: Search filter used in replication
+m-substr: caseIgnoreSubstringsMatch
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-name: ads-replSearchFilter
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.818.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.818.ldif
new file mode 100644
index 0000000..d622a61
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.818.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.818,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: csnOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.818
+m-description: the CSN that was sent to the client as part of cookie
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.4203.666.11.2.1
+m-usage: directoryOperation
+m-name: ads-replLastSentCsn
+creatorsname: uid=admin,ou=system
+m-equality: csnMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.819.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.819.ldif
new file mode 100644
index 0000000..049ec8d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.819.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.819,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.819
+m-description: the alias dereference mode of replication search
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.18060.0.4.1.0.11
+m-name: ads-replAliasDerefMode
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.820.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.820.ldif
new file mode 100644
index 0000000..11c7b9c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.820.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.820,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: distinguishedNameMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.820
+m-description: base DN of the DIT to be searched or replicated
+m-supattributetype: distinguishedName
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-name: ads-searchBaseDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.821.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.821.ldif
new file mode 100644
index 0000000..2110be9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.821.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.821,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.821
+m-description: the search scope of the replication
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.18060.0.4.1.0.10
+m-name: ads-replSearchScope
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.822.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.822.ldif
new file mode 100644
index 0000000..86cac03
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.822.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.822,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.822
+m-description: flag indicating refreshAndPersist mode of replication
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: ads-replRefreshNPersist
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.823.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.823.ldif
new file mode 100644
index 0000000..a8e66b6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.823.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.823,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseIgnoreOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.823
+m-description: replication provider host name
+m-substr: caseIgnoreSubstringsMatch
+m-supattributetype: ads-transportAddress
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-name: ads-replProvHostName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.824.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.824.ldif
new file mode 100644
index 0000000..ff71ebd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.824.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.824,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.824
+m-description: replication provider port number
+m-supattributetype: ads-transportId
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-replProvPort
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.825.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.825.ldif
new file mode 100644
index 0000000..188a835
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.825.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.825,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.825
+m-description: user DN used for authenticating with replication provider
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: ads-replUserDn
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.826.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.826.ldif
new file mode 100644
index 0000000..afe9be9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.826.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.826,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.826
+m-description: replication user password
+m-supattributetype: userPassword
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-name: ads-replUserPassword
+creatorsname: uid=admin,ou=system
+m-equality: octetStringMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.827.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.827.ldif
new file mode 100644
index 0000000..5d9b74f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.827.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.827,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.827
+m-description: time interval between two refreshOnly sessions
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-replRefreshInterval
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.828.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.828.ldif
new file mode 100644
index 0000000..08bbab7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.828.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.828,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.828
+m-description: the attributes to be replicated
+m-substr: caseIgnoreIA5SubstringsMatch
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-name: ads-replAttributes
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.829.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.829.ldif
new file mode 100644
index 0000000..60dc22a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.829.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.829,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.829
+m-description: size limit imposed during replication refreshOnly phase
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-replSearchSizeLimit
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.830.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.830.ldif
new file mode 100644
index 0000000..eac6a98
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.830.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.830,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: integerOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.830
+m-description: search timeout imposed during replication refreshOnly phase
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-name: ads-replSearchTimeOut
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.831.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.831.ldif
new file mode 100644
index 0000000..0bbcfe8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.831.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.831,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: octetStringOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.831
+m-description: cookie sent from the replication provider
+m-substr: octetStringSubstringsMatch
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: directoryOperation
+m-name: ads-replCookie
+creatorsname: uid=admin,ou=system
+m-equality: octetStringMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.832.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.832.ldif
new file mode 100644
index 0000000..321be44
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.832.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.832,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.832
+m-description: FQCN of the replication replication request handler on a master/provider
+m-substr: caseExactSubstringsMatch
+objectclass: top
+objectclass: metaAttributeType
+objectclass: metaTop
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-replReqHandler
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.833.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.833.ldif
new file mode 100644
index 0000000..b76fa4e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.833.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.833,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.833
+m-description: flag to indicate the use of TLS
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: ads-replUseTls
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.834.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.834.ldif
new file mode 100644
index 0000000..c63fbf8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.834.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.834,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.834
+m-description: flag to indicate strict certificate validation
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: ads-replStrictCertValidation
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.837.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.837.ldif
new file mode 100644
index 0000000..da63134
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.837.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.837,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.837
+m-description: The replication consumer ID
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-replConsumerId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.838.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.838.ldif
new file mode 100644
index 0000000..47f5ea0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.838.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.838,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.838
+m-description: A flag set when the replication is enabled
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-name: ads-replEnabled
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.900.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.900.ldif
new file mode 100644
index 0000000..30aee19
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.900.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.900,ou=attributeTypes,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.900
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdAttribute
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.901.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.901.ldif
new file mode 100644
index 0000000..f17cada
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.901.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.901,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.901
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMinAge
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.902.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.902.ldif
new file mode 100644
index 0000000..c75dd49
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.902.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.902,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.902
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMaxAge
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.903.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.903.ldif
new file mode 100644
index 0000000..ef6811d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.903.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.903,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.903
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdInHistory
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.904.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.904.ldif
new file mode 100644
index 0000000..c446358
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.904.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.904,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.904
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdCheckQuality
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.905.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.905.ldif
new file mode 100644
index 0000000..8e3f893
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.905.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.905,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.905
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMinLength
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.906.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.906.ldif
new file mode 100644
index 0000000..5473ad1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.906.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.906,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.906
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMaxLength
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.907.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.907.ldif
new file mode 100644
index 0000000..93a2819
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.907.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.907,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.907
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdExpireWarning
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.908.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.908.ldif
new file mode 100644
index 0000000..4467b1b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.908.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.908,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.908
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdGraceAuthNLimit
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.909.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.909.ldif
new file mode 100644
index 0000000..9ba5b70
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.909.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.909,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.909
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdGraceExpire
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.910.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.910.ldif
new file mode 100644
index 0000000..b5a9f78
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.910.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.910,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.910
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdLockout
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.911.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.911.ldif
new file mode 100644
index 0000000..3c69d52
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.911.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.911,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.911
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdLockoutDuration
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.912.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.912.ldif
new file mode 100644
index 0000000..8459328
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.912.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.912,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.912
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMaxFailure
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.913.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.913.ldif
new file mode 100644
index 0000000..5f61efb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.913.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.913,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.913
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdFailureCountInterval
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.914.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.914.ldif
new file mode 100644
index 0000000..ed64a61
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.914.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.914,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.914
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMustChange
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.915.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.915.ldif
new file mode 100644
index 0000000..0276223
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.915.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.915,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.915
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdAllowUserChange
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.916.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.916.ldif
new file mode 100644
index 0000000..2f0b4f7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.916.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.916,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.916
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdSafeModify
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.917.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.917.ldif
new file mode 100644
index 0000000..3b551e6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.917.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.917,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.917
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMinDelay
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.918.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.918.ldif
new file mode 100644
index 0000000..947c2cb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.918.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.918,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.918
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMaxDelay
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.919.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.919.ldif
new file mode 100644
index 0000000..c5a024a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.919.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.919,ou=attributeTypes,cn=adsconfig,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.919
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-name: ads-pwdMaxIdle
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.920.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.920.ldif
new file mode 100644
index 0000000..fb640dc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.920.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.920,ou=attributetypes,cn=adsconfig,ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.920
+m-name: ads-replLogMaxIdle
+m-description: the duration(in seconds) of consumer inactivity after which the a
+ ssociated log will be deleted. Defaults to 172800 seconds (i.e. 2 days)
+m-equality: bigIntegerMatch
+m-ordering: integerOrderingMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.921.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.921.ldif
new file mode 100644
index 0000000..ce3b19d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.921.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.921,ou=attributeTypes,cn=adsconfig,ou=schema
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.921
+m-description: an ID used to identify the passwordPolicy configuration
+m-substr: caseExactSubstringsMatch
+m-supattributetype: name
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-name: ads-pwdId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.922.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.922.ldif
new file mode 100644
index 0000000..0226744
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.922.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.922,ou=attributetypes,cn=adsconfig,ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.922
+m-name: ads-replLogPurgeThresholdCount
+m-description: the minimum number of entries to be present for beginning purging
+  entries older than the last sent CSN. Default is 10000
+m-equality: integerMatch
+m-ordering: integerOrderingMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.923.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.923.ldif
new file mode 100644
index 0000000..b6821ea
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.923.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.923, ou=attributetypes, cn=adsconfig, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.923
+m-name: ads-replPingerSleep
+m-description: the time interval(in seconds) between subsequent pings to each re
+ plication provider
+m-equality: integerMatch
+m-ordering: integerOrderingMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.925.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.925.ldif
new file mode 100644
index 0000000..2275b84
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.925.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.925, ou=attributetypes, cn=adsconfig, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.925
+m-name: ads-pwdValidator
+m-description: FQCN of password validator
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-substr: caseExactSubstringsMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.930.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.930.ldif
new file mode 100644
index 0000000..e46142f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.930.ldif
@@ -0,0 +1,15 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.930,ou=attributeTypes,cn=adsconfig,ou=schema

+m-ordering: caseExactOrderingMatch

+m-singlevalue: TRUE

+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.930

+m-description: Authenticator Id

+m-substr: caseExactSubstringsMatch

+objectclass: metaTop

+objectclass: metaAttributeType

+objectclass: top

+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44

+m-name: ads-authenticatorId

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

+m-equality: caseExactMatch

+m-length: 0

+

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.931.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.931.ldif
new file mode 100644
index 0000000..f9a9fc8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.931.ldif
@@ -0,0 +1,15 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.931,ou=attributeTypes,cn=adsconfig,ou=schema

+m-ordering: caseExactOrderingMatch

+m-singlevalue: TRUE

+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.931

+m-description: an external host handling delegate authentication

+m-substr: caseExactSubstringsMatch

+objectclass: metaTop

+objectclass: metaAttributeType

+objectclass: top

+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44

+m-name: ads-delegateHost

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

+m-equality: caseExactMatch

+m-length: 0

+

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.932.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.932.ldif
new file mode 100644
index 0000000..32b1701
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.932.ldif
@@ -0,0 +1,14 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.932,ou=attributeTypes,cn=adsconfig,ou=schema

+m-ordering: integerOrderingMatch

+m-singlevalue: TRUE

+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.932

+m-description: Port number on system

+objectclass: metaTop

+objectclass: metaAttributeType

+objectclass: top

+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27

+m-name: ads-delegatePort

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

+m-equality: integerMatch

+m-length: 0

+

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.933.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.933.ldif
new file mode 100644
index 0000000..a600506
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.933.ldif
@@ -0,0 +1,12 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.933,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.933
+m-name: ads-delegateSsl
+m-description: Tells if the delegatedAuthenticator uses SSL
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.934.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.934.ldif
new file mode 100644
index 0000000..5d23bb4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.934.ldif
@@ -0,0 +1,14 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.934,ou=attributeTypes,cn=adsconfig,ou=schema

+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.934

+objectclass: metaTop

+objectclass: metaAttributeType

+objectclass: top

+m-name: ads-authenticatorClass

+m-description: the fully qualified class name of an authenticator implementation

+m-singlevalue: TRUE

+m-substr: caseExactSubstringsMatch

+m-ordering: caseExactOrderingMatch

+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44

+m-equality: caseExactMatch

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

+

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.935.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.935.ldif
new file mode 100644
index 0000000..6dd6f11
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.935.ldif
@@ -0,0 +1,12 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.935,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.935
+m-name: ads-baseDn
+m-description: The base DN from which the authenticator is valid
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-equality: distinguishedNameMatch
+m-singlevalue: TRUE
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.936.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.936.ldif
new file mode 100644
index 0000000..fd5e80b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.936.ldif
@@ -0,0 +1,12 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.936,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.936
+m-name: ads-delegateTls
+m-description: Tells if the authenticator will use StartTLS
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.937.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.937.ldif
new file mode 100644
index 0000000..ac1cc9c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.937.ldif
@@ -0,0 +1,12 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.937,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.937
+m-name: ads-delegateSslTrustManager
+m-description: FQCN of the TrustManager to use to validate the SSL communication
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseExactMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.938.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.938.ldif
new file mode 100644
index 0000000..cc56669
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.938.ldif
@@ -0,0 +1,12 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.938,ou=attributeTypes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.938
+m-name: ads-delegateTlsTrustManager
+m-description: FQCN of the TrustManager to use to validate the startTls communication
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseExactMatch
+m-singlevalue: TRUE
+m-length: 0
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=comparators.ldif
new file mode 100644
index 0000000..706030c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=adsconfig,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..5b60338
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=adsconfig,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..c9688e3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=adsconfig,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=matchingrules.ldif
new file mode 100644
index 0000000..23c334e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=adsconfig,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..3a99650
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=adsconfig,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=nameforms.ldif
new file mode 100644
index 0000000..eedd99d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=adsconfig,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=normalizers.ldif
new file mode 100644
index 0000000..1ae1be4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=adsconfig,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses.ldif
new file mode 100644
index 0000000..318a0be
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=adsconfig,ou=schema
+ou: objectClasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.0.ldif
new file mode 100644
index 0000000..1860d2f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.0.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.0,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.0
+m-name: ads-base
+m-description: The base bean
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-typeobjectclass: ABSTRACT
+m-may: ads-enabled
+m-may: description
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.100.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.100.ldif
new file mode 100644
index 0000000..c5cae3d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.100.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.100,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.100
+m-name: ads-directoryService
+m-description: The DirectoryService ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-directoryServiceId
+m-must: ads-dsReplicaId
+m-must: ads-dsAccessControlEnabled
+m-must: ads-dsAllowAnonymousAccess
+m-must: ads-dsDenormalizeOpAttrsEnabled
+m-must: ads-dsPasswordHidden
+m-must: ads-dsSyncPeriodMillis
+m-may: ads-dsTestEntries
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.120.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.120.ldif
new file mode 100644
index 0000000..0922ae6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.120.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.120,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.120
+m-name: ads-changeLog
+m-description: The ChangeLog
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-changeLogExposed
+m-must: ads-changeLogId
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.130.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.130.ldif
new file mode 100644
index 0000000..ca2ba38
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.130.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.130,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.130
+m-name: ads-interceptor
+m-description: The Interceptor ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-interceptorId
+m-must: ads-interceptorOrder
+m-must: ads-interceptorClassName
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.131.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.131.ldif
new file mode 100644
index 0000000..ebffebf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.131.ldif
@@ -0,0 +1,12 @@
+version: 1

+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.131, ou=objectClasses, cn=adsconfig, ou=schema

+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.131

+m-name: ads-authenticationInterceptor

+m-description: The AuthenticationInterceptor ObjectClass

+objectclass: top

+objectclass: metaTop

+objectclass: metaObjectClass

+m-supobjectclass: ads-interceptor

+createtimestamp: 20100111145217Z

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

+entrycsn: 20100111202217.914000Z#000000#000#000000

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.132.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.132.ldif
new file mode 100755
index 0000000..bf37f27
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.132.ldif
@@ -0,0 +1,14 @@
+version: 1

+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.132, ou=objectClasses, cn=adsconfig, ou=schema

+objectclass: top

+objectclass: metaTop

+objectclass: metaObjectClass

+createtimestamp: 20150812000000Z

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

+entrycsn: 20150812000000.914000Z#000000#000#000000

+m-description: The HashInterceptor ObjectClass

+m-name: ads-hashInterceptor

+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.132

+m-may: ads-hashAlgorithm

+m-may: ads-hashAttribute

+m-supobjectclass: ads-interceptor

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.140.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.140.ldif
new file mode 100644
index 0000000..e91a3c5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.140.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.140,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.140
+m-name: ads-journal
+m-description: The Journal
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-journalWorkingDir
+m-must: ads-journalRotation
+m-must: ads-journalId
+m-must: ads-journalFileName
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.150.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.150.ldif
new file mode 100644
index 0000000..ca3e566
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.150.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.150,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.150
+m-name: ads-partition
+m-description: A generic partition
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-typeobjectclass: ABSTRACT
+m-must: ads-partitionId
+m-must: ads-partitionSuffix
+m-may: ads-contextEntry
+m-may: ads-partitionSyncOnWrite
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.151.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.151.ldif
new file mode 100644
index 0000000..a8dcbd2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.151.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.151,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.151
+m-name: ads-jdbmPartition
+m-description: A JDBM partition
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-partition
+m-may: ads-partitionCacheSize
+m-may: ads-jdbmPartitionOptimizerEnabled
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.160.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.160.ldif
new file mode 100644
index 0000000..e5056bf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.160.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.160,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.160
+m-name: ads-index
+m-description: A generic indexed attribute
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-typeobjectclass: ABSTRACT
+m-must: ads-indexAttributeId
+m-must: ads-indexHasReverse
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.161.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.161.ldif
new file mode 100644
index 0000000..8f49be9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.161.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.161,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.161
+m-name: ads-jdbmIndex
+m-description: A JDBM indexed attribute
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-index
+m-may: ads-indexFileName
+m-may: ads-indexWorkingDir
+m-may: ads-indexNumDupLimit
+m-may: ads-indexCacheSize
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.18.ldif
new file mode 100644
index 0000000..2180702
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.18.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.18,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.18
+m-name: ads-transport
+m-description: A transport (TCP or UDP)
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-typeobjectclass: ABSTRACT
+m-must: ads-transportId
+m-must: ads-systemPort
+m-must: ads-transportAddress
+m-may: ads-transportBacklog
+m-may: ads-transportEnableSSL
+m-may: ads-transportNbThreads
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.19.ldif
new file mode 100644
index 0000000..34fc4bf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.19.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.19,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.19
+m-name: ads-tcpTransport
+m-description: A TCP transport
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-transport
+m-may: ads-enabledProtocols
+m-may: ads-enabledCiphers
+m-may: ads-wantClientAuth
+m-may: ads-needClientAuth
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.20.ldif
new file mode 100644
index 0000000..d91e348
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.20.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.20,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.20
+m-name: ads-udpTransport
+m-description: an UDP transport
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-transport
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.250.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.250.ldif
new file mode 100644
index 0000000..bf67f1c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.250.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.250,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.250
+m-name: ads-server
+m-description: The server ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-typeobjectclass: ABSTRACT
+m-must: ads-serverId
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.260.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.260.ldif
new file mode 100644
index 0000000..5779bc4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.260.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.260,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.260
+m-name: ads-dsBasedServer
+m-description: The DirectoryService based server ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-server
+m-typeobjectclass: ABSTRACT
+m-may: ads-searchBaseDN
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.300.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.300.ldif
new file mode 100644
index 0000000..3b9393a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.300.ldif
@@ -0,0 +1,22 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.300,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.300
+m-name: ads-ldapServer
+m-description: The LdapServer ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-dsBasedServer
+m-must: ads-confidentialityRequired
+m-must: ads-maxSizeLimit
+m-must: ads-maxTimeLimit
+m-must: ads-maxPDUSize
+m-must: ads-saslHost
+m-must: ads-saslPrincipal
+m-must: ads-saslRealms
+m-may: ads-keystoreFile
+m-may: ads-certificatePassword
+m-may: ads-replReqHandler
+m-must: ads-replEnabled
+m-must: ads-replPingerSleep
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.400.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.400.ldif
new file mode 100644
index 0000000..7e6344a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.400.ldif
@@ -0,0 +1,22 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.400,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.400
+m-name: ads-kdcServer
+m-description: The KerberosServer ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-dsBasedServer
+m-must: ads-krbAllowableClockSkew
+m-must: ads-krbEncryptionTypes
+m-must: ads-krbEmptyAddressesAllowed
+m-must: ads-krbForwardableAllowed
+m-must: ads-krbPaEncTimestampRequired
+m-must: ads-krbPostdatedAllowed
+m-must: ads-krbProxiableAllowed
+m-must: ads-krbRenewableAllowed
+m-must: ads-krbMaximumRenewableLifetime
+m-must: ads-krbMaximumTicketLifetime
+m-must: ads-krbPrimaryRealm
+m-must: ads-krbBodyChecksumVerified
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.500.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.500.ldif
new file mode 100644
index 0000000..7b8fd0e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.500.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.500,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.500
+m-name: ads-dnsServer
+m-description: The DnsServer ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-dsBasedServer
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.600.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.600.ldif
new file mode 100644
index 0000000..1a1f739
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.600.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.600,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.600
+m-name: ads-dhcpServer
+m-description: The DhcpServer ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-dsBasedServer
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.700.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.700.ldif
new file mode 100644
index 0000000..0a327eb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.700.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.700,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.700
+m-name: ads-ntpServer
+m-description: The NtpServer ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-server
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.800.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.800.ldif
new file mode 100644
index 0000000..e7fb14d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.800.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.800,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.800
+m-name: ads-changePasswordServer
+m-description: The ChangePassword ObjectClass
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-dsBasedServer
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.801.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.801.ldif
new file mode 100644
index 0000000..a9de95f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.801.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.801,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.801
+m-name: ads-saslMechHandler
+m-description: SASL mechanism handler
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-saslMechName
+m-must: ads-saslMechClassName
+m-may: ads-ntlmMechProvider
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.802.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.802.ldif
new file mode 100644
index 0000000..05e95b3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.802.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.802,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.802
+m-name: ads-extendedOpHandler
+m-description: Extended operation handler
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-extendedOpHandlerClass
+m-must: ads-extendedOpId
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.803.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.803.ldif
new file mode 100644
index 0000000..49a3cf3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.803.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.803,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.803
+m-name: ads-httpWebApp
+m-description: a web app
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-httpWarFile
+m-must: ads-id
+m-must: ads-httpAppCtxPath
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.804.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.804.ldif
new file mode 100644
index 0000000..e63751d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.804.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.804,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.804
+m-name: ads-httpServer
+m-description: integrated jetty http server
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-server
+m-may: ads-httpConfFile
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.805.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.805.ldif
new file mode 100644
index 0000000..f1adc11
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.805.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.805,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.805
+m-name: ads-replEventLog
+m-description: class to hold a replication consumer event log details
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-dsReplicaId
+m-must: ads-replAliasDerefMode
+m-must: ads-searchBaseDN
+m-must: ads-replSearchScope
+m-must: ads-replSearchFilter
+m-must: ads-replRefreshNPersist
+m-must: ads-replLogMaxIdle
+m-must: ads-replLogPurgeThresholdCount
+m-may: ads-replLastSentCsn
+m-may: ads-replCookie
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.806.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.806.ldif
new file mode 100644
index 0000000..30aaa97
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.806.ldif
@@ -0,0 +1,28 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.806,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.806
+m-name: ads-replConsumer
+m-description: replication consumer configuration
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-replConsumerId
+m-must: ads-searchBaseDN
+m-must: ads-replProvHostName
+m-must: ads-replProvPort
+m-must: ads-replAliasDerefMode
+m-must: ads-replAttributes
+m-must: ads-replRefreshInterval
+m-must: ads-replRefreshNPersist
+m-must: ads-replSearchScope
+m-must: ads-replSearchFilter
+m-must: ads-replSearchSizeLimit
+m-must: ads-replSearchTimeOut
+m-must: ads-replUserDn
+m-must: ads-replUserPassword
+m-may: ads-replUseTls
+m-may: ads-replStrictCertValidation
+m-may: ads-replConsumerImpl
+m-may: ads-replCookie
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.900.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.900.ldif
new file mode 100644
index 0000000..97f7da2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.900.ldif
@@ -0,0 +1,32 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.900,ou=objectClasses,cn=adsconfig,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.900
+m-name: ads-passwordPolicy
+m-description: class to hold the PasswordPolicy configuration
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: ads-base
+m-must: ads-pwdId
+m-must: ads-pwdAttribute
+m-may: ads-pwdMinAge
+m-may: ads-pwdMaxAge
+m-may: ads-pwdInHistory
+m-may: ads-pwdCheckQuality
+m-may: ads-pwdMinLength
+m-may: ads-pwdMaxLength
+m-may: ads-pwdExpireWarning
+m-may: ads-pwdGraceAuthNLimit
+m-may: ads-pwdGraceExpire
+m-may: ads-pwdLockout
+m-may: ads-pwdLockoutDuration
+m-may: ads-pwdMaxFailure
+m-may: ads-pwdFailureCountInterval
+m-may: ads-pwdMustChange
+m-may: ads-pwdAllowUserChange
+m-may: ads-pwdSafeModify
+m-may: ads-pwdMinDelay
+m-may: ads-pwdMaxDelay
+m-may: ads-pwdMaxIdle
+m-may: ads-pwdValidator
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.901.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.901.ldif
new file mode 100644
index 0000000..3cdc7bb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.901.ldif
@@ -0,0 +1,15 @@
+version: 1

+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.901, ou=objectClasses, cn=adsconfig, ou=schema

+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.901

+m-name: ads-authenticator

+m-description: A generic authenticator

+objectclass: top

+objectclass: metaTop

+objectclass: metaObjectClass

+m-supobjectclass: ads-base

+m-typeobjectclass: ABSTRACT

+m-must: ads-authenticatorId

+m-must: ads-baseDn

+createtimestamp: 20100111145217Z

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

+entrycsn: 20100111202217.958000Z#000000#000#000000

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.902.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.902.ldif
new file mode 100644
index 0000000..3b6602d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.902.ldif
@@ -0,0 +1,11 @@
+version: 1

+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.902,ou=objectClasses,cn=adsconfig,ou=schema

+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.902

+m-name: ads-authenticatorImpl

+m-description: an authenticator implementation

+objectclass: top

+objectclass: metaTop

+objectclass: metaObjectClass

+m-supobjectclass: ads-authenticator

+m-must: ads-authenticatorClass

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.904.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.904.ldif
new file mode 100644
index 0000000..5f8f709
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.904.ldif
@@ -0,0 +1,16 @@
+version: 1

+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.904,ou=objectClasses,cn=adsconfig,ou=schema

+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.904

+m-name: ads-delegatingAuthenticator

+m-description: delegated authentication configuration

+objectclass: top

+objectclass: metaTop

+objectclass: metaObjectClass

+m-supobjectclass: ads-authenticator

+m-must: ads-delegateHost

+m-must: ads-delegatePort

+m-may: ads-delegateSsl

+m-may: ads-delegateTls

+m-may: ads-delegateSslTrustManager

+m-may: ads-delegateTlsTrustManager

+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system

diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.905.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.905.ldif
new file mode 100644
index 0000000..65ae07b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.905.ldif
@@ -0,0 +1,9 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.905, ou=objectclasses, cn=adsconfig, ou=schema
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.905
+m-name: ads-mavibotIndex
+m-description: A Mavibot index
+m-supObjectClass: ads-index
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.906.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.906.ldif
new file mode 100644
index 0000000..d3d300d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.906.ldif
@@ -0,0 +1,9 @@
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.906, ou=objectclasses, cn=adsconfig, ou=schema
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.906
+m-name: ads-mavibotPartition
+m-description: A Mavibot partition
+m-supObjectClass: ads-partition
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/oid.txt b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/oid.txt
new file mode 100644
index 0000000..d44e15e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=objectclasses/oid.txt
@@ -0,0 +1,32 @@
+
+ads-authenticationInterceptor m-oid=1.3.6.1.4.1.18060.0.4.1.3.131
+ads-authenticator m-oid=1.3.6.1.4.1.18060.0.4.1.3.901
+ads-authenticatorImpl m-oid=1.3.6.1.4.1.18060.0.4.1.3.902
+ads-base m-oid=1.3.6.1.4.1.18060.0.4.1.3.0
+ads-changeLog m-oid=1.3.6.1.4.1.18060.0.4.1.3.120
+ads-changePasswordServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.800
+ads-delegatingAuthenticator m-oid=1.3.6.1.4.1.18060.0.4.1.3.904
+ads-dhcpServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.600
+ads-directoryService m-oid=1.3.6.1.4.1.18060.0.4.1.3.100
+ads-dnsServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.500
+ads-dsBasedServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.260
+ads-extendedOpHandler m-oid=1.3.6.1.4.1.18060.0.4.1.3.802
+ads-httpServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.804
+ads-httpWebApp m-oid=1.3.6.1.4.1.18060.0.4.1.3.803
+ads-index m-oid=1.3.6.1.4.1.18060.0.4.1.3.160
+ads-interceptor m-oid=1.3.6.1.4.1.18060.0.4.1.3.130
+ads-jdbmIndex m-oid=1.3.6.1.4.1.18060.0.4.1.3.161
+ads-jdbmPartition m-oid=1.3.6.1.4.1.18060.0.4.1.3.151
+ads-journal m-oid=1.3.6.1.4.1.18060.0.4.1.3.140
+ads-kdcServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.400
+ads-ldapServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.300
+ads-ntpServer m-oid=1.3.6.1.4.1.18060.0.4.1.3.700
+ads-partition m-oid=1.3.6.1.4.1.18060.0.4.1.3.150
+ads-passwordPolicy m-oid=1.3.6.1.4.1.18060.0.4.1.3.900
+ads-replConsumer m-oid=1.3.6.1.4.1.18060.0.4.1.3.806
+ads-replEventLog m-oid=1.3.6.1.4.1.18060.0.4.1.3.805
+ads-saslMechHandler m-oid=1.3.6.1.4.1.18060.0.4.1.3.801
+ads-server m-oid=1.3.6.1.4.1.18060.0.4.1.3.250
+ads-tcpTransport m-oid=1.3.6.1.4.1.18060.0.4.1.3.19
+ads-transport m-oid=1.3.6.1.4.1.18060.0.4.1.3.18
+ads-udpTransport m-oid=1.3.6.1.4.1.18060.0.4.1.3.20
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..70c64da
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=adsconfig,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.1.0.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.1.0.10.ldif
new file mode 100644
index 0000000..3877097
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.1.0.10.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.10,ou=syntaxCheckers,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntaxChecker
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.10
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.SearchScop
+ eSyntaxChecker
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.1.0.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.1.0.11.ldif
new file mode 100644
index 0000000..5982920
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.1.0.11.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.11,ou=syntaxCheckers,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntaxChecker
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.11
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DerefAlias
+ SyntaxChecker
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: 0.9.2342.19200300.100.1.1=admin,2.5.4.11=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes.ldif
new file mode 100644
index 0000000..10a7f0c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=adsconfig,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.10.ldif
new file mode 100644
index 0000000..8246b4c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.10.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.10,ou=syntaxes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.10
+m-description: Search Scope
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
+
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.11.ldif
new file mode 100644
index 0000000..cc03e06
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=adsconfig/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.11.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.11,ou=syntaxes,cn=adsconfig,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.11
+m-description: Deref Alias
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
+
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache.ldif
new file mode 100644
index 0000000..4dcda78
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: cn=apache,ou=schema
+cn: apache
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes.ldif
new file mode 100644
index 0000000..33f3036
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=apache,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.1.16.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.1.16.4.ldif
new file mode 100644
index 0000000..663430e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.1.16.4.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.4,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: UUID of the entry
+m-usage: DIRECTORY_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: uuidOrderingMatch
+m-collective: FALSE
+m-oid: 1.3.6.1.1.16.4
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.1.16.1
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: entryUUID
+m-equality: uuidMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.1.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.1.20.ldif
new file mode 100644
index 0000000..487c720
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.1.20.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.1.20,ou=attributeTypes,cn=apache,ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.20
+m-name: entryDN
+m-description: DN of the entry
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-singlevalue: TRUE
+m-nousermodification: TRUE
+m-usage: DIRECTORY_OPERATION
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.10.ldif
new file mode 100644
index 0000000..8994cea
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.10,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.10
+m-obsolete: FALSE
+m-description: Used to track a subentry associated with an autonomousArea
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DIRECTORY_OPERATION
+m-name: autonomousAreaSubentry
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.11.ldif
new file mode 100644
index 0000000..0a0faf2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.11.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.11,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.11
+m-obsolete: FALSE
+m-description: Used to track a subentry associated with access control areas
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DIRECTORY_OPERATION
+m-name: accessControlSubentries
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.15.ldif
new file mode 100644
index 0000000..13ea1b4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.15.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.15,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.15
+m-obsolete: FALSE
+m-description: A string up to 256 characters in length
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheServicePid
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.16.ldif
new file mode 100644
index 0000000..6ac3fa7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.16.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.16,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.16
+m-obsolete: FALSE
+m-description: A string up to 256 characters in length
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheServiceFactoryPid
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.17.ldif
new file mode 100644
index 0000000..13f8bd1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.17.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.17,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.17
+m-obsolete: FALSE
+m-description: A string up to 256 characters in length
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheCatalogEntryName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.18.ldif
new file mode 100644
index 0000000..c4b2721
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.18.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.18,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.18
+m-obsolete: FALSE
+m-description: A string up to 256 characters in length
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheCatalogEntryBaseDn
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.19.ldif
new file mode 100644
index 0000000..5efdd88
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.19.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.19,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.19
+m-obsolete: FALSE
+m-description: A windows file path where case does not make a difference
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: windowsFilePath
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.20.ldif
new file mode 100644
index 0000000..aebbdc4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.20.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.20,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.20
+m-obsolete: FALSE
+m-description: A UNIX file path where case does make a difference
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: unixFilePath
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.21.ldif
new file mode 100644
index 0000000..86ce84f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.21.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.21,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.21
+m-obsolete: FALSE
+m-description: The fully qualified name for a (Java) class
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: fullyQualifiedJavaClassName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.22.ldif
new file mode 100644
index 0000000..ac3ae1e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.22.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.22,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.22
+m-obsolete: FALSE
+m-description: The actual byte code for a (Java) class
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-name: javaClassByteCode
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.23.ldif
new file mode 100644
index 0000000..23ad94a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.23.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.23,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: The default search context for the Ldap Class Loader
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.23
+m-supattributetype: distinguishedName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: classLoaderDefaultSearchContext
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.25.ldif
new file mode 100644
index 0000000..6f15b0a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.25.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.25,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.25
+m-obsolete: FALSE
+m-description: Trigger specification that applies to a set of entries
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.59
+m-usage: DIRECTORY_OPERATION
+m-name: prescriptiveTriggerSpecification
+creatorsname: uid=admin,ou=system
+m-equality: directoryStringFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.26.ldif
new file mode 100644
index 0000000..d0ea060
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.26.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.26,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.26
+m-obsolete: FALSE
+m-description: Trigger specification that applies to a single entry
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.59
+m-usage: DIRECTORY_OPERATION
+m-name: entryTriggerSpecification
+creatorsname: uid=admin,ou=system
+m-equality: directoryStringFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.27.ldif
new file mode 100644
index 0000000..01e099d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.27.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.27,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.27
+m-obsolete: FALSE
+m-description: Used to track subentries associated with a trigger area which an entry falls under
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DIRECTORY_OPERATION
+m-name: triggerExecutionSubentries
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.3.ldif
new file mode 100644
index 0000000..25416e5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.3.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.3,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: Index attribute used to track the existence of attributes
+m-usage: DSA_OPERATION
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.3
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: apachePresence
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.31.ldif
new file mode 100644
index 0000000..f507797
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.31.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.31,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.31
+m-obsolete: FALSE
+m-description: Whether or not an entry has been deleted.
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-usage: DIRECTORY_OPERATION
+m-name: entryDeleted
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.32.ldif
new file mode 100644
index 0000000..8e7a645
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.32.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.32,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.32
+m-obsolete: FALSE
+m-description: A multivalued comparator description attribute
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: DIRECTORY_OPERATION
+m-name: comparators
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.33.ldif
new file mode 100644
index 0000000..fdd84f9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.33.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.33,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.33
+m-obsolete: FALSE
+m-description: A multivalued normalizer description attribute
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: DIRECTORY_OPERATION
+m-name: normalizers
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.34.ldif
new file mode 100644
index 0000000..d779744
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.34.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.34,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.34
+m-obsolete: FALSE
+m-description: A multivalued syntaxCheckers description attribute
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: DIRECTORY_OPERATION
+m-name: syntaxCheckers
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.35.ldif
new file mode 100644
index 0000000..5e035eb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.35.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.35,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: time which schema was modified
+m-usage: DIRECTORY_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: generalizedTimeOrderingMatch
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.35
+m-supattributetype: modifyTimestamp
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: schemaModifyTimestamp
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.36.ldif
new file mode 100644
index 0000000..7dd9a47
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.36.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.36,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: the DN of the modifier of the schema
+m-usage: DIRECTORY_OPERATION
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.36
+m-supattributetype: modifiersName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: schemaModifiersName
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.37.ldif
new file mode 100644
index 0000000..c9d43ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.37.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.37,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.37
+m-obsolete: FALSE
+m-description: the DN of the schema subentry the modification info corresponds to
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: subschemaSubentryName
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.38.ldif
new file mode 100644
index 0000000..05a9950
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.38.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.38,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.38
+m-obsolete: FALSE
+m-description: The format of the private key used for TLS
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: privateKeyFormat
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.39.ldif
new file mode 100644
index 0000000..1a8e207
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.39.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.39,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.39
+m-obsolete: FALSE
+m-description: The algorithm used for the key/pair used by the server for TLS
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: keyAlgorithm
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.4.ldif
new file mode 100644
index 0000000..3b7bbc4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.4,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.4
+m-obsolete: FALSE
+m-description: Index attribute used to track one level searches
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: DSA_OPERATION
+m-name: apacheOneLevel
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.40.ldif
new file mode 100644
index 0000000..e978fa1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.40.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.40,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.40
+m-obsolete: FALSE
+m-description: The private key material used for TLS
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-name: privateKey
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.41.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.41.ldif
new file mode 100644
index 0000000..ae25eb5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.41.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.41,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.41
+m-obsolete: FALSE
+m-description: The format of the public key used for TLS
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: publicKeyFormat
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.42.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.42.ldif
new file mode 100644
index 0000000..da1cd70
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.42.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.42,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.42
+m-obsolete: FALSE
+m-description: The public key material used for TLS
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-name: publicKey
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.43.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.43.ldif
new file mode 100644
index 0000000..8bec841
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.43.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.43,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.43
+m-obsolete: FALSE
+m-description: Index attribute used to track sub level searches
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: DSA_OPERATION
+m-name: apacheSubLevel
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.44.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.44.ldif
new file mode 100644
index 0000000..93ca8d4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.44.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.44,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: Revision numbers used in change log
+m-usage: DSA_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: integerOrderingMatch
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.44
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: revisions
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.45.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.45.ldif
new file mode 100644
index 0000000..da66ab4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.45.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.45,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: represents the time when the change event occurred
+m-usage: DSA_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: generalizedTimeOrderingMatch
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.45
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: changeTime
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.46.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.46.ldif
new file mode 100644
index 0000000..f67ff30
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.46.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.46,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.46
+m-obsolete: FALSE
+m-description: type of change operation
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+m-usage: DSA_OPERATION
+m-name: changeType
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.47.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.47.ldif
new file mode 100644
index 0000000..c1e844a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.47.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.47,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: the unique sequential id for the event (a.k.a revision number)
+m-usage: DSA_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: integerOrderingMatch
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.47
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: rev
+m-name: eventId
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.48.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.48.ldif
new file mode 100644
index 0000000..20fd899
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.48.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.48,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.48
+m-obsolete: FALSE
+m-description: the principal committing the change
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DSA_OPERATION
+m-name: committer
+creatorsname: uid=admin,ou=system
+m-equality: exactDnAsStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.49.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.49.ldif
new file mode 100644
index 0000000..fd13907
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.49.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.49,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.49
+m-obsolete: FALSE
+m-description: tells about the changelog context suffix
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DSA_OPERATION
+m-name: changeLogContext
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.5.ldif
new file mode 100644
index 0000000..52e9092
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.5,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.5
+m-obsolete: FALSE
+m-description: Index attribute used to track single level aliases
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.1.16.1
+m-usage: DSA_OPERATION
+m-name: apacheOneAlias
+creatorsname: uid=admin,ou=system
+m-equality: uuidMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.50.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.50.ldif
new file mode 100644
index 0000000..6f9bfa5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.50.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.50,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.50
+m-obsolete: FALSE
+m-description: Index attribute RDN with values both user provided and normalized based on schema
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DSA_OPERATION
+m-name: apacheRdn
+creatorsname: uid=admin,ou=system
+m-equality: exactDnAsStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.51.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.51.ldif
new file mode 100644
index 0000000..8a49dd1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.51.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.51,ou=attributeTypes,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.51
+m-description: attribute holding the id of parent entry
+m-usage: DIRECTORY_OPERATION
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-name: entryParentId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
+m-ordering: caseExactOrderingMatch
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.6.ldif
new file mode 100644
index 0000000..a43de2f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.6.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.6,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.6
+m-obsolete: FALSE
+m-description: Index attribute used to track sub level aliases
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.1.16.1
+m-usage: DSA_OPERATION
+m-name: apacheSubAlias
+creatorsname: uid=admin,ou=system
+m-equality: uuidMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.7.ldif
new file mode 100644
index 0000000..744576a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.7.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.7,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.7
+m-obsolete: FALSE
+m-description: asdf
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DSA_OPERATION
+m-name: apacheAlias
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.8.ldif
new file mode 100644
index 0000000..d70bffb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.8.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.8,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.8
+m-obsolete: FALSE
+m-description: Attribute to describe the name of a Java Preferences API node
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: prefNodeName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.9.ldif
new file mode 100644
index 0000000..9b305c4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.2.9.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.9,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.9
+m-obsolete: FALSE
+m-description: Single-use Authentication Mechanism type/vendor code
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheSamType
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.1.ldif
new file mode 100644
index 0000000..89097c8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.1.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.1,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.1
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: storedProcLangId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.2.ldif
new file mode 100644
index 0000000..65782bb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.2.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.2,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.2
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: storedProcUnitName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.4.ldif
new file mode 100644
index 0000000..ae4b84f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.4.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.4,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.4
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-name: javaByteCode
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.6.ldif
new file mode 100644
index 0000000..964877f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.6.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.6,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.6
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: javaxScriptLangId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.7.ldif
new file mode 100644
index 0000000..517b267
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.1.5.7.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.7,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.7
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: javaxScriptCode
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.666.1.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.666.1.25.ldif
new file mode 100644
index 0000000..419d2f4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.666.1.25.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.1.25,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: the largest committed CSN of a context
+m-usage: DIRECTORY_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: csnOrderingMatch
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.4203.666.1.25
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.4203.666.11.2.1
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: contextCSN
+m-equality: csnMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.666.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.666.1.7.ldif
new file mode 100644
index 0000000..89afd93
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.666.1.7.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.1.7,ou=attributeTypes,cn=apache,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: change sequence number of the entry
+m-usage: DIRECTORY_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: csnOrderingMatch
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.4203.666.1.7
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.4203.666.11.2.1
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: entryCSN
+m-equality: csnMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.4.ldif
new file mode 100644
index 0000000..13dd0a1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.24.4,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.24.4
+m-obsolete: FALSE
+m-description: Access control information that applies to a set of entries
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.1
+m-usage: DIRECTORY_OPERATION
+m-name: prescriptiveACI
+creatorsname: uid=admin,ou=system
+m-equality: directoryStringFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.5.ldif
new file mode 100644
index 0000000..419e528
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.24.5,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.24.5
+m-obsolete: FALSE
+m-description: Access control information that applies to a single entry
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.1
+m-usage: DIRECTORY_OPERATION
+m-name: entryACI
+creatorsname: uid=admin,ou=system
+m-equality: directoryStringFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.6.ldif
new file mode 100644
index 0000000..01f40e5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=attributetypes/m-oid=2.5.24.6.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.24.6,ou=attributeTypes,cn=apache,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.24.6
+m-obsolete: FALSE
+m-description: Access control information that applies to a single subentry
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.1
+m-usage: DIRECTORY_OPERATION
+m-name: subentryACI
+creatorsname: uid=admin,ou=system
+m-equality: directoryStringFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators.ldif
new file mode 100644
index 0000000..d3e7b27
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=apache,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.1.16.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.1.16.2.ldif
new file mode 100644
index 0000000..cf36f15
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.1.16.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.2,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.1.16.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.UuidComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.1.16.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.1.16.3.ldif
new file mode 100644
index 0000000..894f9f0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.1.16.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.3,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.1.16.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.UuidComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif
new file mode 100644
index 0000000..379d9df
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.1,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif
new file mode 100644
index 0000000..201d2c9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.2,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.LongComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif
new file mode 100644
index 0000000..8458cd6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.3,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.StringComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif
new file mode 100644
index 0000000..27aea5c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.2,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.CsnComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif
new file mode 100644
index 0000000..8587020
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.3,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.CsnComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif
new file mode 100644
index 0000000..94c8c64
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=comparators/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.5,ou=comparators,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.5
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.CsnSidComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..abe07b8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=apache,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..4aa1b75
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=apache,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules.ldif
new file mode 100644
index 0000000..b0aa4bb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=apache,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.1.16.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.1.16.2.ldif
new file mode 100644
index 0000000..d317e82
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.1.16.2.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.2,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.1.16.2
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.1.16.1
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: uuidMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.1.16.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.1.16.3.ldif
new file mode 100644
index 0000000..9d825ae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.1.16.3.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.3,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.1.16.3
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.1.16.1
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: uuidOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif
new file mode 100644
index 0000000..211470e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.1,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.1
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: exactDnAsStringMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif
new file mode 100644
index 0000000..e0c54ee
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.2,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.2
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: bigIntegerMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif
new file mode 100644
index 0000000..6d7d6c2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.3,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.3
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: jdbmStringMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif
new file mode 100644
index 0000000..8a47dc5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.2,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.2
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.4203.666.11.2.1
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: csnMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif
new file mode 100644
index 0000000..eaef34d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.3,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.3
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.4203.666.11.2.1
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: csnOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif
new file mode 100644
index 0000000..405f313
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.5,ou=matchingRules,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.5
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.4203.666.11.2.4
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: csnSidMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..3b88dc1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=apache,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=nameforms.ldif
new file mode 100644
index 0000000..e5c4d28
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=apache,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers.ldif
new file mode 100644
index 0000000..ae02860
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=apache,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.1.16.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.1.16.2.ldif
new file mode 100644
index 0000000..7f0ac8c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.1.16.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.2,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.1.16.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.1.16.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.1.16.3.ldif
new file mode 100644
index 0000000..0f03a3e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.1.16.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.3,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.1.16.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif
new file mode 100644
index 0000000..a84669c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.1,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif
new file mode 100644
index 0000000..db42978
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.2,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif
new file mode 100644
index 0000000..157686f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.1.1.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.1.3,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.1.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif
new file mode 100644
index 0000000..41a39ae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.2,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif
new file mode 100644
index 0000000..8b01096
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.3,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif
new file mode 100644
index 0000000..7a713c8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=normalizers/m-oid=1.3.6.1.4.1.4203.666.11.2.5.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.5,ou=normalizers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.5
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses.ldif
new file mode 100644
index 0000000..71a5021
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=apache,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.2.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.2.28.ldif
new file mode 100644
index 0000000..8ab1c86
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.2.28.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.2.28,ou=objectClasses,cn=apache,ou=schema
+m-must: prescriptiveTriggerSpecification
+m-oid: 1.3.6.1.4.1.18060.0.4.1.2.28
+m-obsolete: FALSE
+m-description: Used to track a subentry associated with trigger areas
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: triggerExecutionSubentry
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.1.ldif
new file mode 100644
index 0000000..ab6ef85
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.1,ou=objectClasses,cn=apache,ou=schema
+m-must: prefNodeName
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.1
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: prefNode
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.10.ldif
new file mode 100644
index 0000000..4d7d0df
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.10,ou=objectClasses,cn=apache,ou=schema
+m-must: ou
+m-must: subschemaSubentryName
+m-must: schemaModifyTimestamp
+m-must: schemaModifiersName
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.10
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: a special entry tracking schema modification attributes
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: schemaModificationAttributes
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.11.ldif
new file mode 100644
index 0000000..cd31edd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.11.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.11,ou=objectClasses,cn=apache,ou=schema
+m-must: privateKeyFormat
+m-must: keyAlgorithm
+m-must: privateKey
+m-must: publicKeyFormat
+m-must: publicKey
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.11
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: tlsKeyInfo
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.12.ldif
new file mode 100644
index 0000000..0a21b74
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.12.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.12,ou=objectClasses,cn=apache,ou=schema
+m-must: changeTime
+m-must: changeType
+m-must: rev
+m-must: committer
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.12
+m-description: represents change events
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: changeLogEvent
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.13.ldif
new file mode 100644
index 0000000..172e497
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.13.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.13,ou=objectClasses,cn=apache,ou=schema
+m-must: rev
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.13
+m-description: represents a Tag in change log
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: tag
+creatorsname: uid=admin,ou=system
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.3.ldif
new file mode 100644
index 0000000..9fa441c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.3.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.3,ou=objectClasses,cn=apache,ou=schema
+m-must: cn
+m-must: apacheServicePid
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.3
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheServiceConfiguration
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: apacheServiceFactoryPid
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.4.ldif
new file mode 100644
index 0000000..1ddfd09
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.4.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.4,ou=objectClasses,cn=apache,ou=schema
+m-must: cn
+m-must: apacheServicePid
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.4
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheFactoryConfiguration
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.5.ldif
new file mode 100644
index 0000000..d4ff56e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.5.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.5,ou=objectClasses,cn=apache,ou=schema
+m-must: cn
+m-must: apacheCatalogEntryBaseDn
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.5
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheCatalogEntry
+creatorsname: uid=admin,ou=system
+m-may: apacheCatalogEntryName
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.6.ldif
new file mode 100644
index 0000000..bc685fe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.6.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.6,ou=objectClasses,cn=apache,ou=schema
+m-must: windowsFilePath
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.6
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: windowsFile
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.7.ldif
new file mode 100644
index 0000000..6e0b8f7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.7.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.7,ou=objectClasses,cn=apache,ou=schema
+m-must: unixFilePath
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.7
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: unixFile
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.8.ldif
new file mode 100644
index 0000000..fc82c65
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.8.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.8,ou=objectClasses,cn=apache,ou=schema
+m-must: fullyQualifiedJavaClassName
+m-must: javaClassByteCode
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.8
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaClass
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.9.ldif
new file mode 100644
index 0000000..3cadf50
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.3.9.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.3.9,ou=objectClasses,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.1.3.9
+m-obsolete: FALSE
+m-supobjectclass: subschema
+m-description: RFC2252 extension for controlling subschema (sub)entry in ApacheDS
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheSubschema
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: comparators
+m-may: normalizers
+m-may: syntaxCheckers
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.3.ldif
new file mode 100644
index 0000000..b21651b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.3.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.3,ou=objectClasses,cn=apache,ou=schema
+m-must: storedProcLangId
+m-must: storedProcUnitName
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.3
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: storedProcUnit
+m-typeobjectclass: ABSTRACT
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.5.ldif
new file mode 100644
index 0000000..428807b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.5.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.5,ou=objectClasses,cn=apache,ou=schema
+m-must: javaByteCode
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.5
+m-obsolete: FALSE
+m-supobjectclass: storedProcUnit
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaStoredProcUnit
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.8.ldif
new file mode 100644
index 0000000..4fee3f6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.1.5.8.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.5.8,ou=objectClasses,cn=apache,ou=schema
+m-must: javaxScriptLangId
+m-must: javaxScriptCode
+m-oid: 1.3.6.1.4.1.18060.0.4.1.5.8
+m-obsolete: FALSE
+m-supobjectclass: storedProcUnit
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaxScriptStoredProcUnit
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=2.5.17.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=2.5.17.1.ldif
new file mode 100644
index 0000000..01af724
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=objectclasses/m-oid=2.5.17.1.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.17.1,ou=objectClasses,cn=apache,ou=schema
+m-must: prescriptiveACI
+m-oid: 2.5.17.1
+m-obsolete: FALSE
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: accessControlSubentry
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..efe32ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=apache,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.1.16.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.1.16.1.ldif
new file mode 100644
index 0000000..1119f0f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.1.16.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.1,ou=syntaxCheckers,cn=apache,ou=schema
+m-oid: 1.3.6.1.1.16.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.UuidSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.4203.666.11.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.4203.666.11.2.1.ldif
new file mode 100644
index 0000000..1da8498
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.4203.666.11.2.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.1,ou=syntaxCheckers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.CsnSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.4203.666.11.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.4203.666.11.2.4.ldif
new file mode 100644
index 0000000..29db261
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.4203.666.11.2.4.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.4,ou=syntaxCheckers,cn=apache,ou=schema
+m-oid: 1.3.6.1.4.1.4203.666.11.2.4
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.CsnSidSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes.ldif
new file mode 100644
index 0000000..079db3e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=apache,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.1.16.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.1.16.1.ldif
new file mode 100644
index 0000000..e75188e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.1.16.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.16.1,ou=syntaxes,cn=apache,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.16.1
+m-description: UUID
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.0.ldif
new file mode 100644
index 0000000..3c7f97b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.0.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.0,ou=syntaxes,cn=apache,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.0
+m-description: Java Byte
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.2.ldif
new file mode 100644
index 0000000..bef450c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.2.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.2,ou=syntaxes,cn=apache,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.2
+m-description: Java Short
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.3.ldif
new file mode 100644
index 0000000..4121d8a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.3.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.3,ou=syntaxes,cn=apache,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.3
+m-description: Java Long
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.4.ldif
new file mode 100644
index 0000000..3983e0a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.1.0.4.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.1.0.4,ou=syntaxes,cn=apache,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.1.0.4
+m-description: Java Int
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.4203.666.11.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.4203.666.11.2.1.ldif
new file mode 100644
index 0000000..730057d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.4203.666.11.2.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.1,ou=syntaxes,cn=apache,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.4203.666.11.2.1
+m-description: CSN
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.4203.666.11.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.4203.666.11.2.4.ldif
new file mode 100644
index 0000000..643deba
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apache/ou=syntaxes/m-oid=1.3.6.1.4.1.4203.666.11.2.4.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.666.11.2.4,ou=syntaxes,cn=apache,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.4203.666.11.2.4
+m-description: CSN SID
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns.ldif
new file mode 100644
index 0000000..2aaf84b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns.ldif
@@ -0,0 +1,9 @@
+version: 1
+dn: cn=apachedns,ou=schema
+cn: apachedns
+m-disabled: TRUE
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes.ldif
new file mode 100644
index 0000000..dac7625
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=apachedns,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.1.ldif
new file mode 100644
index 0000000..4463f6f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.1.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.1,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.1
+m-obsolete: FALSE
+m-description: The class of a resource record
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsClass
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.10.ldif
new file mode 100644
index 0000000..72d80b5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.10,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.10
+m-obsolete: FALSE
+m-description: A 32 bit time interval that should elapse before a failed refresh should be retired
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsSoaRetry
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.11.ldif
new file mode 100644
index 0000000..e5a52cc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.11.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.11,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.11
+m-obsolete: FALSE
+m-description: A 32 bit time value that specifies the upper limit on the time interval that can elapse before 
+ the zone is no longer authoritative
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsSoaExpire
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.12.ldif
new file mode 100644
index 0000000..833cb5d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.12.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.12,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.12
+m-obsolete: FALSE
+m-description: The unsigned 32 bit minimum TTL field that should be exported with any RR from this zone.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsSoaMinimum
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.13.ldif
new file mode 100644
index 0000000..aa08cdd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.13.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.13,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.13
+m-obsolete: FALSE
+m-description: An integer denoting the mail exchange preference
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsMxPreference
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.14.ldif
new file mode 100644
index 0000000..6361291
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.14.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.14,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.14
+m-obsolete: FALSE
+m-description: The unsigned 16 bit priority of this target host
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsServicePriority
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.15.ldif
new file mode 100644
index 0000000..0b83f33
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.15.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.15,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.15
+m-obsolete: FALSE
+m-description: The unsigned 16 bit weight specifying a relative weight for entries with the same priority
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsServiceWeight
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.16.ldif
new file mode 100644
index 0000000..24b77cd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.16.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.16,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.16
+m-obsolete: FALSE
+m-description: The unsigned 16 bit port on this target host of this service
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsServicePort
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.2.ldif
new file mode 100644
index 0000000..0d18150
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.2.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.2,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.2
+m-obsolete: FALSE
+m-description: An integer denoting time to live
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsTtl
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.3.ldif
new file mode 100644
index 0000000..307ce31
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.3.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.3,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.3
+m-obsolete: FALSE
+m-description: A domain name represented as a sequence of labels
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsDomainName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.4.ldif
new file mode 100644
index 0000000..9cd6455
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.4,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.4
+m-obsolete: FALSE
+m-description: A string up to 256 characters in length
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsCharacterString
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.5.ldif
new file mode 100644
index 0000000..c77fdeb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.5,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.5
+m-obsolete: FALSE
+m-description: A 4 octet IP address
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsIpAddress
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.6.ldif
new file mode 100644
index 0000000..f53124c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.6.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.6,ou=attributeTypes,cn=apachedns,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: The domain name of the name server that was the primary source of data for this zone
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.6
+m-supattributetype: apacheDnsDomainName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsSoaMName
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.7.ldif
new file mode 100644
index 0000000..d06fb29
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.7.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.7,ou=attributeTypes,cn=apachedns,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: The domain name which specifies the mailbox of the person responsible for this zone
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.7
+m-supattributetype: apacheDnsDomainName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsSoaRName
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.8.ldif
new file mode 100644
index 0000000..faa473c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.8.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.8,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.8
+m-obsolete: FALSE
+m-description: The unsigned 32 bit version number of the original copy of the zone
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsSoaSerial
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.9.ldif
new file mode 100644
index 0000000..dbf5f4b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.2.2.9.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.2.9,ou=attributeTypes,cn=apachedns,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.18060.0.4.2.2.9
+m-obsolete: FALSE
+m-description: A 32 bit time interval before the zone should be refreshed
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: apacheDnsSoaRefresh
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=comparators.ldif
new file mode 100644
index 0000000..5b0473c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=apachedns,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..2119617
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=apachedns,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..0addefb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=apachedns,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=matchingrules.ldif
new file mode 100644
index 0000000..bd799e4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=apachedns,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..c151730
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=apachedns,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=nameforms.ldif
new file mode 100644
index 0000000..1fe3235
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=apachedns,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=normalizers.ldif
new file mode 100644
index 0000000..d87e534
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=apachedns,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses.ldif
new file mode 100644
index 0000000..d181599
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=apachedns,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.1.ldif
new file mode 100644
index 0000000..05ef916
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.1.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.1,ou=objectClasses,cn=apachedns,ou=schema
+m-must: cn
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.1
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: An abstract DNS record objectClass used to build other specific structural objectclasses for di
+ fferent record types
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsAbstractRecord
+m-typeobjectclass: ABSTRACT
+creatorsname: uid=admin,ou=system
+m-may: apacheDnsTtl
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.10.ldif
new file mode 100644
index 0000000..c0858b4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.10.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.10,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsDomainName
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.10
+m-obsolete: FALSE
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A non-authoritative referral or delegation name server
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsReferralNameServer
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.11.ldif
new file mode 100644
index 0000000..65b1e12
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.11.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.11,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsDomainName
+m-must: apacheDnsIpAddress
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.11
+m-obsolete: FALSE
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A non-authoritative referral or glue address record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsReferralAddress
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.2.ldif
new file mode 100644
index 0000000..877992e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.2.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.2,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsIpAddress
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.2
+m-obsolete: FALSE
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: An address A record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsAddressRecord
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.3.ldif
new file mode 100644
index 0000000..abdc4d0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.3.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.3,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsDomainName
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.3
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A pointer PTR record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsPointerRecord
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.4.ldif
new file mode 100644
index 0000000..97da96f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.4.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.4,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsDomainName
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.4
+m-obsolete: FALSE
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A name server NS record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsNameServerRecord
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.5.ldif
new file mode 100644
index 0000000..e68bca8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.5.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.5,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsSoaMName
+m-must: apacheDnsSoaRName
+m-must: apacheDnsSoaMinimum
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.5
+m-obsolete: FALSE
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A start of authority SOA record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsStartOfAuthorityRecord
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: apacheDnsClass
+m-may: apacheDnsSoaSerial
+m-may: apacheDnsSoaRefresh
+m-may: apacheDnsSoaRetry
+m-may: apacheDnsSoaExpire
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.6.ldif
new file mode 100644
index 0000000..62e9fc2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.6.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.6,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsDomainName
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.6
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A canonical name CNAME record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsCanonicalNameRecord
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.7.ldif
new file mode 100644
index 0000000..7308549
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.7.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.7,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsMxPreference
+m-must: apacheDnsDomainName
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.7
+m-obsolete: FALSE
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A mail exchange MX record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsMailExchangeRecord
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.8.ldif
new file mode 100644
index 0000000..dffb3f2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.8.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.8,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsCharacterString
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.8
+m-obsolete: FALSE
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A text TXT record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsTextRecord
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.9.ldif
new file mode 100644
index 0000000..b8277d5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.2.3.9.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.2.3.9,ou=objectClasses,cn=apachedns,ou=schema
+m-must: apacheDnsServicePriority
+m-must: apacheDnsServiceWeight
+m-must: apacheDnsServicePort
+m-must: apacheDnsDomainName
+m-oid: 1.3.6.1.4.1.18060.0.4.2.3.9
+m-supobjectclass: apacheDnsAbstractRecord
+m-description: A service SRV record
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: apacheDnsServiceRecord
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..a126253
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=apachedns,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=syntaxes.ldif
new file mode 100644
index 0000000..7da51de
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachedns/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=apachedns,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta.ldif
new file mode 100644
index 0000000..a572ee8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta.ldif
@@ -0,0 +1,7 @@
+version: 1
+dn: cn=apachemeta,ou=schema
+cn: apachemeta
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes.ldif
new file mode 100644
index 0000000..e6e13da
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=apachemeta,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.1.ldif
new file mode 100644
index 0000000..d14ef76
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.1.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.1,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.1
+m-name: m-oid
+m-description: The Object Identifier
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.2
+m-equality: objectIdentifierMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.10.ldif
new file mode 100644
index 0000000..d73d8ae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.10,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.10
+m-name: m-supAttributeType
+m-description: The list of superior
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.11.ldif
new file mode 100644
index 0000000..ab09be3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.11.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.11,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.11
+m-name: m-equality
+m-description: Equality matching rule
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.12.ldif
new file mode 100644
index 0000000..f9fc713
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.12.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.12,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.12
+m-name: m-ordering
+m-description: Ordering matching rule
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.13.ldif
new file mode 100644
index 0000000..58566ee
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.13.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.13,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.13
+m-name: m-substr
+m-description: Substring matching rule
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.14.ldif
new file mode 100644
index 0000000..36e333a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.14.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.14,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.14
+m-name: m-syntax
+m-description: The syntax OID for attributeTypes and matchingRules
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.2
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.15.ldif
new file mode 100644
index 0000000..2f0528b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.15.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.15,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.15
+m-name: m-singleValue
+m-description: The attribute is single valued
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.16.ldif
new file mode 100644
index 0000000..b3ebc00
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.16.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.16,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.16
+m-name: m-collective
+m-description: The attribute is collective
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.17.ldif
new file mode 100644
index 0000000..db8dbb0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.17.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.17,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.17
+m-name: m-noUserModification
+m-description: The attribute is protected
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.18.ldif
new file mode 100644
index 0000000..33b6fae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.18.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.18,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.18
+m-name: m-usage
+m-description: Usage type of an attributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.2.ldif
new file mode 100644
index 0000000..7aa9dc4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.2.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.2,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.2
+m-name: m-name
+m-description: The Object name
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.6
+m-equality: caseIgnoreMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.20.ldif
new file mode 100644
index 0000000..2f05836
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.20.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.20,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.20
+m-name: m-ruleId
+m-description: The rule ID
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.4
+m-equality: ruleIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.21.ldif
new file mode 100644
index 0000000..1012be3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.21.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.21,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.21
+m-name: m-form
+m-description: The name form associated with this DITStructure rule
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: caseIgnoreMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.22.ldif
new file mode 100644
index 0000000..f35bf4c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.22.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.22,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.22
+m-name: m-supDITStructureRule
+m-description: The list of superiors
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.36
+m-equality: supDITStructureRuleMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.24.ldif
new file mode 100644
index 0000000..3bc86d6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.24.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.24,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.24
+m-name: m-oc
+m-description: The structural ObjectClass
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: numericOidMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.26.ldif
new file mode 100644
index 0000000..842e491
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.26.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.26,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.26
+m-name: m-aux
+m-description: List of auxiliary ObjectClasses
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: numericOidMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.27.ldif
new file mode 100644
index 0000000..318467f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.27.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.27,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.27
+m-name: m-not
+m-description: List of precluded attribute types
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: numericOidMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.29.ldif
new file mode 100644
index 0000000..380f941
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.29.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.29,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.29
+m-name: m-applies
+m-description: List of attribute types the matching rule applies to
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: numericOidMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.3.ldif
new file mode 100644
index 0000000..d8d6e4f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.3.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.3,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.3
+m-name: m-description
+m-description: meta descriptive information
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.31.ldif
new file mode 100644
index 0000000..ce4dd62
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.31.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.31,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.31
+m-name: m-matchingRuleSyntax
+m-description: The MatchingRule Syntax
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.2
+m-equality: numericOidMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.32.ldif
new file mode 100644
index 0000000..48b7884
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.32.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.32,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.32
+m-name: m-fqcn
+m-description: The fully qualified class name of a code based schema entity
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseExactMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.33.ldif
new file mode 100644
index 0000000..b8cecbc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.33.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.33,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.33
+m-name: m-bytecode
+m-description: The Java bytecode for a code based schema entity
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.34.ldif
new file mode 100644
index 0000000..1de65e0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.34.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.34,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.34
+m-name: x-not-human-readable
+m-description: whether or not a syntax is human readable
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.35.ldif
new file mode 100644
index 0000000..3ef0a52
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.35.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.35,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.35
+m-name: x-schema
+m-description: Stores the name of the schema 
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.36.ldif
new file mode 100644
index 0000000..b56feae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.36.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.36,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.36
+m-name: x-read-only
+m-description: Tells if the schema element is read-only or not.
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.37.ldif
new file mode 100644
index 0000000..faa290a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.37.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.37,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.37
+m-name: m-disabled
+m-description: Used as a marker for schemas to enable or disable them.
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.38.ldif
new file mode 100644
index 0000000..6359c18
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.38.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.38,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.38
+m-name: m-dependencies
+m-description: The dependencies of a schema: other schema names.
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.39.ldif
new file mode 100644
index 0000000..a4074f7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.39.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.39,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.39
+m-name: m-length
+m-description: The maximum length for an attribute value.
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.4
+m-equality: caseIgnoreMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.4.ldif
new file mode 100644
index 0000000..9650178
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.4,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.4
+m-name: m-obsolete
+m-description: The type is obsolete
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.5.ldif
new file mode 100644
index 0000000..cbca6ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.5,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.5
+m-name: m-supObjectClass
+m-description: The list of superiors
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.6.ldif
new file mode 100644
index 0000000..2503b87
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.6.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.6,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.6
+m-name: m-must
+m-description: The list of mandatory ATs
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.7.ldif
new file mode 100644
index 0000000..07f6280
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.7.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.7,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.7
+m-name: m-may
+m-description: The list of authorized ATs
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-equality: nameOrNumericIdMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.8.ldif
new file mode 100644
index 0000000..d3b2d59
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=attributetypes/m-oid=1.3.6.1.4.1.18060.0.4.0.2.8.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.2.8,ou=attributeTypes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 1.3.6.1.4.1.18060.0.4.0.2.8
+m-name: m-typeObjectClass
+m-description: The objectclass type
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.1
+m-equality: objectClassTypeMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators.ldif
new file mode 100644
index 0000000..2b93148
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=apachemeta,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif
new file mode 100644
index 0000000..f9811ff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.0,ou=comparators,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.0
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.UniqueMemberComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif
new file mode 100644
index 0000000..dc1b0a4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.1,ou=comparators,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ObjectClassTypeComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif
new file mode 100644
index 0000000..0edb759
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.2,ou=comparators,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.StringComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif
new file mode 100644
index 0000000..c6b7cae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.3,ou=comparators,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif
new file mode 100644
index 0000000..b0cd1d0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=comparators/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.4,ou=comparators,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.4
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..54b1c63
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=apachemeta,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..d06c255
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=apachemeta,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules.ldif
new file mode 100644
index 0000000..061eb6e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=apachemeta,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif
new file mode 100644
index 0000000..6889bab
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.0,ou=matchingRules,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.0
+m-obsolete: FALSE
+m-description: A name or numeric id matchingRule
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.0
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: nameOrNumericIdMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif
new file mode 100644
index 0000000..cb15a84
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.1,ou=matchingRules,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.1
+m-obsolete: FALSE
+m-description: objectClassTypeMatch: for mathing AUXILIARY, STRUCTURAL, ABSTRACT
+m-syntax: 1.3.6.1.4.1.18060.0.4.0.0.1
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: objectClassTypeMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif
new file mode 100644
index 0000000..af3cf6f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.2,ou=matchingRules,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.2
+m-obsolete: FALSE
+m-description: a matching rule for numeric oids
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: numericOidMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif
new file mode 100644
index 0000000..7ed53d6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.3,ou=matchingRules,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.3
+m-obsolete: FALSE
+m-description: A matching rule matching dit structure rule attributes
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.17
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: supDITStructureRuleMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif
new file mode 100644
index 0000000..649d0de
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingrules/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.4,ou=matchingRules,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.4
+m-obsolete: FALSE
+m-description: Rule identifier of this DIT structure rule
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: ruleIdMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..42a6b1a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=apachemeta,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=nameforms.ldif
new file mode 100644
index 0000000..89e3a95
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=apachemeta,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers.ldif
new file mode 100644
index 0000000..69ca745
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=apachemeta,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif
new file mode 100644
index 0000000..d15be51
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.0.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.0,ou=normalizers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.0
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NameOrNumericIdNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif
new file mode 100644
index 0000000..271a343
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.1,ou=normalizers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif
new file mode 100644
index 0000000..801dc16
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.2,ou=normalizers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif
new file mode 100644
index 0000000..a8c5230
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.3,ou=normalizers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif
new file mode 100644
index 0000000..6ac3cb4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=normalizers/m-oid=1.3.6.1.4.1.18060.0.4.0.1.4.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.1.4,ou=normalizers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.1.4
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses.ldif
new file mode 100644
index 0000000..f278f37
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=apachemeta,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.1.ldif
new file mode 100644
index 0000000..bc68fe7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.1.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.1,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.1
+m-name: metaTop
+m-description: Top level objectclass of all meta objects
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: ABSTRACT
+m-must: m-oid
+m-may: m-description
+m-may: x-schema
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.10.ldif
new file mode 100644
index 0000000..610ac17
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.10.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.10,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.10
+m-name: metaSyntaxChecker
+m-description: meta definition of the SyntaxChecker object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-must: m-fqcn
+m-may: m-bytecode
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.11.ldif
new file mode 100644
index 0000000..a08b390
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.11.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.11,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.11
+m-name: metaSchema
+m-description: A schema object under which meta schema definitions are found
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: STRUCTURAL
+m-must: cn
+m-may: m-disabled
+m-may: m-dependencies
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.12.ldif
new file mode 100644
index 0000000..4b43ea8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.12.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.12,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.12
+m-name: metaNormalizer
+m-description: meta definition of a Normalizer object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-must: m-fqcn
+m-may: m-bytecode
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.13.ldif
new file mode 100644
index 0000000..cb42a6f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.13.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.13,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.13
+m-name: metaComparator
+m-description: meta definition of a Comparator object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-must: m-fqcn
+m-may: m-bytecode
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.2.ldif
new file mode 100644
index 0000000..98821a5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.2.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.2,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.2
+m-name: metaObjectClass
+m-description: meta definition of the objectclass object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-must: m-oid
+m-may: m-name
+m-may: m-obsolete
+m-may: m-supObjectClass
+m-may: m-typeObjectClass
+m-may: m-must
+m-may: m-may
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.3.ldif
new file mode 100644
index 0000000..c79e628
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.3.ldif
@@ -0,0 +1,24 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.3,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.3
+m-name: metaAttributeType
+m-description: meta definition of the AttributeType object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-may: m-name
+m-may: m-obsolete
+m-may: m-supAttributeType
+m-may: m-equality
+m-may: m-ordering
+m-may: m-substr
+m-may: m-syntax
+m-may: m-singleValue
+m-may: m-collective
+m-may: m-noUserModification
+m-may: m-usage
+m-may: m-length
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.4.ldif
new file mode 100644
index 0000000..667a7ee
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.4.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.4,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.4
+m-name: metaSyntax
+m-description: meta definition of the Syntax object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-may: x-not-human-readable
+m-may: m-obsolete
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.5.ldif
new file mode 100644
index 0000000..3d7c0df
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.5.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.5,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.5
+m-name: metaMatchingRule
+m-description: meta definition of the MatchingRule object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-must: m-syntax
+m-may: m-name
+m-may: m-obsolete
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.6.ldif
new file mode 100644
index 0000000..389c71b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.6.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.6,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.6
+m-name: metaDITStructureRule
+m-description: meta definition of the DITStructureRule object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: STRUCTURAL
+m-must: m-ruleId
+m-must: m-form
+m-may: m-name
+m-may: m-obsolete
+m-may: m-supDITStructureRule
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.7.ldif
new file mode 100644
index 0000000..195b63a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.7.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.7,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.7
+m-name: metaNameForm
+m-description: meta definition of the NameForm object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-must: m-oc
+m-must: m-must
+m-may: m-name
+m-may: m-obsolete
+m-may: m-may
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.8.ldif
new file mode 100644
index 0000000..8a85870
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.8.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.8,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.8
+m-name: metaMatchingRuleUse
+m-description: meta definition of the MatchingRuleUse object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-must: m-applies
+m-may: m-name
+m-may: m-obsolete
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.9.ldif
new file mode 100644
index 0000000..2d9cdc7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=objectclasses/m-oid=1.3.6.1.4.1.18060.0.4.0.3.9.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.3.9,ou=objectClasses,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.3.9
+m-name: metaDITContentRule
+m-description: meta definition of the DITContentRule object
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: metaTop
+m-typeobjectclass: STRUCTURAL
+m-may: m-name
+m-may: m-obsolete
+m-may: m-aux
+m-may: m-must
+m-may: m-may
+m-may: m-not
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..cb7416b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=apachemeta,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.1.ldif
new file mode 100644
index 0000000..b45f9c5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.1,ou=syntaxCheckers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.ObjectClassTypeSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.2.ldif
new file mode 100644
index 0000000..306a484
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.2,ou=syntaxCheckers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.NumericOidSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.4.ldif
new file mode 100644
index 0000000..a747fd9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.4.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.4,ou=syntaxCheckers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.4
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.NumberSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.6.ldif
new file mode 100644
index 0000000..c63ddb0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.18060.0.4.0.0.6.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.6,ou=syntaxCheckers,cn=apachemeta,ou=schema
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.6
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.ObjectNameSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes.ldif
new file mode 100644
index 0000000..5efe966
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=apachemeta,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.0.ldif
new file mode 100644
index 0000000..22daa16
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.0.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.0,ou=syntaxes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.0
+m-description: Numeric IDs Or Names
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.1.ldif
new file mode 100644
index 0000000..9cf2a97
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.1,ou=syntaxes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.1
+m-description: Object Class Type
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.2.ldif
new file mode 100644
index 0000000..8541886
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.2.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.2,ou=syntaxes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.2
+m-description: Numeric OID
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.4.ldif
new file mode 100644
index 0000000..25abb2a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.4.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.4,ou=syntaxes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.4
+m-description: Numeric String
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.6.ldif
new file mode 100644
index 0000000..408767f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=apachemeta/ou=syntaxes/m-oid=1.3.6.1.4.1.18060.0.4.0.0.6.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.18060.0.4.0.0.6,ou=syntaxes,cn=apachemeta,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.18060.0.4.0.0.6
+m-description: Object Name
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs.ldif
new file mode 100644
index 0000000..dc0b1a6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: cn=autofs,ou=schema
+cn: autofs
+m-disabled: TRUE
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+m-dependencies: cosine
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=attributetypes.ldif
new file mode 100644
index 0000000..bf9ada8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=autofs,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=attributetypes/m-oid=1.3.6.1.4.1.2312.4.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=attributetypes/m-oid=1.3.6.1.4.1.2312.4.1.2.ldif
new file mode 100644
index 0000000..a4f573b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=attributetypes/m-oid=1.3.6.1.4.1.2312.4.1.2.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.2312.4.1.2,ou=attributeTypes,cn=autofs,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.2312.4.1.2
+m-obsolete: FALSE
+m-description: Information used by the autofs automounter
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: automountInformation
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=comparators.ldif
new file mode 100644
index 0000000..4d6d394
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=autofs,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..4dc3db2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=autofs,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..142d569
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=autofs,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=matchingrules.ldif
new file mode 100644
index 0000000..0c5f2a1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=autofs,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..66d59f0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=autofs,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=nameforms.ldif
new file mode 100644
index 0000000..f4c838b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=autofs,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=normalizers.ldif
new file mode 100644
index 0000000..c1420af
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=autofs,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses.ldif
new file mode 100644
index 0000000..0a8de86
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=autofs,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses/m-oid=1.3.6.1.4.1.2312.4.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses/m-oid=1.3.6.1.4.1.2312.4.2.2.ldif
new file mode 100644
index 0000000..a816523
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses/m-oid=1.3.6.1.4.1.2312.4.2.2.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.2312.4.2.2,ou=objectClasses,cn=autofs,ou=schema
+m-must: ou
+m-oid: 1.3.6.1.4.1.2312.4.2.2
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: An group of related automount objects
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: automountMap
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses/m-oid=1.3.6.1.4.1.2312.4.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses/m-oid=1.3.6.1.4.1.2312.4.2.3.ldif
new file mode 100644
index 0000000..1dfc09c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=objectclasses/m-oid=1.3.6.1.4.1.2312.4.2.3.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.2312.4.2.3,ou=objectClasses,cn=autofs,ou=schema
+m-must: cn
+m-must: automountInformation
+m-oid: 1.3.6.1.4.1.2312.4.2.3
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: An entry in an automounter map
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: automount
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..f25ca7a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=autofs,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=syntaxes.ldif
new file mode 100644
index 0000000..1e7551b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=autofs/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=autofs,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective.ldif
new file mode 100644
index 0000000..4689f76
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: cn=collective,ou=schema
+cn: collective
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes.ldif
new file mode 100644
index 0000000..823c84c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=collective,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.10.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.10.1.ldif
new file mode 100644
index 0000000..3e8f415
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.10.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.10.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.10.1
+m-supattributetype: o
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-o
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.11.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.11.1.ldif
new file mode 100644
index 0000000..f8b2214
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.11.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.11.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.11.1
+m-supattributetype: ou
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-ou
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.16.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.16.1.ldif
new file mode 100644
index 0000000..c2e3d88
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.16.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.16.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.16.1
+m-supattributetype: postalAddress
+m-substr: caseIgnoreListSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.41
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-PostalAddress
+m-equality: caseIgnoreListMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.17.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.17.1.ldif
new file mode 100644
index 0000000..1156031
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.17.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.17.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.17.1
+m-supattributetype: postalCode
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-PostalCode
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.18.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.18.1.ldif
new file mode 100644
index 0000000..4548f62
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.18.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.18.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.18.1
+m-supattributetype: postOfficeBox
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-PostOfficeBox
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.19.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.19.1.ldif
new file mode 100644
index 0000000..e8e2880
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.19.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.19.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.19.1
+m-supattributetype: physicalDeliveryOfficeName
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-PhysicalDeliveryOfficeName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.20.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.20.1.ldif
new file mode 100644
index 0000000..aa14371
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.20.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.20.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.20.1
+m-supattributetype: telephoneNumber
+m-substr: telephoneNumberSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.50
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-TelephoneNumber
+m-equality: telephoneNumberMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.21.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.21.1.ldif
new file mode 100644
index 0000000..b4c6152
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.21.1.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.4.21.1,ou=attributeTypes,cn=collective,ou=schema
+m-collective: TRUE
+m-singlevalue: FALSE
+m-oid: 2.5.4.21.1
+m-obsolete: FALSE
+m-supattributetype: telexNumber
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.52
+m-usage: USER_APPLICATIONS
+m-name: c-TelexNumber
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.23.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.23.1.ldif
new file mode 100644
index 0000000..b4354ae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.23.1.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.4.23.1,ou=attributeTypes,cn=collective,ou=schema
+m-collective: TRUE
+m-singlevalue: FALSE
+m-oid: 2.5.4.23.1
+m-obsolete: FALSE
+m-supattributetype: facsimileTelephoneNumber
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.22
+m-usage: USER_APPLICATIONS
+m-name: c-FacsimileTelephoneNumber
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.25.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.25.1.ldif
new file mode 100644
index 0000000..93bce00
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.25.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.25.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.25.1
+m-supattributetype: internationaliSDNNumber
+m-substr: numericStringSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.36
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-InternationalISDNNumber
+m-equality: numericStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.7.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.7.1.ldif
new file mode 100644
index 0000000..caafea7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.7.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.7.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.7.1
+m-supattributetype: l
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-l
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.8.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.8.1.ldif
new file mode 100644
index 0000000..8a4fe05
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.8.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.8.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.8.1
+m-supattributetype: st
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-st
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.9.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.9.1.ldif
new file mode 100644
index 0000000..daa0527
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=attributetypes/m-oid=2.5.4.9.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.9.1,ou=attributeTypes,cn=collective,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: TRUE
+m-oid: 2.5.4.9.1
+m-supattributetype: street
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c-street
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=comparators.ldif
new file mode 100644
index 0000000..947b6f1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=collective,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..c2f5d1b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=collective,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..8a3d116
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=collective,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=matchingrules.ldif
new file mode 100644
index 0000000..20ad146
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=collective,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..98c6c54
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=collective,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=nameforms.ldif
new file mode 100644
index 0000000..d2f401a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=collective,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=normalizers.ldif
new file mode 100644
index 0000000..ece9ad7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=collective,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=objectclasses.ldif
new file mode 100644
index 0000000..23add94
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=collective,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..c108b18
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=collective,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=syntaxes.ldif
new file mode 100644
index 0000000..f3f11f1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=collective/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=collective,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba.ldif
new file mode 100644
index 0000000..ca9156d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba.ldif
@@ -0,0 +1,9 @@
+version: 1
+dn: cn=corba,ou=schema
+cn: corba
+m-disabled: TRUE
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes.ldif
new file mode 100644
index 0000000..5a85bf0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=corba,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.14.ldif
new file mode 100644
index 0000000..16b1431
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.14.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.14,ou=attributeTypes,cn=corba,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.14
+m-obsolete: FALSE
+m-description: Stringified interoperable object reference of a CORBA object
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: corbaIor
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.15.ldif
new file mode 100644
index 0000000..97a2366
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.15.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.15,ou=attributeTypes,cn=corba,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.15
+m-obsolete: FALSE
+m-description: Repository ids of interfaces implemented by a CORBA object
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: corbaRepositoryId
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=comparators.ldif
new file mode 100644
index 0000000..f018a70
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=corba,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..d865928
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=corba,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..a453920
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=corba,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=matchingrules.ldif
new file mode 100644
index 0000000..6cb5960
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=corba,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..c267715
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=corba,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=nameforms.ldif
new file mode 100644
index 0000000..859683e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=corba,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=normalizers.ldif
new file mode 100644
index 0000000..da547ff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=corba,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses.ldif
new file mode 100644
index 0000000..9c548e7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=corba,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.10.ldif
new file mode 100644
index 0000000..2ad0c9b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.10.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.10,ou=objectClasses,cn=corba,ou=schema
+m-must: cn
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.10
+m-supobjectclass: top
+m-description: Container for a CORBA object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: corbaContainer
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.11.ldif
new file mode 100644
index 0000000..d6e10b2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.11.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.11,ou=objectClasses,cn=corba,ou=schema
+m-must: corbaIor
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.11
+m-obsolete: FALSE
+m-supobjectclass: corbaObject
+m-description: CORBA interoperable object reference
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: corbaObjectReference
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.9.ldif
new file mode 100644
index 0000000..07f6b8c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.9.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.9,ou=objectClasses,cn=corba,ou=schema
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.9
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: CORBA object representation
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: corbaObject
+m-typeobjectclass: ABSTRACT
+creatorsname: uid=admin,ou=system
+m-may: corbaRepositoryId
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..6e6935f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=corba,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=syntaxes.ldif
new file mode 100644
index 0000000..712c7a0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=corba/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=corba,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core.ldif
new file mode 100644
index 0000000..34e0a8b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core.ldif
@@ -0,0 +1,7 @@
+version: 1
+dn: cn=core,ou=schema
+cn: core
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes.ldif
new file mode 100644
index 0000000..90f13d0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=core,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.1.ldif
new file mode 100644
index 0000000..5491672
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.1.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.1,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: user identifier
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.1
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: uid
+m-name: userid
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.25.ldif
new file mode 100644
index 0000000..77ff0ea
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.25.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.25,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: RFC1274/2247: domain component
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.25
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: dc
+m-name: domainComponent
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.3.ldif
new file mode 100644
index 0000000..aaca75f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.3.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.3,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: RFC822 Mailbox
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.3
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: mail
+m-name: rfc822Mailbox
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.37.ldif
new file mode 100644
index 0000000..d8d4be3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.37.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.37,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: domain associated with object
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.37
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: associatedDomain
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=1.2.840.113549.1.9.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=1.2.840.113549.1.9.1.ldif
new file mode 100644
index 0000000..ea99059
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=1.2.840.113549.1.9.1.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=1.2.840.113549.1.9.1,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2459: legacy attribute for email addresses in DNs
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.2.840.113549.1.9.1
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: email
+m-name: emailAddress
+m-name: pkcs9email
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.10.ldif
new file mode 100644
index 0000000..eabbcaf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.10.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.10,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: organization this object belongs to
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.10
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: o
+m-name: organizationName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.11.ldif
new file mode 100644
index 0000000..678766b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.11.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.11,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: organizational unit this object belongs to
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.11
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: ou
+m-name: organizationalUnitName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.12.ldif
new file mode 100644
index 0000000..d15b3bf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.12.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.4.12,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: title associated with the entity
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.12
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: title
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.13.ldif
new file mode 100644
index 0000000..d7ba6a3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.13.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.13,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: descriptive information
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.13
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: description
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.14.ldif
new file mode 100644
index 0000000..63ec396
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.14.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.4.14,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.14
+m-obsolete: FALSE
+m-description: RFC2256: search guide, obsoleted by enhancedSearchGuide
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.25
+m-usage: USER_APPLICATIONS
+m-name: searchGuide
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.15.ldif
new file mode 100644
index 0000000..1b4e28a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.15.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.15,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: business category
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.15
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: businessCategory
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.16.ldif
new file mode 100644
index 0000000..a17eb56
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.16.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.16,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: postal address
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.16
+m-substr: caseIgnoreListSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.41
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: postalAddress
+m-equality: caseIgnoreListMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.17.ldif
new file mode 100644
index 0000000..22e93f3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.17.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.17,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: postal code
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.17
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: postalCode
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.18.ldif
new file mode 100644
index 0000000..eb82236
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.18.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.18,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: Post Office Box
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.18
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: postOfficeBox
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.19.ldif
new file mode 100644
index 0000000..c3d7637
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.19.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.19,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: Physical Delivery Office Name
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.19
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: physicalDeliveryOfficeName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.2.ldif
new file mode 100644
index 0000000..d0088f3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.2.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.2,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.2
+m-obsolete: FALSE
+m-description: RFC2256: knowledge information
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: knowledgeInformation
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.20.ldif
new file mode 100644
index 0000000..bb966c9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.20.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.20,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: Telephone Number
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.20
+m-substr: telephoneNumberSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.50
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: telephoneNumber
+m-equality: telephoneNumberMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.21.ldif
new file mode 100644
index 0000000..c819f4f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.21.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.4.21,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.21
+m-obsolete: FALSE
+m-description: RFC2256: Telex Number
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.52
+m-usage: USER_APPLICATIONS
+m-name: telexNumber
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.22.ldif
new file mode 100644
index 0000000..05b9fcc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.22.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.4.22,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.22
+m-obsolete: FALSE
+m-description: RFC2256: Teletex Terminal Identifier
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.51
+m-usage: USER_APPLICATIONS
+m-name: teletexTerminalIdentifier
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.23.ldif
new file mode 100644
index 0000000..2550840
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.23.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.23,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.23
+m-obsolete: FALSE
+m-description: RFC2256: Facsimile (Fax) Telephone Number
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.22
+m-usage: USER_APPLICATIONS
+m-name: facsimileTelephoneNumber
+m-name: fax
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.24.ldif
new file mode 100644
index 0000000..7395e8c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.24.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.24,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: X.121 Address
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.24
+m-substr: numericStringSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.36
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: x121Address
+m-equality: numericStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.25.ldif
new file mode 100644
index 0000000..2c69f20
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.25.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.25,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: international ISDN number
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.25
+m-substr: numericStringSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.36
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: internationaliSDNNumber
+m-equality: numericStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.26.ldif
new file mode 100644
index 0000000..48d76ff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.26.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.4.26,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: registered postal address
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.26
+m-supattributetype: postalAddress
+m-substr: caseIgnoreListSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.41
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: registeredAddress
+m-equality: caseIgnoreListMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.27.ldif
new file mode 100644
index 0000000..0fe05b7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.27.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.27,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: destination indicator
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.27
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: destinationIndicator
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.28.ldif
new file mode 100644
index 0000000..f54f336
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.28.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.4.28,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.4.28
+m-obsolete: FALSE
+m-description: RFC2256: preferred delivery method
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.14
+m-usage: USER_APPLICATIONS
+m-name: preferredDeliveryMethod
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.29.ldif
new file mode 100644
index 0000000..ef37853
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.29.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.29,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.4.29
+m-obsolete: FALSE
+m-description: RFC2256: presentation address
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.43
+m-usage: USER_APPLICATIONS
+m-name: presentationAddress
+creatorsname: uid=admin,ou=system
+m-equality: presentationAddressMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.30.ldif
new file mode 100644
index 0000000..d6f13bc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.30.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.30,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.30
+m-obsolete: FALSE
+m-description: RFC2256: supported application context
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: USER_APPLICATIONS
+m-name: supportedApplicationContext
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.31.ldif
new file mode 100644
index 0000000..bbb6be5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.31.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.31,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: member of a group
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.31
+m-supattributetype: distinguishedName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: member
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.32.ldif
new file mode 100644
index 0000000..6b4edfd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.32.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.32,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: owner (of the object)
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.32
+m-supattributetype: distinguishedName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: owner
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.33.ldif
new file mode 100644
index 0000000..a39a567
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.33.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.33,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: occupant of role
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.33
+m-supattributetype: distinguishedName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: roleOccupant
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.34.ldif
new file mode 100644
index 0000000..ad0fbf6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.34.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.34,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: DN of related object
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.34
+m-supattributetype: distinguishedName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: seeAlso
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.36.ldif
new file mode 100644
index 0000000..6d66b1d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.36.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.36,ou=attributeTypes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 2.5.4.36
+m-name: userCertificate
+m-description: X.509 user certificate
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.8
+m-equality: certificateExactMatch
+m-usage: USER_APPLICATIONS
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.37.ldif
new file mode 100644
index 0000000..e908d0c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.37.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.37,ou=attributeTypes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 2.5.4.37
+m-name: cACertificate
+m-description: X.509 CA certificate
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.8
+m-equality: certificateExactMatch
+m-collective: FALSE
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.38.ldif
new file mode 100644
index 0000000..435f347
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.38.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.38,ou=attributeTypes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 2.5.4.38
+m-name: authorityRevocationList
+m-description: X.509 authority revocation list
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.9
+m-equality: certificateListExactMatch
+m-collective: FALSE
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.39.ldif
new file mode 100644
index 0000000..7651056
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.39.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.39,ou=attributeTypes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 2.5.4.39
+m-name: certificateRevocationList
+m-description: X.509 certificate revocation list
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.9
+m-equality: certificateListExactMatch
+m-collective: FALSE
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.4.ldif
new file mode 100644
index 0000000..de7325a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.4.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.4,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: last (family) name(s) for which the entity is known by
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.4
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: sn
+m-name: surname
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.40.ldif
new file mode 100644
index 0000000..832f53a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.40.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.40,ou=attributeTypes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 2.5.4.40
+m-name: crossCertificatePair
+m-description: X.509 cross certificate pair
+m-equality: certificatePairExactMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.10
+m-collective: FALSE
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.42.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.42.ldif
new file mode 100644
index 0000000..6e91612
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.42.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.42,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: first name(s) for which the entity is known by
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.42
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: givenName
+m-name: gn
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.43.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.43.ldif
new file mode 100644
index 0000000..76c6906
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.43.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.4.43,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: initials of some or all of names, but not the surname(s).
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.43
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: initials
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.44.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.44.ldif
new file mode 100644
index 0000000..550eee0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.44.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.4.44,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: name qualifier indicating a generation
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.44
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: generationQualifier
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.45.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.45.ldif
new file mode 100644
index 0000000..4dbf410
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.45.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.45,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.45
+m-obsolete: FALSE
+m-description: RFC2256: X.500 unique identifier
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.6
+m-usage: USER_APPLICATIONS
+m-name: x500UniqueIdentifier
+creatorsname: uid=admin,ou=system
+m-equality: bitStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.46.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.46.ldif
new file mode 100644
index 0000000..e9cc0fa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.46.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.4.46,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: DN qualifier
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-ordering: caseIgnoreOrderingMatch
+m-collective: FALSE
+m-oid: 2.5.4.46
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: dnQualifier
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.47.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.47.ldif
new file mode 100644
index 0000000..a96ebda
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.47.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.4.47,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.47
+m-obsolete: FALSE
+m-description: RFC2256: enhanced search guide
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.21
+m-usage: USER_APPLICATIONS
+m-name: enhancedSearchGuide
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.48.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.48.ldif
new file mode 100644
index 0000000..5a6d503
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.48.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.48,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.48
+m-obsolete: FALSE
+m-description: RFC2256: protocol information
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.42
+m-usage: USER_APPLICATIONS
+m-name: protocolInformation
+creatorsname: uid=admin,ou=system
+m-equality: protocolInformationMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.5.ldif
new file mode 100644
index 0000000..dc4fc49
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.5.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.5,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: serial number of the entity
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.5
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.44
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: serialNumber
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.50.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.50.ldif
new file mode 100644
index 0000000..065fd0f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.50.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.50,ou=attributeTypes,cn=core,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.50
+m-obsolete: FALSE
+m-description: RFC2256: unique member of a group
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.34
+m-usage: USER_APPLICATIONS
+m-name: uniqueMember
+creatorsname: uid=admin,ou=system
+m-equality: uniqueMemberMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.51.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.51.ldif
new file mode 100644
index 0000000..f10bbbe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.51.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.51,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: house identifier
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.51
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: houseIdentifier
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.52.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.52.ldif
new file mode 100644
index 0000000..62f386f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.52.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.52,ou=attributeTypes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 2.5.4.52
+m-name: supportedAlgorithms
+m-description: X.509 supported algorithms
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.49
+m-equality: algorithmIdentifierMatch
+m-collective: FALSE
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.53.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.53.ldif
new file mode 100644
index 0000000..d5490f5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.53.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.53,ou=attributeTypes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-oid: 2.5.4.53
+m-name: deltaRevocationList
+m-description: X.509 delta revocation list
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.9
+m-equality: certificateListExactMatch
+m-collective: FALSE
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.54.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.54.ldif
new file mode 100644
index 0000000..924d72f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.54.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.4.54,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: name of DMD
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.54
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: dmdName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.6.ldif
new file mode 100644
index 0000000..e6127d8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.6.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.6,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: RFC2256: ISO-3166 country 2-letter code
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.6
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: c
+m-name: countryName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.7.ldif
new file mode 100644
index 0000000..3777504
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.7.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.7,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: locality which this object resides in
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.7
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: l
+m-name: localityName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.8.ldif
new file mode 100644
index 0000000..38b2b47
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.8.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.8,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: state or province which this object resides in
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.8
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: st
+m-name: stateOrProvinceName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.9.ldif
new file mode 100644
index 0000000..1565150
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=attributetypes/m-oid=2.5.4.9.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.4.9,ou=attributeTypes,cn=core,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: street address of this object
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.9
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: street
+m-name: streetAddress
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=comparators.ldif
new file mode 100644
index 0000000..972206c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=core,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=comparators/m-oid=2.5.13.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=comparators/m-oid=2.5.13.34.ldif
new file mode 100644
index 0000000..477583d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=comparators/m-oid=2.5.13.34.ldif
@@ -0,0 +1,9 @@
+version: 1
+dn: m-oid=2.5.13.34,ou=comparators,cn=core,ou=schema
+m-oid: 2.5.13.34
+m-name: certificateEqualityMatch
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.CertificateComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..05f135d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=core,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..0a78203
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=core,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules.ldif
new file mode 100644
index 0000000..b6bb8e8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=core,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.34.ldif
new file mode 100644
index 0000000..92a2e91
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.34.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.13.34,ou=matchingRules,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaMatchingRule
+m-oid: 2.5.13.34
+m-name: certificateExactMatch
+m-description: X.509 Certificate Exact Match
+m-syntax: 1.3.6.1.1.15.1
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.35.ldif
new file mode 100644
index 0000000..9fd3f5d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.35.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.13.35,ou=matchingRules,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaMatchingRule
+m-oid: 2.5.13.35
+m-name: certificateMatch
+m-description: X.509 Certificate Match
+m-syntax: 1.3.6.1.1.15.2
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.36.ldif
new file mode 100644
index 0000000..83833a1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.36.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.13.36,ou=matchingRules,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaMatchingRule
+m-oid: 2.5.13.36
+m-name: certificatePairExactMatch
+m-description: X.509 Certificate Pair Exact Match
+m-syntax: 1.3.6.1.1.15.3
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.37.ldif
new file mode 100644
index 0000000..78531b9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.37.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.13.37,ou=matchingRules,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaMatchingRule
+m-oid: 2.5.13.37
+m-name: certificatePairMatch
+m-description: X.509 Certificate Pair Match
+m-syntax: 1.3.6.1.1.15.4
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.38.ldif
new file mode 100644
index 0000000..15d865e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.38.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.13.38,ou=matchingRules,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaMatchingRule
+m-oid: 2.5.13.38
+m-name: certificateListExactMatch
+m-description: X.509 Certificate List Exact Match
+m-syntax: 1.3.6.1.1.15.5
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.39.ldif
new file mode 100644
index 0000000..ff4d733
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.39.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.13.39,ou=matchingRules,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaMatchingRule
+m-oid: 2.5.13.39
+m-name: certificateListMatch
+m-description: X.509 Certificate List Match
+m-syntax: 1.3.6.1.1.15.6
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.40.ldif
new file mode 100644
index 0000000..05ed3b5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingrules/m-oid=2.5.13.40.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=2.5.13.40,ou=matchingRules,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaMatchingRule
+m-oid: 2.5.13.40
+m-name: algorithmIdentifierMatch
+m-description: X.509 Algorithm Identifier Match
+m-syntax: 1.3.6.1.1.15.7
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..c6d7016
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=core,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=nameforms.ldif
new file mode 100644
index 0000000..be92b6a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=core,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=normalizers.ldif
new file mode 100644
index 0000000..9432efb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=core,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses.ldif
new file mode 100644
index 0000000..cab360b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=core,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.19.ldif
new file mode 100644
index 0000000..60acfce
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.19.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.19,ou=objectClasses,cn=core,ou=schema
+m-must: userPassword
+m-oid: 0.9.2342.19200300.100.4.19
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC1274: simple security object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: simpleSecurityObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.1.3.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.1.3.1.ldif
new file mode 100644
index 0000000..8692c06
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.1.3.1.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.1.3.1,ou=objectClasses,cn=core,ou=schema
+m-must: uid
+m-oid: 1.3.6.1.1.3.1
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2377: uid object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: uidObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.344.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.344.ldif
new file mode 100644
index 0000000..7b0f766
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.344.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.344,ou=objectClasses,cn=core,ou=schema
+m-must: dc
+m-oid: 1.3.6.1.4.1.1466.344
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2247: domain component object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dcObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.4.1.250.3.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.4.1.250.3.15.ldif
new file mode 100644
index 0000000..d622bc9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=1.3.6.1.4.1.250.3.15.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.250.3.15,ou=objectClasses,cn=core,ou=schema
+m-oid: 1.3.6.1.4.1.250.3.15
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2079: object that contains the URI attribute type
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: labeledURIObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: labeledURI
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.10.ldif
new file mode 100644
index 0000000..dee7571
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.10.ldif
@@ -0,0 +1,29 @@
+version: 1
+dn: m-oid=2.5.6.10,ou=objectClasses,cn=core,ou=schema
+m-must: l
+m-oid: 2.5.6.10
+m-obsolete: FALSE
+m-supobjectclass: person
+m-description: RFC2256: an residential person
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: residentialPerson
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: businessCategory
+m-may: x121Address
+m-may: registeredAddress
+m-may: destinationIndicator
+m-may: preferredDeliveryMethod
+m-may: telexNumber
+m-may: teletexTerminalIdentifier
+m-may: telephoneNumber
+m-may: internationaliSDNNumber
+m-may: facsimileTelephoneNumber
+m-may: street
+m-may: postOfficeBox
+m-may: postalCode
+m-may: postalAddress
+m-may: physicalDeliveryOfficeName
+m-may: st
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.11.ldif
new file mode 100644
index 0000000..1e06caa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.11.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.6.11,ou=objectClasses,cn=core,ou=schema
+m-must: cn
+m-oid: 2.5.6.11
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: an application process
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: applicationProcess
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: seeAlso
+m-may: ou
+m-may: l
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.12.ldif
new file mode 100644
index 0000000..5a4a4f7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.12.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: m-oid=2.5.6.12,ou=objectClasses,cn=core,ou=schema
+m-must: presentationAddress
+m-must: cn
+m-oid: 2.5.6.12
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: an application entity
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: applicationEntity
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: supportedApplicationContext
+m-may: seeAlso
+m-may: ou
+m-may: o
+m-may: l
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.13.ldif
new file mode 100644
index 0000000..0af5348
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.13.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.6.13,ou=objectClasses,cn=core,ou=schema
+m-oid: 2.5.6.13
+m-obsolete: FALSE
+m-supobjectclass: applicationEntity
+m-description: RFC2256: a directory system agent (a server)
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dSA
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: knowledgeInformation
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.14.ldif
new file mode 100644
index 0000000..ba52356
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.14.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: m-oid=2.5.6.14,ou=objectClasses,cn=core,ou=schema
+m-must: cn
+m-oid: 2.5.6.14
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: a device
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: device
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: serialNumber
+m-may: seeAlso
+m-may: owner
+m-may: ou
+m-may: o
+m-may: l
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.15.ldif
new file mode 100644
index 0000000..bd79dfb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.15.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.6.15,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.15
+m-name: strongAuthenticationUser
+m-description: X.521 strong authentication user
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-must: userCertificate
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.16.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.16.2.ldif
new file mode 100644
index 0000000..1cf5100
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.16.2.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.6.16.2,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.16.2
+m-name: certificationAuthority-V2
+m-description: X.509 certificate authority, version 2
+m-supobjectclass: certificationAuthority
+m-typeobjectclass: AUXILIARY
+m-may: deltaRevocationList
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.16.ldif
new file mode 100644
index 0000000..eea21c6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.16.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.6.16,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.16
+m-name: certificationAuthority
+m-description: X.509 certificate authority
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-must: authorityRevocationList
+m-must: certificateRevocationList
+m-must: cACertificate
+m-may: crossCertificatePair
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.17.ldif
new file mode 100644
index 0000000..f7cd53f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.17.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: m-oid=2.5.6.17,ou=objectClasses,cn=core,ou=schema
+m-must: uniqueMember
+m-must: cn
+m-oid: 2.5.6.17
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: a group of unique names (DN and Unique Identifier)
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: groupOfUniqueNames
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: businessCategory
+m-may: seeAlso
+m-may: owner
+m-may: ou
+m-may: o
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.18.ldif
new file mode 100644
index 0000000..5d226cb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.18.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.6.18,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.18
+m-name: userSecurityInformation
+m-description: X.521 user security information
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-may: supportedAlgorithms
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.19.ldif
new file mode 100644
index 0000000..315fa26
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.19.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.6.19,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.19
+m-name: cRLDistributionPoint
+m-description: X.509 CRL distribution point
+m-supobjectclass: top
+m-typeobjectclass: STRUCTURAL
+m-must: cn
+m-may: certificateRevocationList
+m-may: authorityRevocationList
+m-may: deltaRevocationList
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.2.ldif
new file mode 100644
index 0000000..b62a8e0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.2.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.6.2,ou=objectClasses,cn=core,ou=schema
+m-must: c
+m-oid: 2.5.6.2
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: a country
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: country
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: searchGuide
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.20.ldif
new file mode 100644
index 0000000..6c65145
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.20.ldif
@@ -0,0 +1,33 @@
+version: 1
+dn: m-oid=2.5.6.20,ou=objectClasses,cn=core,ou=schema
+m-must: dmdName
+m-oid: 2.5.6.20
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dmd
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: userPassword
+m-may: searchGuide
+m-may: seeAlso
+m-may: businessCategory
+m-may: x121Address
+m-may: registeredAddress
+m-may: destinationIndicator
+m-may: preferredDeliveryMethod
+m-may: telexNumber
+m-may: teletexTerminalIdentifier
+m-may: telephoneNumber
+m-may: internationaliSDNNumber
+m-may: facsimileTelephoneNumber
+m-may: street
+m-may: postOfficeBox
+m-may: postalCode
+m-may: postalAddress
+m-may: physicalDeliveryOfficeName
+m-may: st
+m-may: l
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.21.ldif
new file mode 100644
index 0000000..12201e4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.21.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.6.21,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.21
+m-name: pkiUser
+m-description: X.509 PKI User
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-may: userCertificate
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.22.ldif
new file mode 100644
index 0000000..cfc37ed
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.22.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.6.22,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.22
+m-name: pkiCA
+m-description: X.509 PKI Certificate Authority
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-may: cACertificate
+m-may: certificateRevocationList
+m-may: authorityRevocationList
+m-may: crossCertificatePair
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.23.ldif
new file mode 100644
index 0000000..d5c5f80
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.23.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.6.23,ou=objectClasses,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-oid: 2.5.6.23
+m-name: deltaCRL
+m-description: X.509 delta CRL
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-may: deltaRevocationList
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.3.ldif
new file mode 100644
index 0000000..d256477
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.3.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.6.3,ou=objectClasses,cn=core,ou=schema
+m-oid: 2.5.6.3
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: a locality
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: locality
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: searchGuide
+m-may: description
+m-may: street
+m-may: seeAlso
+m-may: st
+m-may: l
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.4.ldif
new file mode 100644
index 0000000..fc64064
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.4.ldif
@@ -0,0 +1,34 @@
+version: 1
+dn: m-oid=2.5.6.4,ou=objectClasses,cn=core,ou=schema
+m-must: o
+m-oid: 2.5.6.4
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: an organization
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: organization
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: userPassword
+m-may: searchGuide
+m-may: seeAlso
+m-may: businessCategory
+m-may: x121Address
+m-may: registeredAddress
+m-may: destinationIndicator
+m-may: preferredDeliveryMethod
+m-may: telexNumber
+m-may: teletexTerminalIdentifier
+m-may: telephoneNumber
+m-may: internationaliSDNNumber
+m-may: facsimileTelephoneNumber
+m-may: street
+m-may: postOfficeBox
+m-may: postalCode
+m-may: postalAddress
+m-may: physicalDeliveryOfficeName
+m-may: st
+m-may: l
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.5.ldif
new file mode 100644
index 0000000..1630d2e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.5.ldif
@@ -0,0 +1,34 @@
+version: 1
+dn: m-oid=2.5.6.5,ou=objectClasses,cn=core,ou=schema
+m-must: ou
+m-oid: 2.5.6.5
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: an organizational unit
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: organizationalUnit
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: userPassword
+m-may: searchGuide
+m-may: seeAlso
+m-may: businessCategory
+m-may: x121Address
+m-may: registeredAddress
+m-may: destinationIndicator
+m-may: preferredDeliveryMethod
+m-may: telexNumber
+m-may: teletexTerminalIdentifier
+m-may: telephoneNumber
+m-may: internationaliSDNNumber
+m-may: facsimileTelephoneNumber
+m-may: street
+m-may: postOfficeBox
+m-may: postalCode
+m-may: postalAddress
+m-may: physicalDeliveryOfficeName
+m-may: st
+m-may: l
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.6.ldif
new file mode 100644
index 0000000..d4b5578
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.6.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.6.6,ou=objectClasses,cn=core,ou=schema
+m-must: sn
+m-must: cn
+m-oid: 2.5.6.6
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: a person
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: person
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: userPassword
+m-may: telephoneNumber
+m-may: seeAlso
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.7.ldif
new file mode 100644
index 0000000..8cc6ff0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.7.ldif
@@ -0,0 +1,30 @@
+version: 1
+dn: m-oid=2.5.6.7,ou=objectClasses,cn=core,ou=schema
+m-oid: 2.5.6.7
+m-obsolete: FALSE
+m-supobjectclass: person
+m-description: RFC2256: an organizational person
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: organizationalPerson
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: title
+m-may: x121Address
+m-may: registeredAddress
+m-may: destinationIndicator
+m-may: preferredDeliveryMethod
+m-may: telexNumber
+m-may: teletexTerminalIdentifier
+m-may: telephoneNumber
+m-may: internationaliSDNNumber
+m-may: facsimileTelephoneNumber
+m-may: street
+m-may: postOfficeBox
+m-may: postalCode
+m-may: postalAddress
+m-may: physicalDeliveryOfficeName
+m-may: ou
+m-may: st
+m-may: l
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.8.ldif
new file mode 100644
index 0000000..19bed82
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.8.ldif
@@ -0,0 +1,33 @@
+version: 1
+dn: m-oid=2.5.6.8,ou=objectClasses,cn=core,ou=schema
+m-must: cn
+m-oid: 2.5.6.8
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: an organizational role
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: organizationalRole
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: x121Address
+m-may: registeredAddress
+m-may: destinationIndicator
+m-may: preferredDeliveryMethod
+m-may: telexNumber
+m-may: teletexTerminalIdentifier
+m-may: telephoneNumber
+m-may: internationaliSDNNumber
+m-may: facsimileTelephoneNumber
+m-may: seeAlso
+m-may: roleOccupant
+m-may: street
+m-may: postOfficeBox
+m-may: postalCode
+m-may: postalAddress
+m-may: physicalDeliveryOfficeName
+m-may: ou
+m-may: st
+m-may: l
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.9.ldif
new file mode 100644
index 0000000..5aeaa4f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=objectclasses/m-oid=2.5.6.9.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: m-oid=2.5.6.9,ou=objectClasses,cn=core,ou=schema
+m-must: cn
+m-must: member
+m-oid: 2.5.6.9
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: a group of names (DNs)
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: groupOfNames
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: businessCategory
+m-may: seeAlso
+m-may: owner
+m-may: ou
+m-may: o
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..0c260b9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=core,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes.ldif
new file mode 100644
index 0000000..73bfb53
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=core,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.1.ldif
new file mode 100644
index 0000000..321f988
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.15.1,ou=syntaxes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.15.1
+m-description: X.509 Certificate Exact Assertion
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.2.ldif
new file mode 100644
index 0000000..2d48240
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.2.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.15.2,ou=syntaxes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.15.2
+m-description: X.509 Certificate Assertion
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.3.ldif
new file mode 100644
index 0000000..60e1c25
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.3.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.15.3,ou=syntaxes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.15.3
+m-description: X.509 Certificate Pair Exact Assertion
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.4.ldif
new file mode 100644
index 0000000..6fff94b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.4.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.15.4,ou=syntaxes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.15.4
+m-description: X.509 Certificate Pair Assertion
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.5.ldif
new file mode 100644
index 0000000..1618794
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.5.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.15.5,ou=syntaxes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.15.5
+m-description: X.509 Certificate List Exact Assertion
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.6.ldif
new file mode 100644
index 0000000..0cbe364
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.6.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.15.6,ou=syntaxes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.15.6
+m-description: X.509 Certificate List Assertion
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.7.ldif
new file mode 100644
index 0000000..ef58dff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=core/ou=syntaxes/m-oid=1.3.6.1.1.15.7.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.15.7,ou=syntaxes,cn=core,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.15.7
+m-description: X.509 Algorithm Identifier
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine.ldif
new file mode 100644
index 0000000..381d6e8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: cn=cosine,ou=schema
+cn: cosine
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes.ldif
new file mode 100644
index 0000000..3374e8a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=cosine,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.10.ldif
new file mode 100644
index 0000000..e94492e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.10,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.10
+m-obsolete: FALSE
+m-description: RFC1274: DN of manager
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: manager
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.11.ldif
new file mode 100644
index 0000000..7539bcb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.11.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.11,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: unique identifier of document
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.11
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: documentIdentifier
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.12.ldif
new file mode 100644
index 0000000..f31d587
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.12.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.12,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: title of document
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.12
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: documentTitle
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.13.ldif
new file mode 100644
index 0000000..922ab16
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.13.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.13,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: version of document
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.13
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: documentVersion
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.14.ldif
new file mode 100644
index 0000000..e80f607
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.14.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.14,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.14
+m-obsolete: FALSE
+m-description: RFC1274: DN of author of document
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: documentAuthor
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.15.ldif
new file mode 100644
index 0000000..7b49b44
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.15.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.15,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: location of document original
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.15
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: documentLocation
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.2.ldif
new file mode 100644
index 0000000..5006c0b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.2.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.2,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.2
+m-obsolete: FALSE
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: textEncodedORAddress
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.20.ldif
new file mode 100644
index 0000000..a463c3c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.20.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.20,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: home telephone number
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.20
+m-substr: telephoneNumberSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.50
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: homePhone
+m-name: homeTelephoneNumber
+m-equality: telephoneNumberMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.21.ldif
new file mode 100644
index 0000000..aa1d4b3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.21.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.21,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.21
+m-obsolete: FALSE
+m-description: RFC1274: DN of secretary
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: secretary
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.22.ldif
new file mode 100644
index 0000000..969da75
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.22.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.22,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.22
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.39
+m-usage: USER_APPLICATIONS
+m-name: otherMailbox
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.26.ldif
new file mode 100644
index 0000000..168cb4c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.26.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.26,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.26
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: aRecord
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.27.ldif
new file mode 100644
index 0000000..82b2011
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.27.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.27,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.27
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: mDRecord
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.28.ldif
new file mode 100644
index 0000000..cfe1c76
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.28.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.28,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.28
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: mXRecord
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.29.ldif
new file mode 100644
index 0000000..9cb3c27
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.29.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.29,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.29
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: nSRecord
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.30.ldif
new file mode 100644
index 0000000..079912a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.30.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.30,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.30
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: sOARecord
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.31.ldif
new file mode 100644
index 0000000..08ab715
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.31.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.31,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.31
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: cNAMERecord
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.38.ldif
new file mode 100644
index 0000000..a07dfec
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.38.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.38,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.38
+m-obsolete: FALSE
+m-description: RFC1274: DN of entry associated with domain
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: associatedName
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.39.ldif
new file mode 100644
index 0000000..e07f7f6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.39.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.39,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: home postal address
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.39
+m-substr: caseIgnoreListSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.41
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: homePostalAddress
+m-equality: caseIgnoreListMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.4.ldif
new file mode 100644
index 0000000..b6eab0d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.4.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.4,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: general information
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.4
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: info
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.40.ldif
new file mode 100644
index 0000000..97a2b98
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.40.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.40,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: personal title
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.40
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: personalTitle
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.41.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.41.ldif
new file mode 100644
index 0000000..f9d4874
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.41.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.41,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: mobile telephone number
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.41
+m-substr: telephoneNumberSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.50
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: mobile
+m-name: mobileTelephoneNumber
+m-equality: telephoneNumberMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.42.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.42.ldif
new file mode 100644
index 0000000..f73417f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.42.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.42,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: pager telephone number
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.42
+m-substr: telephoneNumberSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.50
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: pager
+m-name: pagerTelephoneNumber
+m-equality: telephoneNumberMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.43.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.43.ldif
new file mode 100644
index 0000000..436100e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.43.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.43,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: friendly country name
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.43
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: co
+m-name: friendlyCountryName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.44.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.44.ldif
new file mode 100644
index 0000000..fb43e60
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.44.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.44,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.44
+m-obsolete: FALSE
+m-description: RFC1274: unique identifer
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: uniqueIdentifier
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.45.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.45.ldif
new file mode 100644
index 0000000..888cac6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.45.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.45,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: organizational status
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.45
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: organizationalStatus
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.46.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.46.ldif
new file mode 100644
index 0000000..9dc60a3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.46.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.46,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: Janet mailbox
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.46
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: janetMailbox
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.47.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.47.ldif
new file mode 100644
index 0000000..30db876
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.47.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.47,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.47
+m-obsolete: FALSE
+m-description: RFC1274: mail preference option
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: mailPreferenceOption
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.48.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.48.ldif
new file mode 100644
index 0000000..cd3acbf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.48.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.48,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: name of building
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.48
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: buildingName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.49.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.49.ldif
new file mode 100644
index 0000000..f825a97
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.49.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.49,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 0.9.2342.19200300.100.1.49
+m-obsolete: FALSE
+m-description: RFC1274: DSA Quality
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.19
+m-usage: USER_APPLICATIONS
+m-name: dSAQuality
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.5.ldif
new file mode 100644
index 0000000..6aabb57
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.5.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.5,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: favorite drink
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.5
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: drink
+m-name: favouriteDrink
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.50.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.50.ldif
new file mode 100644
index 0000000..b00a0bc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.50.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.50,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 0.9.2342.19200300.100.1.50
+m-obsolete: FALSE
+m-description: RFC1274: Single Level Quality
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.13
+m-usage: USER_APPLICATIONS
+m-name: singleLevelQuality
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.51.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.51.ldif
new file mode 100644
index 0000000..dd4dc1b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.51.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.51,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 0.9.2342.19200300.100.1.51
+m-obsolete: FALSE
+m-description: RFC1274: Subtree Mininum Quality
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.13
+m-usage: USER_APPLICATIONS
+m-name: subtreeMinimumQuality
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.52.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.52.ldif
new file mode 100644
index 0000000..ca8691a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.52.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.52,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 0.9.2342.19200300.100.1.52
+m-obsolete: FALSE
+m-description: RFC1274: Subtree Maximun Quality
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.13
+m-usage: USER_APPLICATIONS
+m-name: subtreeMaximumQuality
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.53.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.53.ldif
new file mode 100644
index 0000000..97d6603
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.53.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.53,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.53
+m-obsolete: FALSE
+m-description: RFC1274: Personal Signature (G3 fax)
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.23
+m-usage: USER_APPLICATIONS
+m-name: personalSignature
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.54.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.54.ldif
new file mode 100644
index 0000000..6ed3e4e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.54.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.54,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.54
+m-obsolete: FALSE
+m-description: RFC1274: DIT Redirect
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dITRedirect
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.55.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.55.ldif
new file mode 100644
index 0000000..89601c5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.55.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.55,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.55
+m-obsolete: FALSE
+m-description: RFC1274: audio (u-law)
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.4
+m-usage: USER_APPLICATIONS
+m-name: audio
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.56.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.56.ldif
new file mode 100644
index 0000000..e933d7b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.56.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.56,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: publisher of document
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.56
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: documentPublisher
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.6.ldif
new file mode 100644
index 0000000..56c4e69
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.6.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.6,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: room number
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.6
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: roomNumber
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.7.ldif
new file mode 100644
index 0000000..5337240
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.7.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.7,ou=attributeTypes,cn=cosine,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.7
+m-obsolete: FALSE
+m-description: RFC1274: photo (G3 fax)
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.23
+m-usage: USER_APPLICATIONS
+m-name: photo
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.8.ldif
new file mode 100644
index 0000000..8e693fb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.8.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.8,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: categorory of user
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.8
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: userClass
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.9.ldif
new file mode 100644
index 0000000..7c9a89e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.9.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.9,ou=attributeTypes,cn=cosine,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC1274: host computer
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 0.9.2342.19200300.100.1.9
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: host
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=comparators.ldif
new file mode 100644
index 0000000..cb4c6e8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=cosine,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..b9bea42
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=cosine,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..37f0361
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=cosine,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=matchingrules.ldif
new file mode 100644
index 0000000..d592a4d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=cosine,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..7a2748a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=cosine,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=nameforms.ldif
new file mode 100644
index 0000000..bd1787f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=cosine,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=normalizers.ldif
new file mode 100644
index 0000000..d2c0172
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=cosine,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses.ldif
new file mode 100644
index 0000000..44e0ee2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=cosine,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.13.ldif
new file mode 100644
index 0000000..6191f8a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.13.ldif
@@ -0,0 +1,35 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.13,ou=objectClasses,cn=cosine,ou=schema
+m-must: dc
+m-oid: 0.9.2342.19200300.100.4.13
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: domain
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: associatedName
+m-may: o
+m-may: description
+m-may: businessCategory
+m-may: seeAlso
+m-may: searchGuide
+m-may: userPassword
+m-may: l
+m-may: st
+m-may: street
+m-may: physicalDeliveryOfficeName
+m-may: postalAddress
+m-may: postalCode
+m-may: postOfficeBox
+m-may: facsimileTelephoneNumber
+m-may: internationaliSDNNumber
+m-may: telephoneNumber
+m-may: teletexTerminalIdentifier
+m-may: telexNumber
+m-may: preferredDeliveryMethod
+m-may: destinationIndicator
+m-may: registeredAddress
+m-may: x121Address
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.14.ldif
new file mode 100644
index 0000000..7486013
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.14.ldif
@@ -0,0 +1,27 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.14,ou=objectClasses,cn=cosine,ou=schema
+m-oid: 0.9.2342.19200300.100.4.14
+m-supobjectclass: domain
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: RFC822localPart
+creatorsname: uid=admin,ou=system
+m-may: cn
+m-may: sn
+m-may: description
+m-may: seeAlso
+m-may: telephoneNumber
+m-may: physicalDeliveryOfficeName
+m-may: postalAddress
+m-may: postalCode
+m-may: postOfficeBox
+m-may: street
+m-may: facsimileTelephoneNumber
+m-may: internationaliSDNNumber
+m-may: teletexTerminalIdentifier
+m-may: telexNumber
+m-may: preferredDeliveryMethod
+m-may: destinationIndicator
+m-may: registeredAddress
+m-may: x121Address
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.15.ldif
new file mode 100644
index 0000000..3af31c9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.15.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.15,ou=objectClasses,cn=cosine,ou=schema
+m-oid: 0.9.2342.19200300.100.4.15
+m-supobjectclass: domain
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dNSDomain
+creatorsname: uid=admin,ou=system
+m-may: aRecord
+m-may: mDRecord
+m-may: mXRecord
+m-may: nSRecord
+m-may: sOARecord
+m-may: cNAMERecord
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.17.ldif
new file mode 100644
index 0000000..24c6a11
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.17.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.17,ou=objectClasses,cn=cosine,ou=schema
+m-must: associatedDomain
+m-oid: 0.9.2342.19200300.100.4.17
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC1274: an object related to an domain
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: domainRelatedObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.18.ldif
new file mode 100644
index 0000000..2edf653
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.18.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.18,ou=objectClasses,cn=cosine,ou=schema
+m-must: co
+m-oid: 0.9.2342.19200300.100.4.18
+m-obsolete: FALSE
+m-supobjectclass: country
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: friendlyCountry
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.20.ldif
new file mode 100644
index 0000000..0e92145
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.20.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.20,ou=objectClasses,cn=cosine,ou=schema
+m-oid: 0.9.2342.19200300.100.4.20
+m-obsolete: FALSE
+m-supobjectclass: organization
+m-supobjectclass: organizationalUnit
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: pilotOrganization
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: buildingName
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.21.ldif
new file mode 100644
index 0000000..37d7eea
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.21.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.21,ou=objectClasses,cn=cosine,ou=schema
+m-oid: 0.9.2342.19200300.100.4.21
+m-obsolete: FALSE
+m-supobjectclass: dSA
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: pilotDSA
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dSAQuality
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.22.ldif
new file mode 100644
index 0000000..4d62ca8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.22.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.22,ou=objectClasses,cn=cosine,ou=schema
+m-must: dSAQuality
+m-oid: 0.9.2342.19200300.100.4.22
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: qualityLabelledData
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: subtreeMinimumQuality
+m-may: subtreeMaximumQuality
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.4.ldif
new file mode 100644
index 0000000..349a58b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.4.ldif
@@ -0,0 +1,31 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.4,ou=objectClasses,cn=cosine,ou=schema
+m-oid: 0.9.2342.19200300.100.4.4
+m-obsolete: FALSE
+m-supobjectclass: person
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: pilotPerson
+m-name: newPilotPerson
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: uid
+m-may: textEncodedORAddress
+m-may: mail
+m-may: drink
+m-may: roomNumber
+m-may: userClass
+m-may: homePhone
+m-may: homePostalAddress
+m-may: secretary
+m-may: personalTitle
+m-may: preferredDeliveryMethod
+m-may: businessCategory
+m-may: janetMailbox
+m-may: otherMailbox
+m-may: mobile
+m-may: pager
+m-may: organizationalStatus
+m-may: mailPreferenceOption
+m-may: personalSignature
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.5.ldif
new file mode 100644
index 0000000..d221f7b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.5.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.5,ou=objectClasses,cn=cosine,ou=schema
+m-must: uid
+m-oid: 0.9.2342.19200300.100.4.5
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: account
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: description
+m-may: seeAlso
+m-may: l
+m-may: o
+m-may: ou
+m-may: host
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.6.ldif
new file mode 100644
index 0000000..ba9df9f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.6.ldif
@@ -0,0 +1,23 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.6,ou=objectClasses,cn=cosine,ou=schema
+m-must: documentIdentifier
+m-oid: 0.9.2342.19200300.100.4.6
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: document
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: cn
+m-may: description
+m-may: seeAlso
+m-may: l
+m-may: o
+m-may: ou
+m-may: documentTitle
+m-may: documentVersion
+m-may: documentAuthor
+m-may: documentLocation
+m-may: documentPublisher
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.7.ldif
new file mode 100644
index 0000000..959a5ff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.7.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.7,ou=objectClasses,cn=cosine,ou=schema
+m-must: cn
+m-oid: 0.9.2342.19200300.100.4.7
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: room
+creatorsname: uid=admin,ou=system
+m-may: roomNumber
+m-may: description
+m-may: seeAlso
+m-may: telephoneNumber
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.9.ldif
new file mode 100644
index 0000000..8a046bc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=objectclasses/m-oid=0.9.2342.19200300.100.4.9.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.4.9,ou=objectClasses,cn=cosine,ou=schema
+m-must: cn
+m-oid: 0.9.2342.19200300.100.4.9
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: documentSeries
+creatorsname: uid=admin,ou=system
+m-may: description
+m-may: seeAlso
+m-may: telephoneNumber
+m-may: l
+m-may: o
+m-may: ou
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..303dd84
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=cosine,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=syntaxes.ldif
new file mode 100644
index 0000000..8a36df9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=cosine/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=cosine,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp.ldif
new file mode 100644
index 0000000..4521699
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp.ldif
@@ -0,0 +1,9 @@
+version: 1
+dn: cn=dhcp,ou=schema
+cn: dhcp
+m-disabled: TRUE
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes.ldif
new file mode 100644
index 0000000..5687a0b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=dhcp,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.1.ldif
new file mode 100644
index 0000000..d2c54f3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.1.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.1,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.1
+m-obsolete: FALSE
+m-description: The DN of the dhcpServer which is the primary server for the configuration.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpPrimaryDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.10.ldif
new file mode 100644
index 0000000..0f2c602
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.10,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.10
+m-obsolete: FALSE
+m-description: the distinguished name(s) of the dhcpHost objects.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpHostDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.11.ldif
new file mode 100644
index 0000000..65734bc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.11.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.11,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.11
+m-obsolete: FALSE
+m-description: The distinguished name(s) of pools.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpPoolDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.12.ldif
new file mode 100644
index 0000000..cc9aee2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.12.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.12,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.12
+m-obsolete: FALSE
+m-description: The distinguished name(s)   of the groups.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpGroupDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.13.ldif
new file mode 100644
index 0000000..978ce93
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.13.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.13,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.13
+m-obsolete: FALSE
+m-description: The distinguished name(s) of the subnets.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpSubnetDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.14.ldif
new file mode 100644
index 0000000..0c0b775
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.14.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.14,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.14
+m-obsolete: FALSE
+m-description: The distinguished name of a client address.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpLeaseDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.15.ldif
new file mode 100644
index 0000000..b80bf3f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.15.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.15,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.15
+m-obsolete: FALSE
+m-description: The distinguished name(s) client addresses.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpLeasesDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.16.ldif
new file mode 100644
index 0000000..cd9a9ec
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.16.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.16,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.16
+m-obsolete: FALSE
+m-description: The distinguished name(s) of a class(es) in a subclass.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpClassesDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.17.ldif
new file mode 100644
index 0000000..94d3400
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.17.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.17,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.17
+m-obsolete: FALSE
+m-description: The distinguished name(s) of subclass(es).
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpSubclassesDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.18.ldif
new file mode 100644
index 0000000..77361f1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.18.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.18,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.18
+m-obsolete: FALSE
+m-description: The distinguished name(s) of sharedNetworks.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpSharedNetworkDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.19.ldif
new file mode 100644
index 0000000..dc4813b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.19.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.19,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.19
+m-obsolete: FALSE
+m-description: The DN of dhcpService object(s)which contain the configuration information. Each dhcpServer obj
+ ect has this attribute identifying the DHCP configuration(s) that the server is associated with.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpServiceDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.2.ldif
new file mode 100644
index 0000000..acae38a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.2.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.2,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.2
+m-obsolete: FALSE
+m-description: The DN of dhcpServer(s) which provide backup service for the configuration.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpSecondaryDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.20.ldif
new file mode 100644
index 0000000..1f8f09e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.20.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.20,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.20
+m-obsolete: FALSE
+m-description: The version attribute of this object.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpVersion
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.21.ldif
new file mode 100644
index 0000000..e523c55
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.21.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.21,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.21
+m-obsolete: FALSE
+m-description: Description of the DHCP Server implementation e.g. DHCP Servers vendor.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpImplementation
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.22.ldif
new file mode 100644
index 0000000..27a3519
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.22.ldif
@@ -0,0 +1,21 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.22,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.22
+m-obsolete: FALSE
+m-description: This stores information about the current binding-status of an address.  For dynamic addresses 
+ managed by DHCP, the values should be restricted to the following: "FREE", "ACTIVE", "EXPIRED", "RELEASED", "
+ RESET", "ABANDONED", "BACKUP".  For other addresses, it SHOULD be one of the following: "UNKNOWN", "RESERVED"
+  (an address that is managed by DHCP that is reserved for a specific client), "RESERVED-ACTIVE" (same as rese
+ rved, but address is currently in use), "ASSIGNED" (assigned manually or by some other mechanism), "UNASSIGNE
+ D", "NOTASSIGNABLE".
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpAddressState
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.23.ldif
new file mode 100644
index 0000000..884ee3a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.23.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.23,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.23
+m-obsolete: FALSE
+m-description: This is the time the current lease for an address expires.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: USER_APPLICATIONS
+m-name: dhcpExpirationTime
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.24.ldif
new file mode 100644
index 0000000..ab1298c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.24.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.24,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.24
+m-obsolete: FALSE
+m-description: This is the time of the last state change for a leased address.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: USER_APPLICATIONS
+m-name: dhcpStartTimeOfState
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.25.ldif
new file mode 100644
index 0000000..bd79c3c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.25.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.25,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.25
+m-obsolete: FALSE
+m-description: This is the last time a valid DHCP packet was received from the client.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: USER_APPLICATIONS
+m-name: dhcpLastTransactionTime
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.26.ldif
new file mode 100644
index 0000000..fd1dcad
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.26.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.26,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.26
+m-obsolete: FALSE
+m-description: This indicates whether the address was assigned via BOOTP.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-usage: USER_APPLICATIONS
+m-name: dhcpBootpFlag
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.27.ldif
new file mode 100644
index 0000000..d6ce648
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.27.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.27,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.27
+m-obsolete: FALSE
+m-description: This is the name of the domain sent to the client by the server.  It is essentially the same as
+  the value for DHCP option 15 sent to the client, and represents only the domain - not the full FQDN.  To obt
+ ain the full FQDN assigned to the client you must prepend the "dhcpAssignedHostName" to this value with a "."
+ .
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpDomainName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.28.ldif
new file mode 100644
index 0000000..2077d41
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.28.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.28,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.28
+m-obsolete: FALSE
+m-description: This indicates the status of updating DNS resource records on behalf of the client by the DHCP 
+ server for this address.  The value is a 16-bit bitmask.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: dhcpDnsStatus
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.29.ldif
new file mode 100644
index 0000000..be23a47
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.29.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.29,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.29
+m-obsolete: FALSE
+m-description: This is the hostname that was requested by the client.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpRequestedHostName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.3.ldif
new file mode 100644
index 0000000..df9766d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.3.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.3,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.3
+m-obsolete: FALSE
+m-description: Flexible storage for specific data depending on what object this exists in. Like conditional st
+ atements, server parameters, etc. This allows the standard to evolve without needing to adjust the schema.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpStatements
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.30.ldif
new file mode 100644
index 0000000..62c7e94
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.30.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.30,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.30
+m-obsolete: FALSE
+m-description: This is the actual hostname that was assigned to a client. It may not be the name that was requ
+ ested by the client.  The fully qualified domain name can be determined by appending the value of "dhcpDomain
+ Name" (with a dot separator) to this name.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpAssignedHostName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.31.ldif
new file mode 100644
index 0000000..a4b5fc4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.31.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.31,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.31
+m-obsolete: FALSE
+m-description: The distinguished name of a "dhcpClient" that an address is reserved for.  This may not be the 
+ same as the "dhcpAssignedToClient" attribute if the address is being reassigned but the current lease has not
+  yet expired.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpReservedForClient
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.32.ldif
new file mode 100644
index 0000000..09b36ed
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.32.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.32,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.32
+m-obsolete: FALSE
+m-description: This is the distinguished name of a "dhcpClient" that an address is currently assigned to.  Thi
+ s attribute is only present in the class when the address is leased.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpAssignedToClient
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.33.ldif
new file mode 100644
index 0000000..36d9cb3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.33.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.33,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.33
+m-obsolete: FALSE
+m-description: If the client request was received via a relay agent, this contains information about the relay
+  agent that was available from the DHCP request.  This is a hex-encoded option value.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: USER_APPLICATIONS
+m-name: dhcpRelayAgentInfo
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.34.ldif
new file mode 100644
index 0000000..e20d024
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.34.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.34,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.34
+m-obsolete: FALSE
+m-description: The clients hardware address that requested this IP address.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: USER_APPLICATIONS
+m-name: dhcpHWAddress
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.35.ldif
new file mode 100644
index 0000000..d6ba606
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.35.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.35,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.35
+m-obsolete: FALSE
+m-description: HashBucketAssignment bit map for the DHCP Server, as defined in DHC Load Balancing Algorithm [R
+ FC 3074].
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: USER_APPLICATIONS
+m-name: dhcpHashBucketAssignment
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.36.ldif
new file mode 100644
index 0000000..25b82a6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.36.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.36,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.36
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: dhcpDelayedServiceParameter
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.37.ldif
new file mode 100644
index 0000000..d884022
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.37.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.37,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.37
+m-obsolete: FALSE
+m-description: Maximum Client Lead Time configuration in seconds, as defined in DHCP Failover Protocol [FAILOV
+ R]
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: dhcpMaxClientLeadTime
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.38.ldif
new file mode 100644
index 0000000..7185efa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.38.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.38,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.38
+m-obsolete: FALSE
+m-description: Server (Failover Endpoint) state, as defined in DHCP Failover Protocol [FAILOVR]
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpFailOverEndpointState
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.39.ldif
new file mode 100644
index 0000000..aa79106
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.39.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.39,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.39
+m-obsolete: FALSE
+m-description: Generic error log attribute that allows logging error conditions within a dhcpService or a dhcp
+ Subnet, like no IP addresses available for lease.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpErrorLog
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.4.ldif
new file mode 100644
index 0000000..266c27e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.4.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.4,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.4
+m-obsolete: FALSE
+m-description: The starting & ending IP Addresses in the range (inclusive), separated by a hyphen; if the rang
+ e only contains one address, then just the address can be specified with no hyphen.  Each range is defined as
+  a separate value.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpRange
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.5.ldif
new file mode 100644
index 0000000..e8ebce6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.5.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.5,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.5
+m-obsolete: FALSE
+m-description: This attribute contains the permit lists associated with a pool. Each permit list is defined as
+  a separate value.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpPermitList
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.6.ldif
new file mode 100644
index 0000000..a71d444
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.6.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.6,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.6
+m-obsolete: FALSE
+m-description: The subnet mask length for the subnet.  The mask can be easily computed from this length.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: dhcpNetMask
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.7.ldif
new file mode 100644
index 0000000..63087fc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.7.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.7,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.7
+m-obsolete: FALSE
+m-description: Encoded option values to be sent to clients.  Each value represents a single option and contain
+ s (OptionTag, Length, OptionValue) encoded in the format used by DHCP.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: USER_APPLICATIONS
+m-name: dhcpOption
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.8.ldif
new file mode 100644
index 0000000..64a0277
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.8.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.8,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.16.840.1.113719.1.203.4.8
+m-obsolete: FALSE
+m-description: Encoded text string or list of bytes expressed in hexadecimal, separated by colons.  Clients ma
+ tch subclasses based on matching the class data with the results of match or spawn with statements in the cla
+ ss name declarations.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: dhcpClassData
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.9.ldif
new file mode 100644
index 0000000..6ea6a7a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=attributetypes/m-oid=2.16.840.1.113719.1.203.4.9.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.4.9,ou=attributeTypes,cn=dhcp,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113719.1.203.4.9
+m-obsolete: FALSE
+m-description: The distinguished name(s) of the dhcpOption objects containing the configuration options provid
+ ed by the server.
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: dhcpOptionsDN
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=comparators.ldif
new file mode 100644
index 0000000..1417a22
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=dhcp,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..cf59280
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=dhcp,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..a46017b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=dhcp,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=matchingrules.ldif
new file mode 100644
index 0000000..c2674b3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=dhcp,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..0c7742b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=dhcp,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=nameforms.ldif
new file mode 100644
index 0000000..f5e358c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=dhcp,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=normalizers.ldif
new file mode 100644
index 0000000..f99b4d6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=dhcp,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses.ldif
new file mode 100644
index 0000000..852f135
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=dhcp,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.1.ldif
new file mode 100644
index 0000000..d572553
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.1.ldif
@@ -0,0 +1,23 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.1,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-must: dhcpPrimaryDN
+m-oid: 2.16.840.1.113719.1.203.6.1
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Service object that represents the actual DHCP Service configuration. This is a container objec
+ t.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpService
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpSecondaryDN
+m-may: dhcpSharedNetworkDN
+m-may: dhcpSubnetDN
+m-may: dhcpGroupDN
+m-may: dhcpHostDN
+m-may: dhcpClassesDN
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.10.ldif
new file mode 100644
index 0000000..1d94820
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.10.ldif
@@ -0,0 +1,26 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.10,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-must: dhcpAddressState
+m-oid: 2.16.840.1.113719.1.203.6.10
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: This class represents an IP Address, which may or may not have been leased.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpLeases
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpExpirationTime
+m-may: dhcpStartTimeOfState
+m-may: dhcpLastTransactionTime
+m-may: dhcpBootpFlag
+m-may: dhcpDomainName
+m-may: dhcpDnsStatus
+m-may: dhcpRequestedHostName
+m-may: dhcpAssignedHostName
+m-may: dhcpReservedForClient
+m-may: dhcpAssignedToClient
+m-may: dhcpRelayAgentInfo
+m-may: dhcpHWAddress
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.11.ldif
new file mode 100644
index 0000000..202e3de
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.11.ldif
@@ -0,0 +1,27 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.11,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-oid: 2.16.840.1.113719.1.203.6.11
+m-supobjectclass: top
+m-description: This is the object that holds past information about the IP address. The cn is the time/date st
+ amp when the address was assigned or released, the address state at the time, if the address was assigned or 
+ released.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpLog
+creatorsname: uid=admin,ou=system
+m-may: dhcpAddressState
+m-may: dhcpExpirationTime
+m-may: dhcpStartTimeOfState
+m-may: dhcpLastTransactionTime
+m-may: dhcpBootpFlag
+m-may: dhcpDomainName
+m-may: dhcpDnsStatus
+m-may: dhcpRequestedHostName
+m-may: dhcpAssignedHostName
+m-may: dhcpReservedForClient
+m-may: dhcpAssignedToClient
+m-may: dhcpRelayAgentInfo
+m-may: dhcpHWAddress
+m-may: dhcpErrorLog
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.12.ldif
new file mode 100644
index 0000000..ef066b1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.12.ldif
@@ -0,0 +1,21 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.12,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-must: dhcpServiceDN
+m-oid: 2.16.840.1.113719.1.203.6.12
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: DHCP Server Object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpServer
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpVersion
+m-may: dhcpImplementation
+m-may: dhcpHashBucketAssignment
+m-may: dhcpDelayedServiceParameter
+m-may: dhcpMaxClientLeadTime
+m-may: dhcpFailOverEndpointState
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.2.ldif
new file mode 100644
index 0000000..3bb649d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.2.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.2,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-oid: 2.16.840.1.113719.1.203.6.2
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: This stores configuration information for a shared network.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpSharedNetwork
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpSubnetDN
+m-may: dhcpPoolDN
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.3.ldif
new file mode 100644
index 0000000..dbb4f28
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.3.ldif
@@ -0,0 +1,20 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.3,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-must: dhcpNetMask
+m-oid: 2.16.840.1.113719.1.203.6.3
+m-supobjectclass: top
+m-description: This class defines a subnet. This is a container object.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpSubnet
+creatorsname: uid=admin,ou=system
+m-may: dhcpRange
+m-may: dhcpPoolDN
+m-may: dhcpGroupDN
+m-may: dhcpHostDN
+m-may: dhcpClassesDN
+m-may: dhcpLeasesDN
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.4.ldif
new file mode 100644
index 0000000..44bce80
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.4.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.4,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-must: dhcpRange
+m-oid: 2.16.840.1.113719.1.203.6.4
+m-supobjectclass: top
+m-description: This stores configuration information about a pool.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpPool
+creatorsname: uid=admin,ou=system
+m-may: dhcpClassesDN
+m-may: dhcpPermitList
+m-may: dhcpLeasesDN
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.5.ldif
new file mode 100644
index 0000000..ef6e8dd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.5,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-oid: 2.16.840.1.113719.1.203.6.5
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Group object that lists host DNs and parameters. This is a container object.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpGroup
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpHostDN
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.6.ldif
new file mode 100644
index 0000000..d32de93
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.6.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.6,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-oid: 2.16.840.1.113719.1.203.6.6
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: This represents information about a particular client
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpHost
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpLeaseDN
+m-may: dhcpHWAddress
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.7.ldif
new file mode 100644
index 0000000..ca6f5a2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.7.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.7,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-oid: 2.16.840.1.113719.1.203.6.7
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Represents information about a collection of related clients.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpClass
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpSubclassesDN
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.8.ldif
new file mode 100644
index 0000000..3e0cc23
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.8.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.8,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-oid: 2.16.840.1.113719.1.203.6.8
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Represents information about a collection of related classes.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpSubClass
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: dhcpClassData
+m-may: dhcpOptionsDN
+m-may: dhcpStatements
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.9.ldif
new file mode 100644
index 0000000..aa29d7b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=objectclasses/m-oid=2.16.840.1.113719.1.203.6.9.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=2.16.840.1.113719.1.203.6.9,ou=objectClasses,cn=dhcp,ou=schema
+m-must: cn
+m-oid: 2.16.840.1.113719.1.203.6.9
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Represents information about a collection of options defined.
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dhcpOptions
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: dhcpOption
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..5774ffd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=dhcp,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=syntaxes.ldif
new file mode 100644
index 0000000..947749f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=dhcp/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=dhcp,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson.ldif
new file mode 100644
index 0000000..43ecdcc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson.ldif
@@ -0,0 +1,9 @@
+version: 1
+dn: cn=inetorgperson,ou=schema
+cn: inetorgperson
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+m-dependencies: cosine
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes.ldif
new file mode 100644
index 0000000..b3a6c00
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=inetorgperson,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.60.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.60.ldif
new file mode 100644
index 0000000..91fca6c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=0.9.2342.19200300.100.1.60.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=0.9.2342.19200300.100.1.60,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 0.9.2342.19200300.100.1.60
+m-obsolete: FALSE
+m-description: RFC2798: a JPEG image
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.28
+m-usage: USER_APPLICATIONS
+m-name: jpegPhoto
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.1.ldif
new file mode 100644
index 0000000..c053393
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.1,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2798: vehicle license or registration plate
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.16.840.1.113730.3.1.1
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: carLicense
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.2.ldif
new file mode 100644
index 0000000..9e40e5e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.2.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.2,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2798: identifies a department within an organization
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.16.840.1.113730.3.1.2
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: departmentNumber
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.216.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.216.ldif
new file mode 100644
index 0000000..91ec7c4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.216.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.216,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113730.3.1.216
+m-obsolete: FALSE
+m-description: RFC2798: personal identity information, a PKCS #12 PFX
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-name: userPKCS12
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.241.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.241.ldif
new file mode 100644
index 0000000..f7eac44
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.241.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.241,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: RFC2798: preferred name to be used when displaying entries
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.16.840.1.113730.3.1.241
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: displayName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.3.ldif
new file mode 100644
index 0000000..e597e25
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.3.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.3,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: RFC2798: numerically identifies an employee within an organization
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.16.840.1.113730.3.1.3
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: employeeNumber
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.39.ldif
new file mode 100644
index 0000000..c8bcb9b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.39.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.39,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: RFC2798: preferred written or spoken language for a person
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.16.840.1.113730.3.1.39
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: preferredLanguage
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.4.ldif
new file mode 100644
index 0000000..161c0e1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.4.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.4,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2798: type of employment for a person
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.16.840.1.113730.3.1.4
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: employeeType
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.40.ldif
new file mode 100644
index 0000000..158c730
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.40.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.40,ou=attributeTypes,cn=inetorgperson,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113730.3.1.40
+m-obsolete: FALSE
+m-description: RFC2798: PKCS#7 SignedData used to support S/MIME
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-name: userSMIMECertificate
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=comparators.ldif
new file mode 100644
index 0000000..d4a501a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=inetorgperson,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..f2dd4d9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=inetorgperson,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..219bbcd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=inetorgperson,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=matchingrules.ldif
new file mode 100644
index 0000000..ddc48ed
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=inetorgperson,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..0b3cb80
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=inetorgperson,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=nameforms.ldif
new file mode 100644
index 0000000..2e81b66
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=inetorgperson,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=normalizers.ldif
new file mode 100644
index 0000000..c23528b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=inetorgperson,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=objectclasses.ldif
new file mode 100644
index 0000000..518fa59
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=inetorgperson,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=objectclasses/m-oid=2.16.840.1.113730.3.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=objectclasses/m-oid=2.16.840.1.113730.3.2.2.ldif
new file mode 100644
index 0000000..902d208
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=objectclasses/m-oid=2.16.840.1.113730.3.2.2.ldif
@@ -0,0 +1,37 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.2.2,ou=objectClasses,cn=inetorgperson,ou=schema
+m-oid: 2.16.840.1.113730.3.2.2
+m-supobjectclass: organizationalPerson
+m-description: RFC2798: Internet Organizational Person
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: inetOrgPerson
+creatorsname: uid=admin,ou=system
+m-may: audio
+m-may: businessCategory
+m-may: carLicense
+m-may: departmentNumber
+m-may: displayName
+m-may: employeeNumber
+m-may: employeeType
+m-may: givenName
+m-may: homePhone
+m-may: homePostalAddress
+m-may: initials
+m-may: jpegPhoto
+m-may: labeledURI
+m-may: mail
+m-may: manager
+m-may: mobile
+m-may: o
+m-may: pager
+m-may: photo
+m-may: roomNumber
+m-may: secretary
+m-may: uid
+m-may: userCertificate
+m-may: x500UniqueIdentifier
+m-may: preferredLanguage
+m-may: userSMIMECertificate
+m-may: userPKCS12
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..462fe21
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=inetorgperson,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=syntaxes.ldif
new file mode 100644
index 0000000..96c447d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=inetorgperson/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=inetorgperson,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java.ldif
new file mode 100644
index 0000000..8f6a2f4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: cn=java,ou=schema
+cn: java
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes.ldif
new file mode 100644
index 0000000..21cff41
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=java,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.10.ldif
new file mode 100644
index 0000000..3cd17c9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.10,ou=attributeTypes,cn=java,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.10
+m-obsolete: FALSE
+m-description: Fully qualified Java class name of a JNDI object factory
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: javaFactory
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.11.ldif
new file mode 100644
index 0000000..ecbc59b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.11.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.11,ou=attributeTypes,cn=java,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.11
+m-obsolete: FALSE
+m-description: Addresses associated with a JNDI Reference
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: javaReferenceAddress
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.12.ldif
new file mode 100644
index 0000000..9146b9a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.12.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.12,ou=attributeTypes,cn=java,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.12
+m-obsolete: FALSE
+m-description: The Java documentation for the class
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: javaDoc
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.13.ldif
new file mode 100644
index 0000000..1a2d9b7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.13.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.13,ou=attributeTypes,cn=java,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.13
+m-obsolete: FALSE
+m-description: Fully qualified Java class or interface name
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: javaClassNames
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.6.ldif
new file mode 100644
index 0000000..6bcb6e6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.6.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.6,ou=attributeTypes,cn=java,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.6
+m-obsolete: FALSE
+m-description: Fully qualified name of distinguished Java class or interface
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: javaClassName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.7.ldif
new file mode 100644
index 0000000..3b9efcf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.7.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.7,ou=attributeTypes,cn=java,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.7
+m-obsolete: FALSE
+m-description: URL(s) specifying the location of class definition
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: javaCodebase
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.8.ldif
new file mode 100644
index 0000000..b16857f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.4.1.8.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.1.8,ou=attributeTypes,cn=java,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.4.1.8
+m-obsolete: FALSE
+m-description: Serialized form of a Java object
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: USER_APPLICATIONS
+m-name: javaSerializedData
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=comparators.ldif
new file mode 100644
index 0000000..db1f6f1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=java,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..dca5ddd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=java,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..3583f81
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=java,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=matchingrules.ldif
new file mode 100644
index 0000000..44cb438
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=java,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..b301523
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=java,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=nameforms.ldif
new file mode 100644
index 0000000..c412bee
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=java,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=normalizers.ldif
new file mode 100644
index 0000000..550b71b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=java,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses.ldif
new file mode 100644
index 0000000..4caf81c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=java,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.1.ldif
new file mode 100644
index 0000000..385794a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.1.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.1,ou=objectClasses,cn=java,ou=schema
+m-must: cn
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.1
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Container for a Java object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaContainer
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.4.ldif
new file mode 100644
index 0000000..6c5bcd8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.4.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.4,ou=objectClasses,cn=java,ou=schema
+m-must: javaClassName
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.4
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Java object representation
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaObject
+m-typeobjectclass: ABSTRACT
+creatorsname: uid=admin,ou=system
+m-may: javaClassNames
+m-may: javaCodebase
+m-may: javaDoc
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.5.ldif
new file mode 100644
index 0000000..236f647
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.5.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.5,ou=objectClasses,cn=java,ou=schema
+m-must: javaSerializedData
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.5
+m-obsolete: FALSE
+m-supobjectclass: javaObject
+m-description: Java serialized object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaSerializedObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.7.ldif
new file mode 100644
index 0000000..547f2d8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.7.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.7,ou=objectClasses,cn=java,ou=schema
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.7
+m-supobjectclass: javaObject
+m-description: JNDI reference
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaNamingReference
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: javaReferenceAddress
+m-may: javaFactory
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.8.ldif
new file mode 100644
index 0000000..93a4f95
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.4.2.8.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.4.2.8,ou=objectClasses,cn=java,ou=schema
+m-must: javaSerializedData
+m-oid: 1.3.6.1.4.1.42.2.27.4.2.8
+m-supobjectclass: javaObject
+m-description: Java marshalled object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: javaMarshalledObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..cd3a47f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=java,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=syntaxes.ldif
new file mode 100644
index 0000000..04fa6b4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=java/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=java,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc.ldif
new file mode 100644
index 0000000..1516c2f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: cn=krb5kdc,ou=schema
+cn: krb5kdc
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes.ldif
new file mode 100644
index 0000000..82c1ef7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=krb5kdc,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.1.ldif
new file mode 100644
index 0000000..db0fc6c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.1.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.1,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.1
+m-obsolete: FALSE
+m-description: The unparsed Kerberos principal name
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: krb5PrincipalName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.10.ldif
new file mode 100644
index 0000000..f59c431
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.10.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.10,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.5322.10.1.10
+m-obsolete: FALSE
+m-description: Encoded ASN1 Key as an octet string
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.5
+m-usage: USER_APPLICATIONS
+m-name: krb5Key
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.11.ldif
new file mode 100644
index 0000000..dc85667
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.11.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.11,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: Distinguished name of krb5Realm entry
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.5322.10.1.11
+m-supattributetype: distinguishedName
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: krb5PrincipalRealm
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.12.ldif
new file mode 100644
index 0000000..d9fde0f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.12.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.12,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.5322.10.1.12
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: krb5RealmName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.13.ldif
new file mode 100644
index 0000000..33662c1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.13.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.13,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.13
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-usage: USER_APPLICATIONS
+m-name: krb5AccountDisabled
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.14.ldif
new file mode 100644
index 0000000..e54d4a2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.14.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.14,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.14
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-usage: USER_APPLICATIONS
+m-name: krb5AccountLockedOut
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.15.ldif
new file mode 100644
index 0000000..d53830d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.15.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.15,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.15
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: USER_APPLICATIONS
+m-name: krb5AccountExpirationTime
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.2.ldif
new file mode 100644
index 0000000..a73245a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.2.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.2,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.2
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: krb5KeyVersionNumber
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.3.ldif
new file mode 100644
index 0000000..f7516c5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.3.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.3,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.3
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: krb5MaxLife
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.4.ldif
new file mode 100644
index 0000000..c3265fe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.4.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.4,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.4
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: krb5MaxRenew
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.5.ldif
new file mode 100644
index 0000000..2684fc1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.5.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.5,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.5
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: krb5KDCFlags
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.6.ldif
new file mode 100644
index 0000000..53df06a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.6.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.6,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.5322.10.1.6
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: krb5EncryptionType
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.7.ldif
new file mode 100644
index 0000000..0fa24ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.7.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.7,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.7
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: USER_APPLICATIONS
+m-name: krb5ValidStart
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.8.ldif
new file mode 100644
index 0000000..9170caa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.8.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.8,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.8
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: USER_APPLICATIONS
+m-name: krb5ValidEnd
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.9.ldif
new file mode 100644
index 0000000..0fac9bc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=attributetypes/m-oid=1.3.6.1.4.1.5322.10.1.9.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.1.9,ou=attributeTypes,cn=krb5kdc,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.5322.10.1.9
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: USER_APPLICATIONS
+m-name: krb5PasswordEnd
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=comparators.ldif
new file mode 100644
index 0000000..7a32621
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=krb5kdc,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..c6a5eb7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=krb5kdc,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..e80d118
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=krb5kdc,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=matchingrules.ldif
new file mode 100644
index 0000000..7e475b1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=krb5kdc,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..a6b9149
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=krb5kdc,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=nameforms.ldif
new file mode 100644
index 0000000..e9cbd19
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=krb5kdc,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=normalizers.ldif
new file mode 100644
index 0000000..5a696e4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=krb5kdc,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses.ldif
new file mode 100644
index 0000000..8f78ec7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=krb5kdc,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.1.ldif
new file mode 100644
index 0000000..a247341
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.1.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.2.1,ou=objectClasses,cn=krb5kdc,ou=schema
+m-must: krb5PrincipalName
+m-oid: 1.3.6.1.4.1.5322.10.2.1
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: krb5Principal
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: cn
+m-may: krb5PrincipalRealm
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.2.ldif
new file mode 100644
index 0000000..b359f28
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.2.ldif
@@ -0,0 +1,23 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.2.2,ou=objectClasses,cn=krb5kdc,ou=schema
+m-must: krb5KeyVersionNumber
+m-oid: 1.3.6.1.4.1.5322.10.2.2
+m-obsolete: FALSE
+m-supobjectclass: krb5Principal
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: krb5KDCEntry
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: krb5ValidStart
+m-may: krb5ValidEnd
+m-may: krb5PasswordEnd
+m-may: krb5MaxLife
+m-may: krb5MaxRenew
+m-may: krb5KDCFlags
+m-may: krb5EncryptionType
+m-may: krb5Key
+m-may: krb5AccountDisabled
+m-may: krb5AccountLockedOut
+m-may: krb5AccountExpirationTime
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.3.ldif
new file mode 100644
index 0000000..3caf953
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.10.2.3.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.5322.10.2.3,ou=objectClasses,cn=krb5kdc,ou=schema
+m-must: krb5RealmName
+m-oid: 1.3.6.1.4.1.5322.10.2.3
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: krb5Realm
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..d61ce25
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=krb5kdc,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=syntaxes.ldif
new file mode 100644
index 0000000..35f7cad
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=krb5kdc/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=krb5kdc,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla.ldif
new file mode 100644
index 0000000..f4b9cb9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla.ldif
@@ -0,0 +1,9 @@
+version: 1
+dn: cn=mozilla,ou=schema
+cn: mozilla
+m-disabled: TRUE
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes.ldif
new file mode 100644
index 0000000..e4be572
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=mozilla,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.1.ldif
new file mode 100644
index 0000000..5cbd665
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.1.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.1,ou=attributeTypes,cn=mozilla,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.1
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: xmozillanickname
+m-name: mozillaNickname
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.10.ldif
new file mode 100644
index 0000000..1f43bc8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.10,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.10
+m-obsolete: FALSE
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: mozillaHomeFriendlyCountryName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.11.ldif
new file mode 100644
index 0000000..baa1f43
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.11.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.11,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.11
+m-obsolete: FALSE
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: homeurl
+m-name: mozillaHomeUrl
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.12.ldif
new file mode 100644
index 0000000..5f2365a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.12.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.12,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.12
+m-obsolete: FALSE
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: workurl
+m-name: mozillaWorkUrl
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.13.ldif
new file mode 100644
index 0000000..215bc0d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.13.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.13,ou=attributeTypes,cn=mozilla,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: AOL Instant Messenger (AIM) Identity
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.13
+m-substr: telephoneNumberSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.50
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: nsAIMid
+m-equality: telephoneNumberMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.2.ldif
new file mode 100644
index 0000000..1eec65c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.2.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.2,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.13769.2.1.2
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-usage: USER_APPLICATIONS
+m-name: xmozillausehtmlmail
+m-name: mozillaUseHtmlMail
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.3.ldif
new file mode 100644
index 0000000..87cab1d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.3.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.3,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.3
+m-obsolete: FALSE
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: mozillaSecondEmail
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.4.ldif
new file mode 100644
index 0000000..1820399
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.4,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.4
+m-obsolete: FALSE
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: mozillaHomeLocalityName
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.5.ldif
new file mode 100644
index 0000000..4251214
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.5,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.5
+m-obsolete: FALSE
+m-substr: caseIgnoreListSubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.41
+m-usage: USER_APPLICATIONS
+m-name: mozillaPostalAddress2
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreListMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.6.ldif
new file mode 100644
index 0000000..ad2d00a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.6.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.6,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.6
+m-obsolete: FALSE
+m-substr: caseIgnoreListSubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.41
+m-usage: USER_APPLICATIONS
+m-name: mozillaHomePostalAddress2
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreListMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.7.ldif
new file mode 100644
index 0000000..5dcfc9a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.7.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.7,ou=attributeTypes,cn=mozilla,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.7
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: mozillaHomeState
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.8.ldif
new file mode 100644
index 0000000..a3f6b11
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.8.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.8,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.8
+m-obsolete: FALSE
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: mozillaHomePostalCode
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.9.ldif
new file mode 100644
index 0000000..974468a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.9.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.9,ou=attributeTypes,cn=mozilla,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.4.1.13769.2.1.9
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: mozillaHomeCountryName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.96.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.96.ldif
new file mode 100644
index 0000000..9a24228
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.96.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.96,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.13769.2.1.96
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: custom1
+m-name: mozillaCustom1
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.97.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.97.ldif
new file mode 100644
index 0000000..e379a9d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.97.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.97,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.13769.2.1.97
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: custom2
+m-name: mozillaCustom2
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.98.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.98.ldif
new file mode 100644
index 0000000..a78d16f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.98.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.98,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.13769.2.1.98
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: custom3
+m-name: mozillaCustom3
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.99.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.99.ldif
new file mode 100644
index 0000000..c6462ca
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=attributetypes/m-oid=1.3.6.1.4.1.13769.2.1.99.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.1.99,ou=attributeTypes,cn=mozilla,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.13769.2.1.99
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: custom4
+m-name: mozillaCustom4
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=comparators.ldif
new file mode 100644
index 0000000..337ebf0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=mozilla,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..207ff50
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=mozilla,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..fad217d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=mozilla,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=matchingrules.ldif
new file mode 100644
index 0000000..eb27ddd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=mozilla,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..f25e390
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=mozilla,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=nameforms.ldif
new file mode 100644
index 0000000..a920504
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=mozilla,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=normalizers.ldif
new file mode 100644
index 0000000..8202f5c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=mozilla,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=objectclasses.ldif
new file mode 100644
index 0000000..5a68391
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=mozilla,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=objectclasses/m-oid=1.3.6.1.4.1.13769.2.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=objectclasses/m-oid=1.3.6.1.4.1.13769.2.2.1.ldif
new file mode 100644
index 0000000..483d2f4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=objectclasses/m-oid=1.3.6.1.4.1.13769.2.2.1.ldif
@@ -0,0 +1,30 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.13769.2.2.1,ou=objectClasses,cn=mozilla,ou=schema
+m-oid: 1.3.6.1.4.1.13769.2.2.1
+m-obsolete: FALSE
+m-supobjectclass: inetOrgPerson
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: mozillaAbPersonObsolete
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: xmozillanickname
+m-may: xmozillausehtmlmail
+m-may: mozillaSecondEmail
+m-may: mozillaPostalAddress2
+m-may: mozillaHomePostalAddress2
+m-may: mozillaHomeLocalityName
+m-may: mozillaHomeState
+m-may: mozillaHomePostalCode
+m-may: mozillaHomeCountryName
+m-may: mozillaHomeFriendlyCountryName
+m-may: homeurl
+m-may: workurl
+m-may: custom1
+m-may: custom2
+m-may: custom3
+m-may: custom4
+m-may: nsAIMid
+m-may: c
+m-may: co
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..befb909
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=mozilla,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=syntaxes.ldif
new file mode 100644
index 0000000..b4379db
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=mozilla/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=mozilla,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis.ldif
new file mode 100644
index 0000000..12c10d8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: cn=nis,ou=schema
+cn: nis
+m-disabled: TRUE
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+m-dependencies: cosine
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes.ldif
new file mode 100644
index 0000000..da65409
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=nis,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.0.ldif
new file mode 100644
index 0000000..2ad3708
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.0.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.0,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.0
+m-obsolete: FALSE
+m-description: An integer uniquely identifying a user in an administrative domain
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: uidNumber
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.1.ldif
new file mode 100644
index 0000000..a8a3de8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.1.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.1,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.1
+m-obsolete: FALSE
+m-description: An integer uniquely identifying a group in an administrative domain
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: gidNumber
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.10.ldif
new file mode 100644
index 0000000..c0de11b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.10.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.10,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.10
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: shadowExpire
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.11.ldif
new file mode 100644
index 0000000..5adffdc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.11.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.11,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.11
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: shadowFlag
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.12.ldif
new file mode 100644
index 0000000..a115640
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.12.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.12,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.1.1.1.12
+m-obsolete: FALSE
+m-substr: caseExactIA5SubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: memberUid
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.13.ldif
new file mode 100644
index 0000000..99031ce
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.13.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.13,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.1.1.1.13
+m-obsolete: FALSE
+m-substr: caseExactIA5SubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: memberNisNetgroup
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.14.ldif
new file mode 100644
index 0000000..1c27124
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.14.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.14,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.1.1.1.14
+m-obsolete: FALSE
+m-description: Netgroup triple
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.1.1.0.0
+m-usage: USER_APPLICATIONS
+m-name: nisNetgroupTriple
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.15.ldif
new file mode 100644
index 0000000..dc67698
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.15.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.15,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.15
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: ipServicePort
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.16.ldif
new file mode 100644
index 0000000..aa2971b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.16.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.16,ou=attributeTypes,cn=nis,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.1.1.1.16
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: ipServiceProtocol
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.17.ldif
new file mode 100644
index 0000000..a4514b4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.17.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.17,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.17
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: ipProtocolNumber
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.18.ldif
new file mode 100644
index 0000000..45af5fa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.18.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.18,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.18
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: oncRpcNumber
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.19.ldif
new file mode 100644
index 0000000..f3661bd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.19.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.19,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.1.1.1.19
+m-obsolete: FALSE
+m-description: IP address
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: ipHostNumber
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.2.ldif
new file mode 100644
index 0000000..f1343a2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.2.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.2,ou=attributeTypes,cn=nis,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: The GECOS field; the common name
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.1.1.1.2
+m-substr: caseIgnoreIA5SubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: gecos
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.20.ldif
new file mode 100644
index 0000000..88f6122
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.20.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.20,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.20
+m-obsolete: FALSE
+m-description: IP network
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: ipNetworkNumber
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.21.ldif
new file mode 100644
index 0000000..211bfda
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.21.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.21,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.21
+m-obsolete: FALSE
+m-description: IP netmask
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: ipNetmaskNumber
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.22.ldif
new file mode 100644
index 0000000..57dbe00
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.22.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.22,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.1.1.1.22
+m-obsolete: FALSE
+m-description: MAC address
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: macAddress
+creatorsname: uid=admin,ou=system
+m-equality: caseIgnoreIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.23.ldif
new file mode 100644
index 0000000..73d7d17
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.23.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.23,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.1.1.1.23
+m-obsolete: FALSE
+m-description: rpc.bootparamd parameter
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.1.1.0.1
+m-usage: USER_APPLICATIONS
+m-name: bootParameter
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.24.ldif
new file mode 100644
index 0000000..96ca3aa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.24.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.24,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.1.1.1.24
+m-obsolete: FALSE
+m-description: Boot image name
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: bootFile
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.26.ldif
new file mode 100644
index 0000000..f1d7084
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.26.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.26,ou=attributeTypes,cn=nis,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 1.3.6.1.1.1.1.26
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: nisMapName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.27.ldif
new file mode 100644
index 0000000..33858fa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.27.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.27,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.27
+m-obsolete: FALSE
+m-substr: caseExactIA5SubstringsMatch
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: nisMapEntry
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.3.ldif
new file mode 100644
index 0000000..a228140
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.3.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.3,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.3
+m-obsolete: FALSE
+m-description: The absolute path to the home directory
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: homeDirectory
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.4.ldif
new file mode 100644
index 0000000..00a688a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.4,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.4
+m-obsolete: FALSE
+m-description: The path to the login shell
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: USER_APPLICATIONS
+m-name: loginShell
+creatorsname: uid=admin,ou=system
+m-equality: caseExactIA5Match
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.5.ldif
new file mode 100644
index 0000000..dd6312e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.5.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.5,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.5
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: shadowLastChange
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.6.ldif
new file mode 100644
index 0000000..c5c3ca1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.6.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.6,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.6
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: shadowMin
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.7.ldif
new file mode 100644
index 0000000..8359e1c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.7.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.7,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.7
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: shadowMax
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.8.ldif
new file mode 100644
index 0000000..d30c7af
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.8.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.8,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.8
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: shadowWarning
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.9.ldif
new file mode 100644
index 0000000..01a5930
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.9.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.9,ou=attributeTypes,cn=nis,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.1.1.9
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: USER_APPLICATIONS
+m-name: shadowInactive
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=comparators.ldif
new file mode 100644
index 0000000..00ec15d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=nis,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=comparators/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=comparators/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif
new file mode 100644
index 0000000..474ef1b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=comparators/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.1.2.1,ou=comparators,cn=nis,ou=schema
+m-oid: 1.3.6.1.4.1.4203.1.2.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..a9f4afb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=nis,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..d08d9b0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=nis,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingrules.ldif
new file mode 100644
index 0000000..d6d3fae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=nis,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif
new file mode 100644
index 0000000..eda8cf5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingrules/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.1.2.1,ou=matchingRules,cn=nis,ou=schema
+m-oid: 1.3.6.1.4.1.4203.1.2.1
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseExactIA5SubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..5b06014
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=nis,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=nameforms.ldif
new file mode 100644
index 0000000..a6e2b8b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=nis,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=normalizers.ldif
new file mode 100644
index 0000000..54f6321
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=nis,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=normalizers/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=normalizers/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif
new file mode 100644
index 0000000..15190cd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=normalizers/m-oid=1.3.6.1.4.1.4203.1.2.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.1.2.1,ou=normalizers,cn=nis,ou=schema
+m-oid: 1.3.6.1.4.1.4203.1.2.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses.ldif
new file mode 100644
index 0000000..b0658c4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=nis,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.0.ldif
new file mode 100644
index 0000000..b602511
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.0.ldif
@@ -0,0 +1,21 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.0,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: uid
+m-must: uidNumber
+m-must: gidNumber
+m-must: homeDirectory
+m-oid: 1.3.6.1.1.1.2.0
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Abstraction of an account with POSIX attributes
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: posixAccount
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: userPassword
+m-may: loginShell
+m-may: gecos
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.1.ldif
new file mode 100644
index 0000000..53703ca
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.1.ldif
@@ -0,0 +1,21 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.1,ou=objectClasses,cn=nis,ou=schema
+m-must: uid
+m-oid: 1.3.6.1.1.1.2.1
+m-supobjectclass: top
+m-description: Additional attributes for shadow passwords
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: shadowAccount
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: userPassword
+m-may: shadowLastChange
+m-may: shadowMin
+m-may: shadowMax
+m-may: shadowWarning
+m-may: shadowInactive
+m-may: shadowExpire
+m-may: shadowFlag
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.10.ldif
new file mode 100644
index 0000000..009ee15
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.10,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: nisMapEntry
+m-must: nisMapName
+m-oid: 1.3.6.1.1.1.2.10
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: An entry in a NIS map
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: nisObject
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.11.ldif
new file mode 100644
index 0000000..d625f66
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.11.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.11,ou=objectClasses,cn=nis,ou=schema
+m-oid: 1.3.6.1.1.1.2.11
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: A device with a MAC address
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: ieee802Device
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: macAddress
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.12.ldif
new file mode 100644
index 0000000..081fe06
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.12.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.12,ou=objectClasses,cn=nis,ou=schema
+m-oid: 1.3.6.1.1.1.2.12
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: A device with boot parameters
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: bootableDevice
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: bootFile
+m-may: bootParameter
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.2.ldif
new file mode 100644
index 0000000..5d0c476
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.2.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.2,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: gidNumber
+m-oid: 1.3.6.1.1.1.2.2
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Abstraction of a group of accounts
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: posixGroup
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: userPassword
+m-may: memberUid
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.3.ldif
new file mode 100644
index 0000000..888480a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.3.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.3,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: ipServicePort
+m-must: ipServiceProtocol
+m-oid: 1.3.6.1.1.1.2.3
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Abstraction an Internet Protocol service
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: ipService
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.4.ldif
new file mode 100644
index 0000000..d0c7363
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.4.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.4,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: ipProtocolNumber
+m-oid: 1.3.6.1.1.1.2.4
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Abstraction of an IP protocol
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: ipProtocol
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.5.ldif
new file mode 100644
index 0000000..e0e4071
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.5.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.5,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: oncRpcNumber
+m-oid: 1.3.6.1.1.1.2.5
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Abstraction of an ONC/RPC binding
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: oncRpc
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.6.ldif
new file mode 100644
index 0000000..88070ca
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.6.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.6,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: ipHostNumber
+m-oid: 1.3.6.1.1.1.2.6
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Abstraction of a host, an IP device
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: ipHost
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: l
+m-may: description
+m-may: manager
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.7.ldif
new file mode 100644
index 0000000..8ab5c2a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.7.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.7,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-must: ipNetworkNumber
+m-oid: 1.3.6.1.1.1.2.7
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: Abstraction of an IP network
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: ipNetwork
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: ipNetmaskNumber
+m-may: l
+m-may: description
+m-may: manager
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.8.ldif
new file mode 100644
index 0000000..449e3d9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.8.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.8,ou=objectClasses,cn=nis,ou=schema
+m-must: cn
+m-oid: 1.3.6.1.1.1.2.8
+m-supobjectclass: top
+m-description: Abstraction of a netgroup
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: nisNetgroup
+creatorsname: uid=admin,ou=system
+m-may: nisNetgroupTriple
+m-may: memberNisNetgroup
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.9.ldif
new file mode 100644
index 0000000..5bcc5b6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.9.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.2.9,ou=objectClasses,cn=nis,ou=schema
+m-must: nisMapName
+m-oid: 1.3.6.1.1.1.2.9
+m-supobjectclass: top
+m-description: A generic abstraction of a NIS map
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: nisMap
+creatorsname: uid=admin,ou=system
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..eb9df3a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=nis,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers/m-oid=1.3.6.1.1.1.0.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers/m-oid=1.3.6.1.1.1.0.0.ldif
new file mode 100644
index 0000000..7e8f4fd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers/m-oid=1.3.6.1.1.1.0.0.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.0.0,ou=syntaxCheckers,cn=nis,ou=schema
+m-oid: 1.3.6.1.1.1.0.0
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers/m-oid=1.3.6.1.1.1.0.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers/m-oid=1.3.6.1.1.1.0.1.ldif
new file mode 100644
index 0000000..7969f5c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxcheckers/m-oid=1.3.6.1.1.1.0.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.0.1,ou=syntaxCheckers,cn=nis,ou=schema
+m-oid: 1.3.6.1.1.1.0.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes.ldif
new file mode 100644
index 0000000..e5c91e3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=nis,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes/m-oid=1.3.6.1.1.1.0.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes/m-oid=1.3.6.1.1.1.0.0.ldif
new file mode 100644
index 0000000..11314f3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes/m-oid=1.3.6.1.1.1.0.0.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.0.0,ou=syntaxes,cn=nis,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.1.0.0
+m-description: RFC2307 NIS Netgroup Triple
+m-description: NIS Netgroup Triple
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes/m-oid=1.3.6.1.1.1.0.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes/m-oid=1.3.6.1.1.1.0.1.ldif
new file mode 100644
index 0000000..fd9afdd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=nis/ou=syntaxes/m-oid=1.3.6.1.1.1.0.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.0.1,ou=syntaxes,cn=nis,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.1.1.0.1
+m-description: NIS Boot Parameter
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other.ldif
new file mode 100644
index 0000000..6058ebe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: cn=other,ou=schema
+cn: other
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+m-dependencies: apache
+m-dependencies: apachemeta
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=attributetypes.ldif
new file mode 100644
index 0000000..6d7cd98
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=other,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=comparators.ldif
new file mode 100644
index 0000000..5cbcd7d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=other,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..ce76eb0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=other,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..1700472
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=other,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=matchingrules.ldif
new file mode 100644
index 0000000..03fd5ea
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=other,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..ecee6e0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=other,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=nameforms.ldif
new file mode 100644
index 0000000..f6a9719
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=other,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=normalizers.ldif
new file mode 100644
index 0000000..61e1979
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=other,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=objectclasses.ldif
new file mode 100644
index 0000000..39d8ee8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=other,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..c4bee61
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=other,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=syntaxes.ldif
new file mode 100644
index 0000000..2e596a3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=other/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=other,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy.ldif
new file mode 100644
index 0000000..43397b5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy.ldif
@@ -0,0 +1,7 @@
+version: 1
+dn: cn=pwdpolicy,ou=schema
+cn: pwdpolicy
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes.ldif
new file mode 100644
index 0000000..9d4e5fe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=pwdpolicy,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.1.ldif
new file mode 100644
index 0000000..5a38406
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.1.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.1,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.1
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdAttribute
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.10.ldif
new file mode 100644
index 0000000..ce0f55d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.10.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.10,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.10
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdLockoutDuration
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.11.ldif
new file mode 100644
index 0000000..a116b10
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.11.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.11,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.11
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMaxFailure
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.12.ldif
new file mode 100644
index 0000000..74d131b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.12.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.12,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.12
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdFailureCountInterval
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.13.ldif
new file mode 100644
index 0000000..9f1b457
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.13.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.13,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.13
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMustChange
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.14.ldif
new file mode 100644
index 0000000..bd2282a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.14.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.14,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.14
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdAllowUserChange
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.15.ldif
new file mode 100644
index 0000000..41b55fa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.15.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.15,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.15
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdSafeModify
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.16.ldif
new file mode 100644
index 0000000..929016d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.16.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.16,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.16
+m-description: The time the password was last changed
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: directoryOperation
+m-name: pwdChangedTime
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.17.ldif
new file mode 100644
index 0000000..24cf2c6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.17.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.17,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.17
+m-description: The time an user account was locked
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: directoryOperation
+m-name: pwdAccountLockedTime
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.19.ldif
new file mode 100644
index 0000000..bae74fc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.19.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.19,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.19
+m-description: The timestamps of the last consecutive authentication failures
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: directoryOperation
+m-name: pwdFailureTime
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.2.ldif
new file mode 100644
index 0000000..8499ceb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.2.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.2,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.2
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMinAge
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.20.ldif
new file mode 100644
index 0000000..e3829ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.20.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.20,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.20
+m-description: The history of user s passwords
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: directoryOperation
+m-name: pwdHistory
+creatorsname: uid=admin,ou=system
+m-equality: octetStringMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.21.ldif
new file mode 100644
index 0000000..6803bfd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.21.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.21,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.21
+m-description: The timestamps of the grace authentication after the password has expired
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: directoryOperation
+m-name: pwdGraceUseTime
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.22.ldif
new file mode 100644
index 0000000..b17f197
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.22.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.22,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.22
+m-description: The indication that the password has been reset
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-usage: directoryOperation
+m-name: pwdReset
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.23.ldif
new file mode 100644
index 0000000..dc99dba
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.23.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.23,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.23
+m-description: The pwdPolicy subentry in effect for this object
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: directoryOperation
+m-name: pwdPolicySubentry
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.24.ldif
new file mode 100644
index 0000000..b505998
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.24.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.24,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.24
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMinDelay
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.25.ldif
new file mode 100644
index 0000000..8c71173
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.25.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.25,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.25
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMaxDelay
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.26.ldif
new file mode 100644
index 0000000..5a4dbc9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.26.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.26,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.26
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMaxIdle
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.27.ldif
new file mode 100644
index 0000000..2f12f4d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.27.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.27,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.27
+m-description: The time the password becomes enabled
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: directoryOperation
+m-name: pwdStartTime
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.28.ldif
new file mode 100644
index 0000000..d867745
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.28.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.28,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.28
+m-description: The time the password becomes disabled
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: directoryOperation
+m-name: pwdEndTime
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.29.ldif
new file mode 100644
index 0000000..238bb15
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.29.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.29,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-ordering: generalizedTimeOrderingMatch
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.29
+m-description: The timestamp of the last successful authentication
+m-nousermodification: TRUE
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+m-usage: directoryOperation
+m-name: pwdLastSuccess
+creatorsname: uid=admin,ou=system
+m-equality: generalizedTimeMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.3.ldif
new file mode 100644
index 0000000..9d4f33e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.3.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.3,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.3
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMaxAge
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.30.ldif
new file mode 100644
index 0000000..e18b10a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.30.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.30,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.30
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdGraceExpire
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.31.ldif
new file mode 100644
index 0000000..19e3f44
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.31.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.31,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.31
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMaxLength
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.4.ldif
new file mode 100644
index 0000000..967ff2a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.4.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.4,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.4
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdInHistory
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.5.ldif
new file mode 100644
index 0000000..f63f878
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.5.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.5,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.5
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdCheckQuality
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.6.ldif
new file mode 100644
index 0000000..d3f0bc4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.6.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.6,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.6
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdMinLength
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.7.ldif
new file mode 100644
index 0000000..b71bf80
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.7.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.7,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.7
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdExpireWarning
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.8.ldif
new file mode 100644
index 0000000..ae8c251
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.8.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.8,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.8
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdGraceAuthNLimit
+creatorsname: uid=admin,ou=system
+m-equality: integerMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.9.ldif
new file mode 100644
index 0000000..a876365
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=attributetypes/m-oid=1.3.6.1.4.1.42.2.27.8.1.9.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.1.9,ou=attributeTypes,cn=pwdpolicy,ou=schema
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.42.2.27.8.1.9
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaTop
+objectclass: metaAttributeType
+objectclass: top
+m-name: pwdLockout
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
+m-length: 0
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=comparators.ldif
new file mode 100644
index 0000000..7bf03ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=pwdpolicy,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..7237abe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=pwdpolicy,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..b4d38b2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=pwdpolicy,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=matchingrules.ldif
new file mode 100644
index 0000000..2b080c0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=pwdpolicy,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..7f293a8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=pwdpolicy,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=nameforms.ldif
new file mode 100644
index 0000000..53c4ec5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=pwdpolicy,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=normalizers.ldif
new file mode 100644
index 0000000..65e23a7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=pwdpolicy,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=objectclasses.ldif
new file mode 100644
index 0000000..8aed5cf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=pwdpolicy,ou=schema
+ou: objectClasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.8.2.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.8.2.1.ldif
new file mode 100644
index 0000000..a422fab
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=objectclasses/m-oid=1.3.6.1.4.1.42.2.27.8.2.1.ldif
@@ -0,0 +1,31 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.42.2.27.8.2.1,ou=objectClasses,cn=pwdpolicy,ou=schema
+m-must: pwdAttribute
+m-oid: 1.3.6.1.4.1.42.2.27.8.2.1
+m-supobjectclass: top
+m-description: class to hold the PasswordPolicy parameters
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: pwdPolicy
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: pwdMinAge
+m-may: pwdMaxAge
+m-may: pwdInHistory
+m-may: pwdCheckQuality
+m-may: pwdMinLength
+m-may: pwdMaxLength
+m-may: pwdExpireWarning
+m-may: pwdGraceAuthNLimit
+m-may: pwdGraceExpire
+m-may: pwdLockout
+m-may: pwdLockoutDuration
+m-may: pwdMaxFailure
+m-may: pwdFailureCountInterval
+m-may: pwdMustChange
+m-may: pwdAllowUserChange
+m-may: pwdSafeModify
+m-may: pwdMinDelay
+m-may: pwdMaxDelay
+m-may: pwdMaxIdle
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..d61bc08
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=pwdpolicy,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=syntaxes.ldif
new file mode 100644
index 0000000..d056639
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=pwdpolicy/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=pwdpolicy,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis.ldif
new file mode 100644
index 0000000..22dd251
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis.ldif
@@ -0,0 +1,12 @@
+# Generated by Apache Directory Studio on December 20, 2009 11:41:54 PM
+
+# SCHEMA "RFC2307BIS"
+dn: cn=rfc2307bis, ou=schema
+objectclass: metaSchema
+objectclass: top
+cn: rfc2307bis
+m-disabled: TRUE
+m-dependencies: system
+m-dependencies: core
+m-dependencies: nis
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes.ldif
new file mode 100644
index 0000000..28ef0e1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=rfc2307bis,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.28.ldif
new file mode 100644
index 0000000..2244ef2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.28.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.1.1.1.28, ou=attributeTypes, cn=rfc2307bis, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.1.1.28
+m-name: nisPublicKey
+m-description: NIS public key
+m-equality: octetStringMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.29.ldif
new file mode 100644
index 0000000..ed8bafa
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.29.ldif
@@ -0,0 +1,11 @@
+dn: m-oid=1.3.6.1.1.1.1.29, ou=attributeTypes, cn=rfc2307bis, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.1.1.29
+m-name: nisSecretKey
+m-description: NIS secret key
+m-equality: octetStringMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.30.ldif
new file mode 100644
index 0000000..64937dc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.30.ldif
@@ -0,0 +1,10 @@
+dn: m-oid=1.3.6.1.1.1.1.30, ou=attributeTypes, cn=rfc2307bis, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.1.1.30
+m-name: nisDomain
+m-description: NIS domain
+m-equality: caseIgnoreIA5Match
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-length: 0
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.31.ldif
new file mode 100644
index 0000000..1c807fc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.31.ldif
@@ -0,0 +1,12 @@
+dn: m-oid=1.3.6.1.1.1.1.31, ou=attributeTypes, cn=rfc2307bis, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.1.1.31
+m-name: automountMapName
+m-description: automount Map Name
+m-equality: caseExactIA5Match
+m-substr: caseExactIA5SubstringsMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.32.ldif
new file mode 100644
index 0000000..9ffe540
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=attributetypes/m-oid=1.3.6.1.1.1.1.32.ldif
@@ -0,0 +1,12 @@
+dn: m-oid=1.3.6.1.1.1.1.32, ou=attributeTypes, cn=rfc2307bis, ou=schema
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.1.1.32
+m-name: automountKey
+m-description: Automount Key value
+m-equality: caseExactIA5Match
+m-substr: caseExactIA5SubstringsMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-length: 0
+m-singleValue: TRUE
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=comparators.ldif
new file mode 100644
index 0000000..432c109
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=rfc2307bis,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..f351f1c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=rfc2307bis,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..81cb672
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=rfc2307bis,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=matchingrules.ldif
new file mode 100644
index 0000000..fb4d892
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=rfc2307bis,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..b0fd429
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=rfc2307bis,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=nameforms.ldif
new file mode 100644
index 0000000..7ee21fd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=rfc2307bis,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=normalizers.ldif
new file mode 100644
index 0000000..b12b5a7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=rfc2307bis,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses.ldif
new file mode 100644
index 0000000..0d92a47
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=rfc2307bis,ou=schema
+ou: objectClasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.14.ldif
new file mode 100644
index 0000000..b737028
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.14.ldif
@@ -0,0 +1,14 @@
+dn: m-oid=1.3.6.1.1.1.2.14, ou=objectClasses, cn=rfc2307bis, ou=schema
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.1.2.14
+m-name: nisKeyObject
+m-description: An object with a public and secret key
+m-supObjectClass: top
+m-typeObjectClass: AUXILIARY
+m-must: cn
+m-must: nisPublicKey
+m-must: nisSecretKey
+m-may: uidNumber
+m-may: description
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.15.ldif
new file mode 100644
index 0000000..cb77085
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.1.1.2.15.ldif
@@ -0,0 +1,10 @@
+dn: m-oid=1.3.6.1.1.1.2.15, ou=objectClasses, cn=rfc2307bis, ou=schema
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.1.1.2.15
+m-name: nisDomainObject
+m-description: Associates a NIS domain with a naming context
+m-supObjectClass: top
+m-typeObjectClass: AUXILIARY
+m-must: nisDomain
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.13.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.13.1.1.ldif
new file mode 100644
index 0000000..42d566e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=objectclasses/m-oid=1.3.6.1.4.1.5322.13.1.1.ldif
@@ -0,0 +1,8 @@
+dn: m-oid=1.3.6.1.4.1.5322.13.1.1, ou=objectClasses, cn=rfc2307bis, ou=schema
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-oid: 1.3.6.1.4.1.5322.13.1.1
+m-name: namedObject
+m-supObjectClass: top
+m-may: cn
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..5e751b9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=rfc2307bis,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=syntaxes.ldif
new file mode 100644
index 0000000..edab017
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=rfc2307bis/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=rfc2307bis,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba.ldif
new file mode 100644
index 0000000..44576f7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: cn=samba,ou=schema
+cn: samba
+m-disabled: TRUE
+objectclass: metaSchema
+objectclass: top
+m-dependencies: system
+m-dependencies: core
+m-dependencies: inetorgperson
+m-dependencies: nis
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes.ldif
new file mode 100644
index 0000000..5e4b3fd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=samba,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.19.ldif
new file mode 100644
index 0000000..9561911
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.19.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.19,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.19
+m-name: sambaGroupType
+m-description: NT Group Type
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.20.ldif
new file mode 100644
index 0000000..a9b2b4c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.20.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.20,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.20
+m-name: sambaSID
+m-description: Security ID
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.21.ldif
new file mode 100644
index 0000000..8e4a6ce
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.21.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.21,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.21
+m-name: sambaNextUserRid
+m-description: Next NT rid to give our for users
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.22.ldif
new file mode 100644
index 0000000..8509ba9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.22.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.22,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.22
+m-name: sambaNextGroupRid
+m-description: Next NT rid to give out for groups
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.23.ldif
new file mode 100644
index 0000000..7415889
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.23.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.23,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.23
+m-name: sambaPrimaryGroupSID
+m-description: Primary Group Security ID
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.24.ldif
new file mode 100644
index 0000000..adab221
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.24.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.24,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.24
+m-name: sambaLMPassword
+m-description: LanManager Password
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.25.ldif
new file mode 100644
index 0000000..01182c9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.25.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.25,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.25
+m-name: sambaNTPassword
+m-description: MD4 hash of the unicode password
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.26.ldif
new file mode 100644
index 0000000..c362da0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.26.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.26,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.26
+m-name: sambaAcctFlags
+m-description: Account Flags
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.27.ldif
new file mode 100644
index 0000000..480da3e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.27.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.27,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.27
+m-name: sambaPwdLastSet
+m-description: Timestamp of the last password update
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.28.ldif
new file mode 100644
index 0000000..ff2ddef
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.28.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.28,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.28
+m-name: sambaPwdCanChange
+m-description: Timestamp of when the user is allowed to update the password
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.29.ldif
new file mode 100644
index 0000000..36e64a1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.29.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.29,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.29
+m-name: sambaPwdMustChange
+m-description: Timestamp of when the password will expire
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.30.ldif
new file mode 100644
index 0000000..96e1477
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.30.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.30,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.30
+m-name: sambaLogonTime
+m-description: Timestamp of last logon
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.31.ldif
new file mode 100644
index 0000000..ac2545f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.31.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.31,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.31
+m-name: sambaLogoffTime
+m-description: Timestamp of last logoff
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.32.ldif
new file mode 100644
index 0000000..b3c32a9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.32.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.32,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.32
+m-name: sambaKickoffTime
+m-description: Timestamp of when the user will be logged off automatically
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.33.ldif
new file mode 100644
index 0000000..29c57d6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.33.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.33,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.33
+m-name: sambaHomeDrive
+m-description: Driver letter of home directory mapping
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.34.ldif
new file mode 100644
index 0000000..b57c4f7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.34.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.34,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.34
+m-name: sambaLogonScript
+m-description: Logon script path
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.35.ldif
new file mode 100644
index 0000000..8f849bc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.35.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.35,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.35
+m-name: sambaProfilePath
+m-description: Roaming profile path
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.36.ldif
new file mode 100644
index 0000000..1dde6c5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.36.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.36,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.36
+m-name: sambaUserWorkstations
+m-description: List of user workstations the user is allowed to logon to
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.37.ldif
new file mode 100644
index 0000000..a4a2ce8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.37.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.37,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.37
+m-name: sambaHomePath
+m-description: Home directory UNC path
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.38.ldif
new file mode 100644
index 0000000..4626c12
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.38.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.38,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.38
+m-name: sambaDomainName
+m-description: Windows NT domain to which the user belongs
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.39.ldif
new file mode 100644
index 0000000..f941655
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.39.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.39,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.39
+m-name: sambaNextRid
+m-description: Next NT rid to give out for anything
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-collective: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.40.ldif
new file mode 100644
index 0000000..a7cda01
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.40.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.40,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.40
+m-name: sambaAlgorithmicRidBase
+m-description: Base at which the samba RID generation algorithm should operate
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.41.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.41.ldif
new file mode 100644
index 0000000..c042d15
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.41.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.41,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.41
+m-name: sambaShareName
+m-description: Share Name
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.42.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.42.ldif
new file mode 100644
index 0000000..63c56e5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.42.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.42,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.42
+m-name: sambaOptionName
+m-description: Option Name
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-substr: caseIgnoreSubstringsMatch
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-obsolete: FALSE
+m-collective: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.43.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.43.ldif
new file mode 100644
index 0000000..4de584c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.43.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.43,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.43
+m-name: sambaBoolOption
+m-description: A boolean option
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-equality: booleanMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.44.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.44.ldif
new file mode 100644
index 0000000..4732106
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.44.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.44,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.44
+m-name: sambaIntegerOption
+m-description: An integer option
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.45.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.45.ldif
new file mode 100644
index 0000000..2fc2cc4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.45.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.45,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.45
+m-name: sambaStringOption
+m-description: A string option
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseExactIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.46.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.46.ldif
new file mode 100644
index 0000000..222e4ae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.46.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.46,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.46
+m-name: sambaStringListOption
+m-description: A string list option
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-singlevalue: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+m-usage: USER_APPLICATIONS
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.47.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.47.ldif
new file mode 100644
index 0000000..585ed7f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.47.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.47,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.47
+m-name: sambaMungedDial
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseExactMatch
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.48.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.48.ldif
new file mode 100644
index 0000000..e5b68c2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.48.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.48,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.48
+m-name: sambaBadPasswordCount
+m-description: Bad password attempt count
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.49.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.49.ldif
new file mode 100644
index 0000000..1f3e60b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.49.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.49,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.49
+m-name: sambaBadPasswordTime
+m-description: Time of the last bad password attempt
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.50.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.50.ldif
new file mode 100644
index 0000000..e1b194b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.50.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.50,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.50
+m-name: sambaPrivName
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-equality: caseIgnoreMatch
+m-substr: caseIgnoreSubstringsMatch
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-obsolete: FALSE
+m-collective: FALSE
+m-nousermodification: FALSE
+m-supattributetype: name
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.51.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.51.ldif
new file mode 100644
index 0000000..f1d4b1e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.51.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.51,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.51
+m-name: sambaSIDList
+m-description: Security ID List
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.52.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.52.ldif
new file mode 100644
index 0000000..1b76b0a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.52.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.52,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.52
+m-name: sambaPrivilegeList
+m-description: Privileges List
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.53.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.53.ldif
new file mode 100644
index 0000000..227553d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.53.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.53,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.53
+m-name: sambaTrustFlags
+m-description: Trust Password Flags
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.54.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.54.ldif
new file mode 100644
index 0000000..b96dda5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.54.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.54,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.54
+m-name: sambaPasswordHistory
+m-description: Concatenated MD4 hashes of the unicode passwords used on this account
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: FALSE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.55.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.55.ldif
new file mode 100644
index 0000000..a168d41
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.55.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.55,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.55
+m-name: sambaLogonHours
+m-description: Logon Hours
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-equality: caseIgnoreIA5Match
+m-singlevalue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-nousermodification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.58.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.58.ldif
new file mode 100644
index 0000000..b10f244
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.58.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.58,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.58
+m-name: sambaMinPwdLength
+m-description: Minimal password length (default: 5)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.59.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.59.ldif
new file mode 100644
index 0000000..d2c977f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.59.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.59,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.59
+m-name: sambaPwdHistoryLength
+m-description: Length of Password History Entries (default: 0 =>  off)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.60.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.60.ldif
new file mode 100644
index 0000000..11954ba
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.60.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.60,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.60
+m-name: sambaLogonToChgPwd
+m-description: Force Users to logon for password change (default: 0 => off, 2 => on)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.61.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.61.ldif
new file mode 100644
index 0000000..fd934fe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.61.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.61,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.61
+m-name: sambaMaxPwdAge
+m-description: Maximum password age, in seconds (default: -1 => never expire passwords)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.62.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.62.ldif
new file mode 100644
index 0000000..8ecf078
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.62.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.62,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.62
+m-name: sambaMinPwdAge
+m-description: Minimum password age, in seconds (default: 0 => allow immediate password change)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.63.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.63.ldif
new file mode 100644
index 0000000..11f6e94
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.63.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.63,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.63
+m-name: sambaLockoutDuration
+m-description: Lockout duration in minutes (default: 30, -1 => forever)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-equality: integerMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.64.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.64.ldif
new file mode 100644
index 0000000..2c93472
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.64.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.64,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.64
+m-name: sambaLockoutObservationWindow
+m-description: Reset time after lockout in minutes (default: 30)
+objectclass: top
+objectclass: metaTop
+objectclass: metaAttributeType
+m-equality: integerMatch
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.65.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.65.ldif
new file mode 100644
index 0000000..efaf0c5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.65.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.65,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.65
+m-name: sambaLockoutThreshold
+m-description: Lockout users after bad logon attempts (default: 0 => off)
+objectClass: top
+objectClass: metaTop
+objectClass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-noUserModification: FALSE
+m-collective: FALSE
+m-obsolete: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.66.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.66.ldif
new file mode 100644
index 0000000..f68eb77
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.66.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.66,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.66
+m-name: sambaForceLogoff
+m-description: Disconnect Users outside logon hours (default: -1 => off, 0 => on)
+objectClass: top
+objectClass: metaTop
+objectClass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONSm-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.67.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.67.ldif
new file mode 100644
index 0000000..ee9a6a4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=attributetypes/m-oid=1.3.6.1.4.1.7165.2.1.67.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.1.67,ou=attributeTypes,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.1.67
+m-name: sambaRefuseMachinePwdChange
+m-description: Allow Machine Password changes (default: 0 => off)
+objectClass: top
+objectClass: metaTop
+objectClass: metaAttributeType
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-equality: integerMatch
+m-singleValue: TRUE
+m-usage: USER_APPLICATIONS
+m-collective: FALSE
+m-obsolete: FALSE
+m-noUserModification: FALSE
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=comparators.ldif
new file mode 100644
index 0000000..e6b9b45
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=samba,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..4745701
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=samba,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..25248f1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=samba,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=matchingrules.ldif
new file mode 100644
index 0000000..b9a57ab
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=samba,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..50ee3e9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=samba,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=nameforms.ldif
new file mode 100644
index 0000000..3924546
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=samba,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=normalizers.ldif
new file mode 100644
index 0000000..9c7ca8e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=samba,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses.ldif
new file mode 100644
index 0000000..423ff59
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=samba,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.1.2.2.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.1.2.2.10.ldif
new file mode 100644
index 0000000..b4f6043
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.1.2.2.10.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.1.2.2.10,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.1.2.2.10
+m-name: sambaConfig
+m-description: Samba Configuration Section
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-may: description
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.11.ldif
new file mode 100644
index 0000000..84ad6cf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.11.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.11,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.11
+m-name: sambaShare
+m-description: Samba Share Section
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: STRUCTURAL
+m-must: sambaShareName
+m-may: description
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.12.ldif
new file mode 100644
index 0000000..870b32b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.12.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.12,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.12
+m-name: sambaConfigOption
+m-description: Samba Configuration Option
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: STRUCTURAL
+m-must: sambaOptionName
+m-may: sambaBoolOption
+m-may: sambaIntegerOption
+m-may: sambaStringListOption
+m-may: sambaStringOption
+m-may: description
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.13.ldif
new file mode 100644
index 0000000..57c8f4c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.13.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.13,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.13
+m-name: sambaPrivilege
+m-description: Samba Privilege
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-must: sambaSID
+m-may: sambaPrivilegeList
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.14.ldif
new file mode 100644
index 0000000..e5cfa22
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.14.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.14,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.14
+m-name: sambaTrustPassword
+m-description: Samba Trust Password
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: top
+m-must: sambaDomainName
+m-must: sambaNTPassword
+m-must: sambaTrustFlags
+m-may: sambaPwdLastSet
+m-may: sambaSID
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.4.ldif
new file mode 100644
index 0000000..d1cc751
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.4.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.4,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.4
+m-name: sambaGroupMapping
+m-description: Samba Group Mapping
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-must: gidNumber
+m-must: sambaGroupType
+m-must: sambaSID
+m-may: description
+m-may: displayName
+m-may: sambaSIDList
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.5.ldif
new file mode 100644
index 0000000..300b9cc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.5.ldif
@@ -0,0 +1,28 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.5,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.5
+m-name: sambaDomain
+m-description: Samba Domain Information
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: STRUCTURAL
+m-must: sambaDomainName
+m-must: sambaSID
+m-may: sambaAlgorithmicRidBase
+m-may: sambaForceLogoff
+m-may: sambaLockoutDuration
+m-may: sambaLockoutObservationWindow
+m-may: sambaLockoutThreshold
+m-may: sambaLogonToChgPwd
+m-may: sambaMaxPwdAge
+m-may: sambaMinPwdAge
+m-may: sambaMinPwdLength
+m-may: sambaNextGroupRid
+m-may: sambaNextRid
+m-may: sambaNextUserRid
+m-may: sambaPwdHistoryLength
+m-may: sambaRefuseMachinePwdChange
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.6.ldif
new file mode 100644
index 0000000..e46caa2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.6.ldif
@@ -0,0 +1,38 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.6,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.6
+m-name: sambaSamAccount
+m-description: Samba 3.0 Auxilary SAM Account
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-must: sambaSID
+m-must: uid
+m-may: cn
+m-may: description
+m-may: displayName
+m-may: sambaAcctFlags
+m-may: sambaBadPasswordCount
+m-may: sambaBadPasswordTime
+m-may: sambaDomainName
+m-may: sambaHomeDrive
+m-may: sambaHomePath
+m-may: sambaKickoffTime
+m-may: sambaLMPassword
+m-may: sambaLogoffTime
+m-may: sambaLogonHours
+m-may: sambaLogonScript
+m-may: sambaLogonTime
+m-may: sambaMungedDial
+m-may: sambaNTPassword
+m-may: sambaPasswordHistory
+m-may: sambaPrimaryGroupSID
+m-may: sambaProfilePath
+m-may: sambaPwdCanChange
+m-may: sambaPwdLastSet
+m-may: sambaPwdMustChange
+m-may: sambaUserWorkstations
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.7.ldif
new file mode 100644
index 0000000..58e6e57
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.7.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.7,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.7
+m-name: sambaUnixIdPool
+m-description: Pool for allocating UNIX uids/gids
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-must: gidNumber
+m-must: uidNumber
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.8.ldif
new file mode 100644
index 0000000..5281abb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.8.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.8,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.8
+m-name: sambaIdmapEntry
+m-description: Mapping from a SID to an ID
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: AUXILIARY
+m-must: sambaSID
+m-may: gidNumber
+m-may: uidNumber
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.9.ldif
new file mode 100644
index 0000000..0cc08ab
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=objectclasses/m-oid=1.3.6.1.4.1.7165.2.2.9.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.7165.2.2.9,ou=objectClasses,cn=samba,ou=schema
+m-oid: 1.3.6.1.4.1.7165.2.2.9
+m-name: sambaSidEntry
+m-description: Structural Class for a SID
+objectclass: top
+objectclass: metaTop
+objectclass: metaObjectClass
+m-obsolete: FALSE
+m-supobjectclass: top
+m-typeobjectclass: STRUCTURAL
+m-must: sambaSID
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..a7b60b3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=samba,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=syntaxes.ldif
new file mode 100644
index 0000000..b66a377
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=samba/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=samba,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system.ldif
new file mode 100644
index 0000000..f53ab30
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: cn=system,ou=schema
+cn: system
+objectclass: metaSchema
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes.ldif
new file mode 100644
index 0000000..b541b8c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=attributeTypes,cn=system,ou=schema
+ou: attributetypes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.1.4.ldif
new file mode 100644
index 0000000..5f1b40c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.1.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.4,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.4
+m-obsolete: FALSE
+m-description: RFC3045: name of implementation vendor
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: DSA_OPERATION
+m-name: vendorName
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.1.5.ldif
new file mode 100644
index 0000000..37b691a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.1.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.1.5,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.1.5
+m-obsolete: FALSE
+m-description: RFC3045: version of implementation
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: DSA_OPERATION
+m-name: vendorVersion
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.119.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.119.3.ldif
new file mode 100644
index 0000000..510de8d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.119.3.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.119.3,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 1.3.6.1.4.1.1466.101.119.3
+m-obsolete: FALSE
+m-description: RFC2589: entry time-to-live
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: DSA_OPERATION
+m-name: entryTtl
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.119.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.119.4.ldif
new file mode 100644
index 0000000..2a7885f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.119.4.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.119.4,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.119.4
+m-obsolete: FALSE
+m-description: RFC2589: dynamic subtrees
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DSA_OPERATION
+m-name: dynamicSubtrees
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.13.ldif
new file mode 100644
index 0000000..b22f10b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.13.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.13,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.120.13
+m-obsolete: FALSE
+m-description: RFC2252: supported controls
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: DSA_OPERATION
+m-name: supportedControl
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.14.ldif
new file mode 100644
index 0000000..c4d5256
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.14.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.14,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.120.14
+m-obsolete: FALSE
+m-description: RFC2252: supported SASL mechanisms
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: DSA_OPERATION
+m-name: supportedSASLMechanisms
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.15.ldif
new file mode 100644
index 0000000..eebc9ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.15.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.15,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.120.15
+m-obsolete: FALSE
+m-description: RFC2252: supported LDAP versions
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+m-usage: DSA_OPERATION
+m-name: supportedLDAPVersion
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.16.ldif
new file mode 100644
index 0000000..97b5483
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.16.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.16,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.120.16
+m-obsolete: FALSE
+m-description: RFC2252: LDAP syntaxes
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.54
+m-usage: DIRECTORY_OPERATION
+m-name: ldapSyntaxes
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.5.ldif
new file mode 100644
index 0000000..5a82ee7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.5.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.5,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.120.5
+m-obsolete: FALSE
+m-description: RFC2252: naming contexts
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DSA_OPERATION
+m-name: namingContexts
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.6.ldif
new file mode 100644
index 0000000..839b3b5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.6.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.6,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.120.6
+m-obsolete: FALSE
+m-description: RFC2252: alternative servers
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+m-usage: DSA_OPERATION
+m-name: altServer
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.7.ldif
new file mode 100644
index 0000000..6eb7f49
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.1466.101.120.7.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.7,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.1466.101.120.7
+m-obsolete: FALSE
+m-description: RFC2252: supported extended operations
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: DSA_OPERATION
+m-name: supportedExtension
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.250.1.57.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.250.1.57.ldif
new file mode 100644
index 0000000..740f7cc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.250.1.57.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.250.1.57,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.250.1.57
+m-obsolete: FALSE
+m-description: RFC2079: Uniform Resource Identifier with optional label
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: USER_APPLICATIONS
+m-name: labeledURI
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.1.3.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.1.3.5.ldif
new file mode 100644
index 0000000..bc0e954
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=1.3.6.1.4.1.4203.1.3.5.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.1.3.5,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 1.3.6.1.4.1.4203.1.3.5
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: DSA_OPERATION
+m-name: supportedFeatures
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.34.ldif
new file mode 100644
index 0000000..41f955b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.16.840.1.113730.3.1.34.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.1.34,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.16.840.1.113730.3.1.34
+m-obsolete: FALSE
+m-description: namedref: subordinate referral URL
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+m-usage: DISTRIBUTED_OPERATION
+m-name: ref
+creatorsname: uid=admin,ou=system
+m-equality: caseExactMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.1.ldif
new file mode 100644
index 0000000..3d3bc1a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.18.1,ou=attributeTypes,cn=system,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: RFC2252: time which object was created
+m-usage: DIRECTORY_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: generalizedTimeOrderingMatch
+m-collective: FALSE
+m-oid: 2.5.18.1
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: createTimestamp
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.10.ldif
new file mode 100644
index 0000000..61a4b9e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.10.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.18.10,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.18.10
+m-obsolete: FALSE
+m-description: RFC2252: name of controlling subschema entry
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DIRECTORY_OPERATION
+m-name: subschemaSubentry
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.12.ldif
new file mode 100644
index 0000000..bcb0876
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.12.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.18.12,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.18.12
+m-obsolete: FALSE
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DIRECTORY_OPERATION
+m-name: collectiveAttributeSubentries
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.2.ldif
new file mode 100644
index 0000000..256a4ea
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.2.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.18.2,ou=attributeTypes,cn=system,ou=schema
+m-singlevalue: TRUE
+m-obsolete: FALSE
+m-description: RFC2252: time which object was last modified
+m-usage: DIRECTORY_OPERATION
+creatorsname: uid=admin,ou=system
+m-ordering: generalizedTimeOrderingMatch
+m-collective: FALSE
+m-oid: 2.5.18.2
+m-nousermodification: TRUE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: modifyTimestamp
+m-equality: generalizedTimeMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.3.ldif
new file mode 100644
index 0000000..ada2669
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.3.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.18.3,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.18.3
+m-obsolete: FALSE
+m-description: RFC2252: name of creator
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DIRECTORY_OPERATION
+m-name: creatorsName
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.4.ldif
new file mode 100644
index 0000000..cee7c50
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.18.4,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.18.4
+m-obsolete: FALSE
+m-description: RFC2252: name of last modifier
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: DIRECTORY_OPERATION
+m-name: modifiersName
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.5.ldif
new file mode 100644
index 0000000..3ebaafd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.5.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.18.5,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.18.5
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: DIRECTORY_OPERATION
+m-name: administrativeRole
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.6.ldif
new file mode 100644
index 0000000..e882193
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.6.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=2.5.18.6,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.18.6
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.45
+m-usage: DIRECTORY_OPERATION
+m-name: subtreeSpecification
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.7.ldif
new file mode 100644
index 0000000..7e9990e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.7.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.18.7,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.18.7
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: DIRECTORY_OPERATION
+m-name: collectiveExclusions
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.9.ldif
new file mode 100644
index 0000000..2fd9629
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.18.9.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.18.9,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.18.9
+m-obsolete: FALSE
+m-description: X.501: entry has children
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+m-usage: DIRECTORY_OPERATION
+m-name: hasSubordinates
+creatorsname: uid=admin,ou=system
+m-equality: booleanMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.1.ldif
new file mode 100644
index 0000000..926dd31
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.1.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.21.1,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.21.1
+m-obsolete: FALSE
+m-description: RFC2252: DIT structure rules
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.17
+m-usage: DIRECTORY_OPERATION
+m-name: dITStructureRules
+creatorsname: uid=admin,ou=system
+m-equality: integerFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.2.ldif
new file mode 100644
index 0000000..2215731
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.2.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.21.2,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.21.2
+m-obsolete: FALSE
+m-description: RFC2252: DIT content rules
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.16
+m-usage: DIRECTORY_OPERATION
+m-name: dITContentRules
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.4.ldif
new file mode 100644
index 0000000..1696f50
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.4.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.21.4,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.21.4
+m-obsolete: FALSE
+m-description: RFC2252: matching rules
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.30
+m-usage: DIRECTORY_OPERATION
+m-name: matchingRules
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.5.ldif
new file mode 100644
index 0000000..006925e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.5.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.21.5,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.21.5
+m-obsolete: FALSE
+m-description: RFC2252: attribute types
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.3
+m-usage: DIRECTORY_OPERATION
+m-name: attributeTypes
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.6.ldif
new file mode 100644
index 0000000..7a74a60
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.6.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.21.6,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.21.6
+m-obsolete: FALSE
+m-description: RFC2252: object classes
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.37
+m-usage: DIRECTORY_OPERATION
+m-name: objectClasses
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.7.ldif
new file mode 100644
index 0000000..d9553ae
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.7.ldif
@@ -0,0 +1,15 @@
+version: 1
+dn: m-oid=2.5.21.7,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.21.7
+m-obsolete: FALSE
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.35
+m-usage: DIRECTORY_OPERATION
+m-name: nameForms
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.8.ldif
new file mode 100644
index 0000000..2362d7b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.8.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.21.8,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.21.8
+m-obsolete: FALSE
+m-description: RFC2252: matching rule uses
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.31
+m-usage: DIRECTORY_OPERATION
+m-name: matchingRuleUse
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierFirstComponentMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.9.ldif
new file mode 100644
index 0000000..ef19c6c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.21.9.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.21.9,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.21.9
+m-obsolete: FALSE
+m-description: X.500(93): structural object class of entry
+m-nousermodification: TRUE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: DIRECTORY_OPERATION
+m-name: structuralObjectClass
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.0.ldif
new file mode 100644
index 0000000..ef8dcd0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.0.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.0,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.0
+m-obsolete: FALSE
+m-description: RFC2256: object classes of the entity
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+m-usage: USER_APPLICATIONS
+m-name: objectClass
+creatorsname: uid=admin,ou=system
+m-equality: objectIdentifierMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.1.ldif
new file mode 100644
index 0000000..9d369d5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.1.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.1,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: TRUE
+m-oid: 2.5.4.1
+m-obsolete: FALSE
+m-description: RFC2256: name of aliased object
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: aliasedObjectName
+m-name: aliasedEntryName
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.3.ldif
new file mode 100644
index 0000000..795dc54
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.3.ldif
@@ -0,0 +1,19 @@
+version: 1
+dn: m-oid=2.5.4.3,ou=attributeTypes,cn=system,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: common name(s) for which the entity is known by
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.3
+m-supattributetype: name
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: cn
+m-name: commonName
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.35.ldif
new file mode 100644
index 0000000..d0dde9b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.35.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.35,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.35
+m-obsolete: FALSE
+m-description: RFC2256/2307: password of user
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+m-usage: USER_APPLICATIONS
+m-name: userPassword
+creatorsname: uid=admin,ou=system
+m-equality: octetStringMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.41.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.41.ldif
new file mode 100644
index 0000000..08fbeac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.41.ldif
@@ -0,0 +1,17 @@
+version: 1
+dn: m-oid=2.5.4.41,ou=attributeTypes,cn=system,ou=schema
+m-singlevalue: FALSE
+m-obsolete: FALSE
+m-description: RFC2256: common supertype of name attributes
+m-usage: USER_APPLICATIONS
+creatorsname: uid=admin,ou=system
+m-collective: FALSE
+m-oid: 2.5.4.41
+m-substr: caseIgnoreSubstringsMatch
+m-nousermodification: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-name: name
+m-equality: caseIgnoreMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.49.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.49.ldif
new file mode 100644
index 0000000..efedbb4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=attributetypes/m-oid=2.5.4.49.ldif
@@ -0,0 +1,16 @@
+version: 1
+dn: m-oid=2.5.4.49,ou=attributeTypes,cn=system,ou=schema
+m-collective: FALSE
+m-singlevalue: FALSE
+m-oid: 2.5.4.49
+m-obsolete: FALSE
+m-description: RFC2256: common supertype of DN attributes
+m-nousermodification: FALSE
+objectclass: metaAttributeType
+objectclass: metaTop
+objectclass: top
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+m-usage: USER_APPLICATIONS
+m-name: distinguishedName
+creatorsname: uid=admin,ou=system
+m-equality: distinguishedNameMatch
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators.ldif
new file mode 100644
index 0000000..daf83ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=comparators,cn=system,ou=schema
+ou: comparators
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif
new file mode 100644
index 0000000..2dfa037
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.1,ou=comparators,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif
new file mode 100644
index 0000000..ebefc9d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.2,ou=comparators,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif
new file mode 100644
index 0000000..7e5a821
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.3,ou=comparators,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.0.ldif
new file mode 100644
index 0000000..1cff54b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.0.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.0,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.0
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ObjectIdentifierComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.1.ldif
new file mode 100644
index 0000000..813e5dc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.1,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DnComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.10.ldif
new file mode 100644
index 0000000..45c9aaf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.10.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.10,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.10
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.NumericStringComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.11.ldif
new file mode 100644
index 0000000..72f96e2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.11.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.11,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.11
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.12.ldif
new file mode 100644
index 0000000..2967eaa4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.12.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.12,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.12
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.13.ldif
new file mode 100644
index 0000000..199ed00
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.13.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.13,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.13
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.BooleanComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.14.ldif
new file mode 100644
index 0000000..bfe902a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.14.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.14,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.14
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.IntegerComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.15.ldif
new file mode 100644
index 0000000..cbb200c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.15.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.15,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.15
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.IntegerComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.16.ldif
new file mode 100644
index 0000000..4c14f75
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.16.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.16,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.16
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.BitStringComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.17.ldif
new file mode 100644
index 0000000..b5d90f4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.17.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.17,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.17
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.18.ldif
new file mode 100644
index 0000000..1a3b56e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.18.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.18,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.18
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.19.ldif
new file mode 100644
index 0000000..40982ff
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.19.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.19,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.19
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ByteArrayComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.2.ldif
new file mode 100644
index 0000000..0f8ce3b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.2,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.20.ldif
new file mode 100644
index 0000000..01dc1bb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.20.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.20,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.20
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.TelephoneNumberComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.21.ldif
new file mode 100644
index 0000000..847f994
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.21.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.21,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.21
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.TelephoneNumberComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.22.ldif
new file mode 100644
index 0000000..2cff62f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.22.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.22,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.22
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.23.ldif
new file mode 100644
index 0000000..661f011
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.23.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.23,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.23
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.UniqueMemberComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.24.ldif
new file mode 100644
index 0000000..6896cc5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.24.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.24,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.24
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.27.ldif
new file mode 100644
index 0000000..f0f1a75
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.27.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.27,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.27
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.GeneralizedTimeComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.28.ldif
new file mode 100644
index 0000000..5f610ca
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.28.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.28,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.28
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.GeneralizedTimeComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.29.ldif
new file mode 100644
index 0000000..f24639a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.29.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.29,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.29
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.3.ldif
new file mode 100644
index 0000000..af0aef0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.3,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.30.ldif
new file mode 100644
index 0000000..fa44918
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.30.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.30,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.30
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.31.ldif
new file mode 100644
index 0000000..bd3e125
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.31.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.31,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.31
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.32.ldif
new file mode 100644
index 0000000..ac89a36
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.32.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.32,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.32
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.WordComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.33.ldif
new file mode 100644
index 0000000..0484aac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.33.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.33,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.33
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.WordComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.4.ldif
new file mode 100644
index 0000000..84e312b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.4.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.4,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.4
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimToLowerCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.5.ldif
new file mode 100644
index 0000000..96bcf2b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.5.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.5,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.5
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.6.ldif
new file mode 100644
index 0000000..bfad461
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.6.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.6,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.6
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.7.ldif
new file mode 100644
index 0000000..79610a3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.7.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.7,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.7
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.DeepTrimCachingNormalizingComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.8.ldif
new file mode 100644
index 0000000..c552c2c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.8.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.8,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.8
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.NumericStringComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.9.ldif
new file mode 100644
index 0000000..f3aa586
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=comparators/m-oid=2.5.13.9.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.9,ou=comparators,cn=system,ou=schema
+m-oid: 2.5.13.9
+m-fqcn: org.apache.directory.api.ldap.model.schema.comparators.NumericStringComparator
+objectclass: metaComparator
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=ditcontentrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=ditcontentrules.ldif
new file mode 100644
index 0000000..1d4a956
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=ditcontentrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditContentRules,cn=system,ou=schema
+ou: ditcontentrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=ditstructurerules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=ditstructurerules.ldif
new file mode 100644
index 0000000..bdb2c64
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=ditstructurerules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=ditStructureRules,cn=system,ou=schema
+ou: ditstructurerules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules.ldif
new file mode 100644
index 0000000..034914f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRules,cn=system,ou=schema
+ou: matchingrules
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif
new file mode 100644
index 0000000..82d9865
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.1,ou=matchingRules,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.1
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseExactIA5Match
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif
new file mode 100644
index 0000000..0be7b36
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.2,ou=matchingRules,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.2
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.26
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseIgnoreIA5Match
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif
new file mode 100644
index 0000000..3f801be
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.3,ou=matchingRules,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.3
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.58
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseIgnoreIA5SubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.0.ldif
new file mode 100644
index 0000000..d5587ac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.0.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.0,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.0
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: objectIdentifierMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.1.ldif
new file mode 100644
index 0000000..61c3347
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.1.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.1,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.1
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.12
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: distinguishedNameMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.10.ldif
new file mode 100644
index 0000000..01d2b6b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.10.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.10,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.10
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.58
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: numericStringSubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.11.ldif
new file mode 100644
index 0000000..6a03dd4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.11.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.11,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.11
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.41
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseIgnoreListMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.12.ldif
new file mode 100644
index 0000000..e116e87
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.12.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.12,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.12
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.58
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseIgnoreListSubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.13.ldif
new file mode 100644
index 0000000..070408a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.13.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.13,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.13
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.7
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: booleanMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.14.ldif
new file mode 100644
index 0000000..c96fa7a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.14.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.14,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.14
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: integerMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.15.ldif
new file mode 100644
index 0000000..cbd73c6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.15.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.15,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.15
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: integerOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.16.ldif
new file mode 100644
index 0000000..1513d83
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.16.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.16,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.16
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.6
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: bitStringMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.17.ldif
new file mode 100644
index 0000000..f098e0b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.17.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.17,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.17
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: octetStringMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.18.ldif
new file mode 100644
index 0000000..b32e1ce
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.18.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.18,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.18
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: octetStringOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.19.ldif
new file mode 100644
index 0000000..db3f3fe
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.19.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.19,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.19
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.40
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: octetStringSubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.2.ldif
new file mode 100644
index 0000000..dbc1dc8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.2.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.2,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.2
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseIgnoreMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.20.ldif
new file mode 100644
index 0000000..935cb6c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.20.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.20,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.20
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.50
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: telephoneNumberMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.21.ldif
new file mode 100644
index 0000000..87e0f80
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.21.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.21,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.21
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.58
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: telephoneNumberSubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.22.ldif
new file mode 100644
index 0000000..ad3b0c3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.22.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.22,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.22
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.43
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: presentationAddressMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.23.ldif
new file mode 100644
index 0000000..4e49731
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.23.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.23,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.23
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.34
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: uniqueMemberMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.24.ldif
new file mode 100644
index 0000000..fdb4045
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.24.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.24,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.24
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.42
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: protocolInformationMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.27.ldif
new file mode 100644
index 0000000..0359eb4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.27.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.27,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.27
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: generalizedTimeMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.28.ldif
new file mode 100644
index 0000000..6dc1179
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.28.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.28,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.28
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.24
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: generalizedTimeOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.29.ldif
new file mode 100644
index 0000000..2c87699
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.29.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.29,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.29
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.27
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: integerFirstComponentMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.3.ldif
new file mode 100644
index 0000000..49598d3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.3.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.3,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.3
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseIgnoreOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.30.ldif
new file mode 100644
index 0000000..136ff3f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.30.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.30,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.30
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.38
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: objectIdentifierFirstComponentMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.31.ldif
new file mode 100644
index 0000000..5da66f4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.31.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.31,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.31
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: directoryStringFirstComponentMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.32.ldif
new file mode 100644
index 0000000..73a52de
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.32.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.32,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.32
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: wordMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.33.ldif
new file mode 100644
index 0000000..f6fad40
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.33.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.33,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.33
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: keywordMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.4.ldif
new file mode 100644
index 0000000..a8a8dd5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.4.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.4,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.4
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.58
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseIgnoreSubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.5.ldif
new file mode 100644
index 0000000..6ba9f38
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.5.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.5,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.5
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseExactMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.6.ldif
new file mode 100644
index 0000000..6a488a0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.6.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.6,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.6
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseExactOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.7.ldif
new file mode 100644
index 0000000..83b1f1d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.7.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.7,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.7
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.58
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: caseExactSubstringsMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.8.ldif
new file mode 100644
index 0000000..ab2b517
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.8.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.8,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.8
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.36
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: numericStringMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.9.ldif
new file mode 100644
index 0000000..54a3c00
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingrules/m-oid=2.5.13.9.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.13.9,ou=matchingRules,cn=system,ou=schema
+m-oid: 2.5.13.9
+m-obsolete: FALSE
+m-syntax: 1.3.6.1.4.1.1466.115.121.1.36
+objectclass: metaMatchingRule
+objectclass: metaTop
+objectclass: top
+m-name: numericStringOrderingMatch
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingruleuse.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingruleuse.ldif
new file mode 100644
index 0000000..8519ce9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=matchingruleuse.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=matchingRuleUse,cn=system,ou=schema
+ou: matchingruleuse
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=nameforms.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=nameforms.ldif
new file mode 100644
index 0000000..62ec87b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=nameforms.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=nameForms,cn=system,ou=schema
+ou: nameforms
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers.ldif
new file mode 100644
index 0000000..f78d528
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=normalizers,cn=system,ou=schema
+ou: normalizers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif
new file mode 100644
index 0000000..106d595
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.1,ou=normalizers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif
new file mode 100644
index 0000000..236842f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.2,ou=normalizers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif
new file mode 100644
index 0000000..68f05e9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=1.3.6.1.4.1.1466.109.114.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.109.114.3,ou=normalizers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.109.114.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.0.ldif
new file mode 100644
index 0000000..32f1f11
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.0.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.0,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.0
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.ObjectIdentifierNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.1.ldif
new file mode 100644
index 0000000..34a974e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.1,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.1
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDnNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.10.ldif
new file mode 100644
index 0000000..ea28e43
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.10.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.10,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.10
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NumericNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.11.ldif
new file mode 100644
index 0000000..36051b7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.11.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.11,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.11
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.12.ldif
new file mode 100644
index 0000000..0c2b9d1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.12.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.12,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.12
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.13.ldif
new file mode 100644
index 0000000..9f03ee9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.13.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.13,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.13
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.BooleanNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.14.ldif
new file mode 100644
index 0000000..ea4fbce
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.14.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.14,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.14
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NumericNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.15.ldif
new file mode 100644
index 0000000..75095eb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.15.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.15,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.15
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NumericNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.16.ldif
new file mode 100644
index 0000000..55b11dd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.16.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.16,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.16
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.17.ldif
new file mode 100644
index 0000000..0a4feb4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.17.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.17,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.17
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.18.ldif
new file mode 100644
index 0000000..460bc5e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.18.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.18,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.18
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.19.ldif
new file mode 100644
index 0000000..638dc7f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.19.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.19,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.19
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.2.ldif
new file mode 100644
index 0000000..9bfff5d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.2,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.20.ldif
new file mode 100644
index 0000000..5c228b4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.20.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.20,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.20
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.TelephoneNumberNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.21.ldif
new file mode 100644
index 0000000..cba3637
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.21.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.21,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.21
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.TelephoneNumberNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.22.ldif
new file mode 100644
index 0000000..d062733
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.22.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.22,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.22
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.23.ldif
new file mode 100644
index 0000000..f9df55a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.23.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.23,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.23
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.UniqueMemberNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.24.ldif
new file mode 100644
index 0000000..daa6a1a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.24.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.24,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.24
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.27.ldif
new file mode 100644
index 0000000..3df1b63
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.27.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.27,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.27
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.GeneralizedTimeNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.28.ldif
new file mode 100644
index 0000000..316b573
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.28.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.28,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.28
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.GeneralizedTimeNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.29.ldif
new file mode 100644
index 0000000..a284720
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.29.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.29,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.29
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.3.ldif
new file mode 100644
index 0000000..097b8cf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.3,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.30.ldif
new file mode 100644
index 0000000..64e6d2b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.30.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.30,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.30
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.31.ldif
new file mode 100644
index 0000000..f83c6ec
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.31.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.31,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.31
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.32.ldif
new file mode 100644
index 0000000..37ad93f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.32.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.32,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.32
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.33.ldif
new file mode 100644
index 0000000..d11724a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.33.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.33,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.33
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.4.ldif
new file mode 100644
index 0000000..5f27569
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.4.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.4,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.4
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimToLowerNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.5.ldif
new file mode 100644
index 0000000..170a6d6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.5.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.5,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.5
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.6.ldif
new file mode 100644
index 0000000..9ba283b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.6.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.6,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.6
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.7.ldif
new file mode 100644
index 0000000..94e4b15
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.7.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.7,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.7
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.CachingDeepTrimNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.8.ldif
new file mode 100644
index 0000000..2e10f35
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.8.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.8,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.8
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NumericNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.9.ldif
new file mode 100644
index 0000000..11750fb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=normalizers/m-oid=2.5.13.9.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=2.5.13.9,ou=normalizers,cn=system,ou=schema
+m-oid: 2.5.13.9
+m-fqcn: org.apache.directory.api.ldap.model.schema.normalizers.NumericNormalizer
+objectclass: metaNormalizer
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses.ldif
new file mode 100644
index 0000000..8be7ab4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=objectClasses,cn=system,ou=schema
+ou: objectclasses
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.101.119.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.101.119.2.ldif
new file mode 100644
index 0000000..991f4f1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.101.119.2.ldif
@@ -0,0 +1,11 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.119.2,ou=objectClasses,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.101.119.2
+m-supobjectclass: top
+m-description: RFC2589: Dynamic Object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: dynamicObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.101.120.111.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.101.120.111.ldif
new file mode 100644
index 0000000..a7fa9eb
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.1466.101.120.111.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.101.120.111,ou=objectClasses,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.101.120.111
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2252: extensible object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: extensibleObject
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.4203.1.4.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.4203.1.4.1.ldif
new file mode 100644
index 0000000..3b31100
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=1.3.6.1.4.1.4203.1.4.1.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.4203.1.4.1,ou=objectClasses,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.4203.1.4.1
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: OpenLDAP Root DSE object
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: OpenLDAProotDSE
+m-name: LDAProotDSE
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
+m-may: cn
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.16.840.1.113730.3.2.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.16.840.1.113730.3.2.6.ldif
new file mode 100644
index 0000000..23b5475
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.16.840.1.113730.3.2.6.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.16.840.1.113730.3.2.6,ou=objectClasses,cn=system,ou=schema
+m-must: ref
+m-oid: 2.16.840.1.113730.3.2.6
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: namedref: named subordinate referral
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: referral
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.17.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.17.0.ldif
new file mode 100644
index 0000000..78ce61e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.17.0.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.17.0,ou=objectClasses,cn=system,ou=schema
+m-must: cn
+m-must: subtreeSpecification
+m-oid: 2.5.17.0
+m-obsolete: FALSE
+m-supobjectclass: top
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: subentry
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.17.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.17.2.ldif
new file mode 100644
index 0000000..c23f7f9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.17.2.ldif
@@ -0,0 +1,10 @@
+version: 1
+dn: m-oid=2.5.17.2,ou=objectClasses,cn=system,ou=schema
+m-oid: 2.5.17.2
+m-obsolete: FALSE
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: collectiveAttributeSubentry
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.20.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.20.1.ldif
new file mode 100644
index 0000000..0eac124
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.20.1.ldif
@@ -0,0 +1,18 @@
+version: 1
+dn: m-oid=2.5.20.1,ou=objectClasses,cn=system,ou=schema
+m-oid: 2.5.20.1
+m-obsolete: FALSE
+m-description: RFC2252: controlling subschema (sub)entry
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: subschema
+m-typeobjectclass: AUXILIARY
+creatorsname: uid=admin,ou=system
+m-may: dITStructureRules
+m-may: nameForms
+m-may: dITContentRules
+m-may: objectClasses
+m-may: attributeTypes
+m-may: matchingRules
+m-may: matchingRuleUse
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.6.0.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.6.0.ldif
new file mode 100644
index 0000000..03cd8b4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.6.0.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=2.5.6.0,ou=objectClasses,cn=system,ou=schema
+m-must: objectClass
+m-oid: 2.5.6.0
+m-obsolete: FALSE
+m-description: top of the superclass chain
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: top
+m-typeobjectclass: ABSTRACT
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.6.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.6.1.ldif
new file mode 100644
index 0000000..df72c7a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=objectclasses/m-oid=2.5.6.1.ldif
@@ -0,0 +1,13 @@
+version: 1
+dn: m-oid=2.5.6.1,ou=objectClasses,cn=system,ou=schema
+m-must: aliasedObjectName
+m-oid: 2.5.6.1
+m-obsolete: FALSE
+m-supobjectclass: top
+m-description: RFC2256: an alias
+objectclass: metaObjectClass
+objectclass: metaTop
+objectclass: top
+m-name: alias
+m-typeobjectclass: STRUCTURAL
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers.ldif
new file mode 100644
index 0000000..6b97e96
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxCheckers,cn=system,ou=schema
+ou: syntaxcheckers
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.1.ldif
new file mode 100644
index 0000000..709b03d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.1.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.1,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.1
+m-fqcn: org.apache.directory.api.ldap.aci.ACIItemSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.10.ldif
new file mode 100644
index 0000000..e0fa9c4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.10.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.10,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.10
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.CertificatePairSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.11.ldif
new file mode 100644
index 0000000..fc12bbd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.11.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.11,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.11
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.CountrySyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.12.ldif
new file mode 100644
index 0000000..86a5657
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.12.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.12,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.12
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DnSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.13.ldif
new file mode 100644
index 0000000..42f1b00
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.13.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.13,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.13
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DataQualitySyntaxSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.14.ldif
new file mode 100644
index 0000000..6c85095
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.14.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.14,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.14
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DeliveryMethodSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.15.ldif
new file mode 100644
index 0000000..54039e1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.15.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.15,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.15
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DirectoryStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.16.ldif
new file mode 100644
index 0000000..688c05c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.16.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.16,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.16
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DitContentRuleDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.17.ldif
new file mode 100644
index 0000000..554203b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.17.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.17,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.17
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DitStructureRuleDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.18.ldif
new file mode 100644
index 0000000..9f2e288
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.18.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.18,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.18
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DlSubmitPermissionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.19.ldif
new file mode 100644
index 0000000..cb51ae0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.19.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.19,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.19
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DsaQualitySyntaxSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.2.ldif
new file mode 100644
index 0000000..e9e10cd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.2.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.2,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.2
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.AccessPointSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.20.ldif
new file mode 100644
index 0000000..f920687
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.20.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.20,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.20
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.DseTypeSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.21.ldif
new file mode 100644
index 0000000..f87146c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.21.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.21,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.21
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.EnhancedGuideSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.22.ldif
new file mode 100644
index 0000000..6a5173f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.22.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.22,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.22
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.FacsimileTelephoneNumberSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.23.ldif
new file mode 100644
index 0000000..37b8d1f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.23.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.23,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.23
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.FaxSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.24.ldif
new file mode 100644
index 0000000..ba0e7a5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.24.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.24,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.24
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.GeneralizedTimeSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.25.ldif
new file mode 100644
index 0000000..de3cf33
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.25.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.25,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.25
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.GuideSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.26.ldif
new file mode 100644
index 0000000..196d962
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.26.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.26,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.26
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.Ia5StringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.27.ldif
new file mode 100644
index 0000000..054cd1e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.27.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.27,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.27
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.IntegerSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.28.ldif
new file mode 100644
index 0000000..2f3c596
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.28.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.28,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.28
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.JpegSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.29.ldif
new file mode 100644
index 0000000..60fd865
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.29.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.29,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.29
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.MasterAndShadowAccessPointSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.3.ldif
new file mode 100644
index 0000000..4e2b0e9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.3.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.3,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.3
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.AttributeTypeDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.30.ldif
new file mode 100644
index 0000000..a18c196
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.30.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.30,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.30
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.MatchingRuleDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.31.ldif
new file mode 100644
index 0000000..7744020
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.31.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.31,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.31
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.MatchingRuleUseDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.32.ldif
new file mode 100644
index 0000000..60976a0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.32.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.32,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.32
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.MailPreferenceSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.33.ldif
new file mode 100644
index 0000000..5872fd4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.33.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.33,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.33
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.MhsOrAddressSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.34.ldif
new file mode 100644
index 0000000..cb5908e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.34.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.34,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.34
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.NameAndOptionalUIDSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.35.ldif
new file mode 100644
index 0000000..71cc414
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.35.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.35,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.35
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.NameFormDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.36.ldif
new file mode 100644
index 0000000..0f880a4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.36.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.36,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.36
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.NumericStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.37.ldif
new file mode 100644
index 0000000..f5b47d8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.37.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.37,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.37
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.ObjectClassDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.38.ldif
new file mode 100644
index 0000000..019852a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.38.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.38,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.38
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OidSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.39.ldif
new file mode 100644
index 0000000..90f4168
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.39.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.39,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.39
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OtherMailboxSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.4.ldif
new file mode 100644
index 0000000..2c868fc
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.4.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.4,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.4
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.AudioSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.40.ldif
new file mode 100644
index 0000000..c688892
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.40.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.40,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.40
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.41.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.41.ldif
new file mode 100644
index 0000000..07bf2b9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.41.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.41,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.41
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.PostalAddressSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.42.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.42.ldif
new file mode 100644
index 0000000..d27e252
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.42.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.42,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.42
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.ProtocolInformationSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.43.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.43.ldif
new file mode 100644
index 0000000..73f2ea1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.43.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.43,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.43
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.PresentationAddressSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.44.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.44.ldif
new file mode 100644
index 0000000..b539739
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.44.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.44,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.44
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.PrintableStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.45.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.45.ldif
new file mode 100644
index 0000000..816d190
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.45.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.45,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.45
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.SubtreeSpecificationSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.46.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.46.ldif
new file mode 100644
index 0000000..7ecc6b6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.46.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.46,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.46
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupplierInformationSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.47.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.47.ldif
new file mode 100644
index 0000000..e5cb55b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.47.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.47,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.47
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupplierOrConsumerSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.48.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.48.ldif
new file mode 100644
index 0000000..5d00e11
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.48.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.48,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.48
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupplierAndConsumerSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.49.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.49.ldif
new file mode 100644
index 0000000..dd2305e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.49.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.49,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.49
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.SupportedAlgorithmSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.5.ldif
new file mode 100644
index 0000000..3c2007b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.5.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.5,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.5
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.BinarySyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.50.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.50.ldif
new file mode 100644
index 0000000..f37d950
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.50.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.50,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.50
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.TelephoneNumberSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.51.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.51.ldif
new file mode 100644
index 0000000..e3fe577
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.51.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.51,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.51
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.TeletexTerminalIdentifierSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.52.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.52.ldif
new file mode 100644
index 0000000..d231523
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.52.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.52,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.52
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.TelexNumberSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.53.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.53.ldif
new file mode 100644
index 0000000..4eca5bf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.53.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.53,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.53
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.UtcTimeSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.54.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.54.ldif
new file mode 100644
index 0000000..29f2615
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.54.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.54,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.54
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.LdapSyntaxDescriptionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.55.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.55.ldif
new file mode 100644
index 0000000..4c405da
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.55.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.55,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.55
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.56.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.56.ldif
new file mode 100644
index 0000000..57003a9
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.56.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.56,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.56
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.57.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.57.ldif
new file mode 100644
index 0000000..78befee
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.57.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.57,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.57
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.58.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.58.ldif
new file mode 100644
index 0000000..4125f0a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.58.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.58,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.58
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.SubstringAssertionSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.59.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.59.ldif
new file mode 100644
index 0000000..ee3182a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.59.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.59,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.59
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.6.ldif
new file mode 100644
index 0000000..fa25813
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.6.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.6,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.6
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.BitStringSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.7.ldif
new file mode 100644
index 0000000..f7d7d43
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.7.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.7,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.7
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.BooleanSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.8.ldif
new file mode 100644
index 0000000..8dfe4b2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.8.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.8,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.8
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.CertificateSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.9.ldif
new file mode 100644
index 0000000..adf9d55
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxcheckers/m-oid=1.3.6.1.4.1.1466.115.121.1.9.ldif
@@ -0,0 +1,8 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.9,ou=syntaxCheckers,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.9
+m-fqcn: org.apache.directory.api.ldap.model.schema.syntaxCheckers.CertificateListSyntaxChecker
+objectclass: metaSyntaxChecker
+objectclass: metaTop
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes.ldif
new file mode 100644
index 0000000..59ac7a1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes.ldif
@@ -0,0 +1,6 @@
+version: 1
+dn: ou=syntaxes,cn=system,ou=schema
+ou: syntaxes
+objectclass: organizationalUnit
+objectclass: top
+creatorsname: uid=admin,ou=system
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.1.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.1.ldif
new file mode 100644
index 0000000..c42aa98
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.1.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.1,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.1
+m-description: ACI Item
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.10.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.10.ldif
new file mode 100644
index 0000000..492a7a7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.10.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.10,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.10
+m-description: X.509 Certificate Pair
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.11.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.11.ldif
new file mode 100644
index 0000000..311c1d1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.11.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.11,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.11
+m-description: Country String
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.12.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.12.ldif
new file mode 100644
index 0000000..3fca84c
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.12.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.12,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.12
+m-description: DN
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.13.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.13.ldif
new file mode 100644
index 0000000..04010a7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.13.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.13,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.13
+m-description: Data Quality Syntax
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.14.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.14.ldif
new file mode 100644
index 0000000..a6b4fee
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.14.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.14,ou=syntaxes,cn=system,ou=schema
+m-oid: 1.3.6.1.4.1.1466.115.121.1.14
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-description: Delivery Method
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.15.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.15.ldif
new file mode 100644
index 0000000..29732d3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.15.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.15,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.15
+m-description: Directory String
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.16.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.16.ldif
new file mode 100644
index 0000000..9d34a12
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.16.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.16,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.16
+m-description: DIT Content Rule Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.17.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.17.ldif
new file mode 100644
index 0000000..7283b51
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.17.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.17,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.17
+m-description: DIT Structure Rule Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.18.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.18.ldif
new file mode 100644
index 0000000..deca2f3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.18.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.18,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.18
+m-description: DL Submit Permission
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.19.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.19.ldif
new file mode 100644
index 0000000..cff3bfd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.19.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.19,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.19
+m-description: DSA Quality Syntax
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.2.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.2.ldif
new file mode 100644
index 0000000..18f8baf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.2.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.2,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.2
+m-description: Access Point
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.20.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.20.ldif
new file mode 100644
index 0000000..7432c13
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.20.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.20,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.20
+m-description: DSE Type
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.21.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.21.ldif
new file mode 100644
index 0000000..4645136
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.21.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.21,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.21
+m-description: Enhanced Guide
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.22.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.22.ldif
new file mode 100644
index 0000000..7fd5358
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.22.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.22,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.22
+m-description: Facsimile Telephone Number
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.23.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.23.ldif
new file mode 100644
index 0000000..cf0bf16
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.23.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.23,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.23
+m-description: Fax
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.24.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.24.ldif
new file mode 100644
index 0000000..b4f5bd8
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.24.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.24,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.24
+m-description: Generalized Time
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.25.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.25.ldif
new file mode 100644
index 0000000..ec49ca1
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.25.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.25,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.25
+m-description: Guide
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.26.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.26.ldif
new file mode 100644
index 0000000..7222663
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.26.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.26,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.26
+m-description: IA5 String
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.27.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.27.ldif
new file mode 100644
index 0000000..192bec3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.27.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.27,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.27
+m-description: INTEGER
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.28.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.28.ldif
new file mode 100644
index 0000000..5aa02e5
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.28.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.28,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.28
+m-description: JPEG
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.29.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.29.ldif
new file mode 100644
index 0000000..f3d05bd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.29.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.29,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.29
+m-description: Master And Shadow Access Points
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.3.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.3.ldif
new file mode 100644
index 0000000..b3aa1d2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.3.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.3,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.3
+m-description: Attribute Type Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.30.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.30.ldif
new file mode 100644
index 0000000..91c607f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.30.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.30,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.30
+m-description: Matching Rule Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.31.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.31.ldif
new file mode 100644
index 0000000..d3edf23
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.31.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.31,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.31
+m-description: Matching Rule Use Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.32.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.32.ldif
new file mode 100644
index 0000000..2278502
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.32.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.32,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.32
+m-description: Mail Preference
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.33.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.33.ldif
new file mode 100644
index 0000000..78398be
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.33.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.33,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.33
+m-description: MHS OR Address
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.34.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.34.ldif
new file mode 100644
index 0000000..e42cd28
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.34.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.34,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.34
+m-description: Name And Optional UID
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.35.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.35.ldif
new file mode 100644
index 0000000..472e976
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.35.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.35,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.35
+m-description: Name Form Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.36.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.36.ldif
new file mode 100644
index 0000000..bfa7384
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.36.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.36,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.36
+m-description: Numeric String
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.37.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.37.ldif
new file mode 100644
index 0000000..d427923
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.37.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.37,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.37
+m-description: Object Class Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.38.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.38.ldif
new file mode 100644
index 0000000..3061fbf
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.38.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.38,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.38
+m-description: OID
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.39.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.39.ldif
new file mode 100644
index 0000000..93d5347
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.39.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.39,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.39
+m-description: Other Mailbox
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.4.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.4.ldif
new file mode 100644
index 0000000..678d78b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.4.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.4,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.4
+m-description: Audio
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.40.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.40.ldif
new file mode 100644
index 0000000..1b97bed
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.40.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.40,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.40
+m-description: Octet String
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.41.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.41.ldif
new file mode 100644
index 0000000..2e701a6
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.41.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.41,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.41
+m-description: Postal Address
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.42.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.42.ldif
new file mode 100644
index 0000000..29e42ec
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.42.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.42,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.42
+m-description: Protocol Information
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.43.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.43.ldif
new file mode 100644
index 0000000..a0ebd94
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.43.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.43,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.43
+m-description: Presentation Address
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.44.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.44.ldif
new file mode 100644
index 0000000..16dd334
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.44.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.44,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.44
+m-description: Printable String
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.45.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.45.ldif
new file mode 100644
index 0000000..d2574ab
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.45.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.45,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.45
+m-description: Subtree Specification
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.46.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.46.ldif
new file mode 100644
index 0000000..7511990
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.46.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.46,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.46
+m-description: Supplier Information
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.47.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.47.ldif
new file mode 100644
index 0000000..69cf5cd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.47.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.47,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.47
+m-description: Supplier Or Consumer
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.48.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.48.ldif
new file mode 100644
index 0000000..c9d6f2a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.48.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.48,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.48
+m-description: Supplier And Consumer
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.49.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.49.ldif
new file mode 100644
index 0000000..d44fc1b
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.49.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.49,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.49
+m-description: X.509 Supported Algorithm
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.5.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.5.ldif
new file mode 100644
index 0000000..b9d65c7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.5.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.5,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.5
+m-description: Binary
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.50.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.50.ldif
new file mode 100644
index 0000000..92fe97a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.50.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.50,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.50
+m-description: Telephone Number
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.51.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.51.ldif
new file mode 100644
index 0000000..e04d152
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.51.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.51,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.51
+m-description: Teletex Terminal Identifier
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.52.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.52.ldif
new file mode 100644
index 0000000..92054e7
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.52.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.52,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.52
+m-description: Telex Number
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.53.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.53.ldif
new file mode 100644
index 0000000..87e7fc3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.53.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.53,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.53
+m-description: UTC Time
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.54.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.54.ldif
new file mode 100644
index 0000000..7dadd63
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.54.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.54,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.54
+m-description: LDAP Syntax Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.55.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.55.ldif
new file mode 100644
index 0000000..8103855
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.55.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.55,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.55
+m-description: Modify Rights
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.56.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.56.ldif
new file mode 100644
index 0000000..8fe2e6d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.56.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.56,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.56
+m-description: LDAP BootstrapSchema Definition
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.57.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.57.ldif
new file mode 100644
index 0000000..4b94dac
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.57.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.57,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.57
+m-description: LDAP BootstrapSchema Description
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.58.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.58.ldif
new file mode 100644
index 0000000..978c7b2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.58.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.58,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.58
+m-description: Substring Assertion
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.59.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.59.ldif
new file mode 100644
index 0000000..0c6b40f
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.59.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.59,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.59
+m-description: Trigger Specification
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.6.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.6.ldif
new file mode 100644
index 0000000..acbe366
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.6.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.6,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.6
+m-description: Bit String
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.7.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.7.ldif
new file mode 100644
index 0000000..19bd7cd
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.7.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.7,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.7
+m-description: Boolean
+m-obsolete: FALSE
+x-not-human-readable: FALSE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.8.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.8.ldif
new file mode 100644
index 0000000..2cfa308
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.8.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.8,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.8
+m-description: X.509 Certificate
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.9.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.9.ldif
new file mode 100644
index 0000000..0beee8d
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/cn=system/ou=syntaxes/m-oid=1.3.6.1.4.1.1466.115.121.1.9.ldif
@@ -0,0 +1,12 @@
+version: 1
+dn: m-oid=1.3.6.1.4.1.1466.115.121.1.9,ou=syntaxes,cn=system,ou=schema
+objectclass: top
+objectclass: metaTop
+objectclass: metaSyntax
+m-oid: 1.3.6.1.4.1.1466.115.121.1.9
+m-description: X.509 Certificate List
+m-obsolete: FALSE
+x-not-human-readable: TRUE
+entrycsn: 20100111202214.878000Z#000000#000#000000
+creatorsname: uid=admin,ou=system
+createtimestamp: 20100111145217Z
\ No newline at end of file
diff --git a/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/ou=schemamodifications.ldif b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/ou=schemamodifications.ldif
new file mode 100644
index 0000000..0328d65
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/resources/schema/ou=schema/ou=schemamodifications.ldif
@@ -0,0 +1,14 @@
+version: 1
+dn: ou=schemaModifications,ou=schema
+objectClass: schemaModificationAttributes
+objectClass: top
+ou: schemaModifications
+schemaModifiersName: uid=admin,ou=system
+schemaModifyTimestamp: 20090818022733Z
+subschemaSubentryName: cn=schema
+createTimestamp: 20090818022733Z
+creatorsName: uid=admin,ou=system
+entryCSN: 20090818052733.272000Z#000000#000#000000
+modifiersName: uid=admin,ou=system
+modifyTimestamp: 20090818022733Z
+
diff --git a/trunk/ldap/schema/data/src/main/scripts/oid_allocation.pl b/trunk/ldap/schema/data/src/main/scripts/oid_allocation.pl
new file mode 100755
index 0000000..820e0e0
--- /dev/null
+++ b/trunk/ldap/schema/data/src/main/scripts/oid_allocation.pl
@@ -0,0 +1,142 @@
+#!/usr/bin/env perl
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Find;
+use File::Spec;
+use Getopt::Long;
+use Net::LDAP::LDIF;
+use Sort::Versions;
+
+my $json;
+GetOptions(
+    "json" => \$json
+);
+
+# Find path to /src/main using relative to this script
+my @dir_parts = File::Spec->splitdir((fileparse($0))[1]);
+splice(@dir_parts, -2);
+my $dir = File::Spec->catdir(@dir_parts);
+
+my %oid_to_metadata = ();
+find(sub {
+        return unless (-f $_ && /^.*\.ldif$/);
+
+        my ($entry, $oid, $name, $description);
+        my $ldif = Net::LDAP::LDIF->new($_, 'r', onerror => 'undef');
+        while (!$ldif->eof()) {
+            $entry = $ldif->read_entry();
+            $oid = $entry->get_value('m-oid');
+            if ($oid) {
+                $name = $entry->get_value('m-name');
+                $description = $entry->get_value('m-description');
+
+                my $value = $oid_to_metadata{$oid};
+                if (!$value) {
+                    $value = [];
+                    $oid_to_metadata{$oid} = $value;
+                }
+                push(@$value, {
+                        file => $File::Find::name, 
+                        name => $name,
+                        description => $description 
+                    });
+            }
+        }
+    }, $dir);
+
+my %header = (
+    '0' => '### `ou=syntaxes` and `ou=syntaxCheckers`',
+    '1' => '### `ou=comparators` and `ou=matchingRules` and `ou=normalizers`',
+    '2' => '### `ou=attributeTypes`',
+    '2.0' => '#### Base Bean',
+    '2.100' => '#### Directory Service',
+    '2.300' => '#### LDAP Server',
+    '2.400' => '#### Kerberos Server',
+    '2.500' => '#### DNS Server',
+    '2.600' => '#### DHCP Server',
+    '2.700' => '#### NTP Server',
+    '2.800' => '#### ChangePassword Server',
+    '2.900' => '#### Password Policy',
+    '3' => '### `ou=objectClasses`',
+    '3.0' => '#### Base Bean',
+    '3.100' => '#### Directory Service',
+    '3.300' => '#### LDAP Server',
+    '3.400' => '#### Kerberos Server',
+    '3.500' => '#### DNS Server',
+    '3.600' => '#### DHCP Server',
+    '3.700' => '#### NTP Server',
+    '3.800' => '#### ChangePassword Server',
+    '3.900' => '#### Password Policy',
+);
+
+if($json) {
+    # JSON format
+    require JSON;
+    my $json = JSON->new()
+        ->utf8()->indent()->space_after()
+        ->sort_by(sub{no warnings 'once';versioncmp($JSON::PP::a, $JSON::PP::b)})
+        ->encode(\%oid_to_metadata);
+    print($json);
+}
+else {
+    # Default markdown format
+    require POSIX;
+    print("#\n");
+    print("#  Licensed to the Apache Software Foundation (ASF) under one\n");
+    print("#  or more contributor license agreements.  See the NOTICE file\n");
+    print("#  distributed with this work for additional information\n");
+    print("#  regarding copyright ownership.  The ASF licenses this file\n");
+    print("#  to you under the Apache License, Version 2.0 (the\n");
+    print("#  \"License\"); you may not use this file except in compliance\n");
+    print("#  with the License.  You may obtain a copy of the License at\n");
+    print("#\n");
+    print("#    http://www.apache.org/licenses/LICENSE-2.0\n");
+    print("#\n");
+    print("#  Unless required by applicable law or agreed to in writing,\n");
+    print("#  software distributed under the License is distributed on an\n");
+    print("#  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n");
+    print("#  KIND, either express or implied.  See the License for the\n");
+    print("#  specific language governing permissions and limitations\n");
+    print("#  under the License.\n");
+
+    foreach my $oid (sort {versioncmp($a, $b)} keys(%oid_to_metadata)) {
+        next unless ($oid =~ /^1\.3\.6\.1\.4\.1\.18060\.0\.4\.1\.(\d+)\.(\d+).*$/);
+        my $section = "$1";
+        my $section_and_sub = "$section." . POSIX::floor($2/100)*100;
+    
+        if (defined($header{$section})) {
+            print("\n", delete($header{$section}), "\n\n");
+        }
+        if (defined($header{$section_and_sub})) {
+            print("\n", delete($header{$section_and_sub}), "\n\n");
+        }
+    
+        if ($section == 0) {
+            # no name, so use description
+            print("- $oid: ", join(',', (map {defined($_->{description}) ? $_->{description} : ()} @{$oid_to_metadata{$oid}})), "\n");
+        }
+        else {
+            print("- $oid: ", join(',', (map {defined($_->{name}) ? $_->{name} : ()} @{$oid_to_metadata{$oid}})), "\n");
+        }
+    }
+}
diff --git a/trunk/ldap/schema/data/src/site/site.xml b/trunk/ldap/schema/data/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/ldap/schema/data/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/extractor/SchemaLdifExtractorTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/extractor/SchemaLdifExtractorTest.java
new file mode 100644
index 0000000..df18f67
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/extractor/SchemaLdifExtractorTest.java
@@ -0,0 +1,81 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.extractor;
+
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the DefaultSchemaLdifExtractor class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaLdifExtractorTest
+{
+    private static String workingDirectory;
+
+
+    @BeforeClass
+    public static void setup() throws IOException
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = SchemaLdifExtractorTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( new File( workingDirectory + "/schema" ) );
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( new File( workingDirectory + "/schema" ) );
+    }
+
+
+    @Test
+    public void testExtract() throws Exception
+    {
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor(
+            new File( workingDirectory ) );
+        extractor.extractOrCopy();
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/JarLdifSchemaLoaderTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/JarLdifSchemaLoaderTest.java
new file mode 100644
index 0000000..269652a
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/JarLdifSchemaLoaderTest.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Tests the LdifSchemaLoader.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class JarLdifSchemaLoaderTest
+{
+    @Test
+    public void testJarLdifSchemaLoader() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+        SchemaManager sm = new DefaultSchemaManager( loader );
+
+        sm.loadWithDeps( "system" );
+
+        assertTrue( sm.getRegistries().getAttributeTypeRegistry().contains( "cn" ) );
+        assertFalse( sm.getRegistries().getAttributeTypeRegistry().contains( "m-aux" ) );
+
+        sm.loadWithDeps( "apachemeta" );
+
+        assertTrue( sm.getRegistries().getAttributeTypeRegistry().contains( "m-aux" ) );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/LdifSchemaLoaderTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/LdifSchemaLoaderTest.java
new file mode 100644
index 0000000..61edf5e
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/LdifSchemaLoaderTest.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.exception.Exceptions;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the LdifSchemaLoader.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class LdifSchemaLoaderTest
+{
+    private static String workingDirectory;
+
+
+    @BeforeClass
+    public static void setup() throws IOException
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = LdifSchemaLoaderTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( new File( workingDirectory + "/schema" ) );
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( new File( workingDirectory + "/schema" ) );
+    }
+
+
+    @Test
+    public void testLoader() throws Exception
+    {
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy();
+
+        LdifSchemaLoader loader = new LdifSchemaLoader( new File( workingDirectory, "schema" ) );
+        SchemaManager sm = new DefaultSchemaManager( loader );
+
+        boolean loaded = sm.loadAllEnabled();
+
+        if ( !loaded )
+        {
+            fail( "Schema load failed : " + Exceptions.printErrors( sm.getErrors() ) );
+        }
+
+        assertTrue( sm.getRegistries().getAttributeTypeRegistry().contains( "cn" ) );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/MatchingRuleTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/MatchingRuleTest.java
new file mode 100644
index 0000000..2aab6d2
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/MatchingRuleTest.java
@@ -0,0 +1,231 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.comparators.GeneralizedTimeComparator;
+import org.apache.directory.api.ldap.model.schema.comparators.IntegerComparator;
+import org.apache.directory.api.ldap.model.schema.comparators.NumericStringComparator;
+import org.apache.directory.api.ldap.model.schema.comparators.TelephoneNumberComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.GeneralizedTimeNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.NumericNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.TelephoneNumberNormalizer;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests that matching rules of the schema use correct normalizers and comparators.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MatchingRuleTest
+{
+    // A directory in which the ldif files will be stored
+    private static String workingDirectory;
+
+    // The schema repository
+    private static File schemaRepository;
+
+    // The schema manager
+    private static SchemaManager schemaManager;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = MatchingRuleTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        schemaRepository = new File( workingDirectory, "schema" );
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository );
+
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy();
+
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        schemaManager = new DefaultSchemaManager( loader );
+        for ( Schema schema : loader.getAllSchemas() )
+        {
+            schema.enable();
+        }
+        schemaManager.loadAllEnabled();
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository );
+    }
+
+
+    @Test
+    public void testTelephoneNumberMatch() throws Exception
+    {
+        // matching rule: telephoneNumberMatch
+        MatchingRule mr1 = schemaManager.lookupMatchingRuleRegistry( "telephoneNumberMatch" );
+        assertEquals( TelephoneNumberNormalizer.class.getName(), mr1.getNormalizer().getClass().getName() );
+        assertEquals( "+1234567890", mr1.getNormalizer().normalize( " +1 234-567 890 " ) );
+        assertEquals( TelephoneNumberComparator.class.getName(), mr1.getLdapComparator().getClass().getName() );
+        assertEquals( 0, mr1.getLdapComparator().compare( " +1 234-567 890 ", "+1234567890" ) );
+
+        // matching rule: telephoneNumberSubstringsMatch
+        MatchingRule mr2 = schemaManager.lookupMatchingRuleRegistry( "telephoneNumberSubstringsMatch" );
+        assertEquals( TelephoneNumberNormalizer.class.getName(), mr2.getNormalizer().getClass().getName() );
+        assertEquals( "+1234567890", mr2.getNormalizer().normalize( " +1 234-567 890 " ) );
+        assertEquals( TelephoneNumberComparator.class.getName(), mr2.getLdapComparator().getClass().getName() );
+        assertEquals( 0, mr2.getLdapComparator().compare( " +1 234-567 890 ", "+1234567890" ) );
+
+        // test a real attribute: telephoneNumber
+        AttributeType at = schemaManager.lookupAttributeTypeRegistry( "telephoneNumber" );
+        assertNotNull( at.getEquality() );
+        assertEquals( TelephoneNumberNormalizer.class.getName(), at.getEquality().getNormalizer().getClass().getName() );
+        assertEquals( "+1234567890", at.getEquality().getNormalizer().normalize( " +1 234-567 890 " ) );
+        assertEquals( TelephoneNumberComparator.class.getName(), at.getEquality().getLdapComparator().getClass()
+            .getName() );
+        assertEquals( 0, at.getEquality().getLdapComparator().compare( " +1 234-567 890 ", "+1234567890" ) );
+        assertNotNull( at.getSubstring() );
+        assertEquals( TelephoneNumberNormalizer.class.getName(), at.getEquality().getNormalizer().getClass().getName() );
+        assertEquals( "+1234567890", at.getSubstring().getNormalizer().normalize( " +1 234-567 890 " ) );
+        assertNull( at.getOrdering() );
+    }
+
+
+    @Test
+    public void testIntegerMatch() throws Exception
+    {
+        MatchingRule mr1 = schemaManager.lookupMatchingRuleRegistry( "integerMatch" );
+        assertEquals( NumericNormalizer.class.getName(), mr1.getNormalizer().getClass().getName() );
+        assertEquals( "1234567890", mr1.getNormalizer().normalize( " 1 234 567 890 " ) );
+        //assertEquals( IntegerComparator.class.getName(), mr1.getLdapComparator().getClass().getName() );
+        //assertEquals( 0, mr1.getLdapComparator().compare( " 1 234 567 890 ", "1234567890" ) );
+
+        MatchingRule mr2 = schemaManager.lookupMatchingRuleRegistry( "integerOrderingMatch" );
+        assertEquals( NumericNormalizer.class.getName(), mr2.getNormalizer().getClass().getName() );
+        assertEquals( "1234567890", mr2.getNormalizer().normalize( " 1 234 567 890 " ) );
+        assertEquals( IntegerComparator.class.getName(), mr2.getLdapComparator().getClass().getName() );
+        assertEquals( 0, mr2.getLdapComparator().compare( 1234567890L, 1234567890L ) );
+        assertTrue( mr2.getLdapComparator().compare( 123L, 234L ) < 0 );
+        assertTrue( mr2.getLdapComparator().compare( 1234L, 234L ) > 0 );
+
+        // test a real attribute type: uidNumber
+        AttributeType at = schemaManager.lookupAttributeTypeRegistry( "uidNumber" );
+        assertNotNull( at.getEquality() );
+        assertEquals( NumericNormalizer.class.getName(), at.getEquality().getNormalizer().getClass().getName() );
+        assertEquals( "123", at.getEquality().getNormalizer().normalize( " 1 2 3 " ) );
+        //assertEquals( 0, at.getEquality().getLdapComparator().compare( " 1 2 3 ", "123" ) );
+        assertNull( at.getSubstring() );
+        assertNull( at.getOrdering() );
+    }
+
+
+    @Test
+    public void testNumericStringMatch() throws Exception
+    {
+        MatchingRule mr1 = schemaManager.lookupMatchingRuleRegistry( "numericStringMatch" );
+        assertEquals( NumericNormalizer.class.getName(), mr1.getNormalizer().getClass().getName() );
+        assertEquals( "1234567890", mr1.getNormalizer().normalize( " 1 234 567 890 " ) );
+        assertEquals( NumericStringComparator.class.getName(), mr1.getLdapComparator().getClass().getName() );
+        assertEquals( 0, mr1.getLdapComparator().compare( " 1 234 567 890 ", "1234567890" ) );
+
+        MatchingRule mr2 = schemaManager.lookupMatchingRuleRegistry( "numericStringSubstringsMatch" );
+        assertEquals( NumericNormalizer.class.getName(), mr2.getNormalizer().getClass().getName() );
+        assertEquals( "1234567890", mr2.getNormalizer().normalize( " 1 234 567 890 " ) );
+        assertEquals( NumericStringComparator.class.getName(), mr2.getLdapComparator().getClass().getName() );
+        assertEquals( 0, mr2.getLdapComparator().compare( " 1 234 567 890 ", "1234567890" ) );
+
+        MatchingRule mr3 = schemaManager.lookupMatchingRuleRegistry( "numericStringOrderingMatch" );
+        assertEquals( NumericNormalizer.class.getName(), mr3.getNormalizer().getClass().getName() );
+        assertEquals( "1234567890", mr3.getNormalizer().normalize( " 1 234 567 890 " ) );
+        assertEquals( NumericStringComparator.class.getName(), mr3.getLdapComparator().getClass().getName() );
+        assertEquals( 0, mr3.getLdapComparator().compare( " 1 234 567 890 ", "1234567890" ) );
+        assertTrue( mr3.getLdapComparator().compare( " 1 2 3  ", " 2 3 4" ) < 0 );
+        assertTrue( mr3.getLdapComparator().compare( " 1 2 3 4 ", " 2 3 4" ) < 0 );
+    }
+
+
+    @Test
+    public void testGeneralizedTimeStringMatch() throws Exception
+    {
+        MatchingRule mr1 = schemaManager.lookupMatchingRuleRegistry( "generalizedTimeMatch" );
+        assertEquals( GeneralizedTimeNormalizer.class.getName(), mr1.getNormalizer().getClass().getName() );
+
+        String normalized = mr1.getNormalizer().normalize( "2010031415Z" );
+        assertTrue( "20100314150000.000Z".equals( normalized ) || "20100314153000.000Z".equals( normalized )
+            || "20100314154500.000Z".equals( normalized ) );
+        assertEquals( "20100314133102.003Z", mr1.getNormalizer().normalize( "20100314150102.003+0130" ) );
+        assertEquals( GeneralizedTimeComparator.class.getName(), mr1.getLdapComparator().getClass().getName() );
+
+        // Deal with +HH:30 and +HH:45 TZ
+        int compare1 = mr1.getLdapComparator().compare( "2010031415Z", "20100314150000.000+0000" );
+        int compare2 = mr1.getLdapComparator().compare( "2010031415Z", "20100314153000.000+0000" );
+        int compare3 = mr1.getLdapComparator().compare( "2010031415Z", "20100314154500.000+0000" );
+        assertTrue( ( compare1 == 0 ) || ( compare2 == 0 ) || ( compare3 == 0 ) );
+
+        MatchingRule mr2 = schemaManager.lookupMatchingRuleRegistry( "generalizedTimeOrderingMatch" );
+        assertEquals( GeneralizedTimeNormalizer.class.getName(), mr2.getNormalizer().getClass().getName() );
+        normalized = mr2.getNormalizer().normalize( "2010031415Z" );
+        assertTrue( "20100314150000.000Z".equals( normalized ) || "20100314153000.000Z".equals( normalized )
+            || "20100314154500.000Z".equals( normalized ) );
+        assertEquals( "20100314133102.003Z", mr2.getNormalizer().normalize( "20100314150102.003+0130" ) );
+        assertEquals( GeneralizedTimeComparator.class.getName(), mr2.getLdapComparator().getClass().getName() );
+
+        // Deal with +HH:30 and +HH:45 TZ
+        compare1 = mr2.getLdapComparator().compare( "2010031415Z", "20100314150000.000+0000" );
+        compare2 = mr2.getLdapComparator().compare( "2010031415Z", "20100314153000.000+0000" );
+        compare3 = mr2.getLdapComparator().compare( "2010031415Z", "20100314154500.000+0000" );
+        assertTrue( ( compare1 == 0 ) || ( compare2 == 0 ) || ( compare3 == 0 ) );
+        assertTrue( mr2.getLdapComparator().compare( "2010031415Z", "2010031414Z" ) > 0 );
+        assertTrue( mr2.getLdapComparator().compare( "2010031415Z", "2010031416Z" ) < 0 );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerAddTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerAddTest.java
new file mode 100644
index 0000000..c35adf3
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerAddTest.java
@@ -0,0 +1,2020 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableObjectClass;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.UsageEnum;
+import org.apache.directory.api.ldap.model.schema.comparators.BooleanComparator;
+import org.apache.directory.api.ldap.model.schema.comparators.ComparableComparator;
+import org.apache.directory.api.ldap.model.schema.comparators.CsnComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.NoOpNormalizer;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.RegexSyntaxChecker;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test class for SchemaManager, testig the addition of a SchemaObject.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaManagerAddTest
+{
+    // A directory in which the ldif files will be stored
+    private static String workingDirectory;
+
+    // The schema repository
+    private static File schemaRepository;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = SchemaManagerAddTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        // Make sure every test class has its own schema directory
+        workingDirectory = new File( workingDirectory, "SchemaManagerAddTest" ).getAbsolutePath();
+
+        schemaRepository = new File( workingDirectory, "schema" );
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository );
+
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy();
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository.getParentFile() );
+    }
+
+
+    private SchemaManager loadSystem() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        String schemaName = "system";
+
+        schemaManager.loadWithDeps( schemaName );
+
+        return schemaManager;
+    }
+
+
+    /**
+     * Check if an AT is present in the AT registry
+     */
+    private boolean isATPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
+
+            return attributeType != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Check if a MR is present in the MR registry
+     */
+    private boolean isMRPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            MatchingRule matchingRule = schemaManager.lookupMatchingRuleRegistry( oid );
+
+            return matchingRule != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Check if an OC is present in the OC registry
+     */
+    private boolean isOCPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            ObjectClass objectClass = schemaManager.lookupObjectClassRegistry( oid );
+
+            return objectClass != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Check if a S is present in the S registry
+     */
+    private boolean isSyntaxPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            LdapSyntax syntax = schemaManager.lookupLdapSyntaxRegistry( oid );
+
+            return syntax != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    //=========================================================================
+    // For each test, we will check many different things.
+    // If the test is successful, we want to know if the SchemaObject
+    // Registry has grown : its size must be one bigger. If the SchemaObject
+    // is not loadable, then the GlobalOidRegistry must also have grown.
+    //=========================================================================
+    // AttributeType addition tests
+    //-------------------------------------------------------------------------
+    // First, not defined superior
+    //-------------------------------------------------------------------------
+    /**
+     * Try to inject an AttributeType without any superior nor Syntax : it's invalid
+     */
+    @Test
+    public void testAddAttributeTypeNoSupNoSyntaxNoSuperior() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType which is Collective, and userApplication AT
+     */
+    @Test
+    public void testAddAttributeTypeNoSupCollectiveUser() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+        attributeType.setCollective( true );
+
+        // It should not fail
+        assertTrue( schemaManager.add( attributeType ) );
+
+        assertTrue( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType which is a subtype of a Collective AT
+     */
+    @Test
+    public void testAddAttributeTypeSupCollectiveUser() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        // Create the collective attribute first
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+        attributeType.setCollective( true );
+
+        // It should not fail
+        assertTrue( schemaManager.add( attributeType ) );
+
+        assertTrue( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+
+        // Now try to create an AT which is a subtype of teh create collective attribute
+        MutableAttributeType subType = new MutableAttributeType( "1.1.1" );
+        subType.setEqualityOid( "2.5.13.1" );
+        subType.setOrderingOid( null );
+        subType.setSubstringOid( null );
+        subType.setSuperiorOid( "1.1.0" );
+        subType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        subType.setUsage( UsageEnum.USER_APPLICATIONS );
+        subType.setCollective( false );
+
+        // It should fail
+        assertFalse( schemaManager.add( subType ) );
+
+        assertFalse( isATPresent( schemaManager, "1.1.1" ) );
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType which is Collective, but an operational AT
+     */
+    @Test
+    public void testAddAttributeTypeNoSupCollectiveOperational() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.DIRECTORY_OPERATION );
+        attributeType.setCollective( true );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a single valued AttributeType which is Collective
+     */
+    @Test
+    public void testAddAttributeTypeCollectiveOperationalSigleValue() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+        attributeType.setCollective( true );
+        attributeType.setSingleValued( true );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType which is a NO-USER-MODIFICATION and userApplication
+     */
+    @Test
+    public void testAddAttributeTypeNoSupNoUserModificationUserAplication() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+        attributeType.setUserModifiable( false );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType which is a NO-USER-MODIFICATION and is operational
+     */
+    @Test
+    public void testAddAttributeTypeNoSupNoUserModificationOpAttr() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.DISTRIBUTED_OPERATION );
+        attributeType.setUserModifiable( false );
+
+        // It should not fail
+        assertTrue( schemaManager.add( attributeType ) );
+
+        assertTrue( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with an invalid EQUALITY MR
+     */
+    @Test
+    public void testAddAttributeTypeNoSupInvalidEqualityMR() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "0.0" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType without EQUALITY MR
+     */
+    @Test
+    public void testAddAttributeTypeNoEqualityMR() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.8 " );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+
+        // It should be OK
+        assertTrue( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+
+        assertTrue( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with an invalid ORDERING MR
+     */
+    @Test
+    public void testAddAttributeTypeNoSupInvalidOrderingMR() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( null );
+        attributeType.setOrderingOid( "0.0" );
+        attributeType.setSubstringOid( null );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with an invalid SUBSTR MR
+     */
+    @Test
+    public void testAddAttributeTypeNoSupInvalidSubstringMR() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( null );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( "0.0" );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with valid MRs
+     */
+    @Test
+    public void testAddAttributeTypeNoSupValidMR() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( "2.5.13.1" );
+        attributeType.setSubstringOid( "2.5.13.1" );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setUsage( UsageEnum.USER_APPLICATIONS );
+
+        // It should not fail
+        assertTrue( schemaManager.add( attributeType ) );
+
+        assertTrue( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType which already exist
+     */
+    @Test
+    public void testAddAttributeTypeAlreadyExist() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "2.5.18.4" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( "2.5.13.1" );
+        attributeType.setSubstringOid( "2.5.13.1" );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        // The AT must be there
+        assertTrue( isATPresent( schemaManager, "2.5.18.4" ) );
+
+        // Check that it hasen't changed
+        AttributeType original = schemaManager.lookupAttributeTypeRegistry( "2.5.18.4" );
+        assertEquals( "distinguishedNameMatch", original.getEqualityOid() );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with an already attributed name
+     */
+    @Test
+    public void testAddAttributeTypeNameAlreadyExist() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( "2.5.13.1" );
+        attributeType.setSubstringOid( "2.5.13.1" );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setNames( "Test", "cn" );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        // The AT must not be there
+        assertFalse( isATPresent( schemaManager, "1.1.1.0" ) );
+
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with an ObjectClass name
+     */
+    @Test
+    public void testAddAttributeTypeNameOfAnObjectClass() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( "2.5.13.1" );
+        attributeType.setSubstringOid( "2.5.13.1" );
+        attributeType.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        attributeType.setNames( "Test", "referral" );
+
+        // It should be ok
+        assertTrue( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+
+        // The AT must be present
+        assertTrue( isATPresent( schemaManager, "1.1.1.0" ) );
+
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+
+        AttributeType added = schemaManager.lookupAttributeTypeRegistry( "referral" );
+        assertNotNull( added );
+        assertEquals( "1.1.1.0", added.getOid() );
+        assertTrue( added.getNames().contains( "referral" ) );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Then, with a superior
+    //-------------------------------------------------------------------------
+    /**
+     * Try to inject an AttributeType with a superior and no Syntax : it should
+     * take its superior' syntax and MR
+     */
+    @Test
+    public void testAddAttributeTypeSupNoSyntaxNoSuperior() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( null );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSuperiorOid( "2.5.18.4" );
+        attributeType.setUsage( UsageEnum.DIRECTORY_OPERATION );
+
+        // It should not fail
+        assertTrue( schemaManager.add( attributeType ) );
+
+        AttributeType result = schemaManager.lookupAttributeTypeRegistry( "1.1.0" );
+
+        assertEquals( "1.3.6.1.4.1.1466.115.121.1.12", result.getSyntaxOid() );
+        assertEquals( "2.5.13.1", result.getEqualityOid() );
+        assertEquals( atrSize + 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with a superior and different USAGE
+     */
+    @Test
+    public void testAddAttributeTypeSupDifferentUsage() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( null );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSuperiorOid( "2.5.18.4" );
+        attributeType.setUsage( UsageEnum.DISTRIBUTED_OPERATION );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with itself as a superior
+     */
+    @Test
+    public void testAddAttributeTypeSupWithOwnSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( null );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSuperiorOid( "1.1.0" );
+        attributeType.setUsage( UsageEnum.DISTRIBUTED_OPERATION );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject an AttributeType with a bad superior
+     */
+    @Test
+    public void testAddAttributeTypeSupBadSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( null );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+        attributeType.setSuperiorOid( "0.0" );
+        attributeType.setUsage( UsageEnum.DISTRIBUTED_OPERATION );
+
+        // It should fail
+        assertFalse( schemaManager.add( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isATPresent( schemaManager, "1.1.0" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // Comparator addition tests
+    //-------------------------------------------------------------------------
+    @Test
+    public void testAddNewComparator() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ctrSize = schemaManager.getComparatorRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        LdapComparator<?> lc = new BooleanComparator( oid );
+
+        assertTrue( schemaManager.add( lc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+
+        assertEquals( ctrSize + 1, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        LdapComparator<?> added = schemaManager.lookupComparatorRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( lc.getClass().getName(), added.getFqcn() );
+    }
+
+
+    @Test
+    public void testAddAlreadyExistingComparator() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ctrSize = schemaManager.getComparatorRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        LdapComparator<?> bc = new BooleanComparator( oid );
+
+        assertTrue( schemaManager.add( bc ) );
+
+        LdapComparator<?> added = schemaManager.lookupComparatorRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( bc.getClass().getName(), added.getFqcn() );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+        assertEquals( ctrSize + 1, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        LdapComparator<?> lc = new CsnComparator( oid );
+
+        assertFalse( schemaManager.add( lc ) );
+
+        errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+
+        assertEquals( ctrSize + 1, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        added = schemaManager.lookupComparatorRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( bc.getClass().getName(), added.getFqcn() );
+    }
+
+
+    /**
+     * Test that we can't add two comparators with the same class code.
+     */
+    @Test
+    public void testAddComparatorWithWrongFQCN() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ctrSize = schemaManager.getComparatorRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        LdapComparator<?> lc = new BooleanComparator( oid );
+
+        // using java.sql.ResultSet cause it is very unlikely to get loaded
+        // in ADS, as the FQCN is not the one expected
+        lc.setFqcn( "java.sql.ResultSet" );
+
+        assertFalse( schemaManager.add( lc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+
+        assertEquals( ctrSize, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        try
+        {
+            schemaManager.lookupComparatorRegistry( oid );
+            fail();
+        }
+        catch ( Exception e )
+        {
+            // Expected
+            assertTrue( true );
+        }
+    }
+
+
+    //=========================================================================
+    // DitContentRule addition tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // DitStructureRule addition tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // MatchingRule addition tests
+    //-------------------------------------------------------------------------
+    /**
+     * Try to inject a new MatchingRule
+     */
+    @Test
+    public void testAddValidMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.0" );
+        matchingRule.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+
+        // It should not fail
+        assertTrue( schemaManager.add( matchingRule ) );
+
+        assertTrue( isMRPresent( schemaManager, "1.1.0" ) );
+
+        // The C and N must have default values
+        MatchingRule added = schemaManager.lookupMatchingRuleRegistry( "1.1.0" );
+
+        assertEquals( NoOpNormalizer.class.getName(), added.getNormalizer().getClass().getName() );
+        assertEquals( ComparableComparator.class.getName(), added.getLdapComparator().getClass().getName() );
+
+        assertEquals( mrrSize + 1, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a new MatchingRule without a syntax
+     */
+    @Test
+    public void testAddMatchingRuleNoSyntax() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MatchingRule matchingRule = new MatchingRule( "1.1.0" );
+
+        // It should fail (no syntax)
+        assertFalse( schemaManager.add( matchingRule ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isMRPresent( schemaManager, "1.1.0" ) );
+
+        assertEquals( mrrSize, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a new MatchingRule with an existing OID
+     */
+    @Test
+    public void testAddMatchingRuleExistingOID() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "2.5.13.0" );
+        matchingRule.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+
+        // It should fail (oid already registered)
+        assertFalse( schemaManager.add( matchingRule ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+        assertTrue( error instanceof LdapSchemaException );
+
+        // Check that the existing MR has not been replaced
+        assertTrue( isMRPresent( schemaManager, "2.5.13.0" ) );
+        MatchingRule existing = schemaManager.lookupMatchingRuleRegistry( "2.5.13.0" );
+
+        assertEquals( "objectIdentifierMatch", existing.getName() );
+
+        assertEquals( mrrSize, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a new MatchingRule with an existing name
+     */
+    @Test
+    public void testAddMatchingRuleExistingName() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.0" );
+        matchingRule.setNames( "Test", "objectIdentifierMatch" );
+        matchingRule.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+
+        // It should fail (name already registered)
+        assertFalse( schemaManager.add( matchingRule ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertEquals( mrrSize, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a new MatchingRule with an existing AT name
+     */
+    @Test
+    public void testAddMatchingRuleExistingATName() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.0" );
+        matchingRule.setNames( "Test", "cn" );
+        matchingRule.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+
+        // It should not fail
+        assertTrue( schemaManager.add( matchingRule ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+
+        assertEquals( 0, errors.size() );
+
+        // Check that the new MR has been injected
+        assertTrue( isMRPresent( schemaManager, "1.1.0" ) );
+        MatchingRule added = schemaManager.lookupMatchingRuleRegistry( "1.1.0" );
+
+        assertTrue( added.getNames().contains( "cn" ) );
+        assertTrue( added.getNames().contains( "Test" ) );
+
+        assertEquals( mrrSize + 1, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a new MatchingRule with a not existing Syntax
+     */
+    @Test
+    public void testAddMatchingRuleNotExistingSyntax() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.0" );
+        matchingRule.setNames( "Test" );
+        matchingRule.setSyntaxOid( "1.1.1" );
+
+        // It should fail
+        assertFalse( schemaManager.add( matchingRule ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertEquals( mrrSize, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a new MatchingRule with an existing AT name
+     */
+    @Test
+    public void testAddMatchingRuleNotExistingSchema() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableMatchingRule matchingRule = new MutableMatchingRule( "1.1.0" );
+        matchingRule.setNames( "Test" );
+        matchingRule.setSyntaxOid( "1.3.6.1.4.1.1466.115.121.1.26" );
+        matchingRule.setSchemaName( "bad" );
+
+        // It should fail
+        assertFalse( schemaManager.add( matchingRule ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+        assertTrue( error instanceof LdapSchemaException );
+
+        // Check that the new MR has been injected
+        assertFalse( isMRPresent( schemaManager, "1.1.0" ) );
+
+        assertEquals( mrrSize, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // MatchingRuleUse addition tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // NameForm addition tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // Normalizer addition tests
+    //-------------------------------------------------------------------------
+    @Test
+    public void testAddNewNormalizer() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int nrSize = schemaManager.getNormalizerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        Normalizer normalizer = new NoOpNormalizer( oid );
+
+        assertTrue( schemaManager.add( normalizer ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+
+        assertEquals( nrSize + 1, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        Normalizer added = schemaManager.lookupNormalizerRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( normalizer.getClass().getName(), added.getFqcn() );
+    }
+
+
+    @Test
+    public void testAddAlreadyExistingNormalizer() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int nrSize = schemaManager.getNormalizerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        Normalizer normalizer = new NoOpNormalizer( oid );
+
+        assertTrue( schemaManager.add( normalizer ) );
+
+        Normalizer added = schemaManager.lookupNormalizerRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( normalizer.getClass().getName(), added.getFqcn() );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+        assertEquals( nrSize + 1, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        Normalizer normalizer2 = new NoOpNormalizer( oid );
+
+        assertFalse( schemaManager.add( normalizer2 ) );
+
+        errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+
+        assertEquals( nrSize + 1, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        added = schemaManager.lookupNormalizerRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( normalizer.getClass().getName(), added.getFqcn() );
+    }
+
+
+    /**
+     * Test that we can't add two Normalizers with the same class code.
+     */
+    @Test
+    public void testAddNormalizerWithWrongFQCN() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int nrSize = schemaManager.getNormalizerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        Normalizer normalizer = new NoOpNormalizer( oid );
+
+        // using java.sql.ResultSet cause it is very unlikely to get loaded
+        // in ADS, as the FQCN is not the one expected
+        normalizer.setFqcn( "java.sql.ResultSet" );
+
+        assertFalse( schemaManager.add( normalizer ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+
+        assertEquals( nrSize, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        try
+        {
+            schemaManager.lookupNormalizerRegistry( oid );
+            fail();
+        }
+        catch ( Exception e )
+        {
+            // Expected
+            assertTrue( true );
+        }
+    }
+
+
+    //=========================================================================
+    // ObjectClass addition tests
+    //-------------------------------------------------------------------------
+    //-------------------------------------------------------------------------
+    // First, not defined superior
+    //-------------------------------------------------------------------------
+    /**
+     * Addition of a valid OC
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorValid() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        ObjectClass objectClass = new ObjectClass( "1.1.1" );
+
+        assertTrue( schemaManager.add( objectClass ) );
+
+        assertEquals( 0, schemaManager.getErrors().size() );
+
+        ObjectClass added = schemaManager.lookupObjectClassRegistry( "1.1.1" );
+
+        assertNotNull( added );
+
+        assertEquals( ocrSize + 1, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with an existing OID
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorWithExistingOid() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        ObjectClass objectClass = new ObjectClass( "2.5.17.0" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        Throwable error = schemaManager.getErrors().get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        ObjectClass added = schemaManager.lookupObjectClassRegistry( "2.5.17.0" );
+
+        assertNotNull( added );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with an existing OC name
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorWithExistingOCName() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        ObjectClass objectClass = new ObjectClass( "1.1.0" );
+        objectClass.setNames( "Test", "referral" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        Throwable error = schemaManager.getErrors().get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.0" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with an AT name
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorWithATName() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        ObjectClass objectClass = new ObjectClass( "1.1.1" );
+        objectClass.setNames( "Test", "cn" );
+
+        assertTrue( schemaManager.add( objectClass ) );
+
+        assertEquals( 0, schemaManager.getErrors().size() );
+
+        ObjectClass added = schemaManager.lookupObjectClassRegistry( "1.1.1" );
+
+        assertNotNull( added );
+        assertTrue( added.getNames().contains( "Test" ) );
+        assertTrue( added.getNames().contains( "cn" ) );
+
+        assertEquals( ocrSize + 1, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with not existing AT in MAY
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorNonExistingAtInMay() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.addMayAttributeTypeOids( "cn", "none", "userPassword" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        Throwable error = schemaManager.getErrors().get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with not existing AT in MUST
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorNonExistingAtInMust() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.addMustAttributeTypeOids( "cn", "none", "userPassword" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        Throwable error = schemaManager.getErrors().get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with an AT present more than once in MAY
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorATMoreThanOnceInMay() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.addMayAttributeTypeOids( "cn", "ref", "commonName" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with an AT present more than once in MUST
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorATMoreThanOnceInMust() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.addMustAttributeTypeOids( "cn", "ref", "2.5.4.3" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with an AT present in MUST and MAY.
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorATInMustAndMay() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.addMustAttributeTypeOids( "cn", "ref" );
+        objectClass.addMayAttributeTypeOids( "2.5.4.3" );
+
+        // Same AT i MAY and MUST : should fail
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with a collective AT present in MUST or MAY.
+     */
+    @Test
+    public void testAddObjectClassNoSuperiorCollectiveATInMustOrMay() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        schemaManager.loadWithDeps( "collective" );
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        // Check a addition in MUST
+        MutableObjectClass objectClassMust = new MutableObjectClass( "1.1.1" );
+        objectClassMust.addMustAttributeTypeOids( "c-o", "ref" );
+
+        // collective attribute in MUST : failure expected
+        assertFalse( schemaManager.add( objectClassMust ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        // Check an addition in MAY
+        MutableObjectClass objectClassMay = new MutableObjectClass( "1.1.1" );
+        objectClassMay.addMayAttributeTypeOids( "c-o", "ref" );
+
+        // collective attribute in MAY : failure expected
+        assertFalse( schemaManager.add( objectClassMay ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Then, with superiors
+    //-------------------------------------------------------------------------
+    /**
+     * Addition of a valid OC with some superiors
+     */
+    @Test
+    public void testAddObjectClassSuperiorsValid() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.addSuperiorOids( "alias", "referral", "top" );
+
+        assertTrue( schemaManager.add( objectClass ) );
+
+        assertEquals( 0, schemaManager.getErrors().size() );
+
+        ObjectClass added = schemaManager.lookupObjectClassRegistry( "1.1.1" );
+
+        assertNotNull( added );
+        assertTrue( added.getNames().contains( "Test" ) );
+        assertNotNull( added.getSuperiors() );
+        assertEquals( 3, added.getSuperiors().size() );
+
+        Set<String> expectedSups = new HashSet<String>();
+        expectedSups.add( "alias" );
+        expectedSups.add( "referral" );
+        expectedSups.add( "top" );
+
+        for ( ObjectClass addedOC : added.getSuperiors() )
+        {
+            assertTrue( expectedSups.contains( addedOC.getName() ) );
+            expectedSups.remove( addedOC.getName() );
+        }
+
+        assertEquals( ocrSize + 1, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with itself in the SUP list
+     */
+    @Test
+    public void testAddObjectClassSuperiorsWithCycle() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.addSuperiorOids( "alias", "Test", "referral" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with the same OC more than once in SUP
+     */
+    @Test
+    public void testAddObjectClassSuperiorsOcMoreThanOnceInSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.addSuperiorOids( "alias", "referral", "2.5.6.1" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with a non existing OC in SUP
+     */
+    @Test
+    public void testAddObjectClassSuperiorsNonExistingOCInSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.addSuperiorOids( "alias", "refessal" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an ABSTRACT OC with some AUXILIARY superior
+     */
+    @Test
+    public void testAddObjectClassSuperiorsAbstractWithAuxiliaryInSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.ABSTRACT );
+        objectClass.addSuperiorOids( "extensibleObject" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an ABSTRACT OC with some STRUCTURAL superior
+     */
+    @Test
+    public void testAddObjectClassSuperiorsAbstractWithStructuralInSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.ABSTRACT );
+        objectClass.addSuperiorOids( "referral" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an AUXILIARY OC with some STRUCTURAL superior
+     */
+    @Test
+    public void testAddObjectClassSuperiorsAuxiliaryWithStructuralInSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.AUXILIARY );
+        objectClass.addSuperiorOids( "referral" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an STRUCTURAL OC with some AUXILIARY superior
+     */
+    @Test
+    public void testAddObjectClassSuperiorsStructuralWithAuxiliaryInSup() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.addSuperiorOids( "extensibleObject" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with some AT present in MUST and in MAY in one of its
+     * superior
+     */
+    @Test
+    public void testAddObjectClassSuperiorsATInMustPresentInSuperiorsMay() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.addSuperiorOids( "alias", "OpenLDAProotDSE" );
+        objectClass.addMustAttributeTypeOids( "aliasedObjectName", "cn" );
+
+        assertTrue( schemaManager.add( objectClass ) );
+
+        assertEquals( 0, schemaManager.getErrors().size() );
+
+        ObjectClass added = schemaManager.lookupObjectClassRegistry( "1.1.1" );
+
+        assertNotNull( added );
+        assertTrue( added.getNames().contains( "Test" ) );
+        assertNotNull( added.getSuperiors() );
+        assertEquals( 2, added.getSuperiors().size() );
+
+        Set<String> expectedSups = new HashSet<String>();
+        expectedSups.add( "alias" );
+        expectedSups.add( "OpenLDAProotDSE" );
+
+        for ( ObjectClass addedOC : added.getSuperiors() )
+        {
+            assertTrue( expectedSups.contains( addedOC.getName() ) );
+            expectedSups.remove( addedOC.getName() );
+        }
+
+        assertEquals( ocrSize + 1, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Addition of an OC with some AT present in MAY and in MUST in one of its
+     * superior : not allowed
+     */
+    @Test
+    public void testAddObjectClassSuperiorsATInMayPresentInSuperiorsMust() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int ocrSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableObjectClass objectClass = new MutableObjectClass( "1.1.1" );
+        objectClass.setNames( "Test" );
+        objectClass.setType( ObjectClassTypeEnum.STRUCTURAL );
+        objectClass.addSuperiorOids( "alias", "OpenLDAProotDSE" );
+        objectClass.addMayAttributeTypeOids( "aliasedObjectName", "cn" );
+
+        assertFalse( schemaManager.add( objectClass ) );
+
+        assertEquals( 1, schemaManager.getErrors().size() );
+
+        assertTrue( schemaManager.getErrors().get( 0 ) instanceof LdapSchemaException );
+
+        assertFalse( isOCPresent( schemaManager, "1.1.1" ) );
+
+        assertEquals( ocrSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // Syntax addition tests
+    //-------------------------------------------------------------------------
+    /**
+     * Try to inject a new valid Syntax, with no SC : the associated SC
+     * will be the default OctetString SC
+     */
+    @Test
+    public void testAddValidSyntax() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int sSize = schemaManager.getLdapSyntaxRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        LdapSyntax syntax = new LdapSyntax( "1.1.0" );
+
+        // It should not fail
+        assertTrue( schemaManager.add( syntax ) );
+
+        LdapSyntax added = schemaManager.lookupLdapSyntaxRegistry( "1.1.0" );
+
+        assertNotNull( added );
+        assertEquals( OctetStringSyntaxChecker.class.getName(), added.getSyntaxChecker().getClass().getName() );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+
+        assertTrue( isSyntaxPresent( schemaManager, "1.1.0" ) );
+        assertEquals( sSize + 1, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize + 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Try to inject a Syntax with an existing OID
+     */
+    @Test
+    public void testAddSyntaxExistingOid() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int sSize = schemaManager.getLdapSyntaxRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        LdapSyntax syntax = new LdapSyntax( "2.5.4.3" );
+
+        // It should fail
+        assertFalse( schemaManager.add( syntax ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+        Throwable error = errors.get( 0 );
+
+        assertTrue( error instanceof LdapSchemaException );
+        assertEquals( sSize, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // SyntaxChecker addition tests
+    //-------------------------------------------------------------------------
+    @Test
+    public void testAddNewSyntaxChecker() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int nrSize = schemaManager.getSyntaxCheckerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        SyntaxChecker syntaxChecker = new RegexSyntaxChecker( oid );
+
+        assertTrue( schemaManager.add( syntaxChecker ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+
+        assertEquals( nrSize + 1, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        SyntaxChecker added = schemaManager.lookupSyntaxCheckerRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( syntaxChecker.getClass().getName(), added.getFqcn() );
+    }
+
+
+    @Test
+    public void testAddAlreadyExistingSyntaxChecker() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int nrSize = schemaManager.getSyntaxCheckerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        SyntaxChecker syntaxChecker = new RegexSyntaxChecker( oid );
+
+        assertTrue( schemaManager.add( syntaxChecker ) );
+
+        SyntaxChecker added = schemaManager.lookupSyntaxCheckerRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( syntaxChecker.getClass().getName(), added.getFqcn() );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertEquals( 0, errors.size() );
+        assertEquals( nrSize + 1, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        SyntaxChecker syntaxChecker2 = new RegexSyntaxChecker( oid );
+
+        assertFalse( schemaManager.add( syntaxChecker2 ) );
+
+        errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+
+        assertEquals( nrSize + 1, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        added = schemaManager.lookupSyntaxCheckerRegistry( oid );
+
+        assertNotNull( added );
+        assertEquals( syntaxChecker.getClass().getName(), added.getFqcn() );
+    }
+
+
+    /**
+     * Test that we can't add two SyntaxCheckers with the same class code.
+     */
+    @Test
+    public void testAddSyntaxCheckerWithWrongFQCN() throws Exception
+    {
+        SchemaManager schemaManager = loadSystem();
+        int nrSize = schemaManager.getSyntaxCheckerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String oid = "0.0.0";
+        SyntaxChecker syntaxChecker = new RegexSyntaxChecker( oid );
+
+        // using java.sql.ResultSet cause it is very unlikely to get loaded
+        // in ADS, as the FQCN is not the one expected
+        syntaxChecker.setFqcn( "java.sql.ResultSet" );
+
+        assertFalse( schemaManager.add( syntaxChecker ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        errors = schemaManager.getErrors();
+        assertEquals( 1, errors.size() );
+
+        assertEquals( nrSize, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        try
+        {
+            schemaManager.lookupSyntaxCheckerRegistry( oid );
+            fail();
+        }
+        catch ( Exception e )
+        {
+            // Expected
+            assertTrue( true );
+        }
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerDelTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerDelTest.java
new file mode 100644
index 0000000..d3ad072
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerDelTest.java
@@ -0,0 +1,1085 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
+import org.apache.directory.api.ldap.model.schema.LdapSyntax;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
+import org.apache.directory.api.ldap.model.schema.Normalizer;
+import org.apache.directory.api.ldap.model.schema.ObjectClass;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.api.ldap.model.schema.comparators.BooleanComparator;
+import org.apache.directory.api.ldap.model.schema.normalizers.BooleanNormalizer;
+import org.apache.directory.api.ldap.model.schema.syntaxCheckers.BooleanSyntaxChecker;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test class for SchemaManager, testing the deletion of a SchemaObject.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaManagerDelTest
+{
+    // A directory in which the ldif files will be stored
+    private static String workingDirectory;
+
+    // The schema repository
+    private static File schemaRepository;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = SchemaManagerDelTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        // Make sure every test class has its own schema directory
+        workingDirectory = new File( workingDirectory, "SchemaManagerDelTest" ).getAbsolutePath();
+
+        schemaRepository = new File( workingDirectory, "schema" );
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository );
+
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy();
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository.getParentFile() );
+    }
+
+
+    private SchemaManager loadSchema( String schemaName ) throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( schemaName );
+
+        return schemaManager;
+    }
+
+
+    private boolean isAttributeTypePresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
+
+            return attributeType != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    private boolean isComparatorPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            LdapComparator<?> comparator = schemaManager.lookupComparatorRegistry( oid );
+
+            return comparator != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    private boolean isNormalizerPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            Normalizer normalizer = schemaManager.lookupNormalizerRegistry( oid );
+
+            return normalizer != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    private boolean isMatchingRulePresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            MatchingRule matchingRule = schemaManager.lookupMatchingRuleRegistry( oid );
+
+            return matchingRule != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    private boolean isSyntaxPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            LdapSyntax syntax = schemaManager.lookupLdapSyntaxRegistry( oid );
+
+            return syntax != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    private boolean isSyntaxCheckerPresent( SchemaManager schemaManager, String oid )
+    {
+        try
+        {
+            SyntaxChecker syntaxChecker = schemaManager.lookupSyntaxCheckerRegistry( oid );
+
+            return syntaxChecker != null;
+        }
+        catch ( LdapException ne )
+        {
+            return false;
+        }
+    }
+
+
+    //=========================================================================
+    // For each test, we will check many different things.
+    // If the test is successful, we want to know if the SchemaObject
+    // Registry has shrunk : its size must be one lower. If the SchemaObject
+    // is not loadable, then the GlobalOidRegistry must also have grown.
+    //=========================================================================
+    // AttributeType deletion tests
+    //-------------------------------------------------------------------------
+    // First, not defined descendant
+    //-------------------------------------------------------------------------
+    /**
+     * Try to delete an AttributeType not existing in the schemaManager
+     */
+    @Test
+    public void testDeleteNonExistingAttributeType() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "Core" );
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "1.1.0" );
+        attributeType.setEqualityOid( "2.5.13.1" );
+        attributeType.setOrderingOid( null );
+        attributeType.setSubstringOid( null );
+
+        // It should fail
+        assertFalse( schemaManager.delete( attributeType ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Delete an existing AT not referenced by any object
+     */
+    @Test
+    public void testDeleteExistingAttributeType() throws Exception
+    {
+        // First inject such an AT
+        SchemaManager schemaManager = loadSchema( "Core" );
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MutableAttributeType attributeType = new MutableAttributeType( "generationQualifier" );
+        attributeType.setOid( "2.5.4.44" );
+
+        // It should not fail
+        assertTrue( schemaManager.delete( attributeType ) );
+
+        assertFalse( isAttributeTypePresent( schemaManager, "generationQualifier" ) );
+        assertEquals( atrSize - 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Delete an existing AT referenced by some other OC
+     */
+    @Test
+    public void testDeleteExistingAttributeTypeUsedByOC() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "Core" );
+
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        // Try to delete an AT which is referenced by at least one OC
+        // (modifiersName has one descendant : schemaModifiersName)
+        AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( "cn" );
+
+        // It should fail
+        assertFalse( schemaManager.delete( attributeType ) );
+
+        assertTrue( isAttributeTypePresent( schemaManager, "cn" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Delete an existing AT stored in some disabled schema
+     */
+    @Test
+    public void testDelAttributeTypeFromDisabledSchema() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "Core" );
+
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        // Try to delete an AT which is contained by a disabled schema
+        MutableAttributeType attributeType = new MutableAttributeType( "gecos" );
+        attributeType.setOid( "1.3.6.1.1.1.1.2" );
+
+        // It should fail
+        assertFalse( schemaManager.delete( attributeType ) );
+
+        assertFalse( isAttributeTypePresent( schemaManager, "gecos" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Delete an existing AT referenced by some descendant
+     */
+    @Test
+    public void testDeleteExistingAttributeTypeUsedByDescendant() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "Apache" );
+
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        // Try to delete an AT which has descendant
+        // (modifiersName has one descendant : schemaModifiersName)
+        AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( "modifiersName" );
+
+        // It should fail
+        assertFalse( schemaManager.delete( attributeType ) );
+
+        assertTrue( isAttributeTypePresent( schemaManager, "modifiersName" ) );
+        assertEquals( atrSize, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // Comparator deletion tests
+    //-------------------------------------------------------------------------
+
+    @Test
+    public void testDeleteExistingComparator() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int ctrSize = schemaManager.getComparatorRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        LdapComparator<?> lc = new BooleanComparator( "0.1.1" );
+        assertTrue( schemaManager.add( lc ) );
+
+        assertEquals( ctrSize + 1, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        lc = schemaManager.lookupComparatorRegistry( "0.1.1" );
+        assertNotNull( lc );
+        assertTrue( schemaManager.delete( lc ) );
+
+        try
+        {
+            schemaManager.lookupComparatorRegistry( "0.1.1" );
+            fail();
+        }
+        catch ( Exception e )
+        {
+            // expected
+        }
+
+        assertEquals( ctrSize, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteNonExistingComparator() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int ctrSize = schemaManager.getComparatorRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        LdapComparator<?> lc = new BooleanComparator( "0.0" );
+        assertFalse( schemaManager.delete( lc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+
+        assertEquals( ctrSize, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteExistingComaparatorUsedByMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int ctrSize = schemaManager.getComparatorRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        LdapComparator<?> lc = schemaManager.lookupComparatorRegistry( "2.5.13.0" );
+
+        // shouldn't be deleted cause there is a MR associated with it
+        assertFalse( schemaManager.delete( lc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        assertNotNull( schemaManager.lookupComparatorRegistry( "2.5.13.0" ) );
+        assertEquals( ctrSize, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Check that a Comparator which has been used by a deleted MatchingRule
+     * can be removed
+     */
+    @Test
+    public void testDeleteExistingComparatorUsedByRemovedMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int ctrSize = schemaManager.getComparatorRegistry().size();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String OID = "2.5.13.33";
+
+        // Check that the MR and C are present
+        assertTrue( isMatchingRulePresent( schemaManager, OID ) );
+        assertTrue( isComparatorPresent( schemaManager, OID ) );
+
+        // Now try to remove the C
+        LdapComparator<?> lc = schemaManager.lookupComparatorRegistry( OID );
+
+        // shouldn't be deleted cause there is a MR associated with it
+        assertFalse( schemaManager.delete( lc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        // Now delete the using MR : it should be OK
+        MatchingRule mr = new MatchingRule( OID );
+        assertTrue( schemaManager.delete( mr ) );
+
+        assertEquals( mrrSize - 1, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        assertFalse( isMatchingRulePresent( schemaManager, OID ) );
+
+        // and try to delete the Comparator again
+        assertTrue( schemaManager.delete( lc ) );
+
+        assertFalse( isComparatorPresent( schemaManager, OID ) );
+        assertEquals( ctrSize - 1, schemaManager.getComparatorRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // DitContentRule deletion tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // DitStructureRule deletion tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // MatchingRule deletion tests
+    //-------------------------------------------------------------------------
+
+    @Test
+    public void testDeleteExistingMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int mrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MatchingRule mr = new MatchingRule( "2.5.13.33" );
+        assertTrue( schemaManager.delete( mr ) );
+
+        assertEquals( mrSize - 1, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteNonExistingMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int mrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        MatchingRule mr = new MatchingRule( "0.1.1" );
+        assertFalse( schemaManager.delete( mr ) );
+
+        assertEquals( mrSize, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteExistingMatchingRuleUsedByAttributeType() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int mrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        // AT with OID 2.5.18.4 has syntax 1.3.6.1.4.1.1466.115.121.1.12 which is used by MR 2.5.13.1
+        MatchingRule mr = new MatchingRule( "2.5.13.1" );
+        assertFalse( schemaManager.delete( mr ) );
+
+        assertEquals( mrSize, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Check that a MatcingRule which has been used by a deleted AttributeType
+     * can be removed
+     */
+    @Test
+    public void testDeleteExistingMatchingRuleUsedByRemovedAttributeType() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String AT_OID = "2.5.18.9";
+        String MR_OID = "2.5.13.13";
+
+        // Check that the AT and MR are present
+        assertTrue( isAttributeTypePresent( schemaManager, AT_OID ) );
+        assertTrue( isMatchingRulePresent( schemaManager, MR_OID ) );
+
+        // Now try to remove the MR
+        MatchingRule matchingRule = schemaManager.lookupMatchingRuleRegistry( MR_OID );
+
+        // shouldn't be deleted cause there is a AT associated with it
+        assertFalse( schemaManager.delete( matchingRule ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        // Now delete the using AT : it should be OK
+        MutableAttributeType at = new MutableAttributeType( AT_OID );
+        assertTrue( schemaManager.delete( at ) );
+
+        assertEquals( atrSize - 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        assertFalse( isAttributeTypePresent( schemaManager, AT_OID ) );
+
+        // and try to delete the MatchingRule again
+        assertTrue( schemaManager.delete( matchingRule ) );
+
+        assertFalse( isMatchingRulePresent( schemaManager, MR_OID ) );
+        assertEquals( mrrSize - 1, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize - 2, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // MatchingRuleUse deletion tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // NameForm deletion tests
+    //-------------------------------------------------------------------------
+    // TODO
+
+    //=========================================================================
+    // Normalizer deletion tests
+    //-------------------------------------------------------------------------
+
+    @Test
+    public void testDeleteExistingNormalizer() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int nrSize = schemaManager.getNormalizerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        Normalizer nr = new BooleanNormalizer();
+        nr.setOid( "0.1.1" );
+        assertTrue( schemaManager.add( nr ) );
+
+        assertEquals( nrSize + 1, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        // FIXME this lookup is failing ! but it shouldn't be
+        nr = schemaManager.lookupNormalizerRegistry( "0.1.1" );
+        assertNotNull( nr );
+        assertTrue( schemaManager.delete( nr ) );
+
+        try
+        {
+            schemaManager.lookupNormalizerRegistry( "0.1.1" );
+            fail();
+        }
+        catch ( Exception e )
+        {
+            // expected
+        }
+
+        assertEquals( nrSize, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteNonExistingNormalizer() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int nrSize = schemaManager.getNormalizerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        Normalizer nr = new BooleanNormalizer();
+        nr.setOid( "0.0" );
+        assertFalse( schemaManager.delete( nr ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+
+        assertEquals( nrSize, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteExistingNormalizerUsedByMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int nrSize = schemaManager.getNormalizerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        Normalizer nr = schemaManager.lookupNormalizerRegistry( "2.5.13.0" );
+        // shouldn't be deleted cause there is a MR associated with it
+        assertFalse( schemaManager.delete( nr ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        assertNotNull( schemaManager.lookupNormalizerRegistry( "2.5.13.0" ) );
+        assertEquals( nrSize, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Check that a Normalizer which has been used by a deleted MatchingRule
+     * can be removed
+     */
+    @Test
+    public void testDeleteExistingNormalizerUsedByRemovedMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int nrSize = schemaManager.getNormalizerRegistry().size();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String OID = "2.5.13.33";
+
+        // Check that the MR and N are present
+        assertTrue( isMatchingRulePresent( schemaManager, OID ) );
+        assertTrue( isNormalizerPresent( schemaManager, OID ) );
+
+        // Now try to remove the N
+        Normalizer normalizer = schemaManager.lookupNormalizerRegistry( OID );
+
+        // shouldn't be deleted cause there is a MR associated with it
+        assertFalse( schemaManager.delete( normalizer ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        // Now delete the using MR : it should be OK
+        MatchingRule mr = new MatchingRule( OID );
+        assertTrue( schemaManager.delete( mr ) );
+
+        assertEquals( mrrSize - 1, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        assertFalse( isMatchingRulePresent( schemaManager, OID ) );
+
+        // and try to delete the normalizer again
+        assertTrue( schemaManager.delete( normalizer ) );
+
+        assertFalse( isNormalizerPresent( schemaManager, OID ) );
+        assertEquals( nrSize - 1, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // ObjectClass deletion tests
+    //-------------------------------------------------------------------------
+
+    @Test
+    public void testDeleteExistingObjectClass() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int ocSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        ObjectClass oc = new ObjectClass( "2.5.17.2" );
+
+        assertTrue( schemaManager.delete( oc ) );
+
+        assertEquals( ocSize - 1, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        try
+        {
+            schemaManager.lookupObjectClassRegistry( "2.5.17.2" );
+            fail();
+        }
+        catch ( Exception e )
+        {
+            // expected
+        }
+    }
+
+
+    @Test
+    public void testDeleteNonExistingObjectClass() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int ocSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        ObjectClass oc = new ObjectClass( "0.1.1" );
+
+        assertFalse( schemaManager.delete( oc ) );
+
+        assertEquals( ocSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteExistingObjectClassUsedByAnotherObjectClass() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int ocSize = schemaManager.getObjectClassRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        ObjectClass oc = new ObjectClass( "2.5.6.0" );
+
+        // shouldn't delete the 'top' OC
+        assertFalse( schemaManager.delete( oc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        assertEquals( ocSize, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // Syntax deletion tests
+    //-------------------------------------------------------------------------
+
+    @Test
+    public void testDeleteExistingSyntax() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int sSize = schemaManager.getLdapSyntaxRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        // delete a existing syntax not used by AT and MR
+        LdapSyntax syntax = schemaManager.lookupLdapSyntaxRegistry( "1.3.6.1.4.1.1466.115.121.1.10" );
+        assertTrue( schemaManager.delete( syntax ) );
+
+        assertEquals( sSize - 1, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        // add a syntax and then delete (should behave same as above )
+        syntax = new LdapSyntax( "0.1.1" );
+        assertTrue( schemaManager.add( syntax ) );
+
+        assertEquals( sSize, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        syntax = schemaManager.lookupLdapSyntaxRegistry( "0.1.1" );
+        assertTrue( schemaManager.delete( syntax ) );
+
+        try
+        {
+            schemaManager.lookupLdapSyntaxRegistry( "0.1.1" );
+            fail( "shouldn't find the syntax" );
+        }
+        catch ( Exception e )
+        {
+            // expected behaviour
+        }
+
+        assertEquals( sSize - 1, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteNonExistingSyntax() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int sSize = schemaManager.getLdapSyntaxRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        LdapSyntax syntax = new LdapSyntax( "0.1.1" );
+
+        assertFalse( schemaManager.delete( syntax ) );
+
+        assertEquals( sSize, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteExistingSyntaxUsedByMatchingRule() throws Exception
+    {
+
+        SchemaManager schemaManager = loadSchema( "system" );
+        int sSize = schemaManager.getLdapSyntaxRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        //1.3.6.1.4.1.1466.115.121.1.26 is used by MR 1.3.6.1.4.1.1466.109.114.2
+        LdapSyntax syntax = new LdapSyntax( "1.3.6.1.4.1.1466.115.121.1.26" );
+        assertFalse( schemaManager.delete( syntax ) );
+
+        // syntax 1.3.6.1.4.1.1466.115.121.1.12 is used by MR 2.5.13.1 and many AT
+        syntax = new LdapSyntax( "1.3.6.1.4.1.1466.115.121.1.12" );
+
+        assertFalse( schemaManager.delete( syntax ) );
+
+        assertEquals( sSize, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteExistingSyntaxUsedByAttributeType() throws Exception
+    {
+        // syntax 1.3.6.1.4.1.1466.115.121.1.15 is used by AT 1.3.6.1.1.4
+
+        SchemaManager schemaManager = loadSchema( "system" );
+        int sSize = schemaManager.getLdapSyntaxRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        LdapSyntax syntax = new LdapSyntax( "1.3.6.1.4.1.1466.115.121.1.15" );
+
+        assertFalse( schemaManager.delete( syntax ) );
+
+        assertEquals( sSize, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Check that a Syntax which has been used by a deleted MatchingRule
+     * can be removed
+     */
+    @Test
+    public void testDeleteExistingSyntaxUsedByRemovedMatchingRule() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int srSize = schemaManager.getLdapSyntaxRegistry().size();
+        int mrrSize = schemaManager.getMatchingRuleRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String MR_OID = "2.5.13.11";
+        String S_OID = "1.3.6.1.4.1.1466.115.121.1.41";
+
+        // Check that the MR and S are present
+        assertTrue( isMatchingRulePresent( schemaManager, MR_OID ) );
+        assertTrue( isSyntaxPresent( schemaManager, S_OID ) );
+
+        // Now try to remove the S
+        LdapSyntax syntax = schemaManager.lookupLdapSyntaxRegistry( S_OID );
+
+        // shouldn't be deleted cause there is a MR associated with it
+        assertFalse( schemaManager.delete( syntax ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        // Now delete the using MR : it should be OK
+        MatchingRule mr = new MatchingRule( MR_OID );
+        assertTrue( schemaManager.delete( mr ) );
+
+        assertEquals( mrrSize - 1, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        assertFalse( isMatchingRulePresent( schemaManager, MR_OID ) );
+
+        // and try to delete the syntax again
+        assertTrue( schemaManager.delete( syntax ) );
+
+        assertFalse( isSyntaxPresent( schemaManager, S_OID ) );
+        assertEquals( srSize - 1, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize - 2, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Check that a Syntax which has been used by a deleted AttributeType
+     * can be removed
+     */
+    @Test
+    public void testDeleteExistingSyntaxUsedByRemovedAttributeType() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int srSize = schemaManager.getLdapSyntaxRegistry().size();
+        int atrSize = schemaManager.getAttributeTypeRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String AT_OID = "1.3.6.1.4.1.1466.101.120.16";
+        String S_OID = "1.3.6.1.4.1.1466.115.121.1.54";
+
+        // Check that the AT and S are present
+        assertTrue( isAttributeTypePresent( schemaManager, AT_OID ) );
+        assertTrue( isSyntaxPresent( schemaManager, S_OID ) );
+
+        // Now try to remove the S
+        LdapSyntax syntax = schemaManager.lookupLdapSyntaxRegistry( S_OID );
+
+        // shouldn't be deleted cause there is a AT associated with it
+        assertFalse( schemaManager.delete( syntax ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        // Now delete the using AT : it should be OK
+        MutableAttributeType at = new MutableAttributeType( AT_OID );
+        assertTrue( schemaManager.delete( at ) );
+
+        assertEquals( atrSize - 1, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        assertFalse( isAttributeTypePresent( schemaManager, AT_OID ) );
+
+        // and try to delete the syntax again
+        assertTrue( schemaManager.delete( syntax ) );
+
+        assertFalse( isSyntaxPresent( schemaManager, S_OID ) );
+        assertEquals( srSize - 1, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize - 2, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    /**
+     * Check that a SyntaxChecker which has been used by a deleted Syntax
+     * can be removed
+     */
+    @Test
+    public void testDeleteExistingSyntaxCheckerUsedByRemovedSyntax() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int scrSize = schemaManager.getSyntaxCheckerRegistry().size();
+        int srSize = schemaManager.getLdapSyntaxRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        String OID = "1.3.6.1.4.1.1466.115.121.1.33";
+
+        // Check that the S and SC are present
+        assertTrue( isSyntaxCheckerPresent( schemaManager, OID ) );
+        assertTrue( isSyntaxPresent( schemaManager, OID ) );
+
+        // Now try to remove the SC
+        SyntaxChecker sc = schemaManager.lookupSyntaxCheckerRegistry( OID );
+
+        // shouldn't be deleted cause there is a S associated with it
+        assertFalse( schemaManager.delete( sc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        // Now delete the using S : it should be OK
+        LdapSyntax syntax = new LdapSyntax( OID );
+        assertTrue( schemaManager.delete( syntax ) );
+
+        assertEquals( srSize - 1, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+
+        assertFalse( isSyntaxPresent( schemaManager, OID ) );
+
+        // and try to delete the SC again
+        assertTrue( schemaManager.delete( sc ) );
+
+        assertFalse( isSyntaxCheckerPresent( schemaManager, OID ) );
+        assertEquals( scrSize - 1, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize - 1, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    //=========================================================================
+    // SyntaxChecker deletion tests
+    //-------------------------------------------------------------------------
+
+    @Test
+    public void testDeleteExistingSyntaxChecker() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int scrSize = schemaManager.getSyntaxCheckerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        SyntaxChecker sc = new BooleanSyntaxChecker();
+        sc.setOid( "0.1.1" );
+        assertTrue( schemaManager.add( sc ) );
+
+        assertEquals( scrSize + 1, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+
+        sc = schemaManager.lookupSyntaxCheckerRegistry( "0.1.1" );
+        assertNotNull( sc );
+        assertTrue( schemaManager.delete( sc ) );
+
+        try
+        {
+            schemaManager.lookupSyntaxCheckerRegistry( "0.1.1" );
+            fail();
+        }
+        catch ( Exception e )
+        {
+            // expected
+        }
+
+        assertEquals( scrSize, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteNonExistingSyntaxChecker() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int scrSize = schemaManager.getSyntaxCheckerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        SyntaxChecker sc = new BooleanSyntaxChecker();
+        sc.setOid( "0.0" );
+        assertFalse( schemaManager.delete( sc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+
+        assertEquals( scrSize, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+
+
+    @Test
+    public void testDeleteExistingSyntaxCheckerUsedBySyntax() throws Exception
+    {
+        SchemaManager schemaManager = loadSchema( "system" );
+        int scrSize = schemaManager.getSyntaxCheckerRegistry().size();
+        int goidSize = schemaManager.getGlobalOidRegistry().size();
+
+        SyntaxChecker sc = schemaManager.lookupSyntaxCheckerRegistry( "1.3.6.1.4.1.1466.115.121.1.1" );
+
+        //FIXME should return false but is returning true
+        assertFalse( schemaManager.delete( sc ) );
+
+        List<Throwable> errors = schemaManager.getErrors();
+        assertFalse( errors.isEmpty() );
+        assertTrue( errors.get( 0 ) instanceof LdapProtocolErrorException );
+
+        assertEquals( scrSize, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( goidSize, schemaManager.getGlobalOidRegistry().size() );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerEnableDisableLoadTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerEnableDisableLoadTest.java
new file mode 100644
index 0000000..abe0ea4
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerEnableDisableLoadTest.java
@@ -0,0 +1,312 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.api.util.Strings;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test class for SchemaManager enable/disable and loadAllEnbled() methods.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaManagerEnableDisableLoadTest
+{
+    // A directory in which the ldif files will be stored
+    private static String workingDirectory;
+
+    // The schema repository
+    private static File schemaRepository;
+
+    // The schemaManager
+    private SchemaManager schemaManager;
+
+    // List of all the available schemas, enabled or disabled
+    private List<String> allSchemas = Arrays.asList( "system", "core", "cosine", "inetorgperson", "apache",
+        "apachemeta", "collective", "java", "krb5kdc", "other", "nis", "autofs",
+        "apachedns", "dhcp", "samba", "corba", "adsconfig", "pwdpolicy" );
+
+    // List of all the enabled schemas
+    private List<String> enabledSchemas = Arrays.asList( "system", "core", "cosine", "inetorgperson", "apache",
+        "apachemeta", "collective", "java", "krb5kdc", "other", "adsconfig", "pwdpolicy" );
+
+    // List of all the disabled schemas
+    @SuppressWarnings("unused")
+    private List<String> disabledSchemas = Arrays.asList( "nis", "autofs", "apachedns", "dhcp", "samba", "corba" );
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = SchemaManagerEnableDisableLoadTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        // Make sure every test class has its own schema directory
+        workingDirectory = new File( workingDirectory, "SchemaManagerEnableDisableLoadTest" ).getAbsolutePath();
+
+        schemaRepository = new File( workingDirectory, "schema" );
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository );
+
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy();
+    }
+
+
+    @Before
+    public void init() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        schemaManager = new DefaultSchemaManager( loader );
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository.getParentFile() );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Test the loadAllEnabled() method
+    //-------------------------------------------------------------------------
+    /**
+     * Test the loadEnabled() method
+     */
+    @Test
+    public void testLoadAllEnabled() throws Exception
+    {
+        assertTrue( schemaManager.getEnabled().isEmpty() );
+        assertTrue( schemaManager.loadAllEnabled() );
+
+        for ( String schemaName : allSchemas )
+        {
+            assertTrue( schemaManager.isSchemaLoaded( schemaName ) );
+        }
+
+        // The enabled schemas
+        List<Schema> enabled = schemaManager.getEnabled();
+
+        assertEquals( enabled.size(), enabledSchemas.size() );
+
+        for ( Schema schema : enabled )
+        {
+            assertTrue( enabledSchemas.contains( Strings.toLowerCase( schema.getSchemaName() ) ) );
+        }
+
+        // The disabled schemas
+        List<Schema> disabled = schemaManager.getDisabled();
+
+        assertEquals( 0, disabled.size() );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 428, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 49, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 55, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 48, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 123, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 68, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 80, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 686, schemaManager.getGlobalOidRegistry().size() );
+        assertEquals( 12, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "nis" ) );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Test the enable( String... schemaName) method
+    //-------------------------------------------------------------------------
+    /**
+     * Enable a schema which is already enabled
+     */
+    @Test
+    public void testEnableAlreadyEnabled() throws Exception
+    {
+        schemaManager.loadAllEnabled();
+
+        assertTrue( schemaManager.isEnabled( "core" ) );
+        assertTrue( schemaManager.enable( "core" ) );
+        assertTrue( schemaManager.isEnabled( "core" ) );
+    }
+
+
+    /**
+     * Enable a disabled schema
+     */
+    @Test
+    public void testEnableDisabled() throws Exception
+    {
+        schemaManager.loadAllEnabled();
+
+        assertTrue( schemaManager.enable( "nis" ) );
+        assertTrue( schemaManager.enable( "rfc2307bis" ) );
+        assertTrue( schemaManager.isEnabled( "nis" ) );
+        assertTrue( schemaManager.isEnabled( "rfc2307bis" ) );
+
+        assertNotNull( schemaManager.lookupAttributeTypeRegistry( "gecos" ) );
+        assertNotNull( schemaManager.lookupAttributeTypeRegistry( "automountMapName" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 460, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 50, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 56, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 49, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 139, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 70, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 82, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 737, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 14, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "nis" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "rfc2307bis" ) );
+    }
+
+
+    /**
+     * Disable an enabled schema
+     */
+    @Test
+    public void testDisableEnabled() throws Exception
+    {
+        schemaManager.loadAllEnabled();
+
+        assertTrue( schemaManager.enable( "nis" ) );
+        assertTrue( schemaManager.isEnabled( "nis" ) );
+
+        assertEquals( 13, schemaManager.getRegistries().getLoadedSchemas().size() );
+
+        assertTrue( schemaManager.disable( "nis" ) );
+
+        try
+        {
+            schemaManager.lookupAttributeTypeRegistry( "gecos" );
+            fail();
+        }
+        catch ( LdapException ne )
+        {
+            // Expected
+        }
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 428, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 49, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 55, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 48, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 123, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 68, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 80, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 686, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 12, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "nis" ) );
+
+    }
+
+
+    @Test
+    public void testEnableNonExisting()
+    {
+
+    }
+
+
+    /**
+     * Enable multiple schemas, some are enabled, some are disabled, some are not existing
+     */
+    @Test
+    public void testEnableMultipleSchemas()
+    {
+
+    }
+
+
+    /**
+     * Enable a disabled schema, which depends on a disabled schema itself.
+     * Samba is disabled, and depends on nis which is also disabled. Enabling samba
+     * should enabled nis.
+     */
+    @Test
+    public void testEnableDisabledDependingOnDisabled() throws Exception
+    {
+        schemaManager.loadAllEnabled();
+
+        assertFalse( schemaManager.isEnabled( "samba" ) );
+        assertFalse( schemaManager.isEnabled( "nis" ) );
+
+        assertTrue( schemaManager.enable( "samba" ) );
+        assertTrue( schemaManager.isEnabled( "samba" ) );
+        assertTrue( schemaManager.isEnabled( "nis" ) );
+
+        assertNotNull( schemaManager.lookupAttributeTypeRegistry( "gecos" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 502, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 50, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 56, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 49, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 147, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 70, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 82, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 787, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 14, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "samba" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "nis" ) );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerLoadTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerLoadTest.java
new file mode 100644
index 0000000..8645d89
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerLoadTest.java
@@ -0,0 +1,805 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.registries.DefaultSchema;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+/**
+ * A test class for SchemaManager load() method. We test those methods here :
+ * 
+ *  Server API
+ *     boolean load( Schema... schemas ) throws Exception
+ *     boolean load( String... schemas ) throws Exception
+ *     boolean loadDisabled( Schema... schemas ) throws Exception
+ *     boolean loadDisabled( String... schemas ) throws Exception
+ *     boolean loadAllEnabled() throws Exception
+ *
+ *  Studio API :
+ *     boolean loadRelaxed( Schema... schemas ) throws Exception
+ *     boolean loadRelaxed( String... schemas ) throws Exception
+ *     boolean loadAllEnabledRelaxed() throws Exception
+ * 
+ * We check the resulting number of SchemaObjects in the registries. Those number are :
+ * 
+ * Apache :
+ *   AT :  53
+ *   C  :   8
+ *   MR :   8
+ *   N  :   8
+ *   OC :  17
+ *   SC :   3
+ *   S  :   7
+ *   OID:  85
+ * 
+ * ApacheDns :
+ *   AT :  16
+ *   OC :  11
+ *   OID:  27
+ * 
+ * ApacheMeta :
+ *   AT :  31
+ *   C  :   5
+ *   MR :   5
+ *   N  :   7
+ *   OC :  13
+ *   SC :   4
+ *   S  :   5
+ *   OID:  54
+ * 
+ * AutoFs :
+ *   AT :   1
+ *   OC :   2
+ *   OID:   3
+ * 
+ * Collective :
+ *   AT :  13
+ *   OID:  13
+ * 
+ * Corba :
+ *   AT :   2
+ *   OC :   3
+ *   OID:   5
+ * 
+ * Core :
+ *   AT :  54
+ *   OC :  27
+ *   OID:  81
+ * 
+ * Cosine :
+ *   AT :  41
+ *   OC :  13
+ *   OID:  54
+ * 
+ * Dhcp :
+ *   AT :  39
+ *   OC :  12
+ *   OID:  51
+ * 
+ * InetOrgPerson :
+ *   AT :   9
+ *   OC :   1
+ *   OID:  10
+ * 
+ * Java :
+ *   AT :   7
+ *   OC :   5
+ *   OID:  12
+ * 
+ * Krb5Kdc :
+ *   AT :  15
+ *   OC :   3
+ *   OID:  18
+ * 
+ * Mozilla :
+ *   AT :  17
+ *   OC :   1
+ *   OID:  18
+ * 
+ * Nis :
+ *   AT :  27
+ *   C  :   1
+ *   MR :   1
+ *   N  :   1
+ *   OC :  13
+ *   SC :   2
+ *   S  :   2
+ *   OID:  43
+ * 
+ * Other :
+ *   OID:   0
+ * 
+ * Samba :
+ *   AT :  37
+ *   OC :  11
+ *   OID:  48
+ * 
+ * System :
+ *   AT :  38
+ *   C  :  35
+ *   MR :  35
+ *   N  :  35
+ *   OC :   9
+ *   SC :  59
+ *   S  :  59
+ *   OID: 141
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+//@RunWith(ConcurrentJunitRunner.class)
+//@Concurrency()
+public class SchemaManagerLoadTest
+{
+    // A directory in which the ldif files will be stored
+    private static String workingDirectory;
+
+    // The schema repository
+    private static File schemaRepository;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = SchemaManagerLoadTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        // Make sure every test class has its own schema directory
+        workingDirectory = new File( workingDirectory, "SchemaManagerLoadTest" ).getAbsolutePath();
+
+        schemaRepository = new File( workingDirectory, "schema" );
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository );
+
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy();
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository.getParentFile() );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Test the load( String... schemaName) method
+    //-------------------------------------------------------------------------
+    /**
+     * test loading the "system" schema
+     */
+    @Test
+    public void testLoadSystem() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 38, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 35, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 35, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 9, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 59, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 141, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 1, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+    }
+
+
+    /**
+     * test loading the "core" schema, which depends on "system"
+     */
+    @Test
+    public void testLoadCore() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        // Check that we can't load a schema without its dependencies
+        assertFalse( schemaManager.load( "core" ) );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 92, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 36, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 236, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 2, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+    }
+
+
+    /**
+     * test loading the "apache" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadApache() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "apache" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 146, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 44, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 50, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 43, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 53, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 62, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 73, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 322, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "apache" ) );
+    }
+
+
+    /**
+     * test loading the "apacheMeta" schema, which depends on "system"
+     */
+    @Test
+    public void testLoadApacheMeta() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "apacheMeta" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 71, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 40, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 40, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 40, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 22, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 63, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 64, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 197, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 2, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "apachemeta" ) );
+    }
+
+
+    /**
+     * test loading the "java" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadJava() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "Java" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 99, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 41, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 248, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "Java" ) );
+    }
+
+
+    /**
+     * test loading the "other" schema, which depends on "system", "core",
+     * "apache" and "apacheMeta". As we don't have any cross dependencies
+     * with any of this other schemas, we can only load core and system
+     */
+    @Test
+    public void testLoadOther() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "other" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 92, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 36, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 236, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "other" ) );
+    }
+
+
+    /**
+     * test loading the "cosine" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadCosine() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "cosine" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 133, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 49, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 290, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson" schema, which depends on "system", "core"
+     * and "cosine"
+     */
+    @Test
+    public void testLoadInetOrgPerson() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "cosine" ) );
+        assertTrue( schemaManager.load( "InetOrgPerson" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 142, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 50, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 300, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 4, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    /**
+     * test loading the "Collective" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadCollective() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "Collective" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 105, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 36, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 249, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "collective" ) );
+    }
+
+
+    /**
+     * test loading the "Krb5Kdc" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadKrb5Kdc() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "Krb5Kdc" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 107, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 39, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 254, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "Krb5Kdc" ) );
+    }
+
+
+    /**
+     * test loading the "nis" schema, which depends on "system", "core" and "cosine",
+     * but is disabled
+     */
+    @Test
+    public void testLoadNis() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core" ) );
+        assertTrue( schemaManager.load( "cosine" ) );
+        assertFalse( schemaManager.load( "nis" ) );
+
+        AttributeType at = schemaManager.getAttributeType( "uidNumber" );
+        // if nis schema was loaded then the at will not be null
+        assertNull( at );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 133, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 49, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 290, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "nis" ) );
+    }
+
+
+    /**
+     * Test loading a wrong schema
+     */
+    @Test
+    public void testLoadWrongSchema() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        try
+        {
+            schemaManager.loadWithDeps( "bad" );
+            fail();
+        }
+        catch ( LdapUnwillingToPerformException lonse )
+        {
+            // expected
+        }
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 38, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 35, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 35, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 9, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 59, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 141, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 1, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "bad" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson" and "core" schema, which depends on "system" and "cosine"
+     */
+    @Test
+    public void testLoadCoreAndInetOrgPerson() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+        assertTrue( schemaManager.load( "core", "cosine", "InetOrgPerson" ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 142, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 50, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 300, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 4, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson", "core" and a bad schema
+     */
+    @Test
+    public void testLoadCoreInetOrgPersonAndBad() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+
+        try
+        {
+            assertFalse( schemaManager.load( "core", "bad", "cosine", "InetOrgPerson" ) );
+            fail();
+        }
+        catch ( LdapUnwillingToPerformException lonse )
+        {
+            // expected
+        }
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 38, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 35, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 35, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 9, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 59, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 141, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 1, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson", "core" and a disabled schema
+     */
+    @Ignore("ignoring for the moment to let the other tests run on CI")
+    @Test
+    public void testLoadCoreInetOrgPersonAndNis() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.load( "system" ) );
+
+        // Try to load a disabled schema when the registries does
+        // ot allow disabled schema to be loaded
+        assertFalse( schemaManager.load( "core", "nis", "cosine", "InetOrgPerson" ) );
+
+        assertFalse( schemaManager.getErrors().isEmpty() );
+        assertEquals( 38, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 35, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 35, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 9, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 59, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 141, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 1, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "nis" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    //---------------------------------------------------------------------------
+    // Test the load( Schema... ) method
+    //---------------------------------------------------------------------------
+    /**
+     * test loading the "InetOrgPerson", "core" and an empty schema. The empty schema
+     * should be present in the registries, as it's a vaid schema
+     */
+    @Test
+    public void testLoadSchemasWithDepsCoreInetOrgPersonAndBad() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        Schema system = loader.getSchema( "system" );
+        Schema core = loader.getSchema( "core" );
+        Schema empty = new DefaultSchema( "empty" );
+        Schema cosine = loader.getSchema( "cosine" );
+        Schema inetOrgPerson = loader.getSchema( "InetOrgPerson" );
+
+        assertTrue( schemaManager.load( system, core, empty, cosine, inetOrgPerson ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 142, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 50, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 300, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 5, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "empty" ) );
+    }
+
+
+    /**
+     * Test that we can load a new schema
+     */
+    @Test
+    public void loadNewSchema() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        Schema dummy = new DefaultSchema( "dummy" );
+
+        assertTrue( schemaManager.load( dummy ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 0, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 0, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 0, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 0, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 0, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 0, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 0, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 0, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 1, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "dummy" ) );
+    }
+
+
+    /**
+     * Test that we can't load a new schema with bad dependencies
+     */
+    @Test
+    public void loadNewSchemaBadDependencies() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        Schema dummy = new DefaultSchema( "dummy" );
+        dummy.addDependencies( "bad" );
+
+        assertFalse( schemaManager.load( dummy ) );
+
+        assertFalse( schemaManager.getErrors().isEmpty() );
+        assertEquals( 0, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 0, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 0, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 0, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 0, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 0, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 0, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 0, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 0, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "dummy" ) );
+    }
+
+
+    @Ignore("loadDisabled() method need to be fixed")
+    @Test
+    public void testLoadDisabled() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        assertTrue( schemaManager.loadDisabled( "nis" ) );
+
+        assertFalse( schemaManager.getErrors().isEmpty() );
+
+        AttributeType at = schemaManager.getAttributeType( "uidNumber" );
+        // if nis schema was loaded then the at will not be null
+        assertNotNull( at );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerLoadWithDepsTest.java b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerLoadWithDepsTest.java
new file mode 100644
index 0000000..01f0c23
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/java/org/apache/directory/api/ldap/schema/loader/SchemaManagerLoadWithDepsTest.java
@@ -0,0 +1,610 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.ldap.schema.loader;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.registries.DefaultSchema;
+import org.apache.directory.api.ldap.model.schema.registries.Schema;
+import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
+import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test class for SchemaManager loadWithDeps() method. We test those methods here :
+ * 
+ *  Server API
+ *     boolean loadWithDeps( Schema... schemas ) throws Exception
+ *     boolean loadWithDeps( String... schemas ) throws Exception
+ *
+ *  Studio API :
+ *     boolean loadWithDepsRelaxed( Schema... schemas ) throws Exception
+ *     boolean loadWithDepsRelaxed( String... schemas ) throws Exception
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class SchemaManagerLoadWithDepsTest
+{
+    // A directory in which the ldif files will be stored
+    private static String workingDirectory;
+
+    // The schema repository
+    private static File schemaRepository;
+
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        workingDirectory = System.getProperty( "workingDirectory" );
+
+        if ( workingDirectory == null )
+        {
+            String path = SchemaManagerLoadWithDepsTest.class.getResource( "" ).getPath();
+            int targetPos = path.indexOf( "target" );
+            workingDirectory = path.substring( 0, targetPos + 6 );
+        }
+
+        // Make sure every test class has its own schema directory
+        workingDirectory = new File( workingDirectory, "SchemaManagerLoadWithDepsTest" ).getAbsolutePath();
+
+        schemaRepository = new File( workingDirectory, "schema" );
+
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository );
+
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( new File( workingDirectory ) );
+        extractor.extractOrCopy();
+    }
+
+
+    @AfterClass
+    public static void cleanup() throws IOException
+    {
+        // Cleanup the target directory
+        FileUtils.deleteDirectory( schemaRepository.getParentFile() );
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Test the load( String... schemaName) method
+    //-------------------------------------------------------------------------
+    /**
+     * test loading the "system" schema
+     */
+    @Test
+    public void testLoadSystem() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "system" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 38, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 35, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 35, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 9, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 59, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 141, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 1, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+    }
+
+
+    /**
+     * test loading the "core" schema, which depends on "system"
+     */
+    @Test
+    public void testLoadCore() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "core" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 92, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 36, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 236, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 2, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+    }
+
+
+    /**
+     * test loading the "apache" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadApache() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "apache" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 146, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 44, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 50, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 43, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 53, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 62, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 73, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 322, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "apache" ) );
+    }
+
+
+    /**
+     * test loading the "apacheMeta" schema, which depends on "system"
+     */
+    @Test
+    public void testLoadApacheMeta() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "apacheMeta" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 71, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 40, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 40, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 40, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 22, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 63, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 64, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 197, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 2, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "apachemeta" ) );
+    }
+
+
+    /**
+     * test loading the "java" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadJava() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "Java" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 99, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 41, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 248, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "Java" ) );
+    }
+
+
+    /**
+     * test loading the "other" schema, which depends on "system", "core",
+     * "apache" and "apacheMeta"
+     */
+    @Test
+    public void testLoadOther() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "other" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 179, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 49, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 55, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 48, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 66, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 66, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 78, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 378, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 5, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "apache" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "apacheMeta" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "other" ) );
+    }
+
+
+    /**
+     * test loading the "cosine" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadCosine() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "cosine" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 133, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 49, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 290, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson" schema, which depends on "system", "core"
+     * and "cosine"
+     */
+    @Test
+    public void testLoadInetOrgPerson() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "InetOrgPerson" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 142, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 50, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 300, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 4, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    /**
+     * test loading the "Collective" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadCollective() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "Collective" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 105, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 36, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 249, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "collective" ) );
+    }
+
+
+    /**
+     * test loading the "Krb5Kdc" schema, which depends on "system" and "core"
+     */
+    @Test
+    public void testLoadKrb5Kdc() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "Krb5Kdc" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 107, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 39, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 254, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 3, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "Krb5Kdc" ) );
+    }
+
+
+    /**
+     * test loading the "nis" schema, which depends on "system", "core" and "cosine",
+     * but is disabled
+     */
+    @Test
+    public void testLoadNis() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "nis" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 0, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 0, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 0, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 0, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 0, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 0, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 0, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 0, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 0, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+    }
+
+
+    /**
+     * test loading the "rfc2307bis" schema, which depends on "system", "nis" and "core",
+     * but is disabled
+     */
+    @Test
+    public void testLoadRfc2307Bis() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "rfc2307bis" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 0, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 0, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 0, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 0, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 0, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 0, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 0, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 0, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 0, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "nis" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+    }
+
+
+    /**
+     * Test loading a wrong schema
+     */
+    @Test
+    public void testLoadWrongSchema() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        try
+        {
+            schemaManager.loadWithDeps( "bad" );
+            fail();
+        }
+        catch ( LdapUnwillingToPerformException lonse )
+        {
+            // expected
+        }
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 0, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 0, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 0, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 0, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 0, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 0, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 0, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 0, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 0, schemaManager.getRegistries().getLoadedSchemas().size() );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson" and "core" schema, which depends on "system" and "cosine"
+     */
+    @Test
+    public void testLoadCoreAndInetOrgPerson() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "core", "InetOrgPerson" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 142, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 50, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 300, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 4, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson", "core" and a bad schema
+     */
+    @Test
+    public void testLoadCoreInetOrgPersonAndBad() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        try
+        {
+            schemaManager.loadWithDeps( "core", "bad", "InetOrgPerson" );
+            fail();
+        }
+        catch ( LdapUnwillingToPerformException lonse )
+        {
+            // expected
+        }
+
+        // No SchemaObject should be loaded as we had an error
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 0, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 0, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 0, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 0, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 0, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 0, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 0, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 0, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 0, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson", "core" and a disabled schema
+     */
+    @Test
+    public void testLoadCoreInetOrgPersonAndNis() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        schemaManager.loadWithDeps( "core", "nis", "InetOrgPerson" );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 142, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 50, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 300, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 4, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+
+
+    /**
+     * test loading the "InetOrgPerson", "core" and a disabled schema
+     */
+    @Test
+    public void testLoadWithDepsCoreInetOrgPersonAndNis() throws Exception
+    {
+        LdifSchemaLoader loader = new LdifSchemaLoader( schemaRepository );
+        SchemaManager schemaManager = new DefaultSchemaManager( loader );
+
+        Schema system = loader.getSchema( "system" );
+        Schema core = loader.getSchema( "core" );
+        Schema empty = new DefaultSchema( "empty" );
+        Schema cosine = loader.getSchema( "cosine" );
+        Schema inetOrgPerson = loader.getSchema( "InetOrgPerson" );
+
+        assertTrue( schemaManager.load( system, core, empty, cosine, inetOrgPerson ) );
+
+        assertTrue( schemaManager.getErrors().isEmpty() );
+        assertEquals( 142, schemaManager.getAttributeTypeRegistry().size() );
+        assertEquals( 36, schemaManager.getComparatorRegistry().size() );
+        assertEquals( 42, schemaManager.getMatchingRuleRegistry().size() );
+        assertEquals( 35, schemaManager.getNormalizerRegistry().size() );
+        assertEquals( 50, schemaManager.getObjectClassRegistry().size() );
+        assertEquals( 59, schemaManager.getSyntaxCheckerRegistry().size() );
+        assertEquals( 66, schemaManager.getLdapSyntaxRegistry().size() );
+        assertEquals( 300, schemaManager.getGlobalOidRegistry().size() );
+
+        assertEquals( 5, schemaManager.getRegistries().getLoadedSchemas().size() );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "system" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "core" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "cosine" ) );
+        assertNotNull( schemaManager.getRegistries().getLoadedSchema( "InetOrgPerson" ) );
+    }
+}
diff --git a/trunk/ldap/schema/data/src/test/resources/log4j.properties b/trunk/ldap/schema/data/src/test/resources/log4j.properties
new file mode 100644
index 0000000..c3be193
--- /dev/null
+++ b/trunk/ldap/schema/data/src/test/resources/log4j.properties
@@ -0,0 +1,22 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+
diff --git a/trunk/ldap/schema/pom.xml b/trunk/ldap/schema/pom.xml
new file mode 100644
index 0000000..35e33b3
--- /dev/null
+++ b/trunk/ldap/schema/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<!-- $Rev:  $ $Date:  $ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-ldap-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-ldap-schema-parent</artifactId>
+  <name>Apache Directory LDAP API Schema Parent</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>data</module>
+    <module>converter</module>
+  </modules>
+
+</project>
diff --git a/trunk/ldap/src/site/site.xml b/trunk/ldap/src/site/site.xml
new file mode 100644
index 0000000..b6ec180
--- /dev/null
+++ b/trunk/ldap/src/site/site.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="modules" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/pom.xml b/trunk/pom.xml
new file mode 100644
index 0000000..c70bec9
--- /dev/null
+++ b/trunk/pom.xml
@@ -0,0 +1,783 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.project</groupId>
+    <artifactId>project</artifactId>
+    <version>35</version>
+    <relativePath />
+  </parent>
+
+  <groupId>org.apache.directory.api</groupId>
+  <artifactId>api-parent</artifactId>
+  <name>Apache Directory LDAP API</name>
+  <packaging>pom</packaging>
+  <version>1.0.0-M32</version>
+
+  <properties>
+    <additionalparam>-Xdoclint:none</additionalparam>
+    <projectName>ApacheDS-LDAP-API</projectName>
+    <distMgmtSiteUrl>scpexe://people.apache.org/www/directory.apache.org/api/gen-docs/${project.version}/</distMgmtSiteUrl>
+    
+    <!-- Set versions for depending projects -->
+    <skin.version>1.0.2</skin.version>
+    <org.apache.directory.junit.junit-addons.version>0.1</org.apache.directory.junit.junit-addons.version>
+    <org.apache.directory.checkstyle-configuration.version>0.2</org.apache.directory.checkstyle-configuration.version>
+    
+    <!-- Set versions for depending jars -->
+    <antlr.version>2.7.7</antlr.version>
+    <commons.collections.version>3.2.1</commons.collections.version>
+    <commons.io.version>2.4</commons.io.version>
+    <commons.lang.version>2.6</commons.lang.version>
+    <commons.pool.version>1.6</commons.pool.version>
+    <dom4j.version>1.6.1</dom4j.version>
+    <junit.version>4.12</junit.version>
+    <log4j.version>1.2.17</log4j.version>
+    <mina.core.version>2.0.9</mina.core.version>
+    <org.osgi.core.version>6.0.0</org.osgi.core.version>
+    <org.apache.felix.version>4.4.1</org.apache.felix.version>
+    <slf4j.api.version>1.7.10</slf4j.api.version>
+    <slf4j.api.bundleversion>"$«range;[==,=+)»"</slf4j.api.bundleversion>
+    <slf4j.log4j12.version>1.7.10</slf4j.log4j12.version>
+    <xml.apis.version>2.0.2</xml.apis.version>
+    <xpp3.version>1.1.4c</xpp3.version>
+    <pax-exam.version>4.4.0</pax-exam.version>
+    <pax-url.version>2.3.0</pax-url.version>
+    <logback.version>1.1.2</logback.version>
+    <findbugs.annotations.version>1.0.0</findbugs.annotations.version>
+  </properties>
+  
+  <distributionManagement>
+    <site>
+      <id>apache.directory.shared</id>
+      <url>${distMgmtSiteUrl}</url>
+    </site>
+  </distributionManagement>
+
+  <issueManagement>
+    <system>JIRA</system>
+    <url>http://issues.apache.org/jira/browse/DIRAPI</url>
+  </issueManagement>
+
+  <modules>
+    <module>i18n</module>
+    <module>util</module>
+    <module>asn1</module>
+    <module>all</module>
+    <module>ldap</module>
+    <module>dsml</module>
+    <module>integ</module>
+    <module>integ-osgi</module>
+    <module>distribution</module>
+  </modules>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-release-plugin</artifactId>
+          <configuration>
+            <tagNameFormat>@{project.version}</tagNameFormat>
+          </configuration>
+        </plugin>
+
+        <plugin>
+          <groupId>org.apache.rat</groupId>
+          <artifactId>apache-rat-plugin</artifactId>
+          <configuration>
+            <excludeSubProjects>false</excludeSubProjects>
+            <excludes>
+              <!-- MAVEN_DEFAULT_EXCLUDES -->
+              <exclude>**/target/**/*</exclude>
+              <exclude>**/cobertura.ser</exclude>
+              <!-- ECLIPSE_DEFAULT_EXCLUDES -->
+              <exclude>**/.classpath</exclude>
+              <exclude>**/.project</exclude>
+              <exclude>**/.settings/**/*</exclude>
+              <!-- IDEA_DEFAULT_EXCLUDES -->
+              <exclude>**/*.iml</exclude>
+              <exclude>**/*.ipr</exclude>
+              <exclude>**/*.iws</exclude>
+              <!-- MANIFEST_MF_EXCLUDES -->
+              <exclude>**/MANIFEST.MF</exclude>
+              <!-- 3RD_PARTY_LICENSES -->
+              <exclude>distribution/src/main/release/licenses/*</exclude>
+              <exclude>src/main/release/licenses/*</exclude>
+              <!-- Missing license header in dependency reduced pom, see http://jira.codehaus.org/browse/MSHADE-48 -->
+              <exclude>**/dependency-reduced-pom.xml</exclude>
+              <!-- Generated ldif files -->
+              <exclude>ldap/schema/data/src/main/resources/schema/**</exclude>
+              <exclude>ldap/schema/data/src/main/resources/schema-all.ldif</exclude>
+              <exclude>schema/data/src/main/resources/schema/**</exclude>
+              <exclude>schema/data/src/main/resources/schema-all.ldif</exclude>
+              <exclude>data/src/main/resources/schema/**</exclude>
+              <exclude>data/src/main/resources/schema-all.ldif</exclude>
+              <exclude>src/main/resources/schema/**</exclude>
+              <exclude>src/main/resources/schema-all.ldif</exclude>
+            </excludes>
+          </configuration>
+        </plugin>
+
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-checkstyle-plugin</artifactId>
+          <configuration>
+            <failOnViolation>true</failOnViolation>
+            <includeTestSourceDirectory>false</includeTestSourceDirectory>
+          </configuration>
+          <executions>
+            <execution>
+              <id>validate</id>
+              <phase>validate</phase>
+              <goals>
+                <goal>check</goal>
+              </goals>
+            </execution>
+          </executions>
+        </plugin>
+
+        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-antrun-plugin</artifactId>
+                    <versionRange>[1.7,)</versionRange>
+                    <goals>
+                      <goal>run</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+                
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <versionRange>[2.2,)</versionRange>
+                    <goals>
+                      <goal>copy</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+                
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>antlr-maven-plugin</artifactId>
+                    <versionRange>[2.7.7,)</versionRange>
+                    <goals>
+                      <goal>generate</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+                <pluginExecution>
+                    <pluginExecutionFilter>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-checkstyle-plugin</artifactId>
+                        <versionRange>[2.16,)</versionRange>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </pluginExecutionFilter>
+                    <action>
+                        <ignore />
+                    </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-site-plugin</artifactId>
+        <dependencies>
+          <!-- Add support for 'scp'/'sftp' -->
+          <dependency>
+            <groupId>org.apache.maven.wagon</groupId>
+            <artifactId>wagon-ssh</artifactId>
+            <version>2.1</version>
+          </dependency>
+          <!-- Add support for 'scpexe' -->
+          <dependency>
+            <groupId>org.apache.maven.wagon</groupId>
+            <artifactId>wagon-ssh-external</artifactId>
+            <version>2.1</version>
+          </dependency>
+        </dependencies>
+        <configuration>
+          <reportPlugins>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-jxr-plugin</artifactId>
+              <configuration>
+                  <aggregate>true</aggregate>
+              </configuration>
+            </plugin>
+       
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-surefire-report-plugin</artifactId>
+              <configuration>
+                <aggregate>true</aggregate>
+              </configuration>
+            </plugin>
+      
+            <!-- plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-pmd-plugin</artifactId>
+              <configuration>
+                <linkXref>true</linkXref>
+                <sourceEncoding>utf-8</sourceEncoding>
+                <minimumTokens>100</minimumTokens>
+                <targetJdk>1.7</targetJdk>
+                <aggregate>true</aggregate>
+              </configuration>
+            </plugin -->
+      
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-project-info-reports-plugin</artifactId>
+            </plugin>
+      
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>taglist-maven-plugin</artifactId>
+              <configuration>
+                <tags>
+                  <tag>TODO</tag>
+                  <tag>@todo</tag>
+                  <tag>@deprecated</tag>
+                  <tag>FIXME</tag>
+                </tags>
+              </configuration>
+            </plugin>
+      
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-javadoc-plugin</artifactId>
+              <configuration>
+                <minmemory>512m</minmemory>
+                <maxmemory>1g</maxmemory>
+                <linksource>true</linksource>
+                <tags>
+                  <tag>
+                    <name>todo</name>
+                    <!-- todo tag for all places -->
+                    <placement>a</placement>
+                    <head>To do:</head>
+                  </tag>
+                </tags>
+                <source>1.7</source>
+              </configuration>
+              <reportSets>
+                <reportSet>
+                  <reports>
+                    <report>aggregate</report>
+                    <report>test-aggregate</report>
+                  </reports>
+                </reportSet>
+              </reportSets>
+            </plugin>
+      
+<!-- Disabled because of Hudson problems, see http://jira.codehaus.org/browse/MFINDBUGS-126
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>findbugs-maven-plugin</artifactId>
+              <configuration>
+                <xrefLocation>${project.reporting.outputDirectory}/../xref</xrefLocation>
+                <xrefTestLocation>${project.reporting.outputDirectory}/../xref-test</xrefTestLocation>
+                <! - - required by dashboard plugin and hudson - - >
+                <xmlOutput>true</xmlOutput>
+                <effort>Max</effort>
+                <findbugsXmlOutput>true</findbugsXmlOutput>
+                <findbugsXmlWithMessages>true</findbugsXmlWithMessages>
+              </configuration>
+            </plugin>
+-->
+      
+<!-- Disabled because of Hudson problems
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>cobertura-maven-plugin</artifactId>
+              <configuration>
+                <instrumentation>
+                  <excludes>
+                    <exclude>org/apache/directory/api/**/*Constants.class</exclude>
+                  </excludes>
+                </instrumentation>
+              </configuration>
+            </plugin>
+-->
+      
+            <!-- plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-checkstyle-plugin</artifactId>
+              <configuration>
+                <configLocation>directory-checks.xml</configLocation>
+                <suppressionsLocation>${basedir}/src/checkstyle/suppressions.xml</suppressionsLocation>
+                <suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
+                <xrefLocation>${project.reporting.outputDirectory}/../xref</xrefLocation>
+              </configuration>
+            </plugin -->
+      
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>versions-maven-plugin</artifactId>
+              <reportSets>
+                <reportSet>
+                  <reports>
+                    <report>dependency-updates-report</report>
+                    <report>plugin-updates-report</report>
+                    <report>property-updates-report</report>
+                  </reports>
+                </reportSet>
+              </reportSets>
+            </plugin>
+      
+            <plugin>
+              <groupId>org.apache.rat</groupId>
+              <artifactId>apache-rat-plugin</artifactId>
+              <!-- must add configuration here too, it isn't inherited from <pluginConfiguration> :-( -->
+              <configuration>
+                <excludeSubProjects>false</excludeSubProjects>
+                <excludes>
+                  <!-- MAVEN_DEFAULT_EXCLUDES -->
+                  <exclude>**/target/**/*</exclude>
+                  <exclude>**/cobertura.ser</exclude>
+                  <!-- ECLIPSE_DEFAULT_EXCLUDES -->
+                  <exclude>**/.classpath</exclude>
+                  <exclude>**/.project</exclude>
+                  <exclude>**/.settings/**/*</exclude>
+                  <!-- IDEA_DEFAULT_EXCLUDES -->
+                  <exclude>**/*.iml</exclude>
+                  <exclude>**/*.ipr</exclude>
+                  <exclude>**/*.iws</exclude>
+                  <!-- MANIFEST_MF_EXCLUDES -->
+                  <exclude>**/MANIFEST.MF</exclude>
+                  <!-- 3RD_PARTY_LICENSES -->
+                  <exclude>distribution/src/main/release/licenses/*</exclude>
+                  <exclude>src/main/release/licenses/*</exclude>
+                  <!-- Missing license header in dependency reduced pom, see http://jira.codehaus.org/browse/MSHADE-48 -->
+                  <exclude>**/dependency-reduced-pom.xml</exclude>
+                  <!-- Generated ldif files -->
+                  <exclude>**/src/main/resources/schema/**/*.ldif</exclude>
+                  <exclude>**/src/main/resources/schema-all.ldif</exclude>
+                  <exclude>**/src/main/resources/schema/**/*.ldif</exclude>
+                  <exclude>**/src/main/resources/schema-all.ldif</exclude>
+                  <!-- Files having a Bouncy Castle license -->
+                  <exclude>ldap/src/main/java/org/apache/directory/api/asn1/der/*.java</exclude>
+                  <exclude>src/main/java/org/apache/directory/api/asn1/der/*.java</exclude>
+                </excludes>
+              </configuration>
+            </plugin>
+      
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>javancss-maven-plugin</artifactId>
+            </plugin>
+      
+            <plugin>
+              <groupId>org.codehaus.mojo</groupId>
+              <artifactId>jdepend-maven-plugin</artifactId>
+            </plugin>
+      
+<!--
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-changes-plugin</artifactId>
+              <configuration>
+                <onlyCurrentVersion>true</onlyCurrentVersion>
+                <resolutionIds>Fixed</resolutionIds>
+                <statusIds>Resolved,Closed</statusIds>
+                <columnNames>Type,Key,Summary,Status,Resolution,Fix Version</columnNames>
+              </configuration>
+              <reportSets>
+                <reportSet>
+                  <reports>
+                    <report>jira-report</report>
+                  </reports>
+                </reportSet>
+              </reportSets>
+            </plugin>
+-->
+          </reportPlugins>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencyManagement>
+    <dependencies>
+      <!-- Project sub-modules dependencies -->
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-all</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-asn1-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-asn1-ber</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-dsml-engine</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-dsml-parser</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-i18n</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-client-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-codec-core</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-codec-standalone</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-extras-aci</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-extras-codec</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-extras-codec-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-extras-sp</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-extras-trigger</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-extras-util</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-model</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-net-mina</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-schema-converter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-ldap-schema-data</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>api-util</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <!-- Mina dependencies -->
+
+      <dependency>
+        <groupId>org.apache.mina</groupId>
+        <artifactId>mina-core</artifactId>
+        <version>${mina.core.version}</version>
+      </dependency>
+
+      <!-- Commons dependencies -->
+
+      <dependency>
+        <groupId>commons-collections</groupId>
+        <artifactId>commons-collections</artifactId>
+        <version>${commons.collections.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>commons-io</groupId>
+        <artifactId>commons-io</artifactId>
+        <version>${commons.io.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>commons-lang</groupId>
+        <artifactId>commons-lang</artifactId>
+        <version>${commons.lang.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>commons-pool</groupId>
+        <artifactId>commons-pool</artifactId>
+        <version>${commons.pool.version}</version>
+      </dependency>
+
+      <!-- OSGi and Felix Dependencies -->
+
+      <dependency>
+        <groupId>org.osgi</groupId>
+        <artifactId>org.osgi.core</artifactId>
+        <version>${org.osgi.core.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.framework</artifactId>
+        <version>${org.apache.felix.version}</version>
+      </dependency>
+
+      <!-- Test dependencies -->
+
+      <dependency>
+        <groupId>org.apache.directory.junit</groupId>
+        <artifactId>junit-addons</artifactId>
+        <version>${org.apache.directory.junit.junit-addons.version}</version>
+      </dependency>
+
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-container-forked</artifactId>
+          <version>${pax-exam.version}</version>
+      </dependency>
+
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-junit4</artifactId>
+          <version>${pax-exam.version}</version>
+      </dependency>
+
+      <dependency>
+          <groupId>org.ops4j.pax.exam</groupId>
+          <artifactId>pax-exam-link-mvn</artifactId>
+          <version>${pax-exam.version}</version>
+      </dependency>
+
+      <dependency>
+          <groupId>org.ops4j.pax.url</groupId>
+          <artifactId>pax-url-aether</artifactId>
+          <version>${pax-url.version}</version>
+      </dependency>
+
+      <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-classic</artifactId>
+          <version>${logback.version}</version>
+      </dependency>
+
+      <!-- Logging dependencies -->
+
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+        <version>${slf4j.api.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-log4j12</artifactId>
+        <version>${slf4j.log4j12.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>log4j</groupId>
+        <artifactId>log4j</artifactId>
+        <version>${log4j.version}</version>
+      </dependency>
+      
+      <!-- Other dependencies -->
+
+      <dependency>
+        <groupId>antlr</groupId>
+        <artifactId>antlr</artifactId>
+        <version>${antlr.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.servicemix.bundles</groupId>
+        <artifactId>org.apache.servicemix.bundles.antlr</artifactId>
+        <version>${antlr.version}_5</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.servicemix.bundles</groupId>
+        <artifactId>org.apache.servicemix.bundles.dom4j</artifactId>
+        <version>${dom4j.version}_5</version>
+      </dependency>
+
+      <dependency>
+        <groupId>org.apache.servicemix.bundles</groupId>
+        <artifactId>org.apache.servicemix.bundles.xpp3</artifactId>
+        <version>${xpp3.version}_6</version>
+      </dependency>
+
+      <dependency>
+        <groupId>findbugs</groupId>
+        <artifactId>annotations</artifactId>
+        <version>${findbugs.annotations.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>${junit.version}</version>
+      </dependency>
+      
+      <dependency>
+        <groupId>xml-apis</groupId>
+        <artifactId>xml-apis</artifactId>
+        <version>${xml.apis.version}</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies />
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/directory/shared/tags/1.0.0-M32</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/directory/shared/tags/1.0.0-M32</developerConnection>
+    <url>http://svn.apache.org/viewvc/directory/shared/tags/1.0.0-M32</url>
+  </scm>
+
+  <profiles>
+    <profile>
+      <id>apache-release</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-assembly-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>source-release-assembly</id>
+                <configuration>
+                  <!-- we have a dedicated distribution module -->
+                  <skipAssembly>true</skipAssembly>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.rat</groupId>
+            <artifactId>apache-rat-plugin</artifactId>
+            <executions>
+              <execution>
+                <phase>verify</phase>
+                <goals>
+                  <goal>check</goal>
+                </goals>
+              </execution>
+            </executions>
+         </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>
diff --git a/trunk/src/main/appended-resources/supplemental-models.xml b/trunk/src/main/appended-resources/supplemental-models.xml
new file mode 100644
index 0000000..be2d715
--- /dev/null
+++ b/trunk/src/main/appended-resources/supplemental-models.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<supplementalDataModels>
+  <supplement>
+    <project>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+      <name>ANTLR Parser Generator</name>
+      <organization>
+        <name>ANTLR</name>
+        <url>http://www.antlr.org/</url>
+      </organization>
+      <licenses>
+        <license>
+          <name>ANTLR 2 License (public domain)</name>
+          <url>http://www.antlr2.org/license.html</url>
+        </license>
+      </licenses>
+    </project>
+  </supplement>
+
+</supplementalDataModels>
diff --git a/trunk/src/site/resources/images/server-icon_128x128.png b/trunk/src/site/resources/images/server-icon_128x128.png
new file mode 100644
index 0000000..28670e7
--- /dev/null
+++ b/trunk/src/site/resources/images/server-icon_128x128.png
Binary files differ
diff --git a/trunk/src/site/site.xml b/trunk/src/site/site.xml
new file mode 100644
index 0000000..188d4a3
--- /dev/null
+++ b/trunk/src/site/site.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <bannerLeft>
+    <src>images/server-icon_128x128.png</src>
+    <href>http://directory.apache.org/</href>
+    <name>${project.name}</name>
+  </bannerLeft>
+  <skin>
+    <groupId>org.apache.directory.skins</groupId>
+    <artifactId>directory-api-skin</artifactId>
+    <version>${skin.version}</version>
+  </skin>
+  <publishDate position="navigation-bottom" format="dd-MM-yyyy HH:mm"/>
+  <version position="right"/>
+  <body>
+    <breadcrumbs>
+      <item name="Apache Directory Shared" href="http://vm094.oxylos.org/projects/shared/" />
+    </breadcrumbs>
+    <links>
+       <!--
+         Need to encode a part of the url due to Issue
+         http://jira.codehaus.org/browse/MSITE-159
+         and as of https://bugzilla.mozilla.org/show_bug.cgi?id=43659
+         this workaround doesn't works in FF 3.x ...
+        -->
+       <item name="Apache Directory" href="http://directory.apache%2eorg/"/>
+       <item name="Apache" href="http://www.apache%2eorg/"/>
+       <item name="Maven" href="http://maven.apache%2eorg/"/>
+    </links>
+    <menu ref="reports"/>
+    <menu ref="modules"/>
+  </body>
+</project>
diff --git a/trunk/util/pom.xml b/trunk/util/pom.xml
new file mode 100644
index 0000000..9b65ee5
--- /dev/null
+++ b/trunk/util/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.api</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-M32</version>
+  </parent>
+  
+  <artifactId>api-util</artifactId>
+  <name>Apache Directory LDAP API Utilities</name>
+  <packaging>bundle</packaging>
+
+  <description>Utilities shared across this top level project</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>api-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.util</Bundle-SymbolicName>
+            <Export-Package>
+              org.apache.directory.api.util;version=${project.version};-noimport:=true,
+              org.apache.directory.api.util.exception;version=${project.version};-noimport:=true
+            </Export-Package>
+            <Import-Package>
+              org.apache.directory.api.i18n;version=${project.version},
+              org.slf4j;version=${slf4j.api.bundleversion},
+              javax.naming,
+              javax.naming.directory,
+              javax.naming.ldap
+            </Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/util/src/checkstyle/suppressions.xml b/trunk/util/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..f7660f0
--- /dev/null
+++ b/trunk/util/src/checkstyle/suppressions.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+    <suppress files="org.apache.directory.api.util.Position" checks="VisibilityModifier" />
+    <suppress files="org.apache.directory.api.util.Strings" checks="FileLength" />
+    <suppress files="org.apache.directory.api.util.UnixCrypt" checks=".*" />
+</suppressions>
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/AbstractSimpleComponentsMonitor.java b/trunk/util/src/main/java/org/apache/directory/api/util/AbstractSimpleComponentsMonitor.java
new file mode 100644
index 0000000..d02df86
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/AbstractSimpleComponentsMonitor.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util;
+
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Abstract implementation of a components monitor.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractSimpleComponentsMonitor implements ComponentsMonitor
+{
+
+    /** The components. */
+    private List<String> components;
+
+
+    /**
+     * Instantiates a new abstract simple components monitor.
+     *
+     * @param components the components
+     */
+    public AbstractSimpleComponentsMonitor( String[] components )
+    {
+        // register components
+        this.components = new LinkedList<String>( Arrays.asList( components ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ComponentsMonitor useComponent( String component ) throws IllegalArgumentException
+    {
+        if ( !components.remove( component ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04336, component ) );
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean allComponentsUsed()
+    {
+        return components.isEmpty();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getRemainingComponents()
+    {
+        return Collections.unmodifiableList( components );
+    }
+
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/Base64.java b/trunk/util/src/main/java/org/apache/directory/api/util/Base64.java
new file mode 100644
index 0000000..ac2af7d
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/Base64.java
@@ -0,0 +1,218 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Encoding and decoding of Base64 characters to and from raw bytes.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Base64
+{
+
+    /**
+     * Private constructor.
+     */
+    private Base64()
+    {
+    }
+
+
+    /**
+     * Encodes binary data to a Base64 encoded characters.
+     * 
+     * @param data
+     *            the array of bytes to encode
+     * @return base64-coded character array.
+     */
+    public static char[] encode( byte[] data )
+    {
+        char[] out = new char[( ( data.length + 2 ) / 3 ) * 4];
+
+        //
+        // 3 bytes encode to 4 chars. Output is always an even
+        // multiple of 4 characters.
+        //
+        for ( int ii = 0, index = 0; ii < data.length; ii += 3, index += 4 )
+        {
+            boolean isQuadrupel = false;
+            boolean isTripel = false;
+
+            int val = ( 0xFF & data[ii] );
+            val <<= 8;
+            if ( ( ii + 1 ) < data.length )
+            {
+                val |= ( 0xFF & data[ii + 1] );
+                isTripel = true;
+            }
+
+            val <<= 8;
+            if ( ( ii + 2 ) < data.length )
+            {
+                val |= ( 0xFF & data[ii + 2] );
+                isQuadrupel = true;
+            }
+
+            out[index + 3] = ALPHABET[( isQuadrupel ? ( val & 0x3F ) : 64 )];
+            val >>= 6;
+            out[index + 2] = ALPHABET[( isTripel ? ( val & 0x3F ) : 64 )];
+            val >>= 6;
+            out[index + 1] = ALPHABET[val & 0x3F];
+            val >>= 6;
+            out[index + 0] = ALPHABET[val & 0x3F];
+        }
+        return out;
+    }
+
+
+    /**
+     * Decodes a BASE-64 encoded stream to recover the original data. White
+     * space before and after will be trimmed away, but no other manipulation of
+     * the input will be performed. As of version 1.2 this method will properly
+     * handle input containing junk characters (newlines and the like) rather
+     * than throwing an error. It does this by pre-parsing the input and
+     * generating from that a count of VALID input characters.
+     * 
+     * @param data
+     *            data to decode.
+     * @return the decoded binary data.
+     */
+    public static byte[] decode( char[] data )
+    {
+        // as our input could contain non-BASE64 data (newlines,
+        // whitespace of any sort, whatever) we must first adjust
+        // our count of USABLE data so that...
+        // (a) we don't misallocate the output array, and
+        // (b) think that we miscalculated our data length
+        // just because of extraneous throw-away junk
+
+        int tempLen = data.length;
+
+        for ( char c : data )
+        {
+            if ( ( c > 255 ) || CODES[c] < 0 )
+            {
+                // ignore non-valid chars and padding
+                --tempLen;
+            }
+        }
+        // calculate required length:
+        // -- 3 bytes for every 4 valid base64 chars
+        // -- plus 2 bytes if there are 3 extra base64 chars,
+        // or plus 1 byte if there are 2 extra.
+
+        int len = ( tempLen / 4 ) * 3;
+
+        if ( ( tempLen % 4 ) == 3 )
+        {
+            len += 2;
+        }
+
+        if ( ( tempLen % 4 ) == 2 )
+        {
+            len += 1;
+        }
+
+        byte[] out = new byte[len];
+
+        // # of excess bits stored in accum excess bits
+        int shift = 0;
+        int accum = 0;
+        int index = 0;
+
+        // we now go through the entire array (NOT using the 'tempLen' value)
+        for ( char c : data )
+        {
+            int value = ( c > 255 ) ? -1 : CODES[c];
+
+            // skip over non-code bits 
+            if ( value >= 0 )
+            {
+                // shift up by 6 each time thru
+                // loop, with new bits being put in
+                // at the bottom. whenever there
+                // are 8 or more shifted in, write them
+                // out (from the top, leaving any excess
+                // at the bottom for next iteration.
+                accum <<= 6;
+                shift += 6;
+                accum |= value;
+
+                if ( shift >= 8 )
+                {
+                    shift -= 8;
+                    out[index++] = ( byte ) ( ( accum >> shift ) & 0xff );
+                }
+            }
+            // we will also have skipped processing a padding null byte ('=') here;
+            // these are used ONLY for padding to an even length and do not legally
+            // occur as encoded data. for this reason we can ignore the fact
+            // that no index++ operation occurs in that special case: the out[] array
+            // is initialized to all-zero bytes to start with and that works to our
+            // advantage in this combination.
+        }
+
+        // if there is STILL something wrong we just have to throw up now!
+        if ( index != out.length )
+        {
+            throw new Error( I18n.err( I18n.ERR_04348, index, out.length ) );
+        }
+
+        return out;
+    }
+
+    /** code characters for values 0..63 */
+    private static final char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+        .toCharArray();
+
+    /** lookup table for converting base64 characters to value in range 0..63 */
+    private static final byte[] CODES = new byte[256];
+
+    static
+    {
+        for ( int ii = 0; ii < 256; ii++ )
+        {
+            CODES[ii] = -1;
+        }
+
+        for ( int ii = 'A'; ii <= 'Z'; ii++ )
+        {
+            CODES[ii] = ( byte ) ( ii - 'A' );
+        }
+
+        for ( int ii = 'a'; ii <= 'z'; ii++ )
+        {
+            CODES[ii] = ( byte ) ( 26 + ii - 'a' );
+        }
+
+        for ( int ii = '0'; ii <= '9'; ii++ )
+        {
+            CODES[ii] = ( byte ) ( 52 + ii - '0' );
+        }
+
+        CODES['+'] = 62;
+        CODES['/'] = 63;
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/ByteBuffer.java b/trunk/util/src/main/java/org/apache/directory/api/util/ByteBuffer.java
new file mode 100644
index 0000000..4d8db17
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/ByteBuffer.java
@@ -0,0 +1,179 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A dynamically growing byte[]. 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ByteBuffer
+{
+    /** the default initial buffer size */
+    private static final int DEFAULT_INITIAL_SIZE = 10;
+
+    /** the initial size of the buffer in number of bytes: also increment for allocations */
+    private final int initialSize;
+
+    /** the position into the buffer */
+    private int pos = 0;
+
+    /** the bytes of the buffer */
+    private byte[] buf;
+
+
+    public ByteBuffer()
+    {
+        this( DEFAULT_INITIAL_SIZE );
+    }
+
+
+    public ByteBuffer( int initialSize )
+    {
+        if ( initialSize <= 0 )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04354 ) );
+        }
+
+        this.initialSize = initialSize;
+        this.buf = new byte[initialSize];
+    }
+
+
+    public final void clear()
+    {
+        pos = 0;
+    }
+
+
+    public final int position()
+    {
+        return pos;
+    }
+
+
+    public final int capacity()
+    {
+        return buf.length;
+    }
+
+
+    public final byte get( int i )
+    {
+        return buf[i];
+    }
+
+
+    /**
+     * Get's the bytes, the backing store for this buffer.  Note
+     * that you need to use the position index to determine where
+     * to stop reading from this buffer.
+     */
+    public final byte[] buffer()
+    {
+        return buf;
+    }
+
+
+    /**
+     * Get's a copy of the bytes used.
+     */
+    public final byte[] copyOfUsedBytes()
+    {
+        byte[] copy = new byte[pos];
+        System.arraycopy( buf, 0, copy, 0, pos );
+        return copy;
+    }
+
+
+    /**
+     * Appends the bytes to this buffer.
+     */
+    public final void append( byte[] bytes )
+    {
+        if ( pos + bytes.length > buf.length )
+        {
+            growBuffer( bytes.length );
+        }
+
+        System.arraycopy( bytes, 0, buf, pos, bytes.length );
+        pos += bytes.length;
+    }
+
+
+    /**
+     * Appends a byte to this buffer.
+     */
+    public final void append( byte b )
+    {
+        if ( pos >= buf.length )
+        {
+            growBuffer();
+        }
+
+        buf[pos] = b;
+        pos++;
+    }
+
+
+    /**
+     * Appends an int to this buffer.  WARNING: the int is truncated to 
+     * a byte value.
+     */
+    public final void append( int val )
+    {
+        if ( pos >= buf.length )
+        {
+            growBuffer();
+        }
+
+        buf[pos] = ( byte ) val;
+        pos++;
+    }
+
+
+    private void growBuffer( int size )
+    {
+        if ( size > initialSize )
+        {
+            byte[] copy = new byte[buf.length + size];
+            System.arraycopy( buf, 0, copy, 0, pos );
+            this.buf = copy;
+        }
+        else
+        {
+            byte[] copy = new byte[buf.length + initialSize];
+            System.arraycopy( buf, 0, copy, 0, pos );
+            this.buf = copy;
+        }
+    }
+
+
+    private void growBuffer()
+    {
+        byte[] copy = new byte[buf.length + initialSize];
+        System.arraycopy( buf, 0, copy, 0, pos );
+        this.buf = copy;
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/CharConstants.java b/trunk/util/src/main/java/org/apache/directory/api/util/CharConstants.java
new file mode 100644
index 0000000..a3feb13
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/CharConstants.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.util;
+
+
+/**
+ * Various Character constants are kept here.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface CharConstants
+{
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/Chars.java b/trunk/util/src/main/java/org/apache/directory/api/util/Chars.java
new file mode 100644
index 0000000..27e61a6
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/Chars.java
@@ -0,0 +1,934 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.util;
+
+
+/**
+ * Various Character methods are kept here.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Chars
+{
+    /** &lt;alpha> ::= [0x41-0x5A] | [0x61-0x7A] */
+    private static final boolean[] ALPHA =
+        {
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, false, false, false, false, false,
+            false, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, false, false, false, false, false
+    };
+    /** &lt;alpha-lower-case> ::= [0x61-0x7A] */
+    private static final boolean[] ALPHA_LOWER_CASE =
+        {
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, false, false, false, false, false
+    };
+    /** &lt;alpha-upper-case> ::= [0x41-0x5A] */
+    private static final boolean[] ALPHA_UPPER_CASE =
+        {
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+    };
+    /** &lt;alpha-digit> | &lt;digit> */
+    private static final boolean[] ALPHA_DIGIT =
+        {
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            true, true, true, true, true, true, true, true,
+            true, true, false, false, false, false, false, false,
+            false, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, false, false, false, false, false,
+            false, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, true, true, true, true, true,
+            true, true, true, false, false, false, false, false
+    };
+    /** &lt;alpha> | &lt;digit> | '-' */
+    private static final boolean[] CHAR =
+        {
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, true,  false, false,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  false, false, false, false, false, false,
+            false, true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  false, false, false, false, false,
+            false, true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  false, false, false, false, false
+    };
+    /** '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' */
+    private static final boolean[] DIGIT =
+        {
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            true, true, true, true, true, true, true, true,
+            true, true, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false
+    };
+    /** &lt;hex> ::= [0x30-0x39] | [0x41-0x46] | [0x61-0x66] */
+    private static final boolean[] HEX =
+        {
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            true, true, true, true, true, true, true, true,
+            true, true, false, false, false, false, false, false,
+            false, true, true, true, true, true, true, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, true, true, true, true, true, true, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false,
+            false, false, false, false, false, false, false, false };
+
+
+    private Chars()
+    {
+    }
+
+
+    /**
+    * Test if the current character is equal to a specific character.
+    *
+    * @param chars The buffer which contains the data
+    * @param index
+    *            Current position in the buffer
+    * @param car The character we want to compare with the current buffer position
+    * @return <code>true</code> if the current character equals the given character.
+    */
+    public static boolean isCharASCII( char[] chars, int index, char car )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) || ( index >= chars.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( chars[index] == car ) ? true : false );
+        }
+    }
+
+
+    /**
+     * Test if the current character is equal to a specific character.
+     *
+     * @param string The String which contains the data
+     * @param index Current position in the string
+     * @param car The character we want to compare with the current string
+     *            position
+     * @return <code>true</code> if the current character equals the given
+     *         character.
+     */
+    public static boolean isCharASCII( String string, int index, char car )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return string.charAt( index ) == car;
+        }
+    }
+
+
+    /**
+     * Test if the current character is equal to a specific character.
+     *
+     * @param string The String which contains the data
+     * @param index Current position in the string
+     * @param car The character we want to compare with the current string
+     *            position
+     * @return <code>true</code> if the current character equals the given
+     *         character.
+     */
+    public static boolean isICharASCII( String string, int index, char car )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( string.charAt( index ) | 0x20 ) & car ) == car;
+        }
+    }
+
+
+    /**
+     * Test if the current character is equal to a specific character.
+     *
+     * @param bytes The String which contains the data
+     * @param index Current position in the string
+     * @param car The character we want to compare with the current string
+     *            position
+     * @return <code>true</code> if the current character equals the given
+     *         character.
+     */
+    public static boolean isICharASCII( byte[] bytes, int index, char car )
+    {
+        if ( bytes == null )
+        {
+            return false;
+        }
+
+        int length = bytes.length;
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( bytes[index] | 0x20 ) & car ) == car;
+        }
+    }
+
+
+    /**
+     * Test if the current byte is an Alpha character :
+     * &lt;alpha> ::= [0x41-0x5A] | [0x61-0x7A]
+     *
+     * @param c The byte to test
+     *
+     * @return <code>true</code> if the byte is an Alpha
+     *         character
+     */
+    public static boolean isAlpha( byte c )
+    {
+        return ( ( c > 0 ) && ( c <= 127 ) && ALPHA[c] );
+    }
+
+
+    /**
+     * Test if the current character is an Alpha character :
+     * &lt;alpha> ::= [0x41-0x5A] | [0x61-0x7A]
+     *
+     * @param c The char to test
+     *
+     * @return <code>true</code> if the character is an Alpha
+     *         character
+     */
+    public static boolean isAlpha( char c )
+    {
+        return ( ( c > 0 ) && ( c <= 127 ) && ALPHA[c] );
+    }
+
+
+    /**
+     * Test if the current character is an Alpha character : &lt;alpha> ::=
+     * [0x41-0x5A] | [0x61-0x7A]
+     *
+     * @param bytes The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return <code>true</code> if the current character is an Alpha
+     *         character
+     */
+    public static boolean isAlphaASCII( byte[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = bytes[index];
+
+            if ( ( ( c | 0x7F ) != 0x7F ) || !ALPHA[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Test if the current character is an Alpha character : &lt;alpha> ::=
+     * [0x41-0x5A] | [0x61-0x7A]
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return <code>true</code> if the current character is an Alpha
+     *         character
+     */
+    public static boolean isAlphaASCII( char[] chars, int index )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) || ( index >= chars.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = chars[index];
+
+            if ( ( c > 127 ) || !ALPHA[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Test if the current character is an Alpha character : &lt;alpha> ::=
+     * [0x41-0x5A] | [0x61-0x7A]
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return <code>true</code> if the current character is an Alpha
+     *         character
+     */
+    public static boolean isAlphaASCII( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+
+            if ( ( c > 127 ) || !ALPHA[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Test if the current character is a lowercased Alpha character : <br/>
+     * &lt;alpha> ::= [0x61-0x7A]
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return <code>true</code> if the current character is a lower Alpha
+     *         character
+     */
+    public static boolean isAlphaLowercaseASCII( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+
+            if ( ( c > 127 ) || !ALPHA_LOWER_CASE[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Test if the current character is a uppercased Alpha character : <br/>
+     * &lt;alpha> ::= [0x61-0x7A]
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return <code>true</code> if the current character is a lower Alpha
+     *         character
+     */
+    public static boolean isAlphaUppercaseASCII( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+
+            if ( ( c > 127 ) || !ALPHA_UPPER_CASE[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Check if the current character is an 7 bits ASCII CHAR (between 0 and
+     * 127).
+     * &lt;char> ::= &lt;alpha> | &lt;digit>
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return The position of the next character, if the current one is a CHAR.
+     */
+    public static boolean isAlphaDigit( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+
+            if ( ( c > 127 ) || !ALPHA_DIGIT[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Check if the current character is an 7 bits ASCII CHAR (between 0 and
+     * 127). &lt;char> ::= &lt;alpha> | &lt;digit> | '-'
+     *
+     * @param bytes The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return The position of the next character, if the current one is a CHAR.
+     */
+    public static boolean isAlphaDigitMinus( byte[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = bytes[index];
+
+            if ( ( ( c | 0x7F ) != 0x7F ) || !CHAR[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Check if the current character is an 7 bits ASCII CHAR (between 0 and
+     * 127). &lt;char> ::= &lt;alpha> | &lt;digit> | '-'
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return The position of the next character, if the current one is a CHAR.
+     */
+    public static boolean isAlphaDigitMinus( char[] chars, int index )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) || ( index >= chars.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = chars[index];
+
+            if ( ( c > 127 ) || !CHAR[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Check if the current character is an 7 bits ASCII CHAR (between 0 and
+     * 127). &lt;char> ::= &lt;alpha> | &lt;digit> | '-'
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return The position of the next character, if the current one is a CHAR.
+     */
+    public static boolean isAlphaDigitMinus( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+
+            if ( ( c > 127 ) || !CHAR[c] )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * Check if the current character is an 7 bits ASCII CHAR (between 0 and
+     * 127). &lt;char> ::= &lt;alpha> | &lt;digit> | '-'
+     *
+     * @param c The char we want to check
+     * @return The position of the next character, if the current one is a CHAR.
+     */
+    public static boolean isAlphaDigitMinus( char c )
+    {
+        return ( ( c & 0x007F ) == c ) && CHAR[c];
+    }
+
+
+    /**
+     * Test if the current character is a bit, ie 0 or 1.
+     *
+     * @param string
+     *            The String which contains the data
+     * @param index
+     *            Current position in the string
+     * @return <code>true</code> if the current character is a bit (0 or 1)
+     */
+    public static boolean isBit( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+            return ( ( c == '0' ) || ( c == '1' ) );
+        }
+    }
+
+
+    /**
+     * Test if the current character is a digit &lt;digit> ::= '0' | '1' | '2' |
+     * '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param bytes The buffer which contains the data
+     * @return <code>true</code> if the current character is a Digit
+     */
+    public static boolean isDigit( byte[] bytes )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( ( bytes[0] | 0x7F ) != 0x7F ) || !DIGIT[bytes[0]] ) ? false : true );
+        }
+    }
+
+
+    /**
+     * Test if the current character is a digit &lt;digit> ::= '0' | '1' | '2' |
+     * '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param car the character to test
+     *
+     * @return <code>true</code> if the character is a Digit
+     */
+    public static boolean isDigit( char car )
+    {
+        return ( car >= '0' ) && ( car <= '9' );
+    }
+
+
+    /**
+     * Test if the current byte is a digit &lt;digit> ::= '0' | '1' | '2' |
+     * '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param car the byte to test
+     *
+     * @return <code>true</code> if the character is a Digit
+     */
+    public static boolean isDigit( byte car )
+    {
+        return ( car >= '0' ) && ( car <= '9' );
+    }
+
+
+    /**
+     * Test if the current character is a digit &lt;digit> ::= '0' | '1' | '2' |
+     * '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param bytes The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return <code>true</code> if the current character is a Digit
+     */
+    public static boolean isDigit( byte[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( ( bytes[index] | 0x7F ) != 0x7F ) || !DIGIT[bytes[index]] ) ? false : true );
+        }
+    }
+
+
+    /**
+     * Test if the current character is a digit &lt;digit> ::= '0' | '1' | '2' |
+     * '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return <code>true</code> if the current character is a Digit
+     */
+    public static boolean isDigit( char[] chars, int index )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) || ( index >= chars.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( chars[index] > 127 ) || !DIGIT[chars[index]] ) ? false : true );
+        }
+    }
+
+
+    /**
+     * Test if the current character is a digit &lt;digit> ::= '0' | '1' | '2' |
+     * '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return <code>true</code> if the current character is a Digit
+     */
+    public static boolean isDigit( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+            return ( ( ( c > 127 ) || !DIGIT[c] ) ? false : true );
+        }
+    }
+
+
+    /**
+     * Test if the current character is a digit &lt;digit> ::= '0' | '1' | '2' |
+     * '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param chars The buffer which contains the data
+     * @return <code>true</code> if the current character is a Digit
+     */
+    public static boolean isDigit( char[] chars )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( chars[0] > 127 ) || !DIGIT[chars[0]] ) ? false : true );
+        }
+    }
+
+
+    /**
+     * Check if the current char is an Hex Char
+     * &lt;hex> ::= [0x30-0x39] | [0x41-0x46] | [0x61-0x66]
+     *
+     * @param c The char we want to check
+     * @return <code>true</code> if the current char is a Hex char
+     */
+    public static boolean isHex( char c )
+    {
+        return ( ( c | 0x007F ) == 0x007F ) && HEX[c];
+    }
+
+
+    /**
+     * Check if the current byte is an Hex Char
+     * &lt;hex> ::= [0x30-0x39] | [0x41-0x46] | [0x61-0x66]
+     *
+     * @param b The byte we want to check
+     * @return <code>true</code> if the current byte is a Hex byte
+     */
+    public static boolean isHex( byte b )
+    {
+        return ( ( b | 0x7F ) == 0x7F ) && HEX[b];
+    }
+
+
+    /**
+     * Check if the current character is an Hex Char &lt;hex> ::= [0x30-0x39] |
+     * [0x41-0x46] | [0x61-0x66]
+     *
+     * @param bytes The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return <code>true</code> if the current character is a Hex Char
+     */
+    public static boolean isHex( byte[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = bytes[index];
+
+            return ( ( ( c | 0x7F ) == 0x7F ) && HEX[c] );
+        }
+    }
+
+
+    /**
+     * Check if the current character is an Hex Char &lt;hex> ::= [0x30-0x39] |
+     * [0x41-0x46] | [0x61-0x66]
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return <code>true</code> if the current character is a Hex Char
+     */
+    public static boolean isHex( char[] chars, int index )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) || ( index >= chars.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = chars[index];
+
+            return ( ( ( c | 0x007F ) == 0x007F ) && HEX[c] );
+        }
+    }
+
+
+    /**
+     * Check if the current character is an Hex Char &lt;hex> ::= [0x30-0x39] |
+     * [0x41-0x46] | [0x61-0x66]
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return <code>true</code> if the current character is a Hex Char
+     */
+    public static boolean isHex( String string, int index )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            char c = string.charAt( index );
+
+            return ( ( ( c | 0x007F ) == 0x007F ) && HEX[c] );
+        }
+    }
+    
+    
+    /**
+     * Check if the current character is the ASCII character underscore 0x5F.
+     *
+     * @param bytes The buffer which contains the data
+     * @param index Current position in the buffer
+     * @return <code>true</code> if the current character is a the underscore
+     */
+    public static boolean isUnderscore( byte[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) || ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = bytes[index];
+
+            return c == 0x5F;
+        }
+    }
+
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/ComponentsMonitor.java b/trunk/util/src/main/java/org/apache/directory/api/util/ComponentsMonitor.java
new file mode 100644
index 0000000..ef49c4b
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/ComponentsMonitor.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import java.util.List;
+
+
+/**
+ * Monitor used to track existence or duplication of components.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface ComponentsMonitor
+{
+
+    /**
+     * Use a component.
+     *
+     * @param component the component
+     * @return this components monitor
+     * @throws IllegalArgumentException if the component is already used
+     */
+    ComponentsMonitor useComponent( String component ) throws IllegalArgumentException;
+
+
+    /**
+     * Check if all components are used.
+     *
+     * @return true if all components are used
+     */
+    boolean allComponentsUsed();
+
+
+    /**
+     * Checks if the final state is valid. That depends whether the components are mandatory
+     * or optional.
+     *
+     * @return true if the final state is valid
+     */
+    boolean finalStateValid();
+
+
+    /**
+     * Gets the remaining components.
+     *
+     * @return the remaining components
+     */
+    List<String> getRemainingComponents();
+
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/DateUtils.java b/trunk/util/src/main/java/org/apache/directory/api/util/DateUtils.java
new file mode 100644
index 0000000..a5fe65f
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/DateUtils.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import java.util.Calendar;
+import java.util.Date;
+
+
+/**
+ * Gets the generalized time using the "Z" form of the g-time-zone.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class DateUtils
+{
+
+    /**
+     * Private constructor.
+     */
+    private DateUtils()
+    {
+    }
+
+
+    public static Date getDate( String zuluTime )
+    {
+        try
+        {
+            return GeneralizedTime.getDate( zuluTime );
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * Gets the generalized time right now. {@link GeneralizedTime}
+     * 
+     * @return the generalizedTime right now
+     */
+    public static String getGeneralizedTime()
+    {
+        return new GeneralizedTime( Calendar.getInstance() ).toGeneralizedTime();
+    }
+
+
+    /**
+     * 
+     * @see #getGeneralizedTime()
+     *
+     * @param date the date to be converted to generalized time string
+     * @return given date in the generalized time string format
+     */
+    public static String getGeneralizedTime( Date date )
+    {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime( date );
+        return new GeneralizedTime( calendar ).toGeneralizedTime();
+    }
+
+
+    /**
+     * 
+     * @see #getGeneralizedTime()
+     *
+     * @param time the time value to be converted to generalized time string
+     * @return given time in generalized time string format
+     */
+    public static String getGeneralizedTime( long time )
+    {
+        return getGeneralizedTime( new Date( time ) );
+    }
+
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/DummySSLSocketFactory.java b/trunk/util/src/main/java/org/apache/directory/api/util/DummySSLSocketFactory.java
new file mode 100644
index 0000000..22ceaaa
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/DummySSLSocketFactory.java
@@ -0,0 +1,208 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+
+/**
+ * A SSLSocketFactory that accepts every certificat without validation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DummySSLSocketFactory extends SSLSocketFactory
+{
+
+    /** The default instance. */
+    private static SocketFactory instance;
+
+
+    /**
+     * Gets the default instance.
+     * 
+     * Note: This method is invoked from the JNDI framework when 
+     * creating a ldaps:// connection.
+     * 
+     * @return the default instance
+     */
+    public static SocketFactory getDefault()
+    {
+        if ( instance == null )
+        {
+            instance = new DummySSLSocketFactory();
+        }
+        return instance;
+    }
+
+    /** The delegate. */
+    private SSLSocketFactory delegate;
+
+
+    /**
+     * Creates a new instance of DummySSLSocketFactory.
+     */
+    public DummySSLSocketFactory()
+    {
+        try
+        {
+            TrustManager tm = new X509TrustManager()
+            {
+                public X509Certificate[] getAcceptedIssuers()
+                {
+                    return new X509Certificate[0];
+                }
+
+
+                public void checkClientTrusted( X509Certificate[] arg0, String arg1 ) throws CertificateException
+                {
+                }
+
+
+                public void checkServerTrusted( X509Certificate[] arg0, String arg1 ) throws CertificateException
+                {
+                }
+            };
+            TrustManager[] tma =
+                { tm };
+            SSLContext sc = SSLContext.getInstance( "TLS" );
+            sc.init( null, tma, new SecureRandom() );
+            delegate = sc.getSocketFactory();
+        }
+        catch ( Exception e )
+        {
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * @see javax.net.ssl.SSLSocketFactory#getDefaultCipherSuites()
+     */
+    public String[] getDefaultCipherSuites()
+    {
+        return delegate.getDefaultCipherSuites();
+    }
+
+
+    /**
+     * @see javax.net.ssl.SSLSocketFactory#getSupportedCipherSuites()
+     */
+    public String[] getSupportedCipherSuites()
+    {
+        return delegate.getSupportedCipherSuites();
+    }
+
+
+    /**
+     * @see javax.net.ssl.SSLSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean)
+     */
+    public Socket createSocket( Socket arg0, String arg1, int arg2, boolean arg3 ) throws IOException
+    {
+        try
+        {
+            return delegate.createSocket( arg0, arg1, arg2, arg3 );
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+
+    /**
+     * @see javax.net.SocketFactory#createSocket(java.lang.String, int)
+     */
+    public Socket createSocket( String arg0, int arg1 ) throws IOException
+    {
+        try
+        {
+            return delegate.createSocket( arg0, arg1 );
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+
+    /**
+     * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
+     */
+    public Socket createSocket( InetAddress arg0, int arg1 ) throws IOException
+    {
+        try
+        {
+            return delegate.createSocket( arg0, arg1 );
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+
+    /**
+     * @see javax.net.SocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int)
+     */
+    public Socket createSocket( String arg0, int arg1, InetAddress arg2, int arg3 ) throws IOException
+    {
+        try
+        {
+            return delegate.createSocket( arg0, arg1, arg2, arg3 );
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+
+    /**
+     * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int, java.net.InetAddress, int)
+     */
+    public Socket createSocket( InetAddress arg0, int arg1, InetAddress arg2, int arg3 ) throws IOException
+    {
+        try
+        {
+            return delegate.createSocket( arg0, arg1, arg2, arg3 );
+        }
+        catch ( IOException e )
+        {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/EmptyEnumeration.java b/trunk/util/src/main/java/org/apache/directory/api/util/EmptyEnumeration.java
new file mode 100644
index 0000000..c6b2aa7
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/EmptyEnumeration.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import java.util.NoSuchElementException;
+
+import javax.naming.NamingException;
+import javax.naming.NamingEnumeration;
+
+
+/**
+ * An empty NamingEnumeration without any values: meaning
+ * hasMore/hasMoreElements() always returns false, and next/nextElement() always
+ * throws a NoSuchElementException.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EmptyEnumeration<T> implements NamingEnumeration<T>
+{
+
+    /**
+     * @see javax.naming.NamingEnumeration#close()
+     */
+    public void close()
+    {
+    }
+
+
+    /**
+     * Always returns false.
+     * 
+     * @see javax.naming.NamingEnumeration#hasMore()
+     */
+    public boolean hasMore() throws NamingException
+    {
+        return false;
+    }
+
+
+    /**
+     * Always throws NoSuchElementException.
+     * 
+     * @see javax.naming.NamingEnumeration#next()
+     */
+    public T next() throws NamingException
+    {
+        throw new NoSuchElementException();
+    }
+
+
+    /**
+     * Always return false.
+     * 
+     * @see java.util.Enumeration#hasMoreElements()
+     */
+    public boolean hasMoreElements()
+    {
+        return false;
+    }
+
+
+    /**
+     * Always throws NoSuchElementException.
+     * 
+     * @see java.util.Enumeration#nextElement()
+     */
+    public T nextElement()
+    {
+        throw new NoSuchElementException();
+    }
+
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/GeneralizedTime.java b/trunk/util/src/main/java/org/apache/directory/api/util/GeneralizedTime.java
new file mode 100644
index 0000000..80da37c
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/GeneralizedTime.java
@@ -0,0 +1,1046 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * <p>This class represents the generalized time syntax as defined in 
+ * RFC 4517 section 3.3.13.</p>
+ * 
+ * <p>The date, time and time zone information is internally backed
+ * by an {@link java.util.Calendar} object</p>
+ * 
+ * <p>Leap seconds are not supported, as {@link java.util.Calendar}
+ * does not support leap seconds.</p>
+ * 
+ * <pre>
+ * 3.3.13.  Generalized Time
+ *
+ *  A value of the Generalized Time syntax is a character string
+ *  representing a date and time.  The LDAP-specific encoding of a value
+ *  of this syntax is a restriction of the format defined in [ISO8601],
+ *  and is described by the following ABNF:
+ *
+ *     GeneralizedTime = century year month day hour
+ *                          [ minute [ second / leap-second ] ]
+ *                          [ fraction ]
+ *                          g-time-zone
+ *
+ *     century = 2(%x30-39) ; "00" to "99"
+ *     year    = 2(%x30-39) ; "00" to "99"
+ *     month   =   ( %x30 %x31-39 ) ; "01" (January) to "09"
+ *               / ( %x31 %x30-32 ) ; "10" to "12"
+ *     day     =   ( %x30 %x31-39 )    ; "01" to "09"
+ *               / ( %x31-32 %x30-39 ) ; "10" to "29"
+ *               / ( %x33 %x30-31 )    ; "30" to "31"
+ *     hour    = ( %x30-31 %x30-39 ) / ( %x32 %x30-33 ) ; "00" to "23"
+ *     minute  = %x30-35 %x30-39                        ; "00" to "59"
+ *
+ *     second      = ( %x30-35 %x30-39 ) ; "00" to "59"
+ *     leap-second = ( %x36 %x30 )       ; "60"
+ *
+ *     fraction        = ( DOT / COMMA ) 1*(%x30-39)
+ *     g-time-zone     = %x5A  ; "Z"
+ *                       / g-differential
+ *     g-differential  = ( MINUS / PLUS ) hour [ minute ]
+ *     MINUS           = %x2D  ; minus sign ("-")
+ *
+ *  The <DOT>, <COMMA>, and <PLUS> rules are defined in [RFC4512].
+ *
+ *  The above ABNF allows character strings that do not represent valid
+ *  dates (in the Gregorian calendar) and/or valid times (e.g., February
+ *  31, 1994).  Such character strings SHOULD be considered invalid for
+ *  this syntax.
+ *
+ *  The time value represents coordinated universal time (equivalent to
+ *  Greenwich Mean Time) if the "Z" form of <g-time-zone> is used;
+ *  otherwise, the value represents a local time in the time zone
+ *  indicated by <g-differential>.  In the latter case, coordinated
+ *  universal time can be calculated by subtracting the differential from
+ *  the local time.  The "Z" form of <g-time-zone> SHOULD be used in
+ *  preference to <g-differential>.
+ *
+ *  If <minute> is omitted, then <fraction> represents a fraction of an
+ *  hour; otherwise, if <second> and <leap-second> are omitted, then
+ *  <fraction> represents a fraction of a minute; otherwise, <fraction>
+ *  represents a fraction of a second.
+ *
+ *     Examples:
+ *        199412161032Z
+ *        199412160532-0500
+ *
+ *  Both example values represent the same coordinated universal time:
+ *  10:32 AM, December 16, 1994.
+ *
+ *  The LDAP definition for the Generalized Time syntax is:
+ *
+ *     ( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )
+ *
+ *  This syntax corresponds to the GeneralizedTime ASN.1 type from
+ *  [ASN.1], with the constraint that local time without a differential
+ *  SHALL NOT be used.
+ *
+ * </pre>
+ */
+public class GeneralizedTime implements Comparable<GeneralizedTime>
+{
+    /**
+     * The format of the generalized time.
+     */
+    public enum Format
+    {
+        /** Time format with minutes and seconds, excluding fraction. */
+        YEAR_MONTH_DAY_HOUR_MIN_SEC,
+        /** Time format with minutes and seconds, including fraction. */
+        YEAR_MONTH_DAY_HOUR_MIN_SEC_FRACTION,
+
+        /** Time format with minutes, seconds are omitted, excluding fraction. */
+        YEAR_MONTH_DAY_HOUR_MIN,
+        /** Time format with minutes seconds are omitted, including fraction. */
+        YEAR_MONTH_DAY_HOUR_MIN_FRACTION,
+
+        /** Time format, minutes and seconds are omitted, excluding fraction. */
+        YEAR_MONTH_DAY_HOUR,
+        /** Time format, minutes and seconds are omitted, including fraction. */
+        YEAR_MONTH_DAY_HOUR_FRACTION
+    }
+
+    /**
+     * The fraction delimiter of the generalized time.
+     */
+    public enum FractionDelimiter
+    {
+        /** Use a dot as fraction delimiter. */
+        DOT,
+        /** Use a comma as fraction delimiter. */
+        COMMA
+    }
+
+    /**
+     * The time zone format of the generalized time.
+     */
+    public enum TimeZoneFormat
+    {
+        /** g-time-zone (Zulu) format. */
+        Z,
+        /** g-differential format, using hour only. */
+        DIFF_HOUR,
+        /** g-differential format, using hour and minute. */
+        DIFF_HOUR_MINUTE
+    }
+
+    /** The GMT TimeZone */
+    private static final TimeZone GMT = TimeZone.getTimeZone( "GMT" );
+
+    /** The user provided value */
+    private String upGeneralizedTime;
+
+    /** The user provided format */
+    private Format upFormat;
+
+    /** The user provided time zone format */
+    private TimeZoneFormat upTimeZoneFormat;
+
+    /** The user provided fraction delimiter */
+    private FractionDelimiter upFractionDelimiter;
+
+    /** the user provided fraction length */
+    private int upFractionLength;
+
+    /** The calendar */
+    private Calendar calendar;
+
+
+    /**
+     * 
+     * Creates a new instance of GeneralizedTime by setting the date to an instance of Calendar.
+     * @see #GeneralizedTime(Calendar)
+     * 
+     * @param date the date
+     */
+    public GeneralizedTime( Date date )
+    {
+        calendar = new GregorianCalendar( GMT, Locale.ROOT );
+        calendar.setTime( date );
+        setUp( calendar );
+    }
+
+
+    /**
+     * Creates a new instance of GeneralizedTime, based on the given Calendar object.
+     * Uses <pre>Format.YEAR_MONTH_DAY_HOUR_MIN_SEC</pre> as default format and
+     * <pre>TimeZoneFormat.Z</pre> as default time zone format. 
+     *
+     * @param calendar the calendar containing the date, time and timezone information
+     */
+    public GeneralizedTime( Calendar calendar )
+    {
+        setUp( calendar );
+    }
+
+
+    private void setUp( Calendar newCalendar )
+    {
+        if ( newCalendar == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04358 ) );
+        }
+
+        this.calendar = newCalendar;
+        upGeneralizedTime = null;
+        upFormat = Format.YEAR_MONTH_DAY_HOUR_MIN_SEC_FRACTION;
+        upTimeZoneFormat = TimeZoneFormat.Z;
+        upFractionDelimiter = FractionDelimiter.DOT;
+        upFractionLength = 3;
+    }
+
+
+    /**
+     * Creates a new instance of GeneralizedTime, based on the
+     * given generalized time string.
+     *
+     * @param generalizedTime the generalized time
+     * 
+     * @throws ParseException if the given generalized time can't be parsed.
+     */
+    public GeneralizedTime( String generalizedTime ) throws ParseException
+    {
+        if ( generalizedTime == null )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04359 ), 0 );
+        }
+
+        this.upGeneralizedTime = generalizedTime;
+
+        calendar = new GregorianCalendar( GMT, Locale.ROOT );
+        calendar.setTimeInMillis( 0 );
+        calendar.setLenient( false );
+
+        parseYear();
+        parseMonth();
+        parseDay();
+        parseHour();
+
+        if ( upGeneralizedTime.length() < 11 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04360 ), 10 );
+        }
+
+        // pos 10: 
+        // if digit => minute field
+        // if . or , => fraction of hour field
+        // if Z or + or - => timezone field
+        // else error
+        int pos = 10;
+        char c = upGeneralizedTime.charAt( pos );
+        
+        if ( ( '0' <= c ) && ( c <= '9' ) )
+        {
+            parseMinute();
+
+            if ( upGeneralizedTime.length() < 13 )
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04361 ), 12 );
+            }
+
+            // pos 12: 
+            // if digit => second field
+            // if . or , => fraction of minute field
+            // if Z or + or - => timezone field
+            // else error
+            pos = 12;
+            c = upGeneralizedTime.charAt( pos );
+            
+            if ( ( '0' <= c ) && ( c <= '9' ) )
+            {
+                parseSecond();
+
+                if ( upGeneralizedTime.length() < 15 )
+                {
+                    throw new ParseException( I18n.err( I18n.ERR_04362 ), 14 );
+                }
+
+                // pos 14: 
+                // if . or , => fraction of second field
+                // if Z or + or - => timezone field
+                // else error
+                pos = 14;
+                c = upGeneralizedTime.charAt( pos );
+                
+                if ( ( c == '.' ) || ( c == ',' ) )
+                {
+                    // read fraction of second
+                    parseFractionOfSecond();
+                    pos += 1 + upFractionLength;
+
+                    parseTimezone( pos );
+                    upFormat = Format.YEAR_MONTH_DAY_HOUR_MIN_SEC_FRACTION;
+                }
+                else if ( ( c == 'Z' ) || ( c == '+' ) || ( c == '-' ) )
+                {
+                    // read timezone
+                    parseTimezone( pos );
+                    upFormat = Format.YEAR_MONTH_DAY_HOUR_MIN_SEC;
+                }
+                else
+                {
+                    throw new ParseException( I18n.err( I18n.ERR_04363 ), 14 );
+                }
+            }
+            else if ( ( c == '.' ) || ( c == ',' ) )
+            {
+                // read fraction of minute
+                parseFractionOfMinute();
+                pos += 1 + upFractionLength;
+
+                parseTimezone( pos );
+                upFormat = Format.YEAR_MONTH_DAY_HOUR_MIN_FRACTION;
+            }
+            else if ( ( c == 'Z' ) || ( c == '+' ) || ( c == '-' ) )
+            {
+                // read timezone
+                parseTimezone( pos );
+                upFormat = Format.YEAR_MONTH_DAY_HOUR_MIN;
+            }
+            else
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04364 ), 12 );
+            }
+        }
+        else if ( ( c == '.' ) || ( c == ',' ) )
+        {
+            // read fraction of hour
+            parseFractionOfHour();
+            pos += 1 + upFractionLength;
+
+            parseTimezone( pos );
+            upFormat = Format.YEAR_MONTH_DAY_HOUR_FRACTION;
+        }
+        else if ( ( c == 'Z' ) || ( c == '+' ) || ( c == '-' ) )
+        {
+            // read timezone
+            parseTimezone( pos );
+            upFormat = Format.YEAR_MONTH_DAY_HOUR;
+        }
+        else
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04365 ), 10 );
+        }
+
+        // this calculates and verifies the calendar
+        /* Not sure we should do that... */
+        try
+        {
+            calendar.getTimeInMillis();
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04366 ), 0 );
+        }
+
+        calendar.setLenient( true );
+    }
+
+
+    private void parseTimezone( int pos ) throws ParseException
+    {
+        if ( upGeneralizedTime.length() < pos + 1 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04367 ), pos );
+        }
+
+        char c = upGeneralizedTime.charAt( pos );
+        
+        if ( c == 'Z' )
+        {
+            calendar.setTimeZone( GMT );
+            upTimeZoneFormat = TimeZoneFormat.Z;
+
+            if ( upGeneralizedTime.length() > pos + 1 )
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04368 ), pos + 1 );
+            }
+        }
+        else if ( ( c == '+' ) || ( c == '-' ) )
+        {
+            StringBuilder sb = new StringBuilder( "GMT" );
+            sb.append( c );
+
+            String digits = getAllDigits( pos + 1 );
+            sb.append( digits );
+
+            if ( digits.length() == 2 && digits.matches( "^([01]\\d|2[0-3])$" ) )
+            {
+                TimeZone timeZone = TimeZone.getTimeZone( sb.toString() );
+                calendar.setTimeZone( timeZone );
+                upTimeZoneFormat = TimeZoneFormat.DIFF_HOUR;
+            }
+            else if ( digits.length() == 4 && digits.matches( "^([01]\\d|2[0-3])([0-5]\\d)$" ) )
+            {
+                TimeZone timeZone = TimeZone.getTimeZone( sb.toString() );
+                calendar.setTimeZone( timeZone );
+                upTimeZoneFormat = TimeZoneFormat.DIFF_HOUR_MINUTE;
+            }
+            else
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04369 ), pos );
+            }
+
+            if ( upGeneralizedTime.length() > pos + 1 + digits.length() )
+            {
+                throw new ParseException( I18n.err( I18n.ERR_04370 ), pos + 1 + digits.length() );
+            }
+        }
+    }
+
+
+    private void parseFractionOfSecond() throws ParseException
+    {
+        parseFractionDelmiter( 14 );
+        String fraction = getFraction( 14 + 1 );
+        upFractionLength = fraction.length();
+
+        double fract = Double.parseDouble( "0." + fraction );
+        int millisecond = ( int ) Math.floor( fract * 1000 );
+
+        calendar.set( GregorianCalendar.MILLISECOND, millisecond );
+    }
+
+
+    private void parseFractionOfMinute() throws ParseException
+    {
+        parseFractionDelmiter( 12 );
+        String fraction = getFraction( 12 + 1 );
+        upFractionLength = fraction.length();
+
+        double fract = Double.parseDouble( "0." + fraction );
+        int milliseconds = ( int ) Math.round( fract * 1000 * 60 );
+        int second = milliseconds / 1000;
+        int millisecond = milliseconds - ( second * 1000 );
+
+        calendar.set( Calendar.SECOND, second );
+        calendar.set( Calendar.MILLISECOND, millisecond );
+    }
+
+
+    private void parseFractionOfHour() throws ParseException
+    {
+        parseFractionDelmiter( 10 );
+        String fraction = getFraction( 10 + 1 );
+        upFractionLength = fraction.length();
+
+        double fract = Double.parseDouble( "0." + fraction );
+        int milliseconds = ( int ) Math.round( fract * 1000 * 60 * 60 );
+        int minute = milliseconds / ( 1000 * 60 );
+        int second = ( milliseconds - ( minute * 60 * 1000 ) ) / 1000;
+        int millisecond = milliseconds - ( minute * 60 * 1000 ) - ( second * 1000 );
+
+        calendar.set( Calendar.MINUTE, minute );
+        calendar.set( Calendar.SECOND, second );
+        calendar.set( Calendar.MILLISECOND, millisecond );
+    }
+
+
+    private void parseFractionDelmiter( int fractionDelimiterPos )
+    {
+        char c = upGeneralizedTime.charAt( fractionDelimiterPos );
+        upFractionDelimiter = c == '.' ? FractionDelimiter.DOT : FractionDelimiter.COMMA;
+    }
+
+
+    private String getFraction( int startIndex ) throws ParseException
+    {
+        String fraction = getAllDigits( startIndex );
+
+        // minimum one digit
+        if ( fraction.length() == 0 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04371 ), startIndex );
+        }
+
+        return fraction;
+    }
+
+
+    private String getAllDigits( int startIndex )
+    {
+        StringBuilder sb = new StringBuilder();
+        while ( upGeneralizedTime.length() > startIndex )
+        {
+            char c = upGeneralizedTime.charAt( startIndex );
+            if ( '0' <= c && c <= '9' )
+            {
+                sb.append( c );
+                startIndex++;
+            }
+            else
+            {
+                break;
+            }
+        }
+        return sb.toString();
+    }
+
+
+    private void parseSecond() throws ParseException
+    {
+        // read minute
+        if ( upGeneralizedTime.length() < 14 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04372 ), 12 );
+        }
+        try
+        {
+            int second = Strings.parseInt( upGeneralizedTime.substring( 12, 14 ) );
+            calendar.set( Calendar.SECOND, second );
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04373 ), 12 );
+        }
+    }
+
+
+    private void parseMinute() throws ParseException
+    {
+        // read minute
+        if ( upGeneralizedTime.length() < 12 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04374 ), 10 );
+        }
+        try
+        {
+            int minute = Strings.parseInt( upGeneralizedTime.substring( 10, 12 ) );
+            calendar.set( Calendar.MINUTE, minute );
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04375 ), 10 );
+        }
+    }
+
+
+    private void parseHour() throws ParseException
+    {
+        if ( upGeneralizedTime.length() < 10 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04376 ), 8 );
+        }
+        try
+        {
+            int hour = Strings.parseInt( upGeneralizedTime.substring( 8, 10 ) );
+            calendar.set( Calendar.HOUR_OF_DAY, hour );
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04377 ), 8 );
+        }
+    }
+
+
+    private void parseDay() throws ParseException
+    {
+        if ( upGeneralizedTime.length() < 8 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04378 ), 6 );
+        }
+        try
+        {
+            int day = Strings.parseInt( upGeneralizedTime.substring( 6, 8 ) );
+            calendar.set( Calendar.DAY_OF_MONTH, day );
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04379 ), 6 );
+        }
+    }
+
+
+    private void parseMonth() throws ParseException
+    {
+        if ( upGeneralizedTime.length() < 6 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04380 ), 4 );
+        }
+        try
+        {
+            int month = Strings.parseInt( upGeneralizedTime.substring( 4, 6 ) );
+            calendar.set( Calendar.MONTH, month - 1 );
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04381 ), 4 );
+        }
+    }
+
+
+    private void parseYear() throws ParseException
+    {
+        if ( upGeneralizedTime.length() < 4 )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04382 ), 0 );
+        }
+        try
+        {
+            int year = Strings.parseInt( upGeneralizedTime.substring( 0, 4 ) );
+            calendar.set( Calendar.YEAR, year );
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new ParseException( I18n.err( I18n.ERR_04383 ), 0 );
+        }
+    }
+
+
+    /**
+     * Returns the string representation of this generalized time. 
+     * This method uses the same format as the user provided format.
+     *
+     * @return the string representation of this generalized time
+     */
+    public String toGeneralizedTime()
+    {
+        return toGeneralizedTime( upFormat, upFractionDelimiter, upFractionLength, upTimeZoneFormat );
+    }
+
+
+    /**
+     * Returns the string representation of this generalized time. 
+     * This method uses the same format as the user provided format.
+     *
+     * @return the string representation of this generalized time
+     */
+    public String toGeneralizedTimeWithoutFraction()
+    {
+        return toGeneralizedTime( getFormatWithoutFraction( upFormat ), upFractionDelimiter, upFractionLength,
+            upTimeZoneFormat );
+    }
+
+
+    /**
+     * Gets the corresponding format with fraction.
+     *
+     * @param f the format
+     * @return the corresponding format without fraction
+     */
+    private Format getFormatWithoutFraction( Format f )
+    {
+        switch ( f )
+        {
+            case YEAR_MONTH_DAY_HOUR_FRACTION:
+                return Format.YEAR_MONTH_DAY_HOUR;
+            case YEAR_MONTH_DAY_HOUR_MIN_FRACTION:
+                return Format.YEAR_MONTH_DAY_HOUR_MIN;
+            case YEAR_MONTH_DAY_HOUR_MIN_SEC_FRACTION:
+                return Format.YEAR_MONTH_DAY_HOUR_MIN_SEC;
+            default:
+                break;
+        }
+
+        return f;
+    }
+
+
+    /**
+     * Returns the string representation of this generalized time.
+     * 
+     * @param format the target format
+     * @param fractionDelimiter the target fraction delimiter, may be null
+     * @param fractionLength the fraction length
+     * @param timeZoneFormat the target time zone format
+     * 
+     * @return the string
+     */
+    public String toGeneralizedTime( Format format, FractionDelimiter fractionDelimiter, int fractionLength,
+        TimeZoneFormat timeZoneFormat )
+    {
+        Calendar clonedCalendar = ( Calendar ) calendar.clone();
+
+        if ( timeZoneFormat == TimeZoneFormat.Z )
+        {
+            clonedCalendar.setTimeZone( GMT );
+        }
+
+        // Create the result. It can contain a maximum of 23 chars
+        byte[] result = new byte[23];
+
+        // The starting point
+        int pos = 0;
+
+        // Inject the year
+        int year = clonedCalendar.get( Calendar.YEAR );
+
+        result[pos++] = ( byte ) ( ( year / 1000 ) + '0' );
+        year %= 1000;
+
+        result[pos++] = ( byte ) ( ( year / 100 ) + '0' );
+        year %= 100;
+
+        result[pos++] = ( byte ) ( ( year / 10 ) + '0' );
+
+        result[pos++] = ( byte ) ( ( year % 10 ) + '0' );
+
+        // Inject the month
+        int month = clonedCalendar.get( Calendar.MONTH ) + 1;
+
+        result[pos++] = ( byte ) ( ( month / 10 ) + '0' );
+
+        result[pos++] = ( byte ) ( ( month % 10 ) + '0' );
+
+        // Inject the day
+        int day = clonedCalendar.get( Calendar.DAY_OF_MONTH );
+
+        result[pos++] = ( byte ) ( ( day / 10 ) + '0' );
+
+        result[pos++] = ( byte ) ( ( day % 10 ) + '0' );
+
+        // Inject the hour
+        int hour = clonedCalendar.get( Calendar.HOUR_OF_DAY );
+
+        result[pos++] = ( byte ) ( ( hour / 10 ) + '0' );
+
+        result[pos++] = ( byte ) ( ( hour % 10 ) + '0' );
+
+        switch ( format )
+        {
+            case YEAR_MONTH_DAY_HOUR_MIN_SEC:
+                // Inject the minutes
+                int minute = clonedCalendar.get( Calendar.MINUTE );
+
+                result[pos++] = ( byte ) ( ( minute / 10 ) + '0' );
+
+                result[pos++] = ( byte ) ( ( minute % 10 ) + '0' );
+
+                // Inject the seconds
+                int second = clonedCalendar.get( Calendar.SECOND );
+
+                result[pos++] = ( byte ) ( ( second / 10 ) + '0' );
+
+                result[pos++] = ( byte ) ( ( second % 10 ) + '0' );
+
+                break;
+
+            case YEAR_MONTH_DAY_HOUR_MIN_SEC_FRACTION:
+                // Inject the minutes
+                minute = clonedCalendar.get( Calendar.MINUTE );
+
+                result[pos++] = ( byte ) ( ( minute / 10 ) + '0' );
+
+                result[pos++] = ( byte ) ( ( minute % 10 ) + '0' );
+
+                // Inject the seconds
+                second = clonedCalendar.get( Calendar.SECOND );
+
+                result[pos++] = ( byte ) ( ( second / 10 ) + '0' );
+
+                result[pos++] = ( byte ) ( ( second % 10 ) + '0' );
+
+                // Inject the fraction
+                if ( fractionDelimiter == FractionDelimiter.COMMA )
+                {
+                    result[pos++] = ',';
+                }
+                else
+                {
+                    result[pos++] = '.';
+                }
+
+                // Inject the fraction
+                int millisecond = clonedCalendar.get( Calendar.MILLISECOND );
+
+                result[pos++] = ( byte ) ( ( millisecond / 100 ) + '0' );
+                millisecond %= 100;
+
+                result[pos++] = ( byte ) ( ( millisecond / 10 ) + '0' );
+
+                //if ( millisecond > 0 )
+                result[pos++] = ( byte ) ( ( millisecond % 10 ) + '0' );
+
+                break;
+
+            case YEAR_MONTH_DAY_HOUR_MIN:
+                // Inject the minutes
+                minute = clonedCalendar.get( Calendar.MINUTE );
+
+                result[pos++] = ( byte ) ( ( minute / 10 ) + '0' );
+
+                result[pos++] = ( byte ) ( ( minute % 10 ) + '0' );
+                break;
+
+            case YEAR_MONTH_DAY_HOUR_MIN_FRACTION:
+                // Inject the minutes
+                minute = clonedCalendar.get( Calendar.MINUTE );
+
+                result[pos++] = ( byte ) ( ( minute / 10 ) + '0' );
+
+                result[pos++] = ( byte ) ( ( minute % 10 ) + '0' );
+
+                // sec + millis => fraction of a minute
+                int fraction = 1000 * clonedCalendar.get( Calendar.SECOND )
+                    + clonedCalendar.get( Calendar.MILLISECOND );
+                fraction /= 60;
+
+                if ( fraction > 0 )
+                {
+                    if ( fractionDelimiter == FractionDelimiter.COMMA )
+                    {
+                        result[pos++] = ',';
+                    }
+                    else
+                    {
+                        result[pos++] = '.';
+                    }
+
+                    // At this point, the fraction should be in [999, 1]
+                    result[pos++] = ( byte ) ( ( fraction / 100 ) + '0' );
+                    fraction %= 100;
+
+                    if ( fraction > 0 )
+                    {
+                        result[pos++] = ( byte ) ( ( fraction / 10 ) + '0' );
+
+                        if ( fraction > 0 )
+                        {
+                            result[pos++] = ( byte ) ( ( fraction % 10 ) + '0' );
+                        }
+                    }
+                }
+
+                break;
+
+            case YEAR_MONTH_DAY_HOUR:
+                // nothing to add
+                break;
+
+            case YEAR_MONTH_DAY_HOUR_FRACTION:
+                // min + sec + millis => fraction of an hour
+                fraction = 1000 * 60 * clonedCalendar.get( Calendar.MINUTE ) + 1000
+                    * clonedCalendar.get( Calendar.SECOND )
+                    + clonedCalendar.get( Calendar.MILLISECOND );
+                fraction /= 60 * 60;
+
+                // At this point, the fraction should be in [999, 1]
+                if ( fraction > 0 )
+                {
+                    if ( fractionDelimiter == FractionDelimiter.COMMA )
+                    {
+                        result[pos++] = ',';
+                    }
+                    else
+                    {
+                        result[pos++] = '.';
+                    }
+
+                    result[pos++] = ( byte ) ( ( fraction / 100 ) + '0' );
+                    fraction %= 100;
+
+                    if ( fraction > 0 )
+                    {
+                        result[pos++] = ( byte ) ( ( fraction / 10 ) + '0' );
+
+                        if ( fraction > 0 )
+                        {
+                            result[pos++] = ( byte ) ( ( fraction % 10 ) + '0' );
+                        }
+                    }
+                }
+
+                break;
+
+            default:
+                throw new IllegalArgumentException( "Unexpected format " + format );
+        }
+
+        if ( ( timeZoneFormat == TimeZoneFormat.Z ) && clonedCalendar.getTimeZone().hasSameRules( GMT ) )
+        {
+            result[pos++] = 'Z';
+        }
+        else
+        {
+            // g-differential
+            TimeZone timeZone = clonedCalendar.getTimeZone();
+            int rawOffset = timeZone.getRawOffset();
+
+            if ( rawOffset < 0 )
+            {
+                result[pos++] = '-';
+            }
+            else
+            {
+                result[pos++] = '+';
+            }
+
+            rawOffset = Math.abs( rawOffset );
+            hour = rawOffset / ( 60 * 60 * 1000 );
+            int minute = ( rawOffset - ( hour * 60 * 60 * 1000 ) ) / ( 1000 * 60 );
+
+            // The offset hour
+            result[pos++] = ( byte ) ( ( hour / 10 ) + '0' );
+
+            result[pos++] = ( byte ) ( ( hour % 10 ) + '0' );
+
+            if ( ( timeZoneFormat == TimeZoneFormat.DIFF_HOUR_MINUTE ) || ( timeZoneFormat == TimeZoneFormat.Z ) )
+            {
+                // The offset minute
+                result[pos++] = ( byte ) ( ( minute / 10 ) + '0' );
+
+                result[pos++] = ( byte ) ( ( minute % 10 ) + '0' );
+            }
+        }
+
+        return Strings.utf8ToString( result, 0, pos );
+    }
+
+
+    /**
+     * Gets the calendar. It could be used to manipulate this 
+     * {@link GeneralizedTime} settings.
+     * 
+     * @return the calendar
+     */
+    public Calendar getCalendar()
+    {
+        return calendar;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return toGeneralizedTime();
+    }
+
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + calendar.hashCode();
+        return result;
+    }
+
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj instanceof GeneralizedTime )
+        {
+            GeneralizedTime other = ( GeneralizedTime ) obj;
+            return calendar.equals( other.calendar );
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Compares this GeneralizedTime object with the specified GeneralizedTime object.
+     * 
+     * @param other the other GeneralizedTime object
+     * 
+     * @return a negative integer, zero, or a positive integer as this object
+     *      is less than, equal to, or greater than the specified object.
+     * 
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo( GeneralizedTime other )
+    {
+        return calendar.compareTo( other.calendar );
+    }
+
+
+    public long getTime()
+    {
+        return calendar.getTimeInMillis();
+    }
+
+
+    public Date getDate()
+    {
+        return calendar.getTime();
+    }
+
+
+    public int getYear()
+    {
+        return calendar.get( Calendar.YEAR );
+    }
+
+
+    public int getMonth()
+    {
+        return calendar.get( Calendar.MONTH );
+    }
+
+
+    public int getDay()
+    {
+        return calendar.get( Calendar.DATE );
+    }
+
+
+    public int getHour()
+    {
+        return calendar.get( Calendar.HOUR_OF_DAY );
+    }
+
+
+    public int getMinutes()
+    {
+        return calendar.get( Calendar.MINUTE );
+    }
+
+
+    public int getSeconds()
+    {
+        return calendar.get( Calendar.SECOND );
+    }
+
+
+    public int getFraction()
+    {
+        return calendar.get( Calendar.MILLISECOND );
+    }
+
+
+    /**
+     * 
+     *
+     * @param zuluTime
+     * @return
+     */
+    public static Date getDate( String zuluTime ) throws ParseException
+    {
+        return new GeneralizedTime( zuluTime ).calendar.getTime();
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/Hex.java b/trunk/util/src/main/java/org/apache/directory/api/util/Hex.java
new file mode 100644
index 0000000..218717f
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/Hex.java
@@ -0,0 +1,238 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.util;
+
+
+import javax.naming.InvalidNameException;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Various hex and string manipulation methods that are more efficient then
+ * chaining operations: all is done in the same buffer without creating a bunch
+ * of intermediate String objects.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Hex
+{
+    /** &lt;hex> ::= [0x30-0x39] | [0x41-0x46] | [0x61-0x66] */
+    private static final byte[] HEX_VALUE =
+        {
+            // 00 -> 0F
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            // 10 -> 1F
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            // 20 -> 2F
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            // 30 -> 3F ( 0, 1,2, 3, 4,5, 6, 7, 8, 9 )
+             0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, 
+             // 40 -> 4F ( A, B, C, D, E, F )
+            -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+            // 50 -> 5F
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+            // 60 -> 6F ( a, b, c, d, e, f )
+            -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+            // 70 -> 7F
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+    };
+
+    /** Used to build output as Hex */
+    private static final char[] HEX_CHAR =
+        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+
+    private Hex()
+    {
+    }
+
+
+    /**
+     * Translate two chars to an hex value. The chars must be
+     * in [a-fA-F0-9]
+     *
+     * @param high The high value
+     * @param low The low value
+     * @return A byte representation of the two chars
+     */
+    public static byte getHexValue( char high, char low )
+    {
+        if ( ( high > 127 ) || ( low > 127 ) )
+        {
+            return -1;
+        }
+
+        return ( byte ) ( ( HEX_VALUE[high] << 4 ) | HEX_VALUE[low] );
+    }
+
+
+    /**
+     * Translate two bytes to an hex value. The bytes must be
+     * in [0-9a-fA-F]
+     *
+     * @param high The high value
+     * @param low The low value
+     * @return A byte representation of the two bytes
+     */
+    public static byte getHexValue( byte high, byte low )
+    {
+        if ( ( ( high & 0x7F ) != high ) || ( ( low & 0x7F ) != low ) )
+        {
+            return -1;
+        }
+
+        return ( byte ) ( ( HEX_VALUE[high] << 4 ) | HEX_VALUE[low] );
+    }
+
+
+    /**
+     * Return an hex value from a single char
+     * The char must be in [0-9a-fA-F]
+     *
+     * @param c The char we want to convert
+     * @return A byte between 0 and 15
+     */
+    public static byte getHexValue( char c )
+    {
+        if ( c > 127 )
+        {
+            return -1;
+        }
+
+        return HEX_VALUE[c];
+    }
+
+
+    /**
+     * Decodes values of attributes in the DN encoded in hex into a UTF-8
+     * String.  RFC2253 allows a DN's attribute to be encoded in hex.
+     * The encoded value starts with a # then is followed by an even
+     * number of hex characters.
+     *
+     * @param str the string to decode
+     * @return the decoded string
+     * @throws InvalidNameException
+     */
+    public static String decodeHexString( String str ) throws InvalidNameException
+    {
+        if ( str == null || str.length() == 0 )
+        {
+            throw new InvalidNameException( I18n.err( I18n.ERR_04431 ) );
+        }
+
+        char[] chars = str.toCharArray();
+
+        if ( chars[0] != '#' )
+        {
+            throw new InvalidNameException( I18n.err( I18n.ERR_04432, str ) );
+        }
+
+        // the bytes representing the encoded string of hex
+        // this should be ( length - 1 )/2 in size
+        byte[] decoded = new byte[( chars.length - 1 ) >> 1];
+
+        for ( int ii = 1, jj = 0; ii < chars.length; ii += 2, jj++ )
+        {
+            int ch = ( HEX_VALUE[chars[ii]] << 4 )
+                + HEX_VALUE[chars[ii + 1]];
+            decoded[jj] = ( byte ) ch;
+        }
+
+        return Strings.utf8ToString( decoded );
+    }
+
+
+    /**
+     * Convert an escaoed list of bytes to a byte[]
+     *
+     * @param str the string containing hex escapes
+     * @return the converted byte[]
+     */
+    public static byte[] convertEscapedHex( String str ) throws InvalidNameException
+    {
+        if ( str == null )
+        {
+            throw new InvalidNameException( I18n.err( I18n.ERR_04433 ) );
+        }
+
+        int length = str.length();
+
+        if ( length == 0 )
+        {
+            throw new InvalidNameException( I18n.err( I18n.ERR_04434 ) );
+        }
+
+        // create buffer and add everything before start of scan
+        byte[] buf = new byte[str.length() / 3];
+        int pos = 0;
+
+        // start scaning until we find an escaped series of bytes
+        for ( int i = 0; i < length; i++ )
+        {
+            char c = str.charAt( i );
+
+            if ( c == '\\' )
+            {
+                // we have the start of a hex escape sequence
+                if ( Chars.isHex( str, i + 1 ) && Chars.isHex( str, i + 2 ) )
+                {
+                    byte value = ( byte ) ( ( HEX_VALUE[str.charAt( i + 1 )] << 4 )
+                        + HEX_VALUE[str.charAt( i + 2 )] );
+
+                    i += 2;
+                    buf[pos++] = value;
+                }
+            }
+            else
+            {
+                throw new InvalidNameException( I18n.err( I18n.ERR_04435 ) );
+            }
+        }
+
+        return buf;
+    }
+
+
+    /**
+     * Converts an array of bytes into an array of characters representing the
+     * hexadecimal values of each byte in order. The returned array will be
+     * double the length of the passed array, as it takes two characters to
+     * represent any given byte.
+     *
+     * @param data a byte[] to convert to Hex characters
+     * @return A char[] containing hexadecimal characters
+     */
+    public static char[] encodeHex( byte[] data )
+    {
+        int l = data.length;
+
+        char[] out = new char[l << 1];
+
+        // two characters form the hex value.
+        for ( int i = 0, j = 0; i < l; i++ )
+        {
+            out[j++] = HEX_CHAR[( 0xF0 & data[i] ) >>> 4];
+            out[j++] = HEX_CHAR[0x0F & data[i]];
+        }
+
+        return out;
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/KeyValue.java b/trunk/util/src/main/java/org/apache/directory/api/util/KeyValue.java
new file mode 100644
index 0000000..fb5c413
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/KeyValue.java
@@ -0,0 +1,50 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ */

+package org.apache.directory.api.util;

+

+

+/**

+ * Defines a simple key value pair.

+ * <p>

+ * A Map Entry has considerable additional semantics over and above a simple

+ * key-value pair. This interface defines the minimum key value, with just the

+ * two get methods.

+ *

+ * @since Commons Collections 3.0

+ * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $

+ * 

+ * @author Stephen Colebourne

+ */

+public interface KeyValue

+{

+

+    /**

+     * Gets the key from the pair.

+     *

+     * @return the key 

+     */

+    Object getKey();

+

+

+    /**

+     * Gets the value from the pair.

+     *

+     * @return the value

+     */

+    Object getValue();

+

+}

diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/MandatoryAndOptionalComponentsMonitor.java b/trunk/util/src/main/java/org/apache/directory/api/util/MandatoryAndOptionalComponentsMonitor.java
new file mode 100644
index 0000000..47ed9be
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/MandatoryAndOptionalComponentsMonitor.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util;
+
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A monitor that tracks both, mandatory and optional components.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MandatoryAndOptionalComponentsMonitor implements ComponentsMonitor
+{
+
+    /** The mandatory components monitor. */
+    private ComponentsMonitor mandatoryComponentsMonitor;
+
+    /** The optional components monitor. */
+    private ComponentsMonitor optionalComponentsMonitor;
+
+
+    /**
+     * Instantiates a new mandatory and optional components monitor. The mandatory and optional
+     * components must be disjunct.
+     *
+     * @param mandatoryComponents the mandatory components
+     * @param optionalComponents the optional components
+     * @throws IllegalArgumentException if the same component is defined as mandatory and optional
+     */
+    public MandatoryAndOptionalComponentsMonitor( String[] mandatoryComponents, String[] optionalComponents )
+        throws IllegalArgumentException
+    {
+        // check for common elements
+        for ( int i = 0; i < mandatoryComponents.length; i++ )
+        {
+            for ( int j = 0; j < optionalComponents.length; j++ )
+            {
+                if ( mandatoryComponents[i].equals( optionalComponents[j] ) )
+                {
+                    throw new IllegalArgumentException( I18n.err( I18n.ERR_04415, mandatoryComponents[i] ) );
+                }
+            }
+        }
+
+        mandatoryComponentsMonitor = new MandatoryComponentsMonitor( mandatoryComponents );
+        optionalComponentsMonitor = new OptionalComponentsMonitor( optionalComponents );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ComponentsMonitor useComponent( String component )
+    {
+        try
+        {
+            mandatoryComponentsMonitor.useComponent( component );
+        }
+        catch ( IllegalArgumentException e1 )
+        {
+            try
+            {
+                optionalComponentsMonitor.useComponent( component );
+            }
+            catch ( IllegalArgumentException e2 )
+            {
+                throw new IllegalArgumentException( I18n.err( I18n.ERR_04416, component ), e1 );
+            }
+        }
+
+        return this;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean allComponentsUsed()
+    {
+        return ( mandatoryComponentsMonitor.allComponentsUsed() && optionalComponentsMonitor.allComponentsUsed() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean finalStateValid()
+    {
+        return ( mandatoryComponentsMonitor.finalStateValid() && optionalComponentsMonitor.finalStateValid() );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<String> getRemainingComponents()
+    {
+        List<String> remainingComponents = new LinkedList<String>();
+
+        remainingComponents.addAll( mandatoryComponentsMonitor.getRemainingComponents() );
+        remainingComponents.addAll( optionalComponentsMonitor.getRemainingComponents() );
+
+        return Collections.unmodifiableList( remainingComponents );
+    }
+
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/MandatoryComponentsMonitor.java b/trunk/util/src/main/java/org/apache/directory/api/util/MandatoryComponentsMonitor.java
new file mode 100644
index 0000000..2f720ac
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/MandatoryComponentsMonitor.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util;
+
+
+/**
+ * A components monitor for manadatory components.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MandatoryComponentsMonitor extends AbstractSimpleComponentsMonitor
+{
+
+    /**
+     * Instantiates a new mandatory components monitor.
+     *
+     * @param components the components
+     */
+    public MandatoryComponentsMonitor( String[] components )
+    {
+        super( components );
+    }
+
+
+    /**
+     * Checks if the final state is valid. As all components are mandatory it checks 
+     * whether all components are used.
+     * 
+     * @return true if all components are used
+     */
+    public boolean finalStateValid()
+    {
+        return allComponentsUsed();
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/MethodUtils.java b/trunk/util/src/main/java/org/apache/directory/api/util/MethodUtils.java
new file mode 100644
index 0000000..283662b
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/MethodUtils.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class MethodUtils
+{
+    /** The logger. */
+    private static final Logger LOG = LoggerFactory.getLogger( MethodUtils.class );
+
+
+    /**
+     * Private constructor.
+     */
+    private MethodUtils()
+    {
+    }
+
+
+    /**
+     * A replacement for {@link java.lang.Class#getMethod} with extended capability.
+     * 
+     * <p>
+     * This method returns parameter-list assignment-compatible method as well as
+     * exact-signature matching method.
+     * 
+     * @param clazz The class which will be queried for the method.
+     * @param candidateMethodName Name of the method been looked for.
+     * @param candidateParameterTypes Types of the parameters in the signature of the method being loooked for.
+     * @return The Method found.
+     * @throws NoSuchMethodException when the method cannot be found
+     */
+    public static Method getAssignmentCompatibleMethod( Class<?> clazz,
+        String candidateMethodName,
+        Class<?>[] candidateParameterTypes
+        ) throws NoSuchMethodException
+    {
+        if ( LOG.isDebugEnabled() )
+        {
+            StringBuilder buf = new StringBuilder();
+            buf.append( "call to getAssignmentCompatibleMethod(): \n\tclazz = " );
+            buf.append( clazz.getName() );
+            buf.append( "\n\tcandidateMethodName = " );
+            buf.append( candidateMethodName );
+            buf.append( "\n\tcandidateParameterTypes = " );
+
+            for ( Class<?> argClass : candidateParameterTypes )
+            {
+                buf.append( "\n\t\t" );
+                buf.append( argClass.getName() );
+            }
+
+            LOG.debug( buf.toString() );
+        }
+
+        try
+        {
+            // Look for exactly the same signature.
+            Method exactMethod = clazz.getMethod( candidateMethodName, candidateParameterTypes );
+
+            if ( exactMethod != null )
+            {
+                return exactMethod;
+            }
+        }
+        catch ( Exception e )
+        {
+            LOG.info( "Could not find accessible exact match for candidateMethod {}", candidateMethodName, e );
+        }
+
+        /**
+         * Look for the assignment-compatible signature.
+         */
+
+        // Get all methods of the class.
+        Method[] methods = clazz.getMethods();
+
+        // For each method of the class...
+        for ( int mx = 0; mx < methods.length; mx++ )
+        {
+            // If the method name does not match...
+            if ( !candidateMethodName.equals( methods[mx].getName() ) )
+            {
+                // ... Go on with the next method.
+                continue;
+            }
+
+            // ... Get parameter types list.
+            Class<?>[] parameterTypes = methods[mx].getParameterTypes();
+
+            // If parameter types list length mismatch...
+            if ( parameterTypes.length != candidateParameterTypes.length )
+            {
+                // ... Go on with the next method.
+                continue;
+            }
+            // If parameter types list length is OK...
+            // ... For each parameter of the method...
+            for ( int px = 0; px < parameterTypes.length; px++ )
+            {
+                // ... If the parameter is not assignment-compatible with the candidate parameter type...
+                if ( !parameterTypes[px].isAssignableFrom( candidateParameterTypes[px] ) )
+                {
+                    // ... Go on with the next method.
+                    break;
+                }
+            }
+
+            // Return the only one possible and found method.
+            return methods[mx];
+        }
+
+        throw new NoSuchMethodException( clazz.getName() + "." + candidateMethodName
+            + "(" + Arrays.toString( candidateParameterTypes ) + ")" );
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/NoDuplicateKeysMap.java b/trunk/util/src/main/java/org/apache/directory/api/util/NoDuplicateKeysMap.java
new file mode 100644
index 0000000..64a35a6
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/NoDuplicateKeysMap.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util;
+
+
+import java.util.HashMap;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A Map implementation derived from HashMap that only overrides a single method
+ * put() in order to prevent duplicate keyed entries to be added.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("rawtypes")
+public class NoDuplicateKeysMap extends HashMap
+{
+    /**
+     * Overrides java.util.Map.put(java.lang.Object, java.lang.Object) to
+     * prevent duplicate keys.
+     * 
+     * @see java.util.Map#put(java.lang.Object, java.lang.Object)
+     */
+    @SuppressWarnings("unchecked")
+    public Object put( Object key, Object value ) throws IllegalArgumentException
+    {
+        if ( containsKey( key ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04422 ) );
+        }
+        else
+        {
+            return super.put( key, value );
+        }
+    }
+
+    // add a serial version uid, so that if we change things in the future
+    // without changing the format, we can still deserialize properly.
+    private static final long serialVersionUID = 5107433500719957457L;
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/OptionalComponentsMonitor.java b/trunk/util/src/main/java/org/apache/directory/api/util/OptionalComponentsMonitor.java
new file mode 100644
index 0000000..81a6208
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/OptionalComponentsMonitor.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util;
+
+
+/**
+ * A components monitor for optional components.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OptionalComponentsMonitor extends AbstractSimpleComponentsMonitor
+{
+
+    /**
+     * Instantiates a new optional components monitor.
+     *
+     * @param components the components
+     */
+    public OptionalComponentsMonitor( String[] components )
+    {
+        super( components );
+    }
+
+
+    /**
+     * Checks if the final state is valid. As all components are optional this
+     * implementation always returns true.
+     * 
+     * @return always true
+     */
+    public boolean finalStateValid()
+    {
+        return true;
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/OsgiUtils.java b/trunk/util/src/main/java/org/apache/directory/api/util/OsgiUtils.java
new file mode 100644
index 0000000..d4190f8
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/OsgiUtils.java
@@ -0,0 +1,230 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.util;
+
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Utilities for OSGi environments and embedding OSGi containers.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class OsgiUtils
+{
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( OsgiUtils.class );
+
+
+    /**
+     * All the packages that are exported from all bundles found on the system
+     * classpath. The provided filter if not null is used to prune classpath
+     * elements. Any uses terms found are stripped from the bundles.
+     *
+     * @return All the exported packages of all bundles on the classpath.
+     */
+    public static Set<String> getAllBundleExports( FileFilter filter, Set<String> pkgs )
+    {
+        if ( pkgs == null )
+        {
+            pkgs = new HashSet<String>();
+        }
+
+        Set<File> candidates = getClasspathCandidates( filter );
+
+        for ( File candidate : candidates )
+        {
+            String exports = getBundleExports( candidate );
+
+            if ( exports == null )
+            {
+                LOG.debug( "No export found for candidate: {}", candidate );
+                continue;
+            }
+
+            LOG.debug( "Processing exports for candidate: {}\n\n{}\n", candidate, exports );
+            splitIntoPackages( exports, pkgs );
+        }
+
+        return pkgs;
+    }
+
+
+    /**
+     * Splits an Package-Export OSGi Manifest Attribute value into packages
+     * while stripping away the key/value properties.
+     *
+     * @param exports The Package-Export OSGi Manifest Attribute value.
+     * @return The set of exported packages without properties.
+     */
+    public static Set<String> splitIntoPackages( String exports, Set<String> pkgs )
+    {
+        if ( pkgs == null )
+        {
+            pkgs = new HashSet<String>();
+        }
+
+        int index = 0;
+        boolean inPkg = true;
+        boolean inProps = false;
+        StringBuilder pkg = new StringBuilder();
+
+        while ( index < exports.length() )
+        {
+            if ( inPkg && exports.charAt( index ) != ';' )
+            {
+                pkg.append( exports.charAt( index ) );
+                index++;
+            }
+            else if ( inPkg && exports.charAt( index ) == ';' )
+            {
+                inPkg = false;
+                inProps = true;
+
+                pkgs.add( pkg.toString() );
+                LOG.debug( "Added package: {}", pkg.toString() );
+                pkg.setLength( 0 );
+
+                index += 8;
+            }
+            else if ( inProps && exports.charAt( index ) == '"'
+                && index + 1 < exports.length()
+                && exports.charAt( index + 1 ) == ',' )
+            {
+                inPkg = true;
+                inProps = false;
+                index += 2;
+            }
+            else if ( inProps )
+            {
+                index++;
+            }
+            else
+            {
+                LOG.error( "Unexpected parser condition throwing IllegalStateException." );
+                throw new IllegalStateException( "Should never get here!" );
+            }
+        }
+
+        return pkgs;
+    }
+
+
+    public static Set<File> getClasspathCandidates( FileFilter filter )
+    {
+        Set<File> candidates = new HashSet<File>();
+        String separator = System.getProperty( "path.separator" );
+        String[] cpElements = System.getProperty( "java.class.path" ).split( separator );
+
+        for ( String element : cpElements )
+        {
+            File candidate = new File( element );
+
+            if ( candidate.isFile() )
+            {
+                if ( filter != null && filter.accept( candidate ) )
+                {
+                    candidates.add( candidate );
+                    LOG.info( "Accepted candidate with filter: {}", candidate.toString() );
+                }
+                else if ( filter == null && candidate.getName().endsWith( ".jar" ) )
+                {
+                    candidates.add( candidate );
+                    LOG.info( "Accepted candidate without filter: {}", candidate.toString() );
+                }
+                else
+                {
+                    LOG.info( "Rejecting candidate: {}", candidate.toString() );
+                }
+            }
+        }
+
+        return candidates;
+    }
+
+
+    /**
+     * Gets the attribute value for the Export-Bundle OSGi Manifest Attribute.
+     * 
+     * @param bundle The absolute path to a file bundle.
+     * @return The value as it appears in the Manifest, as a comma delimited
+     * list of packages with possible "uses" phrases appended to each package
+     * or null if the attribute does not exist.
+     */
+    public static String getBundleExports( File bundle )
+    {
+        JarFile jar = null;
+        try
+        {
+            jar = new JarFile( bundle );
+            Manifest manifest = jar.getManifest();
+
+            if ( manifest == null )
+            {
+                return null;
+            }
+
+            for ( Map.Entry<Object, Object> attr : manifest.getMainAttributes().entrySet() )
+            {
+                if ( attr.getKey().toString().equals( "Export-Package" ) )
+                {
+                    return attr.getValue().toString();
+                }
+            }
+
+            return null;
+        }
+        catch ( IOException e )
+        {
+            LOG.error( "Failed to open jar file or manifest.", e );
+            throw new RuntimeException( "Failed to open jar file or manifest.", e );
+        }
+        finally
+        {
+            if ( jar != null )
+            {
+                try
+                {
+                    jar.close();
+                }
+                catch ( IOException e )
+                {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+    private OsgiUtils()
+    {
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/Position.java b/trunk/util/src/main/java/org/apache/directory/api/util/Position.java
new file mode 100644
index 0000000..d9ce149
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/Position.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+/**
+ *
+ * This class is used to store the position of a token in a string.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ */
+public class Position
+{
+    /** The starting position in the string */
+    public int start = 0;
+
+    /** The current token length */
+    public int length = 0;
+
+    /** The token end position in the string */
+    public int end = 0;
+
+
+    public String toString()
+    {
+        return "[" + start + ", " + end + ", " + length + "]";
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/SequencedHashMap.java b/trunk/util/src/main/java/org/apache/directory/api/util/SequencedHashMap.java
new file mode 100644
index 0000000..5962d38
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/SequencedHashMap.java
@@ -0,0 +1,1292 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * A map of objects whose mapping entries are sequenced based on the order in
+ * which they were added. This data structure has fast <i>O(1)</i> search time,
+ * deletion time, and insertion time.
+ * <p>
+ * Although this map is sequenced, it cannot implement {@link java.util.List}
+ * because of incompatible interface definitions. The remove methods in List and
+ * Map have different return values (see: {@link java.util.List#remove(Object)}
+ * and {@link java.util.Map#remove(Object)}).
+ * <p>
+ * This class is not thread safe. When a thread safe implementation is required,
+ * use {@link java.util.Collections#synchronizedMap(Map)} as it is documented,
+ * or use explicit synchronization controls.
+ * 
+ * @since Commons Collections 2.0
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@SuppressWarnings("rawtypes")
+public class SequencedHashMap implements Map, Cloneable, Externalizable
+{
+
+    /**
+     * {@link java.util.Map.Entry} that doubles as a node in the linked list of
+     * sequenced mappings.
+     */
+    private static class Entry implements Map.Entry, KeyValue
+    {
+        // Note: This class cannot easily be made clonable. While the actual
+        // implementation of a clone would be simple, defining the semantics is
+        // difficult. If a shallow clone is implemented, then entry.next.prev !=
+        // entry, which is un-intuitive and probably breaks all sorts of
+        // assumptions
+        // in code that uses this implementation. If a deep clone is
+        // implemented, then what happens when the linked list is cyclical (as
+        // is
+        // the case with SequencedHashMap)? It's impossible to know in the clone
+        // when to stop cloning, and thus you end up in a recursive loop,
+        // continuously cloning the "next" in the list.
+
+        private final Object key;
+
+        private Object value;
+
+        // package private to allow the SequencedHashMap to access and
+        // manipulate
+        // them.
+        Entry next = null;
+
+        Entry prev = null;
+
+
+        public Entry( Object key, Object value )
+        {
+            this.key = key;
+            this.value = value;
+        }
+
+
+        // per Map.Entry.getKey()
+        public Object getKey()
+        {
+            return this.key;
+        }
+
+
+        // per Map.Entry.getValue()
+        public Object getValue()
+        {
+            return this.value;
+        }
+
+
+        // per Map.Entry.setValue()
+        public Object setValue( Object newValue )
+        {
+            Object oldValue = this.value;
+            this.value = newValue;
+            return oldValue;
+        }
+
+
+        /**
+         * Compute the instance's hash code
+         * @return the instance's hash code 
+         */
+        public int hashCode()
+        {
+            // implemented per api docs for Map.Entry.hashCode()
+            return ( ( getKey() == null ? 0 : getKey().hashCode() ) ^ ( getValue() == null ? 0 : getValue().hashCode() ) );
+        }
+
+
+        public boolean equals( Object obj )
+        {
+            if ( obj == null )
+            {
+                return false;
+            }
+
+            if ( obj == this )
+            {
+                return true;
+            }
+
+            if ( !( obj instanceof Map.Entry ) )
+            {
+                return false;
+            }
+
+            Map.Entry other = ( Map.Entry ) obj;
+
+            // implemented per api docs for Map.Entry.equals(Object)
+            return ( ( getKey() == null ? other.getKey() == null : getKey().equals( other.getKey() ) ) && ( getValue() == null ? other
+                .getValue() == null
+                : getValue().equals( other.getValue() ) ) );
+        }
+
+
+        public String toString()
+        {
+            return "[" + getKey() + "=" + getValue() + "]";
+        }
+    }
+
+
+    /**
+     * Construct an empty sentinel used to hold the head (sentinel.next) and the
+     * tail (sentinel.prev) of the list. The sentinel has a <code>null</code>
+     * key and value.
+     */
+    private static Entry createSentinel()
+    {
+        Entry s = new Entry( null, null );
+        s.prev = s;
+        s.next = s;
+        return s;
+    }
+
+    /**
+     * Sentinel used to hold the head and tail of the list of entries.
+     */
+    private Entry sentinel;
+
+    /**
+     * Map of keys to entries
+     */
+    private HashMap entries;
+
+    /**
+     * Holds the number of modifications that have occurred to the map,
+     * excluding modifications made through a collection view's iterator (e.g.
+     * entrySet().iterator().remove()). This is used to create a fail-fast
+     * behavior with the iterators.
+     */
+    private transient long modCount = 0;
+
+
+    /**
+     * Construct a new sequenced hash map with default initial size and load
+     * factor.
+     */
+    public SequencedHashMap()
+    {
+        sentinel = createSentinel();
+        entries = new HashMap();
+    }
+
+
+    /**
+     * Construct a new sequenced hash map with the specified initial size and
+     * default load factor.
+     * 
+     * @param initialSize
+     *            the initial size for the hash table
+     * @see HashMap#HashMap(int)
+     */
+    public SequencedHashMap( int initialSize )
+    {
+        sentinel = createSentinel();
+        entries = new HashMap( initialSize );
+    }
+
+
+    /**
+     * Construct a new sequenced hash map with the specified initial size and
+     * load factor.
+     * 
+     * @param initialSize
+     *            the initial size for the hash table
+     * @param loadFactor
+     *            the load factor for the hash table.
+     * @see HashMap#HashMap(int,float)
+     */
+    public SequencedHashMap( int initialSize, float loadFactor )
+    {
+        sentinel = createSentinel();
+        entries = new HashMap( initialSize, loadFactor );
+    }
+
+
+    /**
+     * Construct a new sequenced hash map and add all the elements in the
+     * specified map. The order in which the mappings in the specified map are
+     * added is defined by {@link #putAll(Map)}.
+     */
+    public SequencedHashMap( Map m )
+    {
+        this();
+        putAll( m );
+    }
+
+
+    /**
+     * Removes an internal entry from the linked list. This does not remove it
+     * from the underlying map.
+     */
+    private void removeEntry( Entry entry )
+    {
+        entry.next.prev = entry.prev;
+        entry.prev.next = entry.next;
+    }
+
+
+    /**
+     * Inserts a new internal entry to the tail of the linked list. This does
+     * not add the entry to the underlying map.
+     */
+    private void insertEntry( Entry entry )
+    {
+        entry.next = sentinel;
+        entry.prev = sentinel.prev;
+        sentinel.prev.next = entry;
+        sentinel.prev = entry;
+    }
+
+
+    // per Map.size()
+
+    /**
+     * Implements {@link Map#size()}.
+     */
+    public int size()
+    {
+        // use the underlying Map's size since size is not maintained here.
+        return entries.size();
+    }
+
+
+    /**
+     * Implements {@link Map#isEmpty()}.
+     */
+    public boolean isEmpty()
+    {
+        // for quick check whether the map is entry, we can check the linked
+        // list
+        // and see if there's anything in it.
+        return sentinel.next == sentinel;
+    }
+
+
+    /**
+     * Implements {@link Map#containsKey(Object)}.
+     */
+    public boolean containsKey( Object key )
+    {
+        // pass on to underlying map implementation
+        return entries.containsKey( key );
+    }
+
+
+    /**
+     * Implements {@link Map#containsValue(Object)}.
+     */
+    public boolean containsValue( Object value )
+    {
+        // unfortunately, we cannot just pass this call to the underlying map
+        // because we are mapping keys to entries, not keys to values. The
+        // underlying map doesn't have an efficient implementation anyway, so
+        // this
+        // isn't a big deal.
+
+        // do null comparison outside loop so we only need to do it once. This
+        // provides a tighter, more efficient loop at the expense of slight
+        // code duplication.
+        if ( value == null )
+        {
+            for ( Entry pos = sentinel.next; pos != sentinel; pos = pos.next )
+            {
+                if ( pos.getValue() == null )
+                {
+                    return true;
+                }
+            }
+        }
+        else
+        {
+            for ( Entry pos = sentinel.next; pos != sentinel; pos = pos.next )
+            {
+                if ( value.equals( pos.getValue() ) )
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Implements {@link Map#get(Object)}.
+     */
+    public Object get( Object o )
+    {
+        // find entry for the specified key object
+        Entry entry = ( Entry ) entries.get( o );
+
+        if ( entry == null )
+        {
+            return null;
+        }
+
+        return entry.getValue();
+    }
+
+
+    /**
+     * Return the entry for the "oldest" mapping. That is, return the Map.Entry
+     * for the key-value pair that was first put into the map when compared to
+     * all the other pairings in the map. This behavior is equivalent to using
+     * <code>entrySet().iterator().next()</code>, but this method provides an
+     * optimized implementation.
+     * 
+     * @return The first entry in the sequence, or <code>null</code> if the
+     *         map is empty.
+     */
+    public Map.Entry getFirst()
+    {
+        // sentinel.next points to the "first" element of the sequence -- the
+        // head
+        // of the list, which is exactly the entry we need to return. We must
+        // test
+        // for an empty list though because we don't want to return the
+        // sentinel!
+        return ( isEmpty() ) ? null : sentinel.next;
+    }
+
+
+    /**
+     * Return the key for the "oldest" mapping. That is, return the key for the
+     * mapping that was first put into the map when compared to all the other
+     * objects in the map. This behavior is equivalent to using
+     * <code>getFirst().getKey()</code>, but this method provides a slightly
+     * optimized implementation.
+     * 
+     * @return The first key in the sequence, or <code>null</code> if the map
+     *         is empty.
+     */
+    public Object getFirstKey()
+    {
+        // sentinel.next points to the "first" element of the sequence -- the
+        // head
+        // of the list -- and the requisite key is returned from it. An empty
+        // list
+        // does not need to be tested. In cases where the list is empty,
+        // sentinel.next will point to the sentinel itself which has a null key,
+        // which is exactly what we would want to return if the list is empty (a
+        // nice convenient way to avoid test for an empty list)
+        return sentinel.next.getKey();
+    }
+
+
+    /**
+     * Return the value for the "oldest" mapping. That is, return the value for
+     * the mapping that was first put into the map when compared to all the
+     * other objects in the map. This behavior is equivalent to using
+     * <code>getFirst().getValue()</code>, but this method provides a
+     * slightly optimized implementation.
+     * 
+     * @return The first value in the sequence, or <code>null</code> if the
+     *         map is empty.
+     */
+    public Object getFirstValue()
+    {
+        // sentinel.next points to the "first" element of the sequence -- the
+        // head
+        // of the list -- and the requisite value is returned from it. An empty
+        // list does not need to be tested. In cases where the list is empty,
+        // sentinel.next will point to the sentinel itself which has a null
+        // value,
+        // which is exactly what we would want to return if the list is empty (a
+        // nice convenient way to avoid test for an empty list)
+        return sentinel.next.getValue();
+    }
+
+
+    /**
+     * Return the entry for the "newest" mapping. That is, return the Map.Entry
+     * for the key-value pair that was first put into the map when compared to
+     * all the other pairings in the map. The behavior is equivalent to:
+     * 
+     * <pre>
+     * Object obj = null;
+     * Iterator iter = entrySet().iterator();
+     * while ( iter.hasNext() )
+     * {
+     *     obj = iter.next();
+     * }
+     * return ( Map.Entry ) obj;
+     * </pre>
+     * 
+     * However, the implementation of this method ensures an O(1) lookup of the
+     * last key rather than O(n).
+     * 
+     * @return The last entry in the sequence, or <code>null</code> if the map
+     *         is empty.
+     */
+    public Map.Entry getLast()
+    {
+        // sentinel.prev points to the "last" element of the sequence -- the
+        // tail
+        // of the list, which is exactly the entry we need to return. We must
+        // test
+        // for an empty list though because we don't want to return the
+        // sentinel!
+        return ( isEmpty() ) ? null : sentinel.prev;
+    }
+
+
+    /**
+     * Return the key for the "newest" mapping. That is, return the key for the
+     * mapping that was last put into the map when compared to all the other
+     * objects in the map. This behavior is equivalent to using
+     * <code>getLast().getKey()</code>, but this method provides a slightly
+     * optimized implementation.
+     * 
+     * @return The last key in the sequence, or <code>null</code> if the map
+     *         is empty.
+     */
+    public Object getLastKey()
+    {
+        // sentinel.prev points to the "last" element of the sequence -- the
+        // tail
+        // of the list -- and the requisite key is returned from it. An empty
+        // list
+        // does not need to be tested. In cases where the list is empty,
+        // sentinel.prev will point to the sentinel itself which has a null key,
+        // which is exactly what we would want to return if the list is empty (a
+        // nice convenient way to avoid test for an empty list)
+        return sentinel.prev.getKey();
+    }
+
+
+    /**
+     * Return the value for the "newest" mapping. That is, return the value for
+     * the mapping that was last put into the map when compared to all the other
+     * objects in the map. This behavior is equivalent to using
+     * <code>getLast().getValue()</code>, but this method provides a slightly
+     * optimized implementation.
+     * 
+     * @return The last value in the sequence, or <code>null</code> if the map
+     *         is empty.
+     */
+    public Object getLastValue()
+    {
+        // sentinel.prev points to the "last" element of the sequence -- the
+        // tail
+        // of the list -- and the requisite value is returned from it. An empty
+        // list does not need to be tested. In cases where the list is empty,
+        // sentinel.prev will point to the sentinel itself which has a null
+        // value,
+        // which is exactly what we would want to return if the list is empty (a
+        // nice convenient way to avoid test for an empty list)
+        return sentinel.prev.getValue();
+    }
+
+
+    /**
+     * Implements {@link Map#put(Object, Object)}.
+     */
+    @SuppressWarnings("unchecked")
+    public Object put( Object key, Object value )
+    {
+        modCount++;
+
+        Object oldValue = null;
+
+        // lookup the entry for the specified key
+        Entry e = ( Entry ) entries.get( key );
+
+        // check to see if it already exists
+        if ( e != null )
+        {
+            // remove from list so the entry gets "moved" to the end of list
+            removeEntry( e );
+
+            // update value in map
+            oldValue = e.setValue( value );
+
+            // Note: We do not update the key here because its unnecessary. We
+            // only
+            // do comparisons using equals(Object) and we know the specified key
+            // and
+            // that in the map are equal in that sense. This may cause a problem
+            // if
+            // someone does not implement their hashCode() and/or equals(Object)
+            // method properly and then use it as a key in this map.
+        }
+        else
+        {
+            // add new entry
+            e = new Entry( key, value );
+            entries.put( key, e );
+        }
+        // assert(entry in map, but not list)
+
+        // add to list
+        insertEntry( e );
+
+        return oldValue;
+    }
+
+
+    /**
+     * Implements {@link Map#remove(Object)}.
+     */
+    public Object remove( Object key )
+    {
+        Entry e = removeImpl( key );
+        return ( e == null ) ? null : e.getValue();
+    }
+
+
+    /**
+     * Fully remove an entry from the map, returning the old entry or null if
+     * there was no such entry with the specified key.
+     */
+    private Entry removeImpl( Object key )
+    {
+        Entry e = ( Entry ) entries.remove( key );
+
+        if ( e == null )
+        {
+            return null;
+        }
+
+        modCount++;
+        removeEntry( e );
+
+        return e;
+    }
+
+
+    /**
+     * Adds all the mappings in the specified map to this map, replacing any
+     * mappings that already exist (as per {@link Map#putAll(Map)}). The order
+     * in which the entries are added is determined by the iterator returned
+     * from {@link Map#entrySet()} for the specified map.
+     * 
+     * @param t
+     *            the mappings that should be added to this map.
+     * @throws NullPointerException
+     *             if <code>t</code> is <code>null</code>
+     */
+    public void putAll( Map t )
+    {
+        Iterator iter = t.entrySet().iterator();
+        while ( iter.hasNext() )
+        {
+            Map.Entry entry = ( Map.Entry ) iter.next();
+            put( entry.getKey(), entry.getValue() );
+        }
+    }
+
+
+    /**
+     * Implements {@link Map#clear()}.
+     */
+    public void clear()
+    {
+        modCount++;
+
+        // remove all from the underlying map
+        entries.clear();
+
+        // and the list
+        sentinel.next = sentinel;
+        sentinel.prev = sentinel;
+    }
+
+
+    /**
+     * Implements {@link Map#equals(Object)}.
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj == null )
+        {
+            return false;
+        }
+
+        if ( obj == this )
+        {
+            return true;
+        }
+
+        if ( !( obj instanceof Map ) )
+        {
+            return false;
+        }
+
+        return entrySet().equals( ( ( Map ) obj ).entrySet() );
+    }
+
+
+    /**
+     * Implements {@link Map#hashCode()}.
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        return entrySet().hashCode();
+    }
+
+
+    /**
+     * Provides a string representation of the entries within the map. The
+     * format of the returned string may change with different releases, so this
+     * method is suitable for debugging purposes only. If a specific format is
+     * required, use {@link #entrySet()}.{@link Set#iterator() iterator()} and
+     * iterate over the entries in the map formatting them as appropriate.
+     */
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append( '[' );
+
+        for ( Entry pos = sentinel.next; pos != sentinel; pos = pos.next )
+        {
+            buf.append( pos.getKey() );
+            buf.append( '=' );
+            buf.append( pos.getValue() );
+
+            if ( pos.next != sentinel )
+            {
+                buf.append( ',' );
+            }
+        }
+
+        buf.append( ']' );
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Implements {@link Map#keySet()}.
+     */
+    public Set keySet()
+    {
+        return new AbstractSet()
+        {
+
+            // required impls
+            public Iterator iterator()
+            {
+                return new OrderedIterator( KEY );
+            }
+
+
+            public boolean remove( Object o )
+            {
+                Entry e = SequencedHashMap.this.removeImpl( o );
+                return ( e != null );
+            }
+
+
+            // more efficient impls than abstract set
+            public void clear()
+            {
+                SequencedHashMap.this.clear();
+            }
+
+
+            public int size()
+            {
+                return SequencedHashMap.this.size();
+            }
+
+
+            public boolean isEmpty()
+            {
+                return SequencedHashMap.this.isEmpty();
+            }
+
+
+            public boolean contains( Object o )
+            {
+                return SequencedHashMap.this.containsKey( o );
+            }
+
+        };
+    }
+
+
+    /**
+     * Implements {@link Map#values()}.
+     */
+    public Collection values()
+    {
+        return new AbstractCollection()
+        {
+            // required impl
+            public Iterator iterator()
+            {
+                return new OrderedIterator( VALUE );
+            }
+
+
+            public boolean remove( Object value )
+            {
+                // do null comparison outside loop so we only need to do it
+                // once. This
+                // provides a tighter, more efficient loop at the expense of
+                // slight
+                // code duplication.
+                if ( value == null )
+                {
+                    for ( Entry pos = sentinel.next; pos != sentinel; pos = pos.next )
+                    {
+                        if ( pos.getValue() == null )
+                        {
+                            SequencedHashMap.this.removeImpl( pos.getKey() );
+                            return true;
+                        }
+                    }
+                }
+                else
+                {
+                    for ( Entry pos = sentinel.next; pos != sentinel; pos = pos.next )
+                    {
+                        if ( value.equals( pos.getValue() ) )
+                        {
+                            SequencedHashMap.this.removeImpl( pos.getKey() );
+                            return true;
+                        }
+                    }
+                }
+
+                return false;
+            }
+
+
+            // more efficient impls than abstract collection
+            public void clear()
+            {
+                SequencedHashMap.this.clear();
+            }
+
+
+            public int size()
+            {
+                return SequencedHashMap.this.size();
+            }
+
+
+            public boolean isEmpty()
+            {
+                return SequencedHashMap.this.isEmpty();
+            }
+
+
+            public boolean contains( Object o )
+            {
+                return SequencedHashMap.this.containsValue( o );
+            }
+        };
+    }
+
+
+    /**
+     * Implements {@link Map#entrySet()}.
+     */
+    public Set entrySet()
+    {
+        return new AbstractSet()
+        {
+            // helper
+            private Entry findEntry( Object o )
+            {
+                if ( o == null )
+                {
+                    return null;
+                }
+
+                if ( !( o instanceof Map.Entry ) )
+                {
+                    return null;
+                }
+
+                Map.Entry e = ( Map.Entry ) o;
+                Entry entry = ( Entry ) entries.get( e.getKey() );
+
+                if ( entry != null && entry.equals( e ) )
+                {
+                    return entry;
+                }
+                else
+                {
+                    return null;
+                }
+            }
+
+
+            // required impl
+            public Iterator iterator()
+            {
+                return new OrderedIterator( ENTRY );
+            }
+
+
+            public boolean remove( Object o )
+            {
+                Entry e = findEntry( o );
+
+                if ( e == null )
+                {
+                    return false;
+                }
+
+                return SequencedHashMap.this.removeImpl( e.getKey() ) != null;
+            }
+
+
+            // more efficient impls than abstract collection
+            public void clear()
+            {
+                SequencedHashMap.this.clear();
+            }
+
+
+            public int size()
+            {
+                return SequencedHashMap.this.size();
+            }
+
+
+            public boolean isEmpty()
+            {
+                return SequencedHashMap.this.isEmpty();
+            }
+
+
+            public boolean contains( Object o )
+            {
+                return findEntry( o ) != null;
+            }
+        };
+    }
+
+    // constants to define what the iterator should return on "next"
+    private static final int KEY = 0;
+
+    private static final int VALUE = 1;
+
+    private static final int ENTRY = 2;
+
+    private static final int REMOVED_MASK = 0x80000000;
+
+    private class OrderedIterator implements Iterator
+    {
+        /**
+         * Holds the type that should be returned from the iterator. The value
+         * should be either KEY, VALUE, or ENTRY. To save a tiny bit of memory,
+         * this field is also used as a marker for when remove has been called
+         * on the current object to prevent a second remove on the same element.
+         * Essentially, if this value is negative (i.e. the bit specified by
+         * REMOVED_MASK is set), the current position has been removed. If
+         * positive, remove can still be called.
+         */
+        private int returnType;
+
+        /**
+         * Holds the "current" position in the iterator. When pos.next is the
+         * sentinel, we've reached the end of the list.
+         */
+        private Entry pos = sentinel;
+
+        /**
+         * Holds the expected modification count. If the actual modification
+         * count of the map differs from this value, then a concurrent
+         * modification has occurred.
+         */
+        private transient long expectedModCount = modCount;
+
+
+        /**
+         * Construct an iterator over the sequenced elements in the order in
+         * which they were added. The {@link #next()} method returns the type
+         * specified by <code>returnType</code> which must be either KEY,
+         * VALUE, or ENTRY.
+         */
+        public OrderedIterator( int returnType )
+        {
+            // Set the "removed" bit so that the iterator starts in a state
+            // where "next" must be called before "remove" will succeed.
+            this.returnType = returnType | REMOVED_MASK;
+        }
+
+
+        /**
+         * Returns whether there is any additional elements in the iterator to
+         * be returned.
+         * 
+         * @return <code>true</code> if there are more elements left to be
+         *         returned from the iterator; <code>false</code> otherwise.
+         */
+        public boolean hasNext()
+        {
+            return pos.next != sentinel;
+        }
+
+
+        /**
+         * Returns the next element from the iterator.
+         * 
+         * @return the next element from the iterator.
+         * @throws NoSuchElementException
+         *             if there are no more elements in the iterator.
+         * @throws ConcurrentModificationException
+         *             if a modification occurs in the underlying map.
+         */
+        public Object next()
+        {
+            if ( modCount != expectedModCount )
+            {
+                throw new ConcurrentModificationException();
+            }
+            if ( pos.next == sentinel )
+            {
+                throw new NoSuchElementException();
+            }
+
+            // clear the "removed" flag
+            returnType = returnType & ~REMOVED_MASK;
+
+            pos = pos.next;
+            switch ( returnType )
+            {
+                case KEY:
+                    return pos.getKey();
+                case VALUE:
+                    return pos.getValue();
+                case ENTRY:
+                    return pos;
+                default:
+                    // should never happen
+                    throw new Error( I18n.err( I18n.ERR_04425, returnType ) );
+            }
+
+        }
+
+
+        /**
+         * Removes the last element returned from the {@link #next()} method
+         * from the sequenced map.
+         * 
+         * @throws IllegalStateException
+         *             if there isn't a "last element" to be removed. That is,
+         *             if {@link #next()} has never been called, or if
+         *             {@link #remove()} was already called on the element.
+         * @throws ConcurrentModificationException
+         *             if a modification occurs in the underlying map.
+         */
+        public void remove()
+        {
+            if ( ( returnType & REMOVED_MASK ) != 0 )
+            {
+                throw new IllegalStateException( I18n.err( I18n.ERR_04426 ) );
+            }
+            if ( modCount != expectedModCount )
+            {
+                throw new ConcurrentModificationException();
+            }
+
+            SequencedHashMap.this.removeImpl( pos.getKey() );
+
+            // update the expected mod count for the remove operation
+            expectedModCount++;
+
+            // set the removed flag
+            returnType = returnType | REMOVED_MASK;
+        }
+    }
+
+
+    // APIs maintained from previous version of SequencedHashMap for backwards
+    // compatibility
+
+    /**
+     * Creates a shallow copy of this object, preserving the internal structure
+     * by copying only references. The keys and values themselves are not
+     * <code>clone()</code>'d. The cloned object maintains the same sequence.
+     * 
+     * @return A clone of this instance.
+     * @throws CloneNotSupportedException
+     *             if clone is not supported by a subclass.
+     */
+    public Object clone() throws CloneNotSupportedException
+    {
+        // yes, calling super.clone() silly since we're just blowing away all
+        // the stuff that super might be doing anyway, but for motivations on
+        // this, see:
+        // http://www.javaworld.com/javaworld/jw-01-1999/jw-01-object.html
+        SequencedHashMap map = ( SequencedHashMap ) super.clone();
+
+        // create new, empty sentinel
+        map.sentinel = createSentinel();
+
+        // create a new, empty entry map
+        // note: this does not preserve the initial capacity and load factor.
+        map.entries = new HashMap();
+
+        // add all the mappings
+        map.putAll( this );
+
+        // Note: We cannot just clone the hashmap and sentinel because we must
+        // duplicate our internal structures. Cloning those two will not clone
+        // all
+        // the other entries they reference, and so the cloned hash map will not
+        // be
+        // able to maintain internal consistency because there are two objects
+        // with
+        // the same entries. See discussion in the Entry implementation on why
+        // we
+        // cannot implement a clone of the Entry (and thus why we need to
+        // recreate
+        // everything).
+
+        return map;
+    }
+
+
+    /**
+     * Returns the Map.Entry at the specified index
+     * 
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the specified index is <code>&lt; 0</code> or
+     *             <code>&gt;</code> the size of the map.
+     */
+    private Map.Entry getEntry( int index )
+    {
+        Entry pos = sentinel;
+
+        if ( index < 0 )
+        {
+            throw new ArrayIndexOutOfBoundsException( I18n.err( I18n.ERR_04427, index ) );
+        }
+
+        // loop to one before the position
+        int i = -1;
+        while ( i < ( index - 1 ) && pos.next != sentinel )
+        {
+            i++;
+            pos = pos.next;
+        }
+        // pos.next is the requested position
+
+        // if sentinel is next, past end of list
+        if ( pos.next == sentinel )
+        {
+            throw new ArrayIndexOutOfBoundsException( I18n.err( I18n.ERR_04428, index, ( i + 1 ) ) );
+        }
+
+        return pos.next;
+    }
+
+
+    /**
+     * Gets the key at the specified index.
+     * 
+     * @param index
+     *            the index to retrieve
+     * @return the key at the specified index, or null
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the <code>index</code> is <code>&lt; 0</code> or
+     *             <code>&gt;</code> the size of the map.
+     */
+    public Object get( int index )
+    {
+        return getEntry( index ).getKey();
+    }
+
+
+    /**
+     * Gets the value at the specified index.
+     * 
+     * @param index
+     *            the index to retrieve
+     * @return the value at the specified index, or null
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the <code>index</code> is <code>&lt; 0</code> or
+     *             <code>&gt;</code> the size of the map.
+     */
+    public Object getValue( int index )
+    {
+        return getEntry( index ).getValue();
+    }
+
+
+    /**
+     * Gets the index of the specified key.
+     * 
+     * @param key
+     *            the key to find the index of
+     * @return the index, or -1 if not found
+     */
+    public int indexOf( Object key )
+    {
+        Entry e = ( Entry ) entries.get( key );
+        if ( e == null )
+        {
+            return -1;
+        }
+        int pos = 0;
+        while ( e.prev != sentinel )
+        {
+            pos++;
+            e = e.prev;
+        }
+        return pos;
+    }
+
+
+    /**
+     * Gets an iterator over the keys.
+     * 
+     * @return an iterator over the keys
+     */
+    public Iterator iterator()
+    {
+        return keySet().iterator();
+    }
+
+
+    /**
+     * Gets the last index of the specified key.
+     * 
+     * @param key
+     *            the key to find the index of
+     * @return the index, or -1 if not found
+     */
+    public int lastIndexOf( Object key )
+    {
+        // keys in a map are guaranteed to be unique
+        return indexOf( key );
+    }
+
+
+    /**
+     * Returns a List view of the keys rather than a set view. The returned list
+     * is unmodifiable. This is required because changes to the values of the
+     * list (using {@link java.util.ListIterator#set(Object)}) will effectively
+     * remove the value from the list and reinsert that value at the end of the
+     * list, which is an unexpected side effect of changing the value of a list.
+     * This occurs because changing the key, changes when the mapping is added
+     * to the map and thus where it appears in the list.
+     * <p>
+     * An alternative to this method is to use {@link #keySet()}
+     * 
+     * @see #keySet()
+     * @return The ordered list of keys.
+     */
+    @SuppressWarnings("unchecked")
+    public List sequence()
+    {
+        List l = new ArrayList( size() );
+        Iterator iter = keySet().iterator();
+        while ( iter.hasNext() )
+        {
+            l.add( iter.next() );
+        }
+
+        return Collections.unmodifiableList( l );
+    }
+
+
+    /**
+     * Removes the element at the specified index.
+     * 
+     * @param index
+     *            The index of the object to remove.
+     * @return The previous value corresponding the <code>key</code>, or
+     *         <code>null</code> if none existed.
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the <code>index</code> is <code>&lt; 0</code> or
+     *             <code>&gt;</code> the size of the map.
+     */
+    public Object remove( int index )
+    {
+        return remove( get( index ) );
+    }
+
+
+    // per Externalizable.readExternal(ObjectInput)
+
+    /**
+     * Deserializes this map from the given stream.
+     * 
+     * @param in
+     *            the stream to deserialize from
+     * @throws IOException
+     *             if the stream raises it
+     * @throws ClassNotFoundException
+     *             if the stream raises it
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        int size = in.readInt();
+        for ( int i = 0; i < size; i++ )
+        {
+            Object key = in.readObject();
+            Object value = in.readObject();
+            put( key, value );
+        }
+    }
+
+
+    /**
+     * Serializes this map to the given stream.
+     * 
+     * @param out
+     *            the stream to serialize to
+     * @throws IOException
+     *             if the stream raises it
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        out.writeInt( size() );
+        for ( Entry pos = sentinel.next; pos != sentinel; pos = pos.next )
+        {
+            out.writeObject( pos.getKey() );
+            out.writeObject( pos.getValue() );
+        }
+    }
+
+    // add a serial version uid, so that if we change things in the future
+    // without changing the format, we can still deserialize properly.
+    private static final long serialVersionUID = 3380552487888102930L;
+
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/Serialize.java b/trunk/util/src/main/java/org/apache/directory/api/util/Serialize.java
new file mode 100644
index 0000000..0a5c032
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/Serialize.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.directory.api.util;
+
+
+/**
+ * A class containing static methods used to serialize and deserialize base types
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Serialize
+{
+    public static final byte TRUE = 0x01;
+    public static final byte FALSE = 0x00;
+
+
+    private Serialize()
+    {
+    }
+
+
+    /**
+     * Write an integer into a buffer at a given position
+     * 
+     * @param value The value to serialize
+     * @param buffer The buffer to store the value into
+     * @param pos The position where we serialize the integer
+     */
+    public static int serialize( int value, byte[] buffer, int pos )
+    {
+        if ( buffer.length - pos < 4 )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        buffer[pos++] = ( byte ) ( ( value >>> 24 ) & 0xFF );
+        buffer[pos++] = ( byte ) ( ( value >>> 16 ) & 0xFF );
+        buffer[pos++] = ( byte ) ( ( value >>> 8 ) & 0xFF );
+        buffer[pos++] = ( byte ) ( ( value >>> 0 ) & 0xFF );
+
+        return pos;
+    }
+
+
+    /**
+     * Write a byte[] into a buffer at a given position
+     * 
+     * @param value The value to serialize
+     * @param buffer The buffer to store the value into
+     * @param pos The position where we serialize the byte[]
+     */
+    public static int serialize( byte[] value, byte[] buffer, int pos )
+    {
+        if ( buffer.length - pos < 4 + value.length )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        buffer[pos++] = ( byte ) ( ( value.length >>> 24 ) & 0xFF );
+        buffer[pos++] = ( byte ) ( ( value.length >>> 16 ) & 0xFF );
+        buffer[pos++] = ( byte ) ( ( value.length >>> 8 ) & 0xFF );
+        buffer[pos++] = ( byte ) ( ( value.length >>> 0 ) & 0xFF );
+
+        System.arraycopy( value, 0, buffer, pos, value.length );
+
+        return pos + value.length;
+    }
+
+
+    /**
+     * Read an integer from a buffer at a given position
+     * 
+     * @param buffer The buffer containing the serialized integer
+     * @param pos The position from which we will read an integer
+     * @return the deserialized integer
+     */
+    public static int deserializeInt( byte[] buffer, int pos )
+    {
+        if ( buffer.length - pos < 4 )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        return ( buffer[pos] << 24 ) + ( buffer[pos + 1] << 16 ) + ( buffer[pos + 2] << 8 ) + ( buffer[pos + 3] << 0 );
+    }
+
+
+    /**
+     * Read a byte[] from a buffer at a given position
+     * 
+     * @param buffer The buffer containing the serialized byte[]
+     * @param pos The position from which we will read a byte[]
+     * @return the deserialized byte[]
+     */
+    public static byte[] deserializeBytes( byte[] buffer, int pos )
+    {
+        if ( buffer.length - pos < 4 )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        int len = deserializeInt( buffer, pos );
+        pos += 4;
+
+        if ( len > 0 )
+        {
+            if ( buffer.length - pos < len )
+            {
+                throw new ArrayIndexOutOfBoundsException();
+            }
+
+            byte[] result = new byte[len];
+
+            System.arraycopy( buffer, pos, result, 0, len );
+
+            return result;
+        }
+        else
+        {
+            return Strings.EMPTY_BYTES;
+        }
+    }
+
+
+    /**
+     * Read a boolean from a buffer at a given position
+     * 
+     * @param buffer The buffer containing the serialized boolean
+     * @param pos The position from which we will read a boolean
+     * @return the deserialized boolean
+     */
+    public static boolean deserializeBoolean( byte[] buffer, int pos )
+    {
+        if ( buffer.length - pos < 1 )
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        byte value = buffer[pos];
+
+        return ( value != 0x00 );
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/SingletonEnumeration.java b/trunk/util/src/main/java/org/apache/directory/api/util/SingletonEnumeration.java
new file mode 100644
index 0000000..96a3077
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/SingletonEnumeration.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import javax.naming.NamingEnumeration;
+
+import java.util.NoSuchElementException;
+
+
+/**
+ * A NamingEnumeration over a single element.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SingletonEnumeration<T> implements NamingEnumeration<T>
+{
+    /** The singleton element to return */
+    private final T element;
+
+    /** Can we return a element */
+    private boolean hasMore = true;
+
+
+    /**
+     * Creates a NamingEnumeration over a single element.
+     * 
+     * @param element
+     *            TODO
+     */
+    public SingletonEnumeration( final T element )
+    {
+        this.element = element;
+    }
+
+
+    /**
+     * Makes calls to hasMore to false even if we had more.
+     * 
+     * @see javax.naming.NamingEnumeration#close()
+     */
+    public void close()
+    {
+        hasMore = false;
+    }
+
+
+    /**
+     * @see javax.naming.NamingEnumeration#hasMore()
+     */
+    public boolean hasMore()
+    {
+        return hasMore;
+    }
+
+
+    /**
+     * @see javax.naming.NamingEnumeration#next()
+     */
+    public T next()
+    {
+        if ( hasMore )
+        {
+            hasMore = false;
+            return element;
+        }
+
+        throw new NoSuchElementException();
+    }
+
+
+    /**
+     * @see java.util.Enumeration#hasMoreElements()
+     */
+    public boolean hasMoreElements()
+    {
+        return hasMore;
+    }
+
+
+    /**
+     * @see java.util.Enumeration#nextElement()
+     */
+    public T nextElement()
+    {
+        return next();
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/StringConstants.java b/trunk/util/src/main/java/org/apache/directory/api/util/StringConstants.java
new file mode 100644
index 0000000..6876964
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/StringConstants.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.util;
+
+
+/**
+ * Various String constants are kept here.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class StringConstants
+{
+    /**
+     * The empty String <code>""</code>.
+     *
+     * @since 2.0
+     */
+    public static final String EMPTY = "";
+    /**
+     * The empty byte[]
+     */
+    public static final byte[] EMPTY_BYTES = new byte[]
+        {};
+    /**
+     * The empty String[]
+     */
+    public static final String[] EMPTY_STRINGS = new String[]
+        {};
+    public static final int NOT_EQUAL = -1;
+
+
+    private StringConstants()
+    {
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/Strings.java b/trunk/util/src/main/java/org/apache/directory/api/util/Strings.java
new file mode 100644
index 0000000..12d711e
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/Strings.java
@@ -0,0 +1,2408 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.util;
+
+
+import static org.apache.directory.api.util.Chars.isHex;
+import static org.apache.directory.api.util.Hex.encodeHex;
+import static org.apache.directory.api.util.Hex.getHexValue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.directory.api.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Various string manipulation methods that are more efficient then chaining
+ * string operations: all is done in the same buffer without creating a bunch of
+ * string objects.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Strings
+{
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( Strings.class );
+
+    /** The default charset, because it's not provided by JDK 1.5 */
+    static String defaultCharset = null;
+
+    /** Hex chars */
+    private static final byte[] HEX_CHAR = new byte[]
+        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+    /** A table containing booleans when the corresponding char is printable */
+    private static final boolean[] IS_PRINTABLE_CHAR =
+        {
+            // ---, ---, ---, ---, ---, ---, ---, ---
+            false, false, false, false, false, false, false, false, 
+            // ---, ---, ---, ---, ---, ---, ---, ---
+            false, false, false, false, false, false, false, false, 
+            // ---, ---, ---, ---, ---, ---, ---, ---
+            false, false, false, false, false, false, false, false, 
+            // ---, ---, ---, ---, ---, ---, ---, ---
+            false, false, false, false, false, false, false, false, 
+            // ' ', ---, ---, ---, ---, ---, ---, "'"
+            true,  false, false, false, false, false, false, true,  
+            // '(', ')', ---, '+', ',', '-', '.', '/'
+            true,  true,  false, true,  true,  true,  true,  true,  
+            // '0', '1', '2', '3', '4', '5', '6', '7',
+            true,  true,  true,  true,  true,  true,  true,  true,  
+            // '8', '9', ':', ---, ---, '=', ---, '?'
+            true,  true,  true,  false, false, true,  false, true,  
+            // ---, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+            false, true,  true,  true,  true,  true,  true,  true,  
+            // 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'
+            true,  true,  true,  true,  true,  true,  true,  true,  
+            // 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W'
+            true,  true,  true,  true,  true,  true,  true,  true,  
+            // 'X', 'Y', 'Z', ---, ---, ---, ---, ---
+            true,  true,  true,  false, false, false, false, false, 
+            // ---, 'a', 'b', 'c', 'd', 'e', 'f', 'g'
+            false, true,  true,  true,  true,  true,  true,  true,  
+            // 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'
+            true,  true,  true,  true,  true,  true,  true,  true,  
+            // 'p', 'q', 'r', 's', 't', 'u', 'v', 'w'
+            true,  true,  true,  true,  true,  true,  true,  true, 
+            // 'x', 'y', 'z', ---, ---, ---, ---, ---
+            true,  true,  true,  false, false, false, false, false 
+    };
+
+    private static final char[] TO_LOWER_CASE =
+        {
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+            0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+            0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+            ' ',  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, '\'',
+            '(',  ')',  0x2A, '+',  ',',  '-',  '.',  '/',
+            '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
+            '8',  '9',  ':',  0x3B, 0x3C, '=',  0x3E, '?',
+            0x40, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
+            'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+            'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
+            'x',  'y',  'z',  0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+            0x60, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
+            'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+            'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
+            'x',  'y',  'z',  0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+            0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+            0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+            0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+            0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+            0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+            0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+            0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+            0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+            0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+            0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+            0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+            0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+            0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+            0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+            0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+    };
+
+    private static final byte[] TO_LOWER_CASE_BYTE =
+        {
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+            0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+            0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+            ' ',  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, '\'',
+            '(',  ')',  0x2A, '+',  ',',  '-',  '.',  '/',
+            '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
+            '8',  '9',  ':',  0x3B, 0x3C, '=',  0x3E, '?',
+            0x40, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
+            'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+            'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
+            'x',  'y',  'z',  0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+            0x60, 'a',  'b',  'c',  'd',  'e',  'f',  'g',
+            'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+            'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
+            'x',  'y',  'z',  0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+            ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83,
+            ( byte ) 0x84, ( byte ) 0x85, ( byte ) 0x86, ( byte ) 0x87,
+            ( byte ) 0x88, ( byte ) 0x89, ( byte ) 0x8A, ( byte ) 0x8B,
+            ( byte ) 0x8C, ( byte ) 0x8D, ( byte ) 0x8E, ( byte ) 0x8F,
+            ( byte ) 0x90, ( byte ) 0x91, ( byte ) 0x92, ( byte ) 0x93,
+            ( byte ) 0x94, ( byte ) 0x95, ( byte ) 0x96, ( byte ) 0x97,
+            ( byte ) 0x98, ( byte ) 0x99, ( byte ) 0x9A, ( byte ) 0x9B,
+            ( byte ) 0x9C, ( byte ) 0x9D, ( byte ) 0x9E, ( byte ) 0x9F,
+            ( byte ) 0xA0, ( byte ) 0xA1, ( byte ) 0xA2, ( byte ) 0xA3,
+            ( byte ) 0xA4, ( byte ) 0xA5, ( byte ) 0xA6, ( byte ) 0xA7,
+            ( byte ) 0xA8, ( byte ) 0xA9, ( byte ) 0xAA, ( byte ) 0xAB,
+            ( byte ) 0xAC, ( byte ) 0xAD, ( byte ) 0xAE, ( byte ) 0xAF,
+            ( byte ) 0xB0, ( byte ) 0xB1, ( byte ) 0xB2, ( byte ) 0xB3,
+            ( byte ) 0xB4, ( byte ) 0xB5, ( byte ) 0xB6, ( byte ) 0xB7,
+            ( byte ) 0xB8, ( byte ) 0xB9, ( byte ) 0xBA, ( byte ) 0xBB,
+            ( byte ) 0xBC, ( byte ) 0xBD, ( byte ) 0xBE, ( byte ) 0xBF,
+            ( byte ) 0xC0, ( byte ) 0xC1, ( byte ) 0xC2, ( byte ) 0xC3,
+            ( byte ) 0xC4, ( byte ) 0xC5, ( byte ) 0xC6, ( byte ) 0xC7,
+            ( byte ) 0xC8, ( byte ) 0xC9, ( byte ) 0xCA, ( byte ) 0xCB,
+            ( byte ) 0xCC, ( byte ) 0xCD, ( byte ) 0xCE, ( byte ) 0xCF,
+            ( byte ) 0xD0, ( byte ) 0xD1, ( byte ) 0xD2, ( byte ) 0xD3,
+            ( byte ) 0xD4, ( byte ) 0xD5, ( byte ) 0xD6, ( byte ) 0xD7,
+            ( byte ) 0xD8, ( byte ) 0xD9, ( byte ) 0xDA, ( byte ) 0xDB,
+            ( byte ) 0xDC, ( byte ) 0xDD, ( byte ) 0xDE, ( byte ) 0xDF,
+            ( byte ) 0xE0, ( byte ) 0xE1, ( byte ) 0xE2, ( byte ) 0xE3,
+            ( byte ) 0xE4, ( byte ) 0xE5, ( byte ) 0xE6, ( byte ) 0xE7,
+            ( byte ) 0xE8, ( byte ) 0xE9, ( byte ) 0xEA, ( byte ) 0xEB,
+            ( byte ) 0xEC, ( byte ) 0xED, ( byte ) 0xEE, ( byte ) 0xEF,
+            ( byte ) 0xF0, ( byte ) 0xF1, ( byte ) 0xF2, ( byte ) 0xF3,
+            ( byte ) 0xF4, ( byte ) 0xF5, ( byte ) 0xF6, ( byte ) 0xF7,
+            ( byte ) 0xF8, ( byte ) 0xF9, ( byte ) 0xFA, ( byte ) 0xFB,
+            ( byte ) 0xFC, ( byte ) 0xFD, ( byte ) 0xFE, ( byte ) 0xFF
+    };
+
+    /** upperCase = 'A' .. 'Z', '0'..'9', '-' */
+    private static final char[] UPPER_CASE =
+        {
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, '-', 0, 0,
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 0, 0, 0, 0, 0, 0,
+            0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+            'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+            'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+            'X', 'Y', 'Z', 0, 0, 0, 0, 0,
+            0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+            'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+            'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+            'X', 'Y', 'Z', 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0
+    };
+
+    /** An empty byte array */
+    public static final byte[] EMPTY_BYTES = new byte[0];
+    
+    /** An empty String */
+    public static final String EMPTY_STRING = "";
+
+
+    /**
+     * Private constructor
+     */
+    private Strings()
+    {
+    }
+
+
+    /**
+     * Helper function that dump an array of bytes in hex form
+     *
+     * @param buffer The bytes array to dump
+     * @return A string representation of the array of bytes
+     */
+    public static String dumpBytes( byte[] buffer )
+    {
+        if ( buffer == null )
+        {
+            return "";
+        }
+
+        StringBuffer sb = new StringBuffer();
+
+        for ( int i = 0; i < buffer.length; i++ )
+        {
+            sb.append( "0x" ).append( ( char ) ( HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4] ) ).append(
+                ( char ) ( HEX_CHAR[buffer[i] & 0x000F] ) ).append( " " );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Helper function that dump a byte in hex form
+     *
+     * @param octet The byte to dump
+     * @return A string representation of the byte
+     */
+    public static String dumpByte( byte octet )
+    {
+        return Strings.utf8ToString( new byte[]
+            { '0', 'x', HEX_CHAR[( octet & 0x00F0 ) >> 4], HEX_CHAR[octet & 0x000F] } );
+    }
+
+
+    /**
+     * Helper function that returns a char from an hex
+     *
+     * @param hex The hex to dump
+     * @return A char representation of the hex
+     */
+    public static char dumpHex( byte hex )
+    {
+        return ( char ) HEX_CHAR[hex & 0x000F];
+    }
+
+
+    /**
+     * Helper function that dump an array of bytes in hex pair form,
+     * without '0x' and space chars
+     *
+     * @param buffer The bytes array to dump
+     * @return A string representation of the array of bytes
+     */
+    public static String dumpHexPairs( byte[] buffer )
+    {
+        if ( buffer == null )
+        {
+            return "";
+        }
+
+        char[] str = new char[buffer.length << 1];
+
+        for ( int i = 0, pos = 0; i < buffer.length; i++ )
+        {
+            str[pos++] = ( char ) ( HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4] );
+            str[pos++] = ( char ) ( HEX_CHAR[buffer[i] & 0x000F] );
+        }
+
+        return new String( str );
+    }
+
+
+    /**
+     * Put common code to deepTrim(String) and deepTrimToLower here.
+     *
+     * @param str the string to deep trim
+     * @param toLowerCase how to normalize for case: upper or lower
+     * @return the deep trimmed string
+     * @see Strings#deepTrim( String )
+     *
+     * TODO Replace the toCharArray() by substring manipulations
+     */
+    public static String deepTrim( String str, boolean toLowerCase )
+    {
+        if ( ( null == str ) || ( str.length() == 0 ) )
+        {
+            return "";
+        }
+
+        char ch;
+        char[] buf = str.toCharArray();
+        char[] newbuf = new char[buf.length];
+        boolean wsSeen = false;
+        boolean isStart = true;
+        int pos = 0;
+
+        for ( int i = 0; i < str.length(); i++ )
+        {
+            ch = buf[i];
+
+            // filter out all uppercase characters
+            if ( toLowerCase && Character.isUpperCase( ch ) )
+            {
+                ch = Character.toLowerCase( ch );
+            }
+
+            // Check to see if we should add space
+            if ( Character.isWhitespace( ch ) )
+            {
+                // If the buffer has had characters added already check last
+                // added character. Only append a spc if last character was
+                // not whitespace.
+                if ( wsSeen )
+                {
+                    continue;
+                }
+                else
+                {
+                    wsSeen = true;
+
+                    if ( isStart )
+                    {
+                        isStart = false;
+                    }
+                    else
+                    {
+                        newbuf[pos++] = ch;
+                    }
+                }
+            }
+            else
+            {
+                // Add all non-whitespace
+                wsSeen = false;
+                isStart = false;
+                newbuf[pos++] = ch;
+            }
+        }
+
+        return ( pos == 0 ? "" : new String( newbuf, 0, ( wsSeen ? pos - 1 : pos ) ) );
+    }
+
+
+    /**
+     * This does the same thing as a trim but we also lowercase the string while
+     * performing the deep trim within the same buffer. This saves us from
+     * having to create multiple String and StringBuffer objects and is much
+     * more efficient.
+     *
+     * @see Strings#deepTrim( String )
+     */
+    public static String deepTrimToLower( String string )
+    {
+        return deepTrim( string, true );
+    }
+
+
+    /**
+     * A deep trim of a string remove whitespace from the ends as well as
+     * excessive whitespace within the inside of the string between
+     * non-whitespace characters. A deep trim reduces internal whitespace down
+     * to a single space to preserve the whitespace separated tokenization order
+     * of the String.
+     *
+     * @param string the string to deep trim.
+     * @return the trimmed string.
+     */
+    public static String deepTrim( String string )
+    {
+        return deepTrim( string, false );
+    }
+
+
+    /**
+     * Trims several consecutive characters into one.
+     *
+     * @param str the string to trim consecutive characters of
+     * @param ch the character to trim down
+     * @return the newly trimmed down string
+     */
+    public static String trimConsecutiveToOne( String str, char ch )
+    {
+        if ( ( null == str ) || ( str.length() == 0 ) )
+        {
+            return "";
+        }
+
+        char[] buffer = str.toCharArray();
+        char[] newbuf = new char[buffer.length];
+        int pos = 0;
+        boolean same = false;
+
+        for ( int i = 0; i < buffer.length; i++ )
+        {
+            char car = buffer[i];
+
+            if ( car == ch )
+            {
+                if ( same )
+                {
+                    continue;
+                }
+                else
+                {
+                    same = true;
+                    newbuf[pos++] = car;
+                }
+            }
+            else
+            {
+                same = false;
+                newbuf[pos++] = car;
+            }
+        }
+
+        return new String( newbuf, 0, pos );
+    }
+
+
+    /**
+     * Truncates large Strings showing a portion of the String's head and tail
+     * with the center cut out and replaced with '...'. Also displays the total
+     * length of the truncated string so size of '...' can be interpreted.
+     * Useful for large strings in UIs or hex dumps to log files.
+     *
+     * @param str the string to truncate
+     * @param head the amount of the head to display
+     * @param tail the amount of the tail to display
+     * @return the center truncated string
+     */
+    public static String centerTrunc( String str, int head, int tail )
+    {
+        StringBuffer buf = null;
+
+        // Return as-is if String is smaller than or equal to the head plus the
+        // tail plus the number of characters added to the trunc representation
+        // plus the number of digits in the string length.
+        if ( str.length() <= ( head + tail + 7 + str.length() / 10 ) )
+        {
+            return str;
+        }
+
+        buf = new StringBuffer();
+        buf.append( '[' ).append( str.length() ).append( "][" );
+        buf.append( str.substring( 0, head ) ).append( "..." );
+        buf.append( str.substring( str.length() - tail ) );
+        buf.append( ']' );
+        return buf.toString();
+    }
+
+
+    /**
+     * Gets a hex string from byte array.
+     *
+     * @param res the byte array
+     * @return the hex string representing the binary values in the array
+     */
+    public static String toHexString( byte[] res )
+    {
+        StringBuffer buf = new StringBuffer( res.length << 1 );
+
+        for ( int ii = 0; ii < res.length; ii++ )
+        {
+            String digit = Integer.toHexString( 0xFF & res[ii] );
+
+            if ( digit.length() == 1 )
+            {
+                digit = '0' + digit;
+            }
+
+            buf.append( digit );
+        }
+
+        return buf.toString().toUpperCase();
+    }
+
+
+    /**
+     * Get byte array from hex string
+     *
+     * @param hexString the hex string to convert to a byte array
+     * @return the byte form of the hex string.
+     */
+    public static byte[] toByteArray( String hexString )
+    {
+        int arrLength = hexString.length() >> 1;
+        byte[] buf = new byte[arrLength];
+
+        for ( int ii = 0; ii < arrLength; ii++ )
+        {
+            int index = ii << 1;
+
+            String digit = hexString.substring( index, index + 2 );
+            buf[ii] = ( byte ) Integer.parseInt( digit, 16 );
+        }
+
+        return buf;
+    }
+
+
+    /**
+     * This method is used to insert HTML block dynamically
+     *
+     * @param source the HTML code to be processes
+     * @param replaceNl if true '\n' will be replaced by &lt;br>
+     * @param replaceTag if true '<' will be replaced by &lt; and '>' will be replaced
+     *            by &gt;
+     * @param replaceQuote if true '\"' will be replaced by &quot;
+     * @return the formated html block
+     */
+    public static String formatHtml( String source, boolean replaceNl, boolean replaceTag,
+        boolean replaceQuote )
+    {
+        StringBuffer buf = new StringBuffer();
+        int len = source.length();
+
+        for ( int ii = 0; ii < len; ii++ )
+        {
+            char ch = source.charAt( ii );
+
+            switch ( ch )
+            {
+                case '\"':
+                    if ( replaceQuote )
+                    {
+                        buf.append( "&quot;" );
+                    }
+                    else
+                    {
+                        buf.append( ch );
+                    }
+                    break;
+
+                case '<':
+                    if ( replaceTag )
+                    {
+                        buf.append( "&lt;" );
+                    }
+                    else
+                    {
+                        buf.append( ch );
+                    }
+                    break;
+
+                case '>':
+                    if ( replaceTag )
+                    {
+                        buf.append( "&gt;" );
+                    }
+                    else
+                    {
+                        buf.append( ch );
+                    }
+                    break;
+
+                case '\n':
+                    if ( replaceNl )
+                    {
+                        if ( replaceTag )
+                        {
+                            buf.append( "&lt;br&gt;" );
+                        }
+                        else
+                        {
+                            buf.append( "<br>" );
+                        }
+                    }
+                    else
+                    {
+                        buf.append( ch );
+                    }
+                    break;
+
+                case '\r':
+                    break;
+
+                case '&':
+                    buf.append( "&amp;" );
+                    break;
+
+                default:
+                    buf.append( ch );
+                    break;
+            }
+        }
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Check if a text is present at the current position in another string.
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @param text The text we want to check
+     * @return <code>true</code> if the string contains the text.
+     */
+    public static boolean areEquals( String string, int index, String text )
+    {
+        if ( ( string == null ) || ( text == null ) )
+        {
+            return false;
+        }
+
+        int length1 = string.length();
+        int length2 = text.length();
+
+        if ( ( length1 == 0 ) || ( length1 <= index ) || ( index < 0 )
+            || ( length2 == 0 ) || ( length2 > ( length1 + index ) ) )
+        {
+            return false;
+        }
+        else
+        {
+            return string.substring( index ).startsWith( text );
+        }
+    }
+
+
+    /**
+     * Test if the current character is equal to a specific character. This
+     * function works only for character between 0 and 127, as it does compare a
+     * byte and a char (which is 16 bits wide)
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param car The character we want to compare with the current buffer position
+     * @return <code>true</code> if the current character equals the given character.
+     */
+    public static boolean isCharASCII( byte[] byteArray, int index, char car )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) || ( index >= byteArray.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( byteArray[index] == car ) ? true : false );
+        }
+    }
+
+
+    /**
+     * Test if the current character is equal to a specific character.
+     *
+     * @param string The String which contains the data
+     * @param index Current position in the string
+     * @param car The character we want to compare with the current string position
+     * @return <code>true</code> if the current character equals the given character.
+     */
+    public static boolean isCharASCII( String string, int index, char car )
+    {
+        if ( string == null )
+        {
+            return false;
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return string.charAt( index ) == car;
+        }
+    }
+
+    private static final byte[] UTF8 = new byte[]
+        { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+            0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+            0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
+            0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
+            0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
+            0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
+            0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+            0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F };
+
+
+    /**
+     * Return an UTF-8 encoded String
+     *
+     * @param bytes The byte array to be transformed to a String
+     * @return A String.
+     */
+    public static String utf8ToString( byte[] bytes )
+    {
+        if ( bytes == null )
+        {
+            return "";
+        }
+
+        char[] chars = new char[bytes.length];
+        int pos = 0;
+
+        try
+        {
+            for ( byte b : bytes )
+            {
+                chars[pos++] = ( char ) UTF8[b];
+            }
+        }
+        catch ( ArrayIndexOutOfBoundsException aioobe )
+        {
+            try
+            {
+                return new String( bytes, "UTF-8" );
+            }
+            catch ( UnsupportedEncodingException uee )
+            {
+                // if this happens something is really strange
+                throw new RuntimeException( uee.getMessage(), uee );
+            }
+        }
+
+        return new String( chars );
+    }
+
+
+    /**
+     * Return an UTF-8 encoded String
+     *
+     * @param bytes The byte array to be transformed to a String
+     * @param length The length of the byte array to be converted
+     * @return A String.
+     */
+    public static String utf8ToString( byte[] bytes, int length )
+    {
+        if ( bytes == null )
+        {
+            return "";
+        }
+
+        try
+        {
+            return new String( bytes, 0, length, "UTF-8" );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // if this happens something is really strange
+            throw new RuntimeException( uee );
+        }
+    }
+
+
+    /**
+     * Return an UTF-8 encoded String
+     *
+     * @param bytes  The byte array to be transformed to a String
+     * @param start the starting position in the byte array
+     * @param length The length of the byte array to be converted
+     * @return A String.
+     */
+    public static String utf8ToString( byte[] bytes, int start, int length )
+    {
+        if ( bytes == null )
+        {
+            return "";
+        }
+
+        try
+        {
+            return new String( bytes, start, length, "UTF-8" );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // if this happens something is really strange
+            throw new RuntimeException( uee );
+        }
+    }
+
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param bytes The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param text The text we want to check
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( byte[] bytes, int index, String text )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( bytes.length <= index ) || ( index < 0 )
+            || ( text == null ) )
+        {
+            return StringConstants.NOT_EQUAL;
+        }
+        else
+        {
+            try
+            {
+                byte[] data = text.getBytes( "UTF-8" );
+
+                return areEquals( bytes, index, data );
+            }
+            catch ( UnsupportedEncodingException uee )
+            {
+                // if this happens something is really strange
+                throw new RuntimeException( uee );
+            }
+        }
+    }
+
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param text The text we want to check
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( char[] chars, int index, String text )
+    {
+        return areEquals( chars, index, text, true );
+    }
+
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param text The text we want to check
+     * @param caseSensitive If the comparison is case-sensitive
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( char[] chars, int index, String text, boolean caseSensitive )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( chars.length <= index ) || ( index < 0 )
+            || ( text == null ) )
+        {
+            return StringConstants.NOT_EQUAL;
+        }
+        else
+        {
+            char[] data = text.toCharArray();
+
+            return areEquals( chars, index, data, caseSensitive );
+        }
+    }
+
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param chars2 The text we want to check
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( char[] chars, int index, char[] chars2 )
+    {
+        return areEquals( chars, index, chars2, true );
+    }
+
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param chars The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param chars2 The text we want to check
+     * @param caseSensitive If the comparison is case-sensitive
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( char[] chars, int index, char[] chars2, boolean caseSensitive )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( chars.length <= index ) || ( index < 0 )
+            || ( chars2 == null ) || ( chars2.length == 0 )
+            || ( chars2.length > ( chars.length - index ) ) )
+        {
+            return StringConstants.NOT_EQUAL;
+        }
+        else
+        {
+            for ( int i = 0; i < chars2.length; i++ )
+            {
+                char c1 = chars[index++];
+                char c2 = chars2[i];
+
+                if ( !caseSensitive )
+                {
+                    c1 = Character.toLowerCase( c1 );
+                    c2 = Character.toLowerCase( c2 );
+                }
+
+                if ( c1 != c2 )
+                {
+                    return StringConstants.NOT_EQUAL;
+                }
+            }
+
+            return index;
+        }
+    }
+
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param bytes The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param bytes2 The text we want to check
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( byte[] bytes, int index, byte[] bytes2 )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( bytes.length <= index ) || ( index < 0 )
+            || ( bytes2 == null ) || ( bytes2.length == 0 )
+            || ( bytes2.length > ( bytes.length - index ) ) )
+        {
+            return StringConstants.NOT_EQUAL;
+        }
+        else
+        {
+            for ( int i = 0; i < bytes2.length; i++ )
+            {
+                if ( bytes[index++] != bytes2[i] )
+                {
+                    return StringConstants.NOT_EQUAL;
+                }
+            }
+
+            return index;
+        }
+    }
+
+
+    /**
+     * <p>
+     * Checks if a String is empty ("") or null.
+     * </p>
+     *
+     * <pre>
+     *  StringUtils.isEmpty(null)      = true
+     *  StringUtils.isEmpty(&quot;&quot;)        = true
+     *  StringUtils.isEmpty(&quot; &quot;)       = false
+     *  StringUtils.isEmpty(&quot;bob&quot;)     = false
+     *  StringUtils.isEmpty(&quot;  bob  &quot;) = false
+     * </pre>
+     *
+     * <p>
+     * NOTE: This method changed in Lang version 2.0. It no longer trims the
+     * String. That functionality is available in isBlank().
+     * </p>
+     *
+     * @param str the String to check, may be null
+     * @return <code>true</code> if the String is empty or null
+     */
+    public static boolean isEmpty( String str )
+    {
+        return ( str == null ) || ( str.length() == 0 );
+    }
+
+
+    /**
+     * Checks if a bytes array is empty or null.
+     *
+     * @param bytes The bytes array to check, may be null
+     * @return <code>true</code> if the bytes array is empty or null
+     */
+    public static boolean isEmpty( byte[] bytes )
+    {
+        return ( bytes == null ) || ( bytes.length == 0 );
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from both start and ends of this String,
+     * handling <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start and end characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trim(null)          = null
+     *  StringUtils.trim(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trim(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trim(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trim(&quot;    abc    &quot;) = &quot;abc&quot;
+     * </pre>
+     *
+     * @param str the String to be trimmed, may be null
+     * @return the trimmed string, <code>null</code> if null String input
+     */
+    public static String trim( String str )
+    {
+        return ( isEmpty( str ) ? "" : str.trim() );
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from both start and ends of this bytes
+     * array, handling <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start and end characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trim(null)          = null
+     *  StringUtils.trim(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trim(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trim(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trim(&quot;    abc    &quot;) = &quot;abc&quot;
+     * </pre>
+     *
+     * @param bytes the byte array to be trimmed, may be null
+     *
+     * @return the trimmed byte array
+     */
+    public static byte[] trim( byte[] bytes )
+    {
+        if ( isEmpty( bytes ) )
+        {
+            return StringConstants.EMPTY_BYTES;
+        }
+
+        int start = trimLeft( bytes, 0 );
+        int end = trimRight( bytes, bytes.length - 1 );
+
+        int length = end - start + 1;
+
+        if ( length != 0 )
+        {
+            byte[] newBytes = new byte[end - start + 1];
+
+            System.arraycopy( bytes, start, newBytes, 0, length );
+
+            return newBytes;
+        }
+        else
+        {
+            return StringConstants.EMPTY_BYTES;
+        }
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from start of this String, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimLeft(null)          = null
+     *  StringUtils.trimLeft(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimLeft(&quot;    abc    &quot;) = &quot;abc    &quot;
+     * </pre>
+     *
+     * @param str the String to be trimmed, may be null
+     * @return the trimmed string, <code>null</code> if null String input
+     */
+    public static String trimLeft( String str )
+    {
+        if ( isEmpty( str ) )
+        {
+            return "";
+        }
+
+        int start = 0;
+        int end = str.length();
+
+        while ( ( start < end ) && ( str.charAt( start ) == ' ' ) )
+        {
+            start++;
+        }
+
+        return ( start == 0 ? str : str.substring( start ) );
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from start of this array, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimLeft(null)          = null
+     *  StringUtils.trimLeft(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimLeft(&quot;    abc    &quot;) = &quot;abc    &quot;
+     * </pre>
+     *
+     * @param chars the chars array to be trimmed, may be null
+     * @return the position of the first char which is not a space, or the last
+     *         position of the array.
+     */
+    public static int trimLeft( char[] chars, int pos )
+    {
+        if ( chars == null )
+        {
+            return pos;
+        }
+
+        while ( ( pos < chars.length ) && ( chars[pos] == ' ' ) )
+        {
+            pos++;
+        }
+
+        return pos;
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from a position in this array, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimLeft(null)          = null
+     *  StringUtils.trimLeft(&quot;&quot;,...)            = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;     &quot;,...)       = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;abc&quot;,...)         = &quot;abc&quot;
+     *  StringUtils.trimLeft(&quot;    abc    &quot;,...) = &quot;abc    &quot;
+     * </pre>
+     *
+     * @param string the string to be trimmed, may be null
+     * @param pos The starting position
+     */
+    public static void trimLeft( String string, Position pos )
+    {
+        if ( string == null )
+        {
+            return;
+        }
+
+        int length = string.length();
+
+        while ( ( pos.start < length ) && ( string.charAt( pos.start ) == ' ' ) )
+        {
+            pos.start++;
+        }
+
+        pos.end = pos.start;
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from a position in this array, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimLeft(null)          = null
+     *  StringUtils.trimLeft(&quot;&quot;,...)            = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;     &quot;,...)       = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;abc&quot;,...)         = &quot;abc&quot;
+     *  StringUtils.trimLeft(&quot;    abc    &quot;,...) = &quot;abc    &quot;
+     * </pre>
+     *
+     * @param bytes the byte array to be trimmed, may be null
+     * @param pos The starting position
+     */
+    public static void trimLeft( byte[] bytes, Position pos )
+    {
+        if ( bytes == null )
+        {
+            return;
+        }
+
+        int length = bytes.length;
+
+        while ( ( pos.start < length ) && ( bytes[pos.start] == ' ' ) )
+        {
+            pos.start++;
+        }
+
+        pos.end = pos.start;
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from start of this array, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimLeft(null)          = null
+     *  StringUtils.trimLeft(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimLeft(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimLeft(&quot;    abc    &quot;) = &quot;abc    &quot;
+     * </pre>
+     *
+     * @param bytes the byte array to be trimmed, may be null
+     * @return the position of the first byte which is not a space, or the last
+     *         position of the array.
+     */
+    public static int trimLeft( byte[] bytes, int pos )
+    {
+        if ( bytes == null )
+        {
+            return pos;
+        }
+
+        while ( ( pos < bytes.length ) && ( bytes[pos] == ' ' ) )
+        {
+            pos++;
+        }
+
+        return pos;
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from end of this String, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimRight(null)          = null
+     *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
+     * </pre>
+     *
+     * @param str the String to be trimmed, may be null
+     * @return the trimmed string, <code>null</code> if null String input
+     */
+    public static String trimRight( String str )
+    {
+        if ( isEmpty( str ) )
+        {
+            return "";
+        }
+
+        int length = str.length();
+        int end = length;
+
+        while ( ( end > 0 ) && ( str.charAt( end - 1 ) == ' ' ) )
+        {
+            if ( ( end > 1 ) && ( str.charAt( end - 2 ) == '\\' ) )
+            {
+                break;
+            }
+
+            end--;
+        }
+
+        return ( end == length ? str : str.substring( 0, end ) );
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from end of this String, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimRight(null)          = null
+     *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
+     * </pre>
+     *
+     * @param str the String to be trimmed, may be null
+     * @param escapedSpace The last escaped space, if any
+     * @return the trimmed string, <code>null</code> if null String input
+     */
+    public static String trimRight( String str, int escapedSpace )
+    {
+        if ( isEmpty( str ) )
+        {
+            return "";
+        }
+
+        int length = str.length();
+        int end = length;
+
+        while ( ( end > 0 ) && ( str.charAt( end - 1 ) == ' ' ) && ( end > escapedSpace ) )
+        {
+            if ( ( end > 1 ) && ( str.charAt( end - 2 ) == '\\' ) )
+            {
+                break;
+            }
+
+            end--;
+        }
+
+        return ( end == length ? str : str.substring( 0, end ) );
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from end of this array, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimRight(null)          = null
+     *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
+     * </pre>
+     *
+     * @param chars the chars array to be trimmed, may be null
+     * @return the position of the first char which is not a space, or the last
+     *         position of the array.
+     */
+    public static int trimRight( char[] chars, int pos )
+    {
+        if ( chars == null )
+        {
+            return pos;
+        }
+
+        while ( ( pos >= 0 ) && ( chars[pos - 1] == ' ' ) )
+        {
+            pos--;
+        }
+
+        return pos;
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from end of this string, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimRight(null)          = null
+     *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
+     * </pre>
+     *
+     * @param string the string to be trimmed, may be null
+     * @return the position of the first char which is not a space, or the last
+     *         position of the string.
+     */
+    public static String trimRight( String string, Position pos )
+    {
+        if ( string == null )
+        {
+            return "";
+        }
+
+        while ( ( pos.end >= 0 ) && ( string.charAt( pos.end - 1 ) == ' ' ) )
+        {
+            if ( ( pos.end > 1 ) && ( string.charAt( pos.end - 2 ) == '\\' ) )
+            {
+                break;
+            }
+
+            pos.end--;
+        }
+
+        return ( pos.end == string.length() ? string : string.substring( 0, pos.end ) );
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from end of this string, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimRight(null)          = null
+     *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
+     * </pre>
+     *
+     * @param bytes the byte array to be trimmed, may be null
+     * @return the position of the first char which is not a space, or the last
+     *         position of the byte array.
+     */
+    public static String trimRight( byte[] bytes, Position pos )
+    {
+        if ( bytes == null )
+        {
+            return "";
+        }
+
+        while ( ( pos.end >= 0 ) && ( bytes[pos.end - 1] == ' ' ) )
+        {
+            if ( ( pos.end > 1 ) && ( bytes[pos.end - 2] == '\\' ) )
+            {
+                break;
+            }
+
+            pos.end--;
+        }
+
+        if ( pos.end == bytes.length )
+        {
+            return utf8ToString( bytes );
+        }
+        else
+        {
+            return utf8ToString( bytes, pos.end );
+        }
+    }
+
+
+    /**
+     * <p>
+     * Removes spaces (char &lt;= 32) from end of this array, handling
+     * <code>null</code> by returning <code>null</code>.
+     * </p>
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     *  StringUtils.trimRight(null)          = null
+     *  StringUtils.trimRight(&quot;&quot;)            = &quot;&quot;
+     *  StringUtils.trimRight(&quot;     &quot;)       = &quot;&quot;
+     *  StringUtils.trimRight(&quot;abc&quot;)         = &quot;abc&quot;
+     *  StringUtils.trimRight(&quot;    abc    &quot;) = &quot;    abc&quot;
+     * </pre>
+     *
+     * @param bytes the byte array to be trimmed, may be null
+     * @return the position of the first char which is not a space, or the last
+     *         position of the array.
+     */
+    public static int trimRight( byte[] bytes, int pos )
+    {
+        if ( bytes == null )
+        {
+            return pos;
+        }
+
+        while ( ( pos >= 0 ) && ( bytes[pos] == ' ' ) )
+        {
+            pos--;
+        }
+
+        return pos;
+    }
+
+
+    /**
+     * Get the character at a given position in a string, checking for limits
+     *
+     * @param string The string which contains the data
+     * @param index Current position in the string
+     * @return The character at the given position, or '\0' if something went wrong
+     */
+    public static char charAt( String string, int index )
+    {
+        if ( string == null )
+        {
+            return '\0';
+        }
+
+        int length = string.length();
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return '\0';
+        }
+        else
+        {
+            return string.charAt( index );
+        }
+    }
+
+
+    /**
+     * Get the byte at a given position in a byte array, checking for limits
+     *
+     * @param bytes The byte[] which contains the data
+     * @param index Current position in the byte[]
+     * @return The byte at the given position, or '\0' if something went wrong
+     */
+    public static byte byteAt( byte[] bytes, int index )
+    {
+        if ( bytes == null )
+        {
+            return '\0';
+        }
+
+        int length = bytes.length;
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return '\0';
+        }
+        else
+        {
+            return bytes[index];
+        }
+    }
+
+
+    /**
+     * Get the char at a given position in a byte array, checking for limits
+     *
+     * @param chars The char[] which contains the data
+     * @param index Current position in the char[]
+     * @return The byte at the given position, or '\0' if something went wrong
+     */
+    public static char charAt( char[] chars, int index )
+    {
+        if ( chars == null )
+        {
+            return '\0';
+        }
+
+        int length = chars.length;
+
+        if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
+        {
+            return '\0';
+        }
+        else
+        {
+            return chars[index];
+        }
+    }
+
+
+    /**
+     * Transform an array of ASCII bytes to a string. the byte array should contains
+     * only values in [0, 127].
+     *
+     * @param bytes The byte array to transform
+     * @return The resulting string
+     */
+    public static String asciiBytesToString( byte[] bytes )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) )
+        {
+            return "";
+        }
+
+        char[] result = new char[bytes.length];
+
+        for ( int i = 0; i < bytes.length; i++ )
+        {
+            result[i] = ( char ) bytes[i];
+        }
+
+        return new String( result );
+    }
+
+
+    /**
+     * Return UTF-8 encoded byte[] representation of a String
+     *
+     * @param string The string to be transformed to a byte array
+     * @return The transformed byte array
+     */
+    public static byte[] getBytesUtf8( String string )
+    {
+        if ( string == null )
+        {
+            return EMPTY_BYTES;
+        }
+
+        try
+        {
+            return string.getBytes( "UTF-8" );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // if this happens something is really strange
+            throw new RuntimeException( uee );
+        }
+    }
+
+
+    /**
+     * When the string to convert to bytes is pure ascii, this is a faster 
+     * method than the getBytesUtf8. Otherwise, it's slower.
+     * 
+     * @param string The string to convert to byte[]
+     * @return The bytes 
+     */
+    public static byte[] getBytesUtf8Ascii( String string )
+    {
+        if ( string == null )
+        {
+            return new byte[0];
+        }
+
+        try
+        {
+            try
+            {
+                char[] chars = string.toCharArray();
+                byte[] bytes = new byte[chars.length];
+                int pos = 0;
+
+                for ( char c : chars )
+                {
+                    bytes[pos++] = UTF8[c];
+                }
+
+                return bytes;
+            }
+            catch ( ArrayIndexOutOfBoundsException aioobe )
+            {
+                return string.getBytes( "UTF-8" );
+            }
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // if this happens something is really strange
+            throw new RuntimeException( uee );
+        }
+    }
+
+
+    /**
+     * Get the default charset
+     *
+     * @return The default charset
+     */
+    public static String getDefaultCharsetName()
+    {
+        if ( null == defaultCharset )
+        {
+            try
+            {
+                // Try with jdk 1.5 method, if we are using a 1.5 jdk :)
+                Method method = Charset.class.getMethod( "defaultCharset", new Class[0] );
+                defaultCharset = ( ( Charset ) method.invoke( null, new Object[0] ) ).name();
+            }
+            catch ( NoSuchMethodException e )
+            {
+                // fall back to old method
+                defaultCharset = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
+            }
+            catch ( InvocationTargetException e )
+            {
+                // fall back to old method
+                defaultCharset = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
+            }
+            catch ( IllegalAccessException e )
+            {
+                // fall back to old method
+                defaultCharset = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
+            }
+        }
+
+        return defaultCharset;
+    }
+
+
+    /**
+     * <p>
+     * Compares two Strings, returning <code>true</code> if they are equal.
+     * </p>
+     * <p>
+     * <code>null</code>s are handled without exceptions. Two
+     * <code>null</code> references are considered to be equal. The comparison
+     * is case sensitive.
+     * </p>
+     *
+     * <pre>
+     *  StringUtils.equals(null, null)   = true
+     *  StringUtils.equals(null, &quot;abc&quot;)  = false
+     *  StringUtils.equals(&quot;abc&quot;, null)  = false
+     *  StringUtils.equals(&quot;abc&quot;, &quot;abc&quot;) = true
+     *  StringUtils.equals(&quot;abc&quot;, &quot;ABC&quot;) = false
+     * </pre>
+     *
+     * @see String#equals(Object)
+     * @param str1 the first String, may be null
+     * @param str2 the second String, may be null
+     * @return <code>true</code> if the Strings are equal, case sensitive, or
+     *         both <code>null</code>
+     */
+    public static boolean equals( String str1, String str2 )
+    {
+        return str1 == null ? str2 == null : str1.equals( str2 );
+    }
+
+
+    /**
+     * Utility method that return a String representation of a list
+     *
+     * @param list The list to transform to a string
+     * @return A csv string
+     */
+    public static String listToString( List<?> list )
+    {
+        if ( ( list == null ) || ( list.size() == 0 ) )
+        {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        boolean isFirst = true;
+
+        for ( Object elem : list )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            sb.append( elem );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Utility method that return a String representation of a set
+     *
+     * @param set The set to transform to a string
+     * @return A csv string
+     */
+    public static String setToString( Set<?> set )
+    {
+        if ( ( set == null ) || ( set.size() == 0 ) )
+        {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        boolean isFirst = true;
+
+        for ( Object elem : set )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            sb.append( elem );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Utility method that return a String representation of a list
+     *
+     * @param list The list to transform to a string
+     * @param tabs The tabs to add in front of the elements
+     * @return A csv string
+     */
+    public static String listToString( List<?> list, String tabs )
+    {
+        if ( ( list == null ) || ( list.size() == 0 ) )
+        {
+            return "";
+        }
+
+        StringBuffer sb = new StringBuffer();
+
+        for ( Object elem : list )
+        {
+            sb.append( tabs );
+            sb.append( elem );
+            sb.append( '\n' );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Utility method that return a String representation of a map. The elements
+     * will be represented as "key = value"
+     *
+     * @param map The map to transform to a string
+     * @return A csv string
+     */
+    public static String mapToString( Map<?, ?> map )
+    {
+        if ( ( map == null ) || ( map.size() == 0 ) )
+        {
+            return "";
+        }
+
+        StringBuffer sb = new StringBuffer();
+        boolean isFirst = true;
+
+        for ( Map.Entry<?, ?> entry : map.entrySet() )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append( ", " );
+            }
+
+            sb.append( entry.getKey() );
+            sb.append( " = '" ).append( entry.getValue() ).append( "'" );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Utility method that return a String representation of a map. The elements
+     * will be represented as "key = value"
+     *
+     * @param map The map to transform to a string
+     * @param tabs The tabs to add in ffront of the elements
+     * @return A csv string
+     */
+    public static String mapToString( Map<?, ?> map, String tabs )
+    {
+        if ( ( map == null ) || ( map.size() == 0 ) )
+        {
+            return "";
+        }
+
+        StringBuffer sb = new StringBuffer();
+
+        for ( Map.Entry<?, ?> entry : map.entrySet() )
+        {
+            sb.append( tabs );
+            sb.append( entry.getKey() );
+
+            sb.append( " = '" ).append( entry.getValue().toString() ).append( "'\n" );
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     * Rewrote the toLowercase method to improve performances.
+     * In Ldap, attributesType are supposed to use ASCII chars :
+     * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
+     *
+     * @param value The String to lowercase
+     * @return The lowercase string
+     * @deprecated Use {@link #toLowerCaseAscii(String)}
+     */
+    public static String toLowerCase( String value )
+    {
+        if ( ( null == value ) || ( value.length() == 0 ) )
+        {
+            return "";
+        }
+
+        char[] chars = value.toCharArray();
+
+        for ( int i = 0; i < chars.length; i++ )
+        {
+            chars[i] = TO_LOWER_CASE[chars[i]];
+        }
+
+        return new String( chars );
+    }
+
+
+    /**
+     * Rewrote the toLowercase method to improve performances.
+     * In Ldap, attributesType are supposed to use ASCII chars :
+     * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
+     *
+     * @param value The String to lowercase
+     * @return The lowercase string
+     */
+    public static String toLowerCaseAscii( String value )
+    {
+        if ( ( null == value ) || ( value.length() == 0 ) )
+        {
+            return "";
+        }
+
+        char[] chars = value.toCharArray();
+
+        for ( int i = 0; i < chars.length; i++ )
+        {
+            chars[i] = TO_LOWER_CASE[chars[i]];
+        }
+
+        return new String( chars );
+    }
+
+
+    /**
+     * Rewrote the toLowercase method to improve performances.
+     * In Ldap, attributesType are supposed to use ASCII chars :
+     * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
+     *
+     * @param value The byte[] to lowercase
+     * @return The lowercase string
+     */
+    public static String toLowerCase( byte[] value )
+    {
+        if ( ( null == value ) || ( value.length == 0 ) )
+        {
+            return "";
+        }
+
+        for ( int i = 0; i < value.length; i++ )
+        {
+            value[i] = TO_LOWER_CASE_BYTE[value[i]];
+        }
+
+        return Strings.utf8ToString( value );
+    }
+
+
+    /**
+     * Rewrote the toLowercase method to improve performances.
+     * In Ldap, attributesType are supposed to use ASCII chars :
+     * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
+     *
+     * @param value The String to uppercase
+     * @return The uppercase string
+     * @deprecated Use {@link toUpperCaseAscii(String)}
+     */
+    public static String toUpperCase( String value )
+    {
+        if ( ( null == value ) || ( value.length() == 0 ) )
+        {
+            return "";
+        }
+
+        char[] chars = value.toCharArray();
+
+        for ( int i = 0; i < chars.length; i++ )
+        {
+            chars[i] = UPPER_CASE[chars[i]];
+        }
+
+        return new String( chars );
+    }
+
+
+    /**
+     * Rewrote the toLowercase method to improve performances.
+     * In Ldap, attributesType are supposed to use ASCII chars :
+     * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only.
+     *
+     * @param value The String to uppercase
+     * @return The uppercase string
+     */
+    public static String toUpperCaseAscii( String value )
+    {
+        if ( ( null == value ) || ( value.length() == 0 ) )
+        {
+            return "";
+        }
+
+        char[] chars = value.toCharArray();
+
+        for ( int i = 0; i < chars.length; i++ )
+        {
+            chars[i] = UPPER_CASE[chars[i]];
+        }
+
+        return new String( chars );
+    }
+
+
+    /**
+     * <p>
+     * Converts a String to upper case as per {@link String#toUpperCase()}.
+     * </p>
+     * <p>
+     * A <code>null</code> input String returns <code>null</code>.
+     * </p>
+     *
+     * <pre>
+     *  StringUtils.upperCase(null)  = null
+     *  StringUtils.upperCase(&quot;&quot;)    = &quot;&quot;
+     *  StringUtils.upperCase(&quot;aBc&quot;) = &quot;ABC&quot;
+     * </pre>
+     *
+     * @param str the String to upper case, may be null
+     * @return the upper cased String, <code>null</code> if null String input
+     */
+    public static String upperCase( String str )
+    {
+        if ( str == null )
+        {
+            return null;
+        }
+
+        return str.toUpperCase( Locale.ROOT );
+    }
+
+
+    /**
+     * <p>
+     * Converts a String to lower case as per {@link String#toLowerCase()}.
+     * </p>
+     * <p>
+     * A <code>null</code> input String returns <code>null</code>.
+     * </p>
+     *
+     * <pre>
+     *  StringUtils.lowerCase(null)  = null
+     *  StringUtils.lowerCase(&quot;&quot;)    = &quot;&quot;
+     *  StringUtils.lowerCase(&quot;aBc&quot;) = &quot;abc&quot;
+     * </pre>
+     *
+     * @param str the String to lower case, may be null
+     * @return the lower cased String, <code>null</code> if null String input
+     */
+    public static String lowerCase( String str )
+    {
+        if ( str == null )
+        {
+            return null;
+        }
+
+        return str.toLowerCase( Locale.ROOT );
+    }
+
+
+    /**
+     * Rewrote the toLowercase method to improve performances.
+     * In Ldap, attributesType are supposed to use ASCII chars :
+     * 'a'-'z', 'A'-'Z', '0'-'9', '.' and '-' only. We will take
+     * care of any other chars either.
+     *
+     * @param str The String to lowercase
+     * @return The lowercase string
+     */
+    public static String lowerCaseAscii( String str )
+    {
+        if ( str == null )
+        {
+            return null;
+        }
+
+        char[] chars = str.toCharArray();
+        int pos = 0;
+
+        for ( char c : chars )
+        {
+            chars[pos++] = TO_LOWER_CASE[c];
+        }
+
+        return new String( chars );
+    }
+
+
+    /**
+     *
+     * Check that a String is a valid PrintableString. A PrintableString contains only
+     * the following set of chars :
+     * { ' ', ''', '(', ')', '+', '-', '.', '/', [0-9], ':', '=', '?', [A-Z], [a-z]}
+     *
+     * @param str The String to check
+     * @return <code>true</code> if the string is a PrintableString or is empty,
+     * <code>false</code> otherwise
+     */
+    public static boolean isPrintableString( String str )
+    {
+        if ( ( str == null ) || ( str.length() == 0 ) )
+        {
+            return true;
+        }
+
+        for ( char c : str.toCharArray() )
+        {
+            if ( ( c > 127 ) || !IS_PRINTABLE_CHAR[c] )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * <p>
+     * Checks if a String is not empty ("") and not null.
+     * </p>
+     *
+     * <pre>
+     *  StringUtils.isNotEmpty(null)      = false
+     *  StringUtils.isNotEmpty(&quot;&quot;)        = false
+     *  StringUtils.isNotEmpty(&quot; &quot;)       = true
+     *  StringUtils.isNotEmpty(&quot;bob&quot;)     = true
+     *  StringUtils.isNotEmpty(&quot;  bob  &quot;) = true
+     * </pre>
+     *
+     * @param str the String to check, may be null
+     * @return <code>true</code> if the String is not empty and not null
+     */
+    public static boolean isNotEmpty( String str )
+    {
+        return ( str != null ) && ( str.length() > 0 );
+    }
+
+
+    /**
+     *
+     * Check that a String is a valid IA5String. An IA5String contains only
+     * char which values is between [0, 7F]
+     *
+     * @param str The String to check
+     * @return <code>true</code> if the string is an IA5String or is empty,
+     * <code>false</code> otherwise
+     */
+    public static boolean isIA5String( String str )
+    {
+        if ( ( str == null ) || ( str.length() == 0 ) )
+        {
+            return true;
+        }
+
+        // All the chars must be in [0x00, 0x7F]
+        for ( char c : str.toCharArray() )
+        {
+            if ( ( c < 0 ) || ( c > 0x7F ) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Checks to see if a String is a valid UUID.
+     *
+     * @param uuid the UUID to check for validity
+     * @return true if the UUID is valid, false otherwise
+     */
+    public static boolean isValidUuid( String uuid )
+    {
+        if ( uuid.length() < 36 )
+        {
+            return false;
+        }
+
+        if ( isHex( uuid.charAt( 0 ) ) && isHex( uuid.charAt( 1 ) ) && isHex( uuid.charAt( 2 ) )
+            && isHex( uuid.charAt( 3 ) ) && isHex( uuid.charAt( 4 ) ) && isHex( uuid.charAt( 5 ) )
+            && isHex( uuid.charAt( 6 ) ) && isHex( uuid.charAt( 7 ) ) && ( uuid.charAt( 8 ) == '-' )
+            && isHex( uuid.charAt( 9 ) ) && isHex( uuid.charAt( 10 ) ) && isHex( uuid.charAt( 11 ) )
+            && isHex( uuid.charAt( 12 ) ) && ( uuid.charAt( 13 ) == '-' ) && isHex( uuid.charAt( 14 ) )
+            && isHex( uuid.charAt( 15 ) ) && isHex( uuid.charAt( 16 ) ) && isHex( uuid.charAt( 17 ) )
+            && ( uuid.charAt( 18 ) == '-' ) && isHex( uuid.charAt( 19 ) ) && isHex( uuid.charAt( 20 ) )
+            && isHex( uuid.charAt( 21 ) ) && isHex( uuid.charAt( 22 ) ) && ( uuid.charAt( 23 ) == '-' )
+            && isHex( uuid.charAt( 24 ) ) && isHex( uuid.charAt( 25 ) ) && isHex( uuid.charAt( 26 ) )
+            && isHex( uuid.charAt( 27 ) ) && isHex( uuid.charAt( 28 ) ) && isHex( uuid.charAt( 29 ) )
+            && isHex( uuid.charAt( 30 ) ) && isHex( uuid.charAt( 31 ) ) && isHex( uuid.charAt( 32 ) )
+            && isHex( uuid.charAt( 33 ) ) && isHex( uuid.charAt( 34 ) ) && isHex( uuid.charAt( 35 ) ) )
+        {
+            // There is not that much more we can check.
+            LOG.debug( "Syntax valid for '{}'", uuid );
+            return true;
+        }
+
+        LOG.debug( "Syntax invalid for '{}'", uuid );
+        return false;
+    }
+
+
+    /**
+     * converts the bytes of a UUID to string
+     *
+     * @param bytes bytes of a UUID
+     * @return UUID in string format
+     */
+    public static String uuidToString( byte[] bytes )
+    {
+        if ( ( bytes == null ) || ( bytes.length != 16 ) )
+        {
+            return "Invalid UUID";
+        }
+
+        char[] hex = encodeHex( bytes );
+        StringBuffer sb = new StringBuffer();
+        sb.append( hex, 0, 8 );
+        sb.append( '-' );
+        sb.append( hex, 8, 4 );
+        sb.append( '-' );
+        sb.append( hex, 12, 4 );
+        sb.append( '-' );
+        sb.append( hex, 16, 4 );
+        sb.append( '-' );
+        sb.append( hex, 20, 12 );
+
+        return Strings.toLowerCase( sb.toString() );
+    }
+
+
+    /**
+     * converts the string representation of an UUID to bytes
+     *
+     * @param string the string representation of an UUID
+     * @return the bytes, null if the the syntax is not valid
+     */
+    public static byte[] uuidToBytes( String string )
+    {
+        if ( !isValidUuid( string ) )
+        {
+            return null;
+        }
+
+        char[] chars = string.toCharArray();
+        byte[] bytes = new byte[16];
+        bytes[0] = getHexValue( chars[0], chars[1] );
+        bytes[1] = getHexValue( chars[2], chars[3] );
+        bytes[2] = getHexValue( chars[4], chars[5] );
+        bytes[3] = getHexValue( chars[6], chars[7] );
+
+        bytes[4] = getHexValue( chars[9], chars[10] );
+        bytes[5] = getHexValue( chars[11], chars[12] );
+
+        bytes[6] = getHexValue( chars[14], chars[15] );
+        bytes[7] = getHexValue( chars[16], chars[17] );
+
+        bytes[8] = getHexValue( chars[19], chars[20] );
+        bytes[9] = getHexValue( chars[21], chars[22] );
+
+        bytes[10] = getHexValue( chars[24], chars[25] );
+        bytes[11] = getHexValue( chars[26], chars[27] );
+        bytes[12] = getHexValue( chars[28], chars[29] );
+        bytes[13] = getHexValue( chars[30], chars[31] );
+        bytes[14] = getHexValue( chars[32], chars[33] );
+        bytes[15] = getHexValue( chars[34], chars[35] );
+
+        return bytes;
+    }
+
+
+    /**
+     * Copy a byte array into a new byte array
+     *
+     * @param value the byte array to copy
+     * @return The copied byte array
+     */
+    public static byte[] copy( byte[] value )
+    {
+        if ( isEmpty( value ) )
+        {
+            return StringConstants.EMPTY_BYTES;
+        }
+
+        byte[] copy = new byte[value.length];
+        System.arraycopy( value, 0, copy, 0, value.length );
+
+        return copy;
+    }
+
+
+    /**
+     * From commons-httpclients. Converts the byte array of HTTP content
+     * characters to a string. If the specified charset is not supported,
+     * default system encoding is used.
+     *
+     * @param data the byte array to be encoded
+     * @param offset the index of the first byte to encode
+     * @param length the number of bytes to encode
+     * @param charset the desired character encoding
+     * @return The result of the conversion.
+     * @since 3.0
+     */
+    public static String getString( final byte[] data, int offset, int length, String charset )
+    {
+        if ( data == null )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04411 ) );
+        }
+
+        if ( ( charset == null ) || ( charset.length() == 0 ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_04412 ) );
+        }
+
+        try
+        {
+            return new String( data, offset, length, charset );
+        }
+        catch ( UnsupportedEncodingException e )
+        {
+            return new String( data, offset, length );
+        }
+    }
+
+
+    /**
+     * From commons-httpclients. Converts the byte array of HTTP content
+     * characters to a string. If the specified charset is not supported,
+     * default system encoding is used.
+     *
+     * @param data the byte array to be encoded
+     * @param charset the desired character encoding
+     * @return The result of the conversion.
+     * @since 3.0
+     */
+    public static String getString( final byte[] data, String charset )
+    {
+        return getString( data, 0, data.length, charset );
+    }
+
+
+    /**
+     * Create a new UUID using a long as the least significant bits
+     * 
+     * @param value The least significant bits.
+     * @return
+     */
+    public static String getUUID( long value )
+    {
+        return new UUID( 0, value ).toString();
+    }
+    
+    
+    /**
+     * Past an ASCII String to a number
+     *
+     * @param value The string to parse
+     * @return the parsed value.
+     * @throws NumberFormatException If we don't have a number
+     */
+    public static int parseInt( String value ) throws NumberFormatException
+    {
+        long res = 0;
+        
+        for ( char c : value.toCharArray() )
+        {
+            if ( ( c >= '0' ) && ( c <= '9' ) )
+            {
+                res = res * 10 + ( c - '0' );
+                
+                if ( res > Integer.MAX_VALUE )
+                {
+                    throw new NumberFormatException( "Integer " + value + " is too big" );
+                }
+            }
+            else
+            {
+                throw new NumberFormatException( "Integer " + value + " is not valid" );
+            }
+        }
+        
+        return ( int ) res;
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/SynchronizedLRUMap.java b/trunk/util/src/main/java/org/apache/directory/api/util/SynchronizedLRUMap.java
new file mode 100644
index 0000000..6991201
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/SynchronizedLRUMap.java
@@ -0,0 +1,204 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import java.io.Externalizable;
+
+
+/**
+ * <p>
+ * An implementation of a Map which has a maximum size and uses a Least Recently
+ * Used algorithm to remove items from the Map when the maximum size is reached
+ * and new items are added.
+ * </p>
+ * <p>
+ * A synchronized version can be obtained with:
+ * <code>Collections.synchronizedMap( theMapToSynchronize )</code> If it will
+ * be accessed by multiple threads, you _must_ synchronize access to this Map.
+ * Even concurrent get(Object) operations produce indeterminate behaviour.
+ * </p>
+ * <p>
+ * Unlike the Collections 1.0 version, this version of LRUMap does use a true
+ * LRU algorithm. The keys for all gets and puts are moved to the front of the
+ * list. LRUMap is now a subclass of SequencedHashMap, and the "LRU" key is now
+ * equivalent to LRUMap.getFirst().
+ * </p>
+ * 
+ * @since Commons Collections 1.0
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class SynchronizedLRUMap extends SequencedHashMap implements Externalizable
+{
+    // add a serial version uid, so that if we change things in the future
+    // without changing the format, we can still deserialize properly.
+    private static final long serialVersionUID = 2197433140769957051L;
+
+    private int maximumSize = 0;
+
+
+    /**
+     * Default constructor, primarily for the purpose of de-externalization.
+     * This constructors sets a default LRU limit of 100 keys, but this value
+     * may be overridden internally as a result of de-externalization.
+     */
+    public SynchronizedLRUMap()
+    {
+        this( 100 );
+    }
+
+
+    /**
+     * Create a new LRUMap with a maximum capacity of <i>i</i>. Once <i>i</i>
+     * capacity is achieved, subsequent gets and puts will push keys out of the
+     * map. See .
+     * 
+     * @param i
+     *            Maximum capacity of the LRUMap
+     */
+    public SynchronizedLRUMap( int i )
+    {
+        super( i );
+        maximumSize = i;
+    }
+
+
+    /**
+     * <p>
+     * Get the value for a key from the Map. The key will be promoted to the
+     * Most Recently Used position. Note that get(Object) operations will modify
+     * the underlying Collection. Calling get(Object) inside of an iteration
+     * over keys, values, etc. is currently unsupported.
+     * </p>
+     * 
+     * @param key
+     *            Key to retrieve
+     * @return Returns the value. Returns null if the key has a null value <i>or</i>
+     *         if the key has no value.
+     */
+    public synchronized Object get( Object key )
+    {
+        if ( !containsKey( key ) )
+        {
+            return null;
+        }
+
+        Object value = remove( key );
+        super.put( key, value );
+        return value;
+    }
+
+
+    /**
+     * <p>
+     * Removes the key and its Object from the Map.
+     * </p>
+     * <p>
+     * (Note: this may result in the "Least Recently Used" object being removed
+     * from the Map. In that case, the removeLRU() method is called. See javadoc
+     * for removeLRU() for more details.)
+     * </p>
+     * 
+     * @param key
+     *            Key of the Object to add.
+     * @param value
+     *            Object to add
+     * @return Former value of the key
+     */
+    public Object put( Object key, Object value )
+    {
+
+        int mapSize = size();
+        Object retval = null;
+
+        if ( mapSize >= maximumSize )
+        {
+            synchronized ( this )
+            {
+                // don't retire LRU if you are just
+                // updating an existing key
+                if ( !containsKey( key ) )
+                {
+                    // lets retire the least recently used item in the cache
+                    removeLRU();
+                }
+
+                retval = super.put( key, value );
+            }
+        }
+        else
+        {
+            synchronized ( this )
+            {
+                retval = super.put( key, value );
+            }
+        }
+
+        return retval;
+    }
+
+
+    /**
+     * This method is used internally by the class for finding and removing the
+     * LRU Object.
+     */
+    private void removeLRU()
+    {
+        Object key = getFirstKey();
+        // be sure to call super.get(key), or you're likely to
+        // get infinite promotion recursion
+        super.get( key );
+
+        remove( key );
+    }
+
+
+    // Properties
+    // -------------------------------------------------------------------------
+    /**
+     * Getter for property maximumSize.
+     * 
+     * @return Value of property maximumSize.
+     */
+    public int getMaximumSize()
+    {
+        return maximumSize;
+    }
+
+
+    /**
+     * Setter for property maximumSize.
+     * 
+     * @param maximumSize
+     *            New value of property maximumSize.
+     */
+    public void setMaximumSize( int maximumSize )
+    {
+        synchronized ( this )
+        {
+            this.maximumSize = maximumSize;
+
+            while ( size() > maximumSize )
+            {
+                removeLRU();
+            }
+        }
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/Unicode.java b/trunk/util/src/main/java/org/apache/directory/api/util/Unicode.java
new file mode 100644
index 0000000..b892e48
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/Unicode.java
@@ -0,0 +1,510 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.api.util;
+
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+
+/**
+ * Various unicode manipulation methods that are more efficient then chaining
+ * operations: all is done in the same buffer without creating a bunch of string
+ * objects.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Unicode
+{
+    private static final int UTF8_MULTI_BYTES_MASK = 0x0080;
+    private static final int UTF8_TWO_BYTES_MASK = 0x00E0;
+    private static final int UTF8_TWO_BYTES = 0x00C0;
+    private static final int UTF8_THREE_BYTES_MASK = 0x00F0;
+    private static final int UTF8_THREE_BYTES = 0x00E0;
+    private static final int UTF8_FOUR_BYTES_MASK = 0x00F8;
+    private static final int UTF8_FOUR_BYTES = 0x00F0;
+    private static final int UTF8_FIVE_BYTES_MASK = 0x00FC;
+    private static final int UTF8_FIVE_BYTES = 0x00F8;
+    private static final int UTF8_SIX_BYTES_MASK = 0x00FE;
+    private static final int UTF8_SIX_BYTES = 0x00FC;
+
+    /** %01-%27 %2B-%5B %5D-%7F */
+    private static final boolean[] UNICODE_SUBSET =
+        {
+            // '\0'
+            false, true,  true,  true,  true,  true,  true,  true, 
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            // '(', ')', '*'
+            false, false, false, true,  true,  true,  true,  true, 
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            // '\'
+            true,  true,  true,  true,  false, true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+            true,  true,  true,  true,  true,  true,  true,  true,
+        };
+    private static final int CHAR_ONE_BYTE_MASK = 0xFFFFFF80;
+    private static final int CHAR_TWO_BYTES_MASK = 0xFFFFF800;
+    private static final int CHAR_THREE_BYTES_MASK = 0xFFFF0000;
+    private static final int CHAR_FOUR_BYTES_MASK = 0xFFE00000;
+    private static final int CHAR_FIVE_BYTES_MASK = 0xFC000000;
+    private static final int CHAR_SIX_BYTES_MASK = 0x80000000;
+
+    /**
+     * Count the number of bytes needed to return an Unicode char. This can be
+     * from 1 to 6.
+     *
+     * @param bytes The bytes to read
+     * @param pos Position to start counting. It must be a valid start of a
+     *            encoded char !
+     * @return The number of bytes to create a char, or -1 if the encoding is
+     *         wrong. TODO : Should stop after the third byte, as a char is only
+     *         2 bytes long.
+     */
+    public static int countBytesPerChar( byte[] bytes, int pos )
+    {
+        if ( bytes == null )
+        {
+            return -1;
+        }
+
+        if ( ( bytes[pos] & UTF8_MULTI_BYTES_MASK ) == 0 )
+        {
+            return 1;
+        }
+        else if ( ( bytes[pos] & UTF8_TWO_BYTES_MASK ) == UTF8_TWO_BYTES )
+        {
+            return 2;
+        }
+        else if ( ( bytes[pos] & UTF8_THREE_BYTES_MASK ) == UTF8_THREE_BYTES )
+        {
+            return 3;
+        }
+        else if ( ( bytes[pos] & UTF8_FOUR_BYTES_MASK ) == UTF8_FOUR_BYTES )
+        {
+            return 4;
+        }
+        else if ( ( bytes[pos] & UTF8_FIVE_BYTES_MASK ) == UTF8_FIVE_BYTES )
+        {
+            return 5;
+        }
+        else if ( ( bytes[pos] & UTF8_SIX_BYTES_MASK ) == UTF8_SIX_BYTES )
+        {
+            return 6;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+
+    /**
+     * Return the Unicode char which is coded in the bytes at position 0.
+     *
+     * @param bytes The byte[] represntation of an Unicode string.
+     * @return The first char found.
+     */
+    public static char bytesToChar( byte[] bytes )
+    {
+        return bytesToChar( bytes, 0 );
+    }
+
+
+    /**
+     * Return the Unicode char which is coded in the bytes at the given
+     * position.
+     *
+     * @param bytes The byte[] represntation of an Unicode string.
+     * @param pos The current position to start decoding the char
+     * @return The decoded char, or -1 if no char can be decoded TODO : Should
+     *         stop after the third byte, as a char is only 2 bytes long.
+     */
+    public static char bytesToChar( byte[] bytes, int pos )
+    {
+        if ( bytes == null )
+        {
+            return ( char ) -1;
+        }
+
+        if ( ( bytes[pos] & UTF8_MULTI_BYTES_MASK ) == 0 )
+        {
+            return ( char ) bytes[pos];
+        }
+        else
+        {
+            if ( ( bytes[pos] & UTF8_TWO_BYTES_MASK ) == UTF8_TWO_BYTES )
+            {
+                // Two bytes char
+                // 110x-xxyy 10zz-zzzz -> 0000-0xxx yyzz-zzzz
+                return ( char ) ( ( ( bytes[pos] & 0x1C ) << 6 ) + ( ( bytes[pos] & 0x03 ) << 6 ) + ( bytes[pos + 1] & 0x3F ) );
+            }
+            else if ( ( bytes[pos] & UTF8_THREE_BYTES_MASK ) == UTF8_THREE_BYTES )
+            {
+                // Three bytes char
+                // 1110-tttt 10xx-xxyy 10zz-zzzz -> tttt-xxxx yyzz-zzzz (FF FF)
+                return ( char ) ( ( ( bytes[pos] & 0x0F ) << 12 )
+                    + ( ( bytes[pos + 1] & 0x3C ) << 6 )
+                    + ( ( bytes[pos + 1] & 0x03 ) << 6 )
+                    + ( bytes[pos + 2] & 0x3F )
+                );
+            }
+            else if ( ( bytes[pos] & UTF8_FOUR_BYTES_MASK ) == UTF8_FOUR_BYTES )
+            {
+                // Four bytes char
+                return ( char ) (
+                // 1111-0ttt 10uu-vvvv 10xx-xxyy 10zz-zzzz -> 000t-ttuu vvvv-xxxx yyzz-zzzz (1FFFFF)
+                ( ( bytes[pos] & 0x07 ) << 18 )
+                    + ( ( bytes[pos + 1] & 0x30 ) << 16 )
+                    + ( ( bytes[pos + 1] & 0x0F ) << 12 )
+                    + ( ( bytes[pos + 2] & 0x3C ) << 6 )
+                    + ( ( bytes[pos + 2] & 0x03 ) << 6 )
+                    + ( bytes[pos + 3] & 0x3F )
+                );
+            }
+            else if ( ( bytes[pos] & UTF8_FIVE_BYTES_MASK ) == UTF8_FIVE_BYTES )
+            {
+                // Five bytes char
+                return ( char ) (
+                // 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+                // 0000-00tt uuuu-uuvv wwww-xxxx yyzz-zzzz (03 FF FF FF)
+                ( ( bytes[pos] & 0x03 ) << 24 )
+                    + ( ( bytes[pos + 1] & 0x3F ) << 18 )
+                    + ( ( bytes[pos + 2] & 0x30 ) << 12 )
+                    + ( ( bytes[pos + 2] & 0x0F ) << 12 )
+                    + ( ( bytes[pos + 3] & 0x3C ) << 6 )
+                    + ( ( bytes[pos + 3] & 0x03 ) << 6 )
+                    + ( bytes[pos + 4] & 0x3F )
+                );
+            }
+            else if ( ( bytes[pos] & UTF8_FIVE_BYTES_MASK ) == UTF8_FIVE_BYTES )
+            {
+                // Six bytes char
+                return ( char ) (
+                // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz
+                // -> 0stt-tttt uuuu-uuvv wwww-xxxx yyzz-zzzz (7F FF FF FF)
+                ( ( bytes[pos] & 0x01 ) << 30 )
+                    + ( ( bytes[pos + 1] & 0x3F ) << 24 )
+                    + ( ( bytes[pos + 2] & 0x3F ) << 18 )
+                    + ( ( bytes[pos + 3] & 0x30 ) << 12 )
+                    + ( ( bytes[pos + 3] & 0x0F ) << 12 )
+                    + ( ( bytes[pos + 4] & 0x3C ) << 6 )
+                    + ( ( bytes[pos + 4] & 0x03 ) << 6 )
+                    + ( bytes[pos + 5] & 0x3F )
+                );
+            }
+            else
+            {
+                return ( char ) -1;
+            }
+        }
+    }
+
+
+    /**
+     * Return the number of bytes that hold an Unicode char.
+     *
+     * @param car The character to be decoded
+     * @return The number of bytes to hold the char. TODO : Should stop after
+     *         the third byte, as a char is only 2 bytes long.
+     */
+    public static int countNbBytesPerChar( char car )
+    {
+        if ( ( car & CHAR_ONE_BYTE_MASK ) == 0 )
+        {
+            return 1;
+        }
+        else if ( ( car & CHAR_TWO_BYTES_MASK ) == 0 )
+        {
+            return 2;
+        }
+        else if ( ( car & CHAR_THREE_BYTES_MASK ) == 0 )
+        {
+            return 3;
+        }
+        else if ( ( car & CHAR_FOUR_BYTES_MASK ) == 0 )
+        {
+            return 4;
+        }
+        else if ( ( car & CHAR_FIVE_BYTES_MASK ) == 0 )
+        {
+            return 5;
+        }
+        else if ( ( car & CHAR_SIX_BYTES_MASK ) == 0 )
+        {
+            return 6;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+
+    /**
+     * Count the number of bytes included in the given char[].
+     *
+     * @param chars The char array to decode
+     * @return The number of bytes in the char array
+     */
+    public static int countBytes( char[] chars )
+    {
+        if ( chars == null )
+        {
+            return 0;
+        }
+
+        int nbBytes = 0;
+        int currentPos = 0;
+
+        while ( currentPos < chars.length )
+        {
+            int nbb = countNbBytesPerChar( chars[currentPos] );
+
+            // If the number of bytes necessary to encode a character is
+            // above 3, we will need two UTF-16 chars
+            currentPos += ( nbb < 4 ? 1 : 2 );
+            nbBytes += nbb;
+        }
+
+        return nbBytes;
+    }
+
+
+    /**
+     * Count the number of chars included in the given byte[].
+     *
+     * @param bytes The byte array to decode
+     * @return The number of char in the byte array
+     */
+    public static int countChars( byte[] bytes )
+    {
+        if ( bytes == null )
+        {
+            return 0;
+        }
+
+        int nbChars = 0;
+        int currentPos = 0;
+
+        while ( currentPos < bytes.length )
+        {
+            currentPos += countBytesPerChar( bytes, currentPos );
+            nbChars++;
+        }
+
+        return nbChars;
+    }
+
+
+    /**
+     * Return the Unicode char which is coded in the bytes at the given
+     * position.
+     *
+     * @param car The character to be transformed to an array of bytes
+     *
+     * @return The byte array representing the char
+     *
+     * TODO : Should stop after the third byte, as a char is only 2 bytes long.
+     */
+    public static byte[] charToBytes( char car )
+    {
+        byte[] bytes = new byte[countNbBytesPerChar( car )];
+
+        if ( car <= 0x7F )
+        {
+            // Single byte char
+            bytes[0] = ( byte ) car;
+            return bytes;
+        }
+        else if ( car <= 0x7FF )
+        {
+            // two bytes char
+            bytes[0] = ( byte ) ( 0x00C0 + ( ( car & 0x07C0 ) >> 6 ) );
+            bytes[1] = ( byte ) ( 0x0080 + ( car & 0x3F ) );
+        }
+        else
+        {
+            // Three bytes char
+            bytes[0] = ( byte ) ( 0x00E0 + ( ( car & 0xF000 ) >> 12 ) );
+            bytes[1] = ( byte ) ( 0x0080 + ( ( car & 0x0FC0 ) >> 6 ) );
+            bytes[2] = ( byte ) ( 0x0080 + ( car & 0x3F ) );
+        }
+
+        return bytes;
+    }
+
+
+    /**
+     * Check if the current char is in the unicodeSubset : all chars but
+     * '\0', '(', ')', '*' and '\'
+     *
+     * @param str The string to check
+     * @param pos Position of the current char
+     * @return True if the current char is in the unicode subset
+     */
+    public static boolean isUnicodeSubset( String str, int pos )
+    {
+        if ( ( str == null ) || ( str.length() <= pos ) || ( pos < 0 ) )
+        {
+            return false;
+        }
+
+        char c = str.charAt( pos );
+
+        return ( ( c > 127 ) || UNICODE_SUBSET[c] );
+    }
+
+
+    /**
+     * Check if the current char is in the unicodeSubset : all chars but
+     * '\0', '(', ')', '*' and '\'
+     *
+     * @param c The char to check
+     * @return True if the current char is in the unicode subset
+     */
+    public static boolean isUnicodeSubset( char c )
+    {
+        return ( ( c > 127 ) || UNICODE_SUBSET[c] );
+    }
+
+
+    /**
+     * Check if the current byte is in the unicodeSubset : all chars but
+     * '\0', '(', ')', '*' and '\'
+     *
+     * @param b The byte to check
+     * @return True if the current byte is in the unicode subset
+     */
+    public static boolean isUnicodeSubset( byte b )
+    {
+        return ( ( b < 0 ) || ( b > 127 ) || UNICODE_SUBSET[b] );
+    }
+
+
+    /**
+     *
+     * Writes four bytes of length information to the output stream, followed by the modified UTF-8 representation
+     * of every character in the string str. If str is null, the string value 'null' is written with a length of 0
+     * instead of throwing an NullPointerException. Each character in the string s  is converted to a group of one,
+     * two, or three bytes, depending on the value of the character.
+     *
+     * Due to given restrictions (total number of written bytes in a row can't exceed 65535) the total length is
+     * written in the length information (four bytes (writeInt)) and the string is split into smaller parts
+     * if necessary and written. As each character may be converted to a group of maximum 3 bytes and 65535 bytes
+     * can be written at maximum we're on the save side when writing a chunk of only 21845 (65535/3) characters at
+     * once.
+     *
+     * See also {@link java.io.DataOutput#writeUTF(String)}.
+     *
+     * @param objectOutput The objectOutput to write to
+     * @param str The value to write
+     * @throws java.io.IOException If the value can't be written to the file
+     */
+    public static void writeUTF( ObjectOutput objectOutput, String str ) throws IOException
+    {
+        // Write a 'null' string
+        if ( str == null )
+        {
+            objectOutput.writeInt( 0 );
+            objectOutput.writeUTF( "null" );
+        }
+        else
+        {
+            // Write length of string
+            objectOutput.writeInt( str.length() );
+
+            StringBuffer strBuf = new StringBuffer( str );
+
+            // Write the string in portions not larger than 21845 characters
+            while ( strBuf != null )
+            {
+                if ( strBuf.length() < 21845 )
+                {
+                    objectOutput.writeUTF( strBuf.substring( 0, strBuf.length() ) );
+                    strBuf = null;
+                }
+                else
+                {
+                    objectOutput.writeUTF( strBuf.substring( 0, 21845 ) );
+                    strBuf.delete( 0, 21845 );
+                }
+            }
+        }
+    }
+
+
+    /**
+     *
+     * Reads in a string that has been encoded using a modified UTF-8  format. The general contract of readUTF  is
+     * that it reads a representation of a Unicode character string encoded in modified UTF-8 format; this string of
+     * characters is then returned as a String.
+     *
+     * First, four bytes are read (readInt) and used to construct an unsigned 16-bit integer in exactly the manner
+     * of the readUnsignedShort  method . This integer value is called the UTF length and specifies the number of
+     * additional bytes to be read. These bytes are then converted to characters by considering them in groups. The
+     * length of each group is computed from the value of the first byte of the group. The byte following a group, if
+     * any, is the first byte of the next group.
+     *
+     *See also {@link java.io.DataInput#readUTF()}.
+     *
+     * @param objectInput The objectInput to read from
+     * @return The read string
+     * @throws java.io.IOException If the value can't be read
+     */
+    public static String readUTF( ObjectInput objectInput ) throws IOException
+    {
+        StringBuffer strBuf = null;
+
+        // Read length of the string
+        int strLength = objectInput.readInt();
+
+        // Start reading the string
+        strBuf = new StringBuffer( objectInput.readUTF() );
+
+        if ( strLength == 0 && strBuf.toString().equals( "null" ) )
+        {
+            // The special case of a 'null' string
+            return null;
+        }
+        else
+        {
+            while ( strLength > strBuf.length() )
+            {
+                strBuf.append( objectInput.readUTF() );
+            }
+            return strBuf.toString();
+        }
+    }
+
+
+    private Unicode()
+    {
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/UnixCrypt.java b/trunk/util/src/main/java/org/apache/directory/api/util/UnixCrypt.java
new file mode 100644
index 0000000..bbc3a91
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/UnixCrypt.java
@@ -0,0 +1,714 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+/*
+ * @(#)UnixCrypt.java    0.9 96/11/25
+ *
+ * Copyright (c) 1996 Aki Yoshida. All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software
+ * for non-commercial or commercial purposes and without fee is
+ * hereby granted provided that this copyright notice appears in
+ * all copies.
+ */
+
+/**
+ * Unix crypt(3C) utility
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ * modified April 2001
+ * by Iris Van den Broeke, Daniel Deville
+ */
+
+package org.apache.directory.api.util;
+
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/*
+ * @(#)UnixCrypt.java   0.9 96/11/25
+ *
+ * Copyright (c) 1996 Aki Yoshida. All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software
+ * for non-commercial or commercial purposes and without fee is
+ * hereby granted provided that this copyright notice appears in
+ * all copies.
+*/
+
+/**
+ * Unix crypt(3C) utility
+ *
+   * @author  Aki Yoshida
+ * 2001
+ * by Iris Van den Broeke, Daniel Deville
+ */
+
+/* ------------------------------------------------------------ */
+/** Unix Crypt.
+ * Implements the one way cryptography used by Unix systems for
+ * simple password protection.
+   * @author Greg Wilkins (gregw)
+ */
+public class UnixCrypt extends Object
+{
+
+    /* (mostly) Standard DES Tables from Tom Truscott */
+    private static final byte[] IP =
+        { 
+            /* initial permutation */
+            58, 50, 42, 34, 26, 18, 10, 2,
+            60, 52, 44, 36, 28, 20, 12, 4,
+            62, 54, 46, 38, 30, 22, 14, 6,
+            64, 56, 48, 40, 32, 24, 16, 8,
+            57, 49, 41, 33, 25, 17, 9, 1,
+            59, 51, 43, 35, 27, 19, 11, 3,
+            61, 53, 45, 37, 29, 21, 13, 5,
+            63, 55, 47, 39, 31, 23, 15, 7 };
+
+    /* The final permutation is the inverse of IP - no table is necessary */
+    private static final byte[] ExpandTr =
+        { 
+            /* expansion operation */
+            32, 1, 2, 3, 4, 5,
+            4, 5, 6, 7, 8, 9,
+            8, 9, 10, 11, 12, 13,
+            12, 13, 14, 15, 16, 17,
+            16, 17, 18, 19, 20, 21,
+            20, 21, 22, 23, 24, 25,
+            24, 25, 26, 27, 28, 29,
+            28, 29, 30, 31, 32, 1 };
+
+    private static final byte[] PC1 =
+        { 
+            /* permuted choice table 1 */
+            57, 49, 41, 33, 25, 17, 9,
+            1, 58, 50, 42, 34, 26, 18,
+            10, 2, 59, 51, 43, 35, 27,
+            19, 11, 3, 60, 52, 44, 36,
+
+            63, 55, 47, 39, 31, 23, 15,
+            7, 62, 54, 46, 38, 30, 22,
+            14, 6, 61, 53, 45, 37, 29,
+            21, 13, 5, 28, 20, 12, 4 };
+
+    private static final byte[] Rotates =
+        { 
+            /* PC1 rotation schedule */
+            1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
+
+    private static final byte[] PC2 =
+        { 
+            /* permuted choice table 2 */
+            9, 18, 14, 17, 11, 24, 1, 5,
+            22, 25, 3, 28, 15, 6, 21, 10,
+            35, 38, 23, 19, 12, 4, 26, 8,
+            43, 54, 16, 7, 27, 20, 13, 2,
+
+            0, 0, 41, 52, 31, 37, 47, 55,
+            0, 0, 30, 40, 51, 45, 33, 48,
+            0, 0, 44, 49, 39, 56, 34, 53,
+            0, 0, 46, 42, 50, 36, 29, 32 };
+
+    private static final byte[][] S =
+        { 
+            /* 48->32 bit substitution tables */
+            /* S[1]         */
+            { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+                0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+                4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+                15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 },
+            /* S[2]         */
+            { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+                3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+                0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+                13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 },
+            /* S[3]         */
+            { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+                13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+                13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+                1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 },
+            /* S[4]         */
+            { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+                13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+                10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+                3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 },
+            /* S[5]         */
+            { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+                14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+                4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+                11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 },
+            /* S[6]         */
+            { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+                10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+                9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+                4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 },
+            /* S[7]         */
+            { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+                13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+                1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+                6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 },
+            /* S[8]         */
+            { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+                1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+                7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+                2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } };
+
+    private static final byte[] P32Tr =
+        { 
+            /* 32-bit permutation function */
+            16, 7, 20, 21,
+            29, 12, 28, 17,
+            1, 15, 23, 26,
+            5, 18, 31, 10,
+            2, 8, 24, 14,
+            32, 27, 3, 9,
+            19, 13, 30, 6,
+            22, 11, 4, 25 };
+
+    private static final byte[] CIFP =
+        { 
+            /* compressed/interleaved permutation */
+            1, 2, 3, 4, 17, 18, 19, 20,
+            5, 6, 7, 8, 21, 22, 23, 24,
+            9, 10, 11, 12, 25, 26, 27, 28,
+            13, 14, 15, 16, 29, 30, 31, 32,
+
+            33, 34, 35, 36, 49, 50, 51, 52,
+            37, 38, 39, 40, 53, 54, 55, 56,
+            41, 42, 43, 44, 57, 58, 59, 60,
+            45, 46, 47, 48, 61, 62, 63, 64 };
+
+    private static final byte[] ITOA64 =
+        { 
+            /* 0..63 => ascii-64 */
+            ( byte ) '.',
+            ( byte ) '/',
+            ( byte ) '0',
+            ( byte ) '1',
+            ( byte ) '2',
+            ( byte ) '3',
+            ( byte ) '4',
+            ( byte ) '5',
+            ( byte ) '6',
+            ( byte ) '7',
+            ( byte ) '8',
+            ( byte ) '9',
+            ( byte ) 'A',
+            ( byte ) 'B',
+            ( byte ) 'C',
+            ( byte ) 'D',
+            ( byte ) 'E',
+            ( byte ) 'F',
+            ( byte ) 'G',
+            ( byte ) 'H',
+            ( byte ) 'I',
+            ( byte ) 'J',
+            ( byte ) 'K',
+            ( byte ) 'L',
+            ( byte ) 'M',
+            ( byte ) 'N',
+            ( byte ) 'O',
+            ( byte ) 'P',
+            ( byte ) 'Q',
+            ( byte ) 'R',
+            ( byte ) 'S',
+            ( byte ) 'T',
+            ( byte ) 'U',
+            ( byte ) 'V',
+            ( byte ) 'W',
+            ( byte ) 'X',
+            ( byte ) 'Y',
+            ( byte ) 'Z',
+            ( byte ) 'a',
+            ( byte ) 'b',
+            ( byte ) 'c',
+            ( byte ) 'd',
+            ( byte ) 'e',
+            ( byte ) 'f',
+            ( byte ) 'g',
+            ( byte ) 'h',
+            ( byte ) 'i',
+            ( byte ) 'j',
+            ( byte ) 'k',
+            ( byte ) 'l',
+            ( byte ) 'm',
+            ( byte ) 'n',
+            ( byte ) 'o',
+            ( byte ) 'p',
+            ( byte ) 'q',
+            ( byte ) 'r',
+            ( byte ) 's',
+            ( byte ) 't',
+            ( byte ) 'u',
+            ( byte ) 'v',
+            ( byte ) 'w',
+            ( byte ) 'x',
+            ( byte ) 'y',
+            ( byte ) 'z' };
+
+    /* =====  Tables that are initialized at run time  ==================== */
+
+    private static byte[] A64TOI = new byte[128]; /* ascii-64 => 0..63 */
+
+    /* Initial key schedule permutation */
+    private static long[][] PC1ROT = new long[16][16];
+
+    /* Subsequent key schedule rotation permutations */
+    private static long[][][] PC2ROT = new long[2][16][16];
+
+    /* Initial permutation/expansion table */
+    private static long[][] IE3264 = new long[8][16];
+
+    /* Table that combines the S, P, and E operations.  */
+    private static long[][] SPE = new long[8][64];
+
+    /* compressed/interleaved => final permutation table */
+    private static long[][] CF6464 = new long[16][16];
+
+    /* ==================================== */
+
+    static
+    {
+        byte[] perm = new byte[64];
+        byte[] temp = new byte[64];
+
+        // inverse table.
+        for ( int i = 0; i < 64; i++ )
+        {
+            A64TOI[ITOA64[i]] = ( byte ) i;
+        }
+
+        // PC1ROT - bit reverse, then PC1, then Rotate, then PC2
+        for ( int i = 0; i < 64; i++ )
+        {
+            perm[i] = ( byte ) 0;
+        }
+        
+        for ( int i = 0; i < 64; i++ )
+        {
+            int k;
+            
+            if ( ( k = PC2[i] ) == 0 )
+            {
+                continue;
+            }
+            
+            k += Rotates[0] - 1;
+            
+            if ( ( k % 28 ) < Rotates[0] )
+            {
+                k -= 28;
+            }
+            
+            k = PC1[k];
+            
+            if ( k > 0 )
+            {
+                k--;
+                k = ( k | 0x07 ) - ( k & 0x07 );
+                k++;
+            }
+            
+            perm[i] = ( byte ) k;
+        }
+        
+        init_perm( PC1ROT, perm, 8 );
+
+        // PC2ROT - PC2 inverse, then Rotate, then PC2
+        for ( int j = 0; j < 2; j++ )
+        {
+            int k;
+            
+            for ( int i = 0; i < 64; i++ )
+            {
+                perm[i] = temp[i] = 0;
+            }
+            
+            for ( int i = 0; i < 64; i++ )
+            {
+                if ( ( k = PC2[i] ) == 0 )
+                {
+                    continue;
+                }
+                
+                temp[k - 1] = ( byte ) ( i + 1 );
+            }
+            
+            for ( int i = 0; i < 64; i++ )
+            {
+                if ( ( k = PC2[i] ) == 0 )
+                {
+                    continue;
+                }
+                
+                k += j;
+                
+                if ( ( k % 28 ) <= j )
+                {
+                    k -= 28;
+                }
+                
+                perm[i] = temp[k];
+            }
+
+            init_perm( PC2ROT[j], perm, 8 );
+        }
+
+        // Bit reverse, intial permupation, expantion
+        for ( int i = 0; i < 8; i++ )
+        {
+            for ( int j = 0; j < 8; j++ )
+            {
+                int k = ( j < 2 ) ? 0 : IP[ExpandTr[i * 6 + j - 2] - 1];
+                
+                if ( k > 32 )
+                {
+                    k -= 32;
+                }
+                else if ( k > 0 )
+                {
+                    k--;
+                }
+                
+                if ( k > 0 )
+                {
+                    k--;
+                    k = ( k | 0x07 ) - ( k & 0x07 );
+                    k++;
+                }
+                
+                perm[i * 8 + j] = ( byte ) k;
+            }
+        }
+
+        init_perm( IE3264, perm, 8 );
+
+        // Compression, final permutation, bit reverse
+        for ( int i = 0; i < 64; i++ )
+        {
+            int k = IP[CIFP[i] - 1];
+            
+            if ( k > 0 )
+            {
+                k--;
+                k = ( k | 0x07 ) - ( k & 0x07 );
+                k++;
+            }
+            
+            perm[k - 1] = ( byte ) ( i + 1 );
+        }
+
+        init_perm( CF6464, perm, 8 );
+
+        // SPE table
+        for ( int i = 0; i < 48; i++ )
+        {
+            perm[i] = P32Tr[ExpandTr[i] - 1];
+        }
+        
+        for ( int t = 0; t < 8; t++ )
+        {
+            for ( int j = 0; j < 64; j++ )
+            {
+                int k = ( ( ( j >> 0 ) & 0x01 ) << 5 ) | ( ( ( j >> 1 ) & 0x01 ) << 3 ) |
+                    ( ( ( j >> 2 ) & 0x01 ) << 2 ) | ( ( ( j >> 3 ) & 0x01 ) << 1 ) |
+                    ( ( ( j >> 4 ) & 0x01 ) << 0 ) | ( ( ( j >> 5 ) & 0x01 ) << 4 );
+                k = S[t][k];
+                k = ( ( ( k >> 3 ) & 0x01 ) << 0 ) | ( ( ( k >> 2 ) & 0x01 ) << 1 ) |
+                    ( ( ( k >> 1 ) & 0x01 ) << 2 ) | ( ( ( k >> 0 ) & 0x01 ) << 3 );
+                
+                for ( int i = 0; i < 32; i++ )
+                {
+                    temp[i] = 0;
+                }
+                
+                for ( int i = 0; i < 4; i++ )
+                {
+                    temp[4 * t + i] = ( byte ) ( ( k >> i ) & 0x01 );
+                }
+                
+                long kk = 0;
+                
+                for ( int i = 24; --i >= 0; )
+                {
+                    kk = ( ( kk << 1 ) |
+                        ( ( long ) temp[perm[i] - 1] ) << 32 |
+                        ( temp[perm[i + 24] - 1] ) );
+                }
+
+                SPE[t][j] = to_six_bit( kk );
+            }
+        }
+    }
+
+
+    /**
+     * You can't call the constructer.
+     */
+    private UnixCrypt()
+    {
+    }
+
+
+    /**
+     * Returns the transposed and split code of a 24-bit code
+     * into a 4-byte code, each having 6 bits.
+     */
+    private static int to_six_bit( int num )
+    {
+        return ( ( ( num << 26 ) & 0xfc000000 ) | ( ( num << 12 ) & 0xfc0000 ) |
+            ( ( num >> 2 ) & 0xfc00 ) | ( ( num >> 16 ) & 0xfc ) );
+    }
+
+
+    /**
+     * Returns the transposed and split code of two 24-bit code 
+     * into two 4-byte code, each having 6 bits.
+     */
+    private static long to_six_bit( long num )
+    {
+        return ( ( ( num << 26 ) & 0xfc000000fc000000L ) | ( ( num << 12 ) & 0xfc000000fc0000L ) |
+            ( ( num >> 2 ) & 0xfc000000fc00L ) | ( ( num >> 16 ) & 0xfc000000fcL ) );
+    }
+
+
+    /**
+     * Returns the permutation of the given 64-bit code with
+     * the specified permutataion table.
+     */
+    private static long perm6464( long c, long[][] p )
+    {
+        long out = 0L;
+        
+        for ( int i = 8; --i >= 0; )
+        {
+            int t = ( int ) ( 0x00ff & c );
+            c >>= 8;
+            long tp = p[i << 1][t & 0x0f];
+            out |= tp;
+            tp = p[( i << 1 ) + 1][t >> 4];
+            out |= tp;
+        }
+        
+        return out;
+    }
+
+
+    /**
+     * Returns the permutation of the given 32-bit code with
+     * the specified permutataion table.
+     */
+    private static long perm3264( int c, long[][] p )
+    {
+        long out = 0L;
+        
+        for ( int i = 4; --i >= 0; )
+        {
+            int t = ( 0x00ff & c );
+            c >>= 8;
+            long tp = p[i << 1][t & 0x0f];
+            out |= tp;
+            tp = p[( i << 1 ) + 1][t >> 4];
+            out |= tp;
+        }
+        
+        return out;
+    }
+
+
+    /**
+     * Returns the key schedule for the given key.
+     */
+    private static long[] des_setkey( long keyword )
+    {
+        long K = perm6464( keyword, PC1ROT );
+        long[] KS = new long[16];
+        KS[0] = K & ~0x0303030300000000L;
+
+        for ( int i = 1; i < 16; i++ )
+        {
+            KS[i] = K;
+            K = perm6464( K, PC2ROT[Rotates[i] - 1] );
+
+            KS[i] = K & ~0x0303030300000000L;
+        }
+        return KS;
+    }
+
+
+    /**
+     * Returns the DES encrypted code of the given word with the specified 
+     * environment.
+     */
+    private static long des_cipher( long in, int salt, int num_iter, long[] KS )
+    {
+        salt = to_six_bit( salt );
+        long L = in;
+        long R = L;
+        L &= 0x5555555555555555L;
+        R = ( R & 0xaaaaaaaa00000000L ) | ( ( R >> 1 ) & 0x0000000055555555L );
+        L = ( ( ( ( L << 1 ) | ( L << 32 ) ) & 0xffffffff00000000L ) |
+            ( ( R | ( R >> 32 ) ) & 0x00000000ffffffffL ) );
+
+        L = perm3264( ( int ) ( L >> 32 ), IE3264 );
+        R = perm3264( ( int ) ( L & 0xffffffff ), IE3264 );
+
+        while ( --num_iter >= 0 )
+        {
+            for ( int loop_count = 0; loop_count < 8; loop_count++ )
+            {
+                long kp;
+                long B;
+                long k;
+
+                kp = KS[( loop_count << 1 )];
+                k = ( ( R >> 32 ) ^ R ) & salt & 0xffffffffL;
+                k |= ( k << 32 );
+                B = ( k ^ R ^ kp );
+
+                L ^= ( SPE[0][( int ) ( ( B >> 58 ) & 0x3f )] ^ SPE[1][( int ) ( ( B >> 50 ) & 0x3f )] ^
+                    SPE[2][( int ) ( ( B >> 42 ) & 0x3f )] ^ SPE[3][( int ) ( ( B >> 34 ) & 0x3f )] ^
+                    SPE[4][( int ) ( ( B >> 26 ) & 0x3f )] ^ SPE[5][( int ) ( ( B >> 18 ) & 0x3f )] ^
+                    SPE[6][( int ) ( ( B >> 10 ) & 0x3f )] ^ SPE[7][( int ) ( ( B >> 2 ) & 0x3f )] );
+
+                kp = KS[( loop_count << 1 ) + 1];
+                k = ( ( L >> 32 ) ^ L ) & salt & 0xffffffffL;
+                k |= ( k << 32 );
+                B = ( k ^ L ^ kp );
+
+                R ^= ( SPE[0][( int ) ( ( B >> 58 ) & 0x3f )] ^ SPE[1][( int ) ( ( B >> 50 ) & 0x3f )] ^
+                    SPE[2][( int ) ( ( B >> 42 ) & 0x3f )] ^ SPE[3][( int ) ( ( B >> 34 ) & 0x3f )] ^
+                    SPE[4][( int ) ( ( B >> 26 ) & 0x3f )] ^ SPE[5][( int ) ( ( B >> 18 ) & 0x3f )] ^
+                    SPE[6][( int ) ( ( B >> 10 ) & 0x3f )] ^ SPE[7][( int ) ( ( B >> 2 ) & 0x3f )] );
+            }
+            // swap L and R
+            L ^= R;
+            R ^= L;
+            L ^= R;
+        }
+        L = ( ( ( ( L >> 35 ) & 0x0f0f0f0fL ) | ( ( ( L & 0xffffffff ) << 1 ) & 0xf0f0f0f0L ) ) << 32 |
+            ( ( ( R >> 35 ) & 0x0f0f0f0fL ) | ( ( ( R & 0xffffffff ) << 1 ) & 0xf0f0f0f0L ) ) );
+
+        L = perm6464( L, CF6464 );
+
+        return L;
+    }
+
+
+    /**
+     * Initializes the given permutation table with the mapping table.
+     */
+    private static void init_perm( long[][] perm, byte[] p, int chars_out )
+    {
+        for ( int k = 0; k < chars_out * 8; k++ )
+        {
+
+            int l = p[k] - 1;
+            
+            if ( l < 0 )
+            {
+                continue;
+            }
+            
+            int i = l >> 2;
+            l = 1 << ( l & 0x03 );
+            
+            for ( int j = 0; j < 16; j++ )
+            {
+                int s = ( ( k & 0x07 ) + ( ( 7 - ( k >> 3 ) ) << 3 ) );
+                
+                if ( ( j & l ) != 0x00 )
+                {
+                    perm[i][j] |= ( 1L << s );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Encrypts String into crypt (Unix) code.
+     * @param key the key to be encrypted
+     * @param setting the salt to be used
+     * @return the encrypted String
+     */
+    @SuppressWarnings("deprecation")
+    public static String crypt( String key, String setting )
+    {
+        /* encryption constant */
+        long constdatablock = 0L; 
+        /* encrypted result */
+        byte[] cryptresult = new byte[13]; 
+        long keyword = 0L;
+        
+        /* invalid parameters! */
+        if ( key == null || setting == null )
+        {
+         // will NOT match under ANY circumstances!
+            return "*"; 
+        } 
+
+        int keylen = key.length();
+
+        for ( int i = 0; i < 8; i++ )
+        {
+            keyword = ( keyword << 8 ) | ( ( i < keylen ) ? 2 * key.charAt( i ) : 0 );
+        }
+
+        long[] KS = des_setkey( keyword );
+
+        int salt = 0;
+        
+        for ( int i = 2; --i >= 0; )
+        {
+            char c = ( i < setting.length() ) ? setting.charAt( i ) : '.';
+            cryptresult[i] = ( byte ) c;
+            salt = ( salt << 6 ) | ( 0x00ff & A64TOI[c] );
+        }
+
+        long rsltblock = des_cipher( constdatablock, salt, 25, KS );
+
+        cryptresult[12] = ITOA64[( ( ( int ) rsltblock ) << 2 ) & 0x3f];
+        rsltblock >>= 4;
+        
+        for ( int i = 12; --i >= 2; )
+        {
+            cryptresult[i] = ITOA64[( ( int ) rsltblock ) & 0x3f];
+            rsltblock >>= 6;
+        }
+
+        return new String( cryptresult, 0x00, 0, 13 );
+    }
+
+
+    public static void main( String[] arg )
+    {
+        if ( arg.length != 2 )
+        {
+            System.err.println( I18n.err( I18n.ERR_04439 ) );
+            System.exit( 1 );
+        }
+
+        System.err.println( I18n.err( I18n.ERR_04440, crypt( arg[0], arg[1] ) ) );
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/exception/Exceptions.java b/trunk/util/src/main/java/org/apache/directory/api/util/exception/Exceptions.java
new file mode 100644
index 0000000..edd4ea2
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/exception/Exceptions.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util.exception;
+
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * Provides utilities for manipulating and examining <code>Throwable</code>
+ * objects.
+ * </p>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class Exceptions
+{
+    /**
+     * Private constructor
+     */
+    private Exceptions()
+    {
+    }
+
+
+    /**
+     * Appends the messages of each Throwable to a string, separated by a new line.
+     *
+     * @param errors the errors
+     * @return the string with all error message
+     */
+    public static String printErrors( List<Throwable> errors )
+    {
+        StringBuilder sb = new StringBuilder();
+
+        for ( Throwable error : errors )
+        {
+            sb.append( "Error : " ).append( error.getMessage() ).append( "\n" );
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/exception/InvalidCharacterException.java b/trunk/util/src/main/java/org/apache/directory/api/util/exception/InvalidCharacterException.java
new file mode 100644
index 0000000..8a9ced2
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/exception/InvalidCharacterException.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.directory.api.util.exception;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.i18n.I18n;
+
+
+/**
+ * Exception thrown when a Character is invalid
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InvalidCharacterException extends IOException
+{
+    private static final long serialVersionUID = 1L;
+    private int input;
+
+
+    public InvalidCharacterException( int input )
+    {
+        this.input = input;
+    }
+
+
+    @Override
+    public String getMessage()
+    {
+        return I18n.err( I18n.ERR_04335, Integer.toHexString( input ) );
+    }
+}
\ No newline at end of file
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/exception/MultiException.java b/trunk/util/src/main/java/org/apache/directory/api/util/exception/MultiException.java
new file mode 100644
index 0000000..3a2378f
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/exception/MultiException.java
@@ -0,0 +1,189 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util.exception;
+
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+
+/**
+ * This exception is thrown when Base class for nested exceptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MultiException extends Exception
+{
+    /** The serialVersionUID. */
+    static final long serialVersionUID = 2889747406899775761L;
+
+    /** Collection of nested exceptions. */
+    private Collection<Throwable> nestedExceptions = new ArrayList<Throwable>();
+
+
+    /**
+     * Constructs an Exception without a message.
+     */
+    public MultiException()
+    {
+        super();
+    }
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     * 
+     * @param message
+     *            The message associated with the exception.
+     */
+    public MultiException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Lists the nested exceptions that this Exception encapsulates.
+     * 
+     * @return an Iterator over the nested exceptions.
+     */
+    public Iterator<Throwable> listNestedExceptions()
+    {
+        return nestedExceptions.iterator();
+    }
+
+
+    /**
+     * Gets the size of this nested exception which equals the number of
+     * exception nested within.
+     * 
+     * @return the size of this nested exception.
+     */
+    public int size()
+    {
+        return nestedExceptions.size();
+    }
+
+
+    /**
+     * Tests to see if there are any nested exceptions within this
+     * MultiException.
+     * 
+     * @return true if no exceptions are nested, false otherwise.
+     */
+    public boolean isEmpty()
+    {
+        return nestedExceptions.isEmpty();
+    }
+
+
+    /**
+     * Add an exeception to this multiexception.
+     * 
+     * @param nested
+     *            exception to add to this MultiException.
+     */
+    public void addThrowable( Throwable nested )
+    {
+        nestedExceptions.add( nested );
+    }
+
+
+    // ///////////////////////////////////////////
+    // Overriden Throwable Stack Trace Methods //
+    // ///////////////////////////////////////////
+
+    /**
+     * Beside printing out the standard stack trace this method prints out the
+     * stack traces of all the nested exceptions.
+     * 
+     * @param out
+     *            PrintWriter to write the nested stack trace to.
+     */
+    public void printStackTrace( PrintWriter out )
+    {
+        super.printStackTrace( out );
+
+        out.println( "Nested exceptions to follow:\n" );
+        boolean isFirst = true;
+
+        for ( Throwable throwable : nestedExceptions )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                out.println( "\n\t<<========= Next Nested Exception" + " ========>>\n" );
+            }
+
+            throwable.printStackTrace();
+        }
+
+        out.println( "\n\t<<========= Last Nested Exception" + " ========>>\n" );
+    }
+
+
+    /**
+     * Beside printing out the standard stack trace this method prints out the
+     * stack traces of all the nested exceptions.
+     * 
+     * @param out
+     *            PrintStream to write the nested stack trace to.
+     */
+    public void printStackTrace( PrintStream out )
+    {
+        super.printStackTrace( out );
+
+        out.println( "Nested exceptions to follow:\n" );
+        boolean isFirst = true;
+
+        for ( Throwable throwable : nestedExceptions )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                out.println( "\n\t<<========= Next Nested Exception" + " ========>>\n" );
+            }
+
+            throwable.printStackTrace();
+        }
+
+        out.println( "\n\t<<========= Last Nested Exception" + " ========>>\n" );
+    }
+
+
+    /**
+     * Beside printing out the standard stack trace this method prints out the
+     * stack traces of all the nested exceptions using standard error.
+     */
+    public void printStackTrace()
+    {
+        this.printStackTrace( System.err );
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/exception/NotImplementedException.java b/trunk/util/src/main/java/org/apache/directory/api/util/exception/NotImplementedException.java
new file mode 100644
index 0000000..0614d68
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/exception/NotImplementedException.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util.exception;
+
+
+/**
+ * This exception is thrown when a Backend operation is either temporarily
+ * unsupported or perminantly unsupported as part of its implementation. Write
+ * operations on a backend set to readonly throw a type of unsupported exception
+ * called ReadOnlyException.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NotImplementedException extends RuntimeException
+{
+    /** The serialVersionUID. */
+    static final long serialVersionUID = -5899307402675964298L;
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     */
+    public NotImplementedException()
+    {
+        super( "N O T   I M P L E M E N T E D   Y E T !" );
+    }
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     * 
+     * @param msg
+     *            The message associated with the exception.
+     */
+    public NotImplementedException( String msg )
+    {
+        super( "N O T   I M P L E M E N T E D   Y E T !\n" + msg );
+    }
+}
diff --git a/trunk/util/src/main/java/org/apache/directory/api/util/exception/RuntimeMultiException.java b/trunk/util/src/main/java/org/apache/directory/api/util/exception/RuntimeMultiException.java
new file mode 100644
index 0000000..def81bf
--- /dev/null
+++ b/trunk/util/src/main/java/org/apache/directory/api/util/exception/RuntimeMultiException.java
@@ -0,0 +1,198 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util.exception;
+
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+
+/**
+ * This exception is thrown when Base class for nested exceptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class RuntimeMultiException extends RuntimeException
+{
+    /** The serialVersionUID. */
+    private static final long serialVersionUID = 8582253398936366771L;
+
+    /** Collection of nested exceptions. */
+    private Collection<Throwable> nestedExceptions = new ArrayList<Throwable>();
+
+
+    /**
+     * Constructs an Exception without a message.
+     */
+    public RuntimeMultiException()
+    {
+        super();
+    }
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     *
+     * @param message The message associated with the exception.
+     */
+    public RuntimeMultiException( String message )
+    {
+        super( message );
+    }
+
+
+    /**
+     * Constructs an Exception with a detailed message.
+     *
+     * @param message The message associated with the exception.
+     */
+    public RuntimeMultiException( String message, Throwable t )
+    {
+        super( message );
+        nestedExceptions.add( t );
+    }
+
+
+    /**
+     * Lists the nested exceptions that this Exception encapsulates.
+     * 
+     * @return an Iterator over the nested exceptions.
+     */
+    public Iterator<Throwable> listNestedExceptions()
+    {
+        return nestedExceptions.iterator();
+    }
+
+
+    /**
+     * Gets the size (number of) exceptions nested within this exception.
+     * 
+     * @return the size of this nested exception.
+     */
+    public int size()
+    {
+        return nestedExceptions.size();
+    }
+
+
+    /**
+     * Tests to see if exceptions are nested within this exception.
+     * 
+     * @return true if an exception is nested, false otherwise
+     */
+    public boolean isEmpty()
+    {
+        return nestedExceptions.isEmpty();
+    }
+
+
+    /**
+     * Add an exeception to this multiexception.
+     * 
+     * @param nested
+     *            exception to add to this MultiException.
+     */
+    public void addThrowable( Throwable nested )
+    {
+        nestedExceptions.add( nested );
+    }
+
+
+    // ///////////////////////////////////////////
+    // Overriden Throwable Stack Trace Methods //
+    // ///////////////////////////////////////////
+
+    /**
+     * Beside printing out the standard stack trace this method prints out the
+     * stack traces of all the nested exceptions.
+     * 
+     * @param out
+     *            PrintWriter to write the nested stack trace to.
+     */
+    public void printStackTrace( PrintWriter out )
+    {
+        super.printStackTrace( out );
+
+        out.println( "Nested exceptions to follow:\n" );
+        boolean isFirst = true;
+
+        for ( Throwable throwable : nestedExceptions )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                out.println( "\n\t<<========= Next Nested Exception" + " ========>>\n" );
+            }
+
+            throwable.printStackTrace();
+        }
+
+        out.println( "\n\t<<========= Last Nested Exception" + " ========>>\n" );
+    }
+
+
+    /**
+     * Beside printing out the standard stack trace this method prints out the
+     * stack traces of all the nested exceptions.
+     * 
+     * @param out
+     *            PrintStream to write the nested stack trace to.
+     */
+    public void printStackTrace( PrintStream out )
+    {
+        super.printStackTrace( out );
+
+        out.println( "Nested exceptions to follow:\n" );
+        boolean isFirst = true;
+
+        for ( Throwable throwable : nestedExceptions )
+        {
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                out.println( "\n\t<<========= Next Nested Exception" + " ========>>\n" );
+            }
+
+            throwable.printStackTrace();
+        }
+
+        out.println( "\n\t<<========= Last Nested Exception" + " ========>>\n" );
+    }
+
+
+    /**
+     * Beside printing out the standard stack trace this method prints out the
+     * stack traces of all the nested exceptions using standard error.
+     */
+    public void printStackTrace()
+    {
+        this.printStackTrace( System.err );
+    }
+}
diff --git a/trunk/util/src/site/site.xml b/trunk/util/src/site/site.xml
new file mode 100644
index 0000000..8f27351
--- /dev/null
+++ b/trunk/util/src/site/site.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+-->
+<project name="${project.name}">
+  <body>
+    <menu ref="parent" />
+    <menu ref="reports" />
+  </body>
+</project>
diff --git a/trunk/util/src/test/java/org/apache/directory/api/util/ByteBufferTest.java b/trunk/util/src/test/java/org/apache/directory/api/util/ByteBufferTest.java
new file mode 100644
index 0000000..fc102ea
--- /dev/null
+++ b/trunk/util/src/test/java/org/apache/directory/api/util/ByteBufferTest.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A test case for a dynamically growing byte[]. 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class ByteBufferTest
+{
+    @Test
+    public void testByteBufferGrowth()
+    {
+        ByteBuffer buf = new ByteBuffer();
+        assertEquals( 10, buf.capacity() );
+
+        for ( int ii = 0; ii < 20; ii++ )
+        {
+            buf.append( ii );
+            assertEquals( ii, buf.get( ii ) );
+            assertEquals( ii, buf.buffer()[ii] );
+        }
+
+        assertEquals( 20, buf.capacity() );
+        buf.append( 20 );
+        assertEquals( 30, buf.capacity() );
+
+        // -------------------------------------------------------------------
+
+        buf = new ByteBuffer( 5 );
+        assertEquals( 5, buf.capacity() );
+
+        for ( int ii = 0; ii < 5; ii++ )
+        {
+            buf.append( ii );
+            assertEquals( ii, buf.get( ii ) );
+            assertEquals( ii, buf.buffer()[ii] );
+        }
+
+        assertEquals( 5, buf.capacity() );
+        buf.append( 5 );
+        assertEquals( 10, buf.capacity() );
+    }
+
+
+    @Test
+    public void testCopyOfUsedBytes()
+    {
+        ByteBuffer buf = new ByteBuffer();
+        byte[] bytes = buf.copyOfUsedBytes();
+        assertEquals( 0, bytes.length );
+
+        for ( int ii = 0; ii < 20; ii++ )
+        {
+            buf.append( ii );
+            assertEquals( ii, buf.get( ii ) );
+            assertEquals( ii, buf.buffer()[ii] );
+            assertEquals( ii, buf.copyOfUsedBytes()[ii] );
+        }
+    }
+
+
+    @Test
+    public void testAppendByteArray()
+    {
+        ByteBuffer buf = new ByteBuffer();
+        buf.append( new byte[]
+            { 0, 1, 2, 3, 4 } );
+        for ( int ii = 0; ii < 5; ii++ )
+        {
+            assertEquals( ii, buf.get( ii ) );
+            assertEquals( ii, buf.buffer()[ii] );
+            assertEquals( ii, buf.copyOfUsedBytes()[ii] );
+        }
+    }
+}
diff --git a/trunk/util/src/test/java/org/apache/directory/api/util/GeneralizedTimeTest.java b/trunk/util/src/test/java/org/apache/directory/api/util/GeneralizedTimeTest.java
new file mode 100644
index 0000000..34ed303
--- /dev/null
+++ b/trunk/util/src/test/java/org/apache/directory/api/util/GeneralizedTimeTest.java
@@ -0,0 +1,1235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThat;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.api.util.GeneralizedTime.Format;
+import org.apache.directory.api.util.GeneralizedTime.TimeZoneFormat;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Tests the DateUtils class methods.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class GeneralizedTimeTest
+{
+    private static final Logger LOG = LoggerFactory.getLogger( GeneralizedTimeTest.class );
+
+
+    // Test all valid variants:
+    // Time: min + sec / min + no sec / no min + no sec 
+    // Fraction: no fraction, dot, comma
+    // Timezone: Z / +HH / +HHmm / -HH / -HHmm
+
+    /**
+     * Tests yyyyMMddHHmmssZ.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecZulu() throws ParseException
+    {
+        String gt = "20080102121314Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss+04.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecPlusHour() throws ParseException
+    {
+        String gt = "20080102121314+04";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss-1030.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecMinusHourMin() throws ParseException
+    {
+        String gt = "20080102121314-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss.SSSZ.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecDotFractionZulu() throws ParseException
+    {
+        String gt = "20080102121314.987Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss.SSS+0100.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecDotFractionPlusHour() throws ParseException
+    {
+        String gt = "20080102121314.987+0100";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss.SSS-1030.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecDotFractionMinusHourMin() throws ParseException
+    {
+        String gt = "20080102121314.987-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss,SSSZ.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecCommaFractionZulu() throws ParseException
+    {
+        String gt = "20080102121314,987Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss,SSS+0100.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecCommaFractionPlusHour() throws ParseException
+    {
+        String gt = "20080102121314,987+0100";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmss,SSS-1030.
+     */
+    @Test
+    public void testYearMonthDayHourMinSecCommaFractionMinusHourMin() throws ParseException
+    {
+        String gt = "20080102121314,987-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmmZ.
+     */
+    @Test
+    public void testYearMonthDayHourMinZulu() throws ParseException
+    {
+        String gt = "200801021213Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm+HH.
+     */
+    @Test
+    public void testYearMonthDayHourMinPlusHour() throws ParseException
+    {
+        String gt = "200801021213+04";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm-HHmm.
+     */
+    @Test
+    public void testYearMonthDayHourMinMinusHourMin() throws ParseException
+    {
+        String gt = "200801021213-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm.SSSZ.
+     */
+    @Test
+    public void testYearMonthDayHourMinDotFractionZulu() throws ParseException
+    {
+        String gt = "200801021213.987Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm.SSS+0100.
+     */
+    @Test
+    public void testYearMonthDayHourMinDotFractionPlusHour() throws ParseException
+    {
+        String gt = "200801021213.987+0100";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm.SSS-1030.
+     */
+    @Test
+    public void testYearMonthDayHourMinDotFractionMinusHourMin() throws ParseException
+    {
+        String gt = "200801021213.987-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm,SSSZ.
+     */
+    @Test
+    public void testYearMonthDayHourMinCommaFractionZulu() throws ParseException
+    {
+        String gt = "200801021213,987Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm,SSS+0100.
+     */
+    @Test
+    public void testYearMonthDayHourMinCommaFractionPlusHour() throws ParseException
+    {
+        String gt = "200801021213,987+0100";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHmm,SSS-1030.
+     */
+    @Test
+    public void testYearMonthDayHourMinCommaFractionMinusHourMin() throws ParseException
+    {
+        String gt = "200801021213,987-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHHZ.
+     */
+    @Test
+    public void testYearMonthDayHourZulu() throws ParseException
+    {
+        String gt = "2008010212Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH+HH.
+     */
+    @Test
+    public void testYearMonthDayHourPlusHour() throws ParseException
+    {
+        String gt = "2008010212+04";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH-HHmm.
+     */
+    @Test
+    public void testYearMonthDayHourMinusHourMin() throws ParseException
+    {
+        String gt = "2008010212-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH.SSSZ.
+     */
+    @Test
+    public void testYearMonthDayHourDotFractionZulu() throws ParseException
+    {
+        String gt = "200801021213.987Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH.SSS+0100.
+     */
+    @Test
+    public void testYearMonthDayHourDotFractionPlusHour() throws ParseException
+    {
+        String gt = "2008010212.987+0100";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH.SSS-1030.
+     */
+    @Test
+    public void testYearMonthDayHourDotFractionMinusHourMin() throws ParseException
+    {
+        String gt = "2008010212.987-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH,SSSZ.
+     */
+    @Test
+    public void testYearMonthDayHourCommaFractionZulu() throws ParseException
+    {
+        String gt = "2008010212,987Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH,SSS+0100.
+     */
+    @Test
+    public void testYearMonthDayHourCommaFractionPlusHour() throws ParseException
+    {
+        String gt = "2008010212,987+0100";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests yyyyMMddHH,SSS-1030.
+     */
+    @Test
+    public void testYearMonthDayHourCommaFractionMinusHourMin() throws ParseException
+    {
+        String gt = "2008010212,987-1030";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests fraction of a second.
+     */
+    @Test
+    public void testFractionOfSecond() throws ParseException
+    {
+        String gt = "20080102121314,987Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+        assertEquals( 987, generalizedTime.getCalendar().get( Calendar.MILLISECOND ) );
+    }
+
+
+    /**
+     * Tests fraction of a minute.
+     */
+    @Test
+    public void testFractionOfMinute1() throws ParseException
+    {
+        String gt = "200801021213,5Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+        assertEquals( 30, generalizedTime.getCalendar().get( Calendar.SECOND ) );
+        assertEquals( 0, generalizedTime.getCalendar().get( Calendar.MILLISECOND ) );
+    }
+
+
+    /**
+     * Tests fraction of a minute.
+     */
+    @Test
+    public void testFractionOfMinute2() throws ParseException
+    {
+        String gt = "200801021213,125Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+        assertEquals( 7, generalizedTime.getCalendar().get( Calendar.SECOND ) );
+        assertEquals( 500, generalizedTime.getCalendar().get( Calendar.MILLISECOND ) );
+    }
+
+
+    /**
+     * Tests fraction of an hour.
+     */
+    @Test
+    public void testFractionOfHour1() throws ParseException
+    {
+        String gt = "2008010212,5Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+        assertEquals( 30, generalizedTime.getCalendar().get( Calendar.MINUTE ) );
+        assertEquals( 0, generalizedTime.getCalendar().get( Calendar.SECOND ) );
+        assertEquals( 0, generalizedTime.getCalendar().get( Calendar.MILLISECOND ) );
+    }
+
+
+    /**
+     * Tests fraction of an hour.
+     */
+    @Test
+    public void testFractionOfHour2() throws ParseException
+    {
+        String gt = "2008010212,125Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+        assertEquals( 7, generalizedTime.getCalendar().get( Calendar.MINUTE ) );
+        assertEquals( 30, generalizedTime.getCalendar().get( Calendar.SECOND ) );
+        assertEquals( 0, generalizedTime.getCalendar().get( Calendar.MILLISECOND ) );
+    }
+
+
+    /**
+     * Test formatting
+     */
+    @Test
+    public void testFormatting() throws ParseException
+    {
+        String gt = "20080102121314Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+
+        result = generalizedTime.toGeneralizedTime( Format.YEAR_MONTH_DAY_HOUR_MIN, null, 0, TimeZoneFormat.Z );
+        assertEquals( "200801021213Z", result );
+
+        result = generalizedTime.toGeneralizedTime( Format.YEAR_MONTH_DAY_HOUR, null, 0, TimeZoneFormat.Z );
+        assertEquals( "2008010212Z", result );
+
+        result = generalizedTime.toGeneralizedTime( Format.YEAR_MONTH_DAY_HOUR_MIN, null, 0,
+            TimeZoneFormat.DIFF_HOUR_MINUTE );
+        assertEquals( "200801021213+0000", result );
+
+        result = generalizedTime.toGeneralizedTime( Format.YEAR_MONTH_DAY_HOUR, null, 0,
+            TimeZoneFormat.DIFF_HOUR_MINUTE );
+        assertEquals( "2008010212+0000", result );
+    }
+
+
+    /**
+     * Test adjustment of time while formatting. 
+     */
+    @Test
+    public void testAdjustWhileFormatting() throws ParseException
+    {
+        String gt = "20080102121314+0130";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+
+        result = generalizedTime.toGeneralizedTime( Format.YEAR_MONTH_DAY_HOUR_MIN_SEC, null, 0, TimeZoneFormat.Z );
+        assertEquals( "20080102104314Z", result );
+    }
+
+
+    /**
+     * Testcases from GeneralizedTimeSyntaxCheckerTest#testCorrectCase().
+     */
+    @Test
+    public void testGeneralizedTimeSyntaxCheckerTestCorrectCase() throws ParseException
+    {
+        new GeneralizedTime( "20061205184527Z" );
+        new GeneralizedTime( "20061205184527+0500" );
+        new GeneralizedTime( "20061205184527-1234" );
+        new GeneralizedTime( "20061205184527.123Z" );
+        new GeneralizedTime( "20061205184527,123+0100" );
+        new GeneralizedTime( "2006120519Z" );
+    }
+
+
+    /**
+     * Testcases from GeneralizedTimeSyntaxCheckerTest#testErrorCase().
+     */
+    @Test
+    public void testGeneralizedTimeSyntaxCheckerTestErrorCase()
+    {
+        try
+        {
+            new GeneralizedTime( "20060005184527Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061305184527Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20062205184527Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061200184527Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061235184527Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205604527Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205186027Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205184561Z" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205184527Z+" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205184527+2400" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205184527+9900" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205184527+1260" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+        try
+        {
+            new GeneralizedTime( "20061205184527+1299" );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests leap second.
+     * The GeneralizedTime class does not support leap seconds!
+     */
+    @Test
+    public void testLeapSecond() throws ParseException
+    {
+        String gt = "20051231235960Z";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests Feb 29 in a leap year.
+     */
+    @Test
+    public void testFebruary29inLeapYear() throws ParseException
+    {
+        String gt = "20080229000000Z";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests Feb 29 in a non-leap year.
+     */
+    @Test
+    public void testFebruary29inNonLeapYear() throws ParseException
+    {
+        String gt = "20070229000000Z";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests null.
+     */
+    @Test
+    public void testNull() throws ParseException
+    {
+        try
+        {
+            String gt = null;
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        try
+        {
+            Calendar calendar = null;
+            new GeneralizedTime( calendar );
+            fail( "Expected IllegalArgumentException" );
+        }
+        catch ( IllegalArgumentException iae )
+        {
+            // expected
+        }
+
+    }
+
+
+    /**
+     * Tests empty string.
+     */
+    @Test
+    public void testEmpty() throws ParseException
+    {
+        String gt = "";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests invalid cases.
+     */
+    @Test
+    public void testInvalid() throws ParseException
+    {
+        // too short year
+        String gt = "200";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // non-digits in year
+        gt = "2XX8";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // too short month
+        gt = "20081";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // non-digits in month
+        gt = "20081X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // too short day
+        gt = "2008122";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // non-digits in day
+        gt = "2008122X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // too short hour
+        gt = "200812211";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // non-digits in hour
+        gt = "20081221X1";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // too short minute
+        gt = "20081221121";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // non-digits in minute
+        gt = "20081221121X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // too short second
+        gt = "2008122112131";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // non-digits in minute
+        gt = "2008122112131X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // missing time zone
+        gt = "2008010212";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // missing time zone
+        gt = "200801021213";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // missing time zone
+        gt = "20080102121314";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no digit
+        gt = "2008010212X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no digit
+        gt = "200801021213X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no digit
+        gt = "20080102121314X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // missing time zone
+        gt = "20080102121314,1";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // time zone is not last char
+        gt = "20080102121314ZX";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // time zone is not last char
+        gt = "20080102121314+0430X";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+
+        // no fraction digit
+        gt = "20080102121314,Z";
+        try
+        {
+            new GeneralizedTime( gt );
+            fail( "Expected ParseException" );
+        }
+        catch ( ParseException pe )
+        {
+            // expected
+        }
+    }
+
+
+    /**
+     * Tests constructor with calendar object.
+     */
+    @Test
+    public void testCalendar() throws ParseException
+    {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set( Calendar.YEAR, 2008 );
+        calendar.set( Calendar.MONTH, 0 );
+        calendar.set( Calendar.DAY_OF_MONTH, 2 );
+        calendar.set( Calendar.HOUR_OF_DAY, 12 );
+        calendar.set( Calendar.MINUTE, 13 );
+        calendar.set( Calendar.SECOND, 14 );
+        calendar.set( Calendar.MILLISECOND, 222 );
+        calendar.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
+
+        GeneralizedTime generalizedTime = new GeneralizedTime( calendar );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( "20080102121314.222Z", result );
+    }
+
+
+    /**
+     * Tests a complete round trip.
+     */
+    @Test
+    public void testRoundTrip() throws ParseException
+    {
+        Calendar calendar = Calendar.getInstance( TimeZone.getTimeZone( "GMT" ) );
+        calendar.setTimeInMillis( 123456789000L ); // default format is without millis
+
+        // create form calendar
+        GeneralizedTime generalizedTime1 = new GeneralizedTime( calendar );
+
+        // get the string value
+        String gt1 = generalizedTime1.toGeneralizedTime();
+        Calendar calendar1 = generalizedTime1.getCalendar();
+
+        // create from string value
+        GeneralizedTime generalizedTime2 = new GeneralizedTime( gt1 );
+
+        // get the calendar value 
+        Calendar calendar2 = generalizedTime2.getCalendar();
+        String gt2 = generalizedTime2.toGeneralizedTime();
+
+        // assert that all are equal
+        assertEquals( calendar, calendar1 );
+        assertEquals( calendar, calendar2 );
+        assertEquals( calendar1, calendar2 );
+        assertEquals( gt1, gt2 );
+        assertTrue( calendar.isLenient() );
+        assertTrue( calendar1.isLenient() );
+        assertTrue( calendar2.isLenient() );
+    }
+
+
+    /**
+     * Tests the compareTo() method.
+     */
+    @Test
+    public void testCompareTo() throws ParseException
+    {
+        String gt1 = "20080102121313,999Z";
+        GeneralizedTime generalizedTime1 = new GeneralizedTime( gt1 );
+
+        String gt2 = "20080102121314Z";
+        GeneralizedTime generalizedTime2 = new GeneralizedTime( gt2 );
+
+        String gt3 = "20080102121314,001Z";
+        GeneralizedTime generalizedTime3 = new GeneralizedTime( gt3 );
+
+        assertTrue( generalizedTime1.compareTo( generalizedTime2 ) < 0 );
+        assertTrue( generalizedTime1.compareTo( generalizedTime3 ) < 0 );
+        assertTrue( generalizedTime2.compareTo( generalizedTime3 ) < 0 );
+
+        assertTrue( generalizedTime2.compareTo( generalizedTime1 ) > 0 );
+        assertTrue( generalizedTime3.compareTo( generalizedTime1 ) > 0 );
+        assertTrue( generalizedTime3.compareTo( generalizedTime2 ) > 0 );
+
+        assertTrue( generalizedTime1.compareTo( generalizedTime1 ) == 0 );
+        assertTrue( generalizedTime2.compareTo( generalizedTime2 ) == 0 );
+        assertTrue( generalizedTime3.compareTo( generalizedTime3 ) == 0 );
+    }
+
+
+    /**
+     * Tests the equals() method.
+     */
+    @Test
+    public void testEquals() throws ParseException
+    {
+        String gt1 = "20080102121314Z";
+        GeneralizedTime generalizedTime1 = new GeneralizedTime( gt1 );
+
+        String gt2 = "20080102121314Z";
+        GeneralizedTime generalizedTime2 = new GeneralizedTime( gt2 );
+
+        String gt3 = "20080102121314,001Z";
+        GeneralizedTime generalizedTime3 = new GeneralizedTime( gt3 );
+
+        assertTrue( generalizedTime1.equals( generalizedTime2 ) );
+        assertFalse( generalizedTime1.equals( generalizedTime3 ) );
+        assertFalse( generalizedTime1.equals( null ) );
+    }
+
+
+    /**
+     * Tests DIRSHARED-29 (GeneralizedTime.toString() generates wrong output 
+     * when TimeZone has hours < 10 and minutes > 10).
+     */
+    public void testDIRSHARED29() throws ParseException
+    {
+        String gt = "20090312123456+0130";
+        GeneralizedTime generalizedTime = new GeneralizedTime( gt );
+        String result = generalizedTime.toGeneralizedTime();
+        assertEquals( gt, result );
+    }
+
+
+    /**
+     * Tests to make sure the GeneralizedTime parser preserves the milliseconds 
+     * component.
+     * 
+     * @see <a href="https://issues.apache.org/jira/browse/DIRSHARED-131">DIRSHARED-131</a>
+     */
+    @Test
+    public void testMillisecondsPreservation() throws ParseException
+    {
+        Date date = new Date();
+        long originalTime = 0;
+        long millisLost = 0;
+        long trimmedMillis = 0;
+
+        // Get the current date and time now, also with trimmed milliseconds
+
+        while ( millisLost == 0 )
+        {
+            date = new Date();
+            originalTime = date.getTime();
+            trimmedMillis = originalTime / 1000;
+            trimmedMillis = trimmedMillis * 1000;
+            millisLost = originalTime - trimmedMillis;
+        }
+
+        LOG.info( "original time = {}", originalTime );
+        LOG.info( "trimmed milliseconds = {}", trimmedMillis );
+        LOG.info( "milliseconds lost = {}", millisLost );
+
+        // Set time on new Calendar instance, and generate the GT string
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime( date );
+        GeneralizedTime gt = new GeneralizedTime( calendar );
+        assertEquals( "calendar time must equal the date time", date.getTime(), calendar.getTime().getTime() );
+        String gtStr = gt.toGeneralizedTime();
+        LOG.info( "generalized time string of original time = {}", gtStr );
+
+        // Parse and regenerate calendar from gtStr
+        GeneralizedTime recalculatedGt = new GeneralizedTime( gtStr );
+        long recalculatedTime = recalculatedGt.getCalendar().getTime().getTime();
+        LOG.info( "recalculated time = {}", recalculatedTime );
+        LOG.info( "generalized time string of recalculated time = {}", recalculatedGt.toGeneralizedTime() );
+
+        assertEquals( "The time after round trip GeneralizedTime generation should stay the same",
+            originalTime, recalculatedTime );
+    }
+    
+    static DateFormat format = new SimpleDateFormat( "dd/MM/yyyy HH:mm:ss.SSSS z" );
+    
+    @Test
+    public void fractionCloseToOne() throws ParseException
+    {
+        GeneralizedTime close = new GeneralizedTime( "20000101000000.9994Z" );
+        
+        assertThat( close.getDate(), is( equalTo( format.parse( "01/01/2000 00:00:00.999 GMT" ) ) ) );
+        
+        GeneralizedTime closer = new GeneralizedTime( "20000101000000.9995Z" );
+        
+        assertThat( closer.getDate(), is( equalTo( format.parse( "01/01/2000 00:00:00.999 GMT" ) ) ) );
+
+        GeneralizedTime larger = new GeneralizedTime( "20000101000000.9Z" );
+        
+        assertThat( larger.getDate(), is( equalTo( format.parse( "01/01/2000 00:00:00.900 GMT" ) ) ) );
+        
+    }
+}
diff --git a/trunk/util/src/test/java/org/apache/directory/api/util/HexTest.java b/trunk/util/src/test/java/org/apache/directory/api/util/HexTest.java
new file mode 100644
index 0000000..318a554
--- /dev/null
+++ b/trunk/util/src/test/java/org/apache/directory/api/util/HexTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.naming.NamingException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+
+/**
+ * Tests the StringTools class methods.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class HexTest
+{
+    @Test
+    public void testDecodeHexString() throws Exception
+    {
+        // weird stuff - corner cases
+        try
+        {
+            assertEquals( "", Hex.decodeHexString( "" ) );
+            fail( "should not get here" );
+        }
+        catch ( NamingException e )
+        {
+        }
+
+        assertEquals( "", Hex.decodeHexString( "#" ) );
+        assertEquals( "F", Hex.decodeHexString( "#46" ) );
+
+        try
+        {
+            assertEquals( "F", Hex.decodeHexString( "46" ) );
+            fail( "should not get here" );
+        }
+        catch ( NamingException e )
+        {
+        }
+
+        assertEquals( "Ferry", Hex.decodeHexString( "#4665727279" ) );
+    }
+}
diff --git a/trunk/util/src/test/java/org/apache/directory/api/util/MethodUtilsTest.java b/trunk/util/src/test/java/org/apache/directory/api/util/MethodUtilsTest.java
new file mode 100644
index 0000000..4961982
--- /dev/null
+++ b/trunk/util/src/test/java/org/apache/directory/api/util/MethodUtilsTest.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.api.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Test case for {@link MethodUtils}.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class MethodUtilsTest
+{
+    private static class TestClass
+    {
+        @SuppressWarnings("unused")
+        public static void methodA( String str )
+        {
+
+        }
+
+
+        @SuppressWarnings("unused")
+        public static void methodB( Collection<?> c )
+        {
+
+        }
+    }
+
+
+    @Test
+    public void testSameBehaviourOfStandardGetMethod()
+    {
+        Method m1 = null;
+        Method m2 = null;
+
+        try
+        {
+            m1 = TestClass.class.getMethod( "methodA", new Class[]
+                { String.class } );
+        }
+        catch ( SecurityException e )
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        catch ( NoSuchMethodException e )
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        try
+        {
+            m2 = MethodUtils.getAssignmentCompatibleMethod( TestClass.class, "methodA", new Class[]
+                { String.class } );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        assertEquals( m1, m2 );
+
+    }
+
+
+    @Test
+    public void testNewBehaviourOfAssignmentCompatibleGetMethod()
+    {
+        Method m2 = null;
+
+        try
+        {
+            TestClass.class.getMethod( "methodB", new Class[]
+                { ArrayList.class } );
+            fail( "We should not have come here." );
+        }
+        catch ( SecurityException e )
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        catch ( NoSuchMethodException e )
+        {
+            assertNotNull( e );
+        }
+
+        try
+        {
+            m2 = MethodUtils.getAssignmentCompatibleMethod( TestClass.class, "methodB", new Class[]
+                { ArrayList.class } );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        assertNotNull( m2 );
+
+    }
+
+}
diff --git a/trunk/util/src/test/java/org/apache/directory/api/util/OsgiUtilsTest.java b/trunk/util/src/test/java/org/apache/directory/api/util/OsgiUtilsTest.java
new file mode 100644
index 0000000..d9296b7
--- /dev/null
+++ b/trunk/util/src/test/java/org/apache/directory/api/util/OsgiUtilsTest.java
@@ -0,0 +1,157 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.api.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Set;
+
+import org.junit.Test;
+
+
+/**
+ * Unit tests for OsgiUtils.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OsgiUtilsTest
+{
+    private static final FileFilter REJECTION_FILTER = new FileFilter()
+    {
+        public boolean accept( File pathname )
+        {
+            return false;
+        }
+    };
+
+    private static final FileFilter JUNIT_SLF4J_FILTER = new FileFilter()
+    {
+        public boolean accept( File pathname )
+        {
+            return pathname.getAbsolutePath().contains( "junit" ) || pathname.getAbsolutePath().contains( "slf4j" );
+        }
+    };
+
+    private static final FileFilter ONLY_ONE_FILTER = new FileFilter()
+    {
+        boolean isDone = false;
+
+
+        public boolean accept( File pathname )
+        {
+            if ( isDone )
+            {
+                return false;
+            }
+
+            isDone = true;
+            return true;
+        }
+    };
+
+
+    @Test
+    public void testSplitIntoPackageVersions()
+    {
+        Set<String> pkgs = OsgiUtils.splitIntoPackages(
+            "org.ops4j.store.intern;uses:=\"org.ops4j.store,org.ops4j.io,org.apache.commons.logging\";"
+                + "version=\"1.2.2\",org.ops4j.store;uses:=\"org.ops4j.store.intern\";version=\"1.2.2", null );
+
+        assertTrue( "org.ops4j.store.intern", pkgs.contains( "org.ops4j.store.intern" ) );
+        assertTrue( "org.ops4j.store", pkgs.contains( "org.ops4j.store" ) );
+
+        assertEquals( "Expecting 2 packages", 2, pkgs.size() );
+    }
+
+
+    @Test
+    public void testSplitIntoPackages()
+    {
+        Set<String> pkgs = OsgiUtils.splitIntoPackages(
+            "org.apache.log4j.net;uses:=\"org.apache.log4j,org.apache.log4j.spi,"
+                + "javax.naming,org.apache.log4j.helpers,javax.jms,org.apache.log4j.xml,"
+                + "javax.mail,javax.mail.internet,org.w3c.dom,javax.jmdns\","
+                + "org.apache.log4j.jmx;uses:=\"org.apache.log4j,javax.management,"
+                + "com.sun.jdmk.comm,org.apache.log4j.helpers,org.apache.log4j.spi\","
+                + "org.apache.log4j.jdbc;uses:=\"org.apache.log4j,org.apache.log4j.spi\","
+                + "org.apache.log4j.config;uses:=\"org.apache.log4j.helpers,org.apache.log4j,"
+                + "org.apache.log4j.spi\",org.apache.log4j.helpers;uses:=\"org.apache.log4j,"
+                + "org.apache.log4j.spi,org.apache.log4j.pattern\",org.apache.log4j;uses:=\""
+                + "org.apache.log4j.spi,org.apache.log4j.helpers,org.apache.log4j.pattern,"
+                + "org.apache.log4j.or,org.apache.log4j.config\",org.apache.log4j.or.jms;"
+                + "uses:=\"org.apache.log4j.helpers,javax.jms,org.apache.log4j.or\","
+                + "org.apache.log4j.nt;uses:=\"org.apache.log4j.helpers,org.apache.log4j,"
+                + "org.apache.log4j.spi\",org.apache.log4j.or.sax;uses:=\"org.apache.log4j.or,"
+                + "org.xml.sax\",org.apache.log4j.pattern;uses:=\"org.apache.log4j.helpers,"
+                + "org.apache.log4j.spi,org.apache.log4j,org.apache.log4j.or\","
+                + "org.apache.log4j.spi;uses:=\"org.apache.log4j,org.apache.log4j.helpers,"
+                + "com.ibm.uvm.tools,org.apache.log4j.or\",org.apache.log4j.or;uses:=\""
+                + "org.apache.log4j.helpers,org.apache.log4j.spi,org.apache.log4j\","
+                + "org.apache.log4j.xml;uses:=\"javax.xml.parsers,org.w3c.dom,org.xml.sax,"
+                + "org.apache.log4j.config,org.apache.log4j.helpers,org.apache.log4j,"
+                + "org.apache.log4j.spi,org.apache.log4j.or\",org.apache.log4j.varia;uses:=\""
+                + "org.apache.log4j.spi,org.apache.log4j,org.apache.log4j.helpers\"", null );
+
+        assertTrue( "org.apache.log4j.net", pkgs.contains( "org.apache.log4j.net" ) );
+        assertTrue( "org.apache.log4j.jmx", pkgs.contains( "org.apache.log4j.jmx" ) );
+        assertTrue( "org.apache.log4j.jdbc", pkgs.contains( "org.apache.log4j.jdbc" ) );
+        assertTrue( "org.apache.log4j.config", pkgs.contains( "org.apache.log4j.config" ) );
+        assertTrue( "org.apache.log4j.helpers", pkgs.contains( "org.apache.log4j.helpers" ) );
+        assertTrue( "org.apache.log4j", pkgs.contains( "org.apache.log4j" ) );
+        assertTrue( "org.apache.log4j.or", pkgs.contains( "org.apache.log4j.or" ) );
+        assertTrue( "org.apache.log4j.or.jms", pkgs.contains( "org.apache.log4j.or.jms" ) );
+        assertTrue( "org.apache.log4j.or.sax", pkgs.contains( "org.apache.log4j.or.sax" ) );
+        assertTrue( "org.apache.log4j.nt", pkgs.contains( "org.apache.log4j.nt" ) );
+        assertTrue( "org.apache.log4j.spi", pkgs.contains( "org.apache.log4j.spi" ) );
+        assertTrue( "org.apache.log4j.pattern", pkgs.contains( "org.apache.log4j.pattern" ) );
+        assertTrue( "org.apache.log4j.xml", pkgs.contains( "org.apache.log4j.xml" ) );
+        assertTrue( "org.apache.log4j.varia", pkgs.contains( "org.apache.log4j.varia" ) );
+
+        assertEquals( "Expecting 14 packages", 14, pkgs.size() );
+    }
+
+
+    @Test
+    public void testGetClasspathCandidates()
+    {
+        Set<File> candidates = OsgiUtils.getClasspathCandidates( REJECTION_FILTER );
+        assertEquals( "Should have no results with REJECTION_FILTER", 0, candidates.size() );
+
+        candidates = OsgiUtils.getClasspathCandidates( ONLY_ONE_FILTER );
+        assertEquals( "Should have one result with ONLY_ONE_FILTER", 1, candidates.size() );
+
+        candidates = OsgiUtils.getClasspathCandidates( JUNIT_SLF4J_FILTER );
+        assertTrue( "Should have at least 4 results with JUNIT_SLF4J_FILTER", candidates.size() >= 4 );
+
+        candidates = OsgiUtils.getClasspathCandidates( null );
+        assertTrue( "Should have at least 4 results with no filter", candidates.size() >= 4 );
+    }
+
+
+    @Test
+    public void testGetAllBundleExports()
+    {
+        OsgiUtils.getAllBundleExports( null, null );
+    }
+}
diff --git a/trunk/util/src/test/java/org/apache/directory/api/util/StringsTest.java b/trunk/util/src/test/java/org/apache/directory/api/util/StringsTest.java
new file mode 100644
index 0000000..b44dc62
--- /dev/null
+++ b/trunk/util/src/test/java/org/apache/directory/api/util/StringsTest.java
@@ -0,0 +1,328 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Tests the Strings class methods.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class StringsTest
+{
+    @Test
+    public void testTrimConsecutiveToOne()
+    {
+        String input = null;
+        String result = null;
+
+        input = "akarasulu**";
+        result = Strings.trimConsecutiveToOne( input, '*' );
+        assertEquals( "akarasulu*", result );
+
+        input = "*****akarasulu**";
+        result = Strings.trimConsecutiveToOne( input, '*' );
+        assertEquals( "*akarasulu*", result );
+
+        input = "**akarasulu";
+        result = Strings.trimConsecutiveToOne( input, '*' );
+        assertEquals( "*akarasulu", result );
+
+        input = "**akar****asulu**";
+        result = Strings.trimConsecutiveToOne( input, '*' );
+        assertEquals( "*akar*asulu*", result );
+
+        input = "akarasulu";
+        result = Strings.trimConsecutiveToOne( input, '*' );
+        assertEquals( "akarasulu", result );
+
+        input = "*a*k*a*r*a*s*u*l*u*";
+        result = Strings.trimConsecutiveToOne( input, '*' );
+        assertEquals( "*a*k*a*r*a*s*u*l*u*", result );
+
+    }
+
+
+    @Test
+    public void testListToString()
+    {
+        List<String> list = new ArrayList<String>();
+
+        list.add( "elem1" );
+        list.add( "elem2" );
+        list.add( "elem3" );
+
+        assertEquals( "elem1, elem2, elem3", Strings.listToString( list ) );
+    }
+
+
+    @Test
+    public void testMapToString()
+    {
+        class Value
+        {
+            String name;
+
+            int val;
+
+
+            public Value( String name, int val )
+            {
+                this.name = name;
+                this.val = val;
+            }
+
+
+            public String toString()
+            {
+                return "[" + name + ", " + val + "]";
+            }
+        }
+
+        Map<String, Value> map = new HashMap<String, Value>();
+
+        map.put( "elem1", new Value( "name1", 1 ) );
+        map.put( "elem2", new Value( "name2", 2 ) );
+        map.put( "elem3", new Value( "name3", 3 ) );
+
+        String result = Strings.mapToString( map );
+
+        boolean res = "elem1 = '[name1, 1]', elem2 = '[name2, 2]', elem3 = '[name3, 3]'".equals( result )
+            || "elem1 = '[name1, 1]', elem3 = '[name3, 3]', elem2 = '[name2, 2]'".equals( result )
+            || "elem2 = '[name2, 2]', elem1 = '[name1, 1]', elem3 = '[name3, 3]'".equals( result )
+            || "elem2 = '[name2, 2]', elem3 = '[name3, 3]', elem1 = '[name1, 1]'".equals( result )
+            || "elem3 = '[name3, 3]', elem1 = '[name1, 1]', elem2 = '[name2, 2]'".equals( result )
+            || "elem3 = '[name3, 3]', elem2 = '[name2, 2]', elem1 = '[name1, 1]'".equals( result );
+
+        assertTrue( res );
+    }
+
+
+    @Test
+    public void testDeepTrim()
+    {
+        assertEquals( "", Strings.deepTrim( " ", false ) );
+        assertEquals( "ab", Strings.deepTrim( " ab ", false ) );
+        assertEquals( "a b", Strings.deepTrim( " a b ", false ) );
+        assertEquals( "a b", Strings.deepTrim( " a  b ", false ) );
+        assertEquals( "a b", Strings.deepTrim( "  a  b  ", false ) );
+        assertEquals( "ab", Strings.deepTrim( "ab ", false ) );
+        assertEquals( "ab", Strings.deepTrim( " ab", false ) );
+        assertEquals( "ab", Strings.deepTrim( "ab  ", false ) );
+        assertEquals( "ab", Strings.deepTrim( "  ab", false ) );
+        assertEquals( "a b", Strings.deepTrim( "a b", false ) );
+        assertEquals( "a b", Strings.deepTrim( "a  b", false ) );
+        assertEquals( "a b", Strings.deepTrim( " a b", false ) );
+        assertEquals( "a b", Strings.deepTrim( "a b ", false ) );
+    }
+
+
+    @Test
+    public void testTrim()
+    {
+        assertEquals( "", Strings.trim( ( String ) null ) );
+        assertEquals( "", Strings.trim( "" ) );
+        assertEquals( "", Strings.trim( " " ) );
+        assertEquals( "", Strings.trim( "  " ) );
+        assertEquals( "a", Strings.trim( "a  " ) );
+        assertEquals( "a", Strings.trim( "  a" ) );
+        assertEquals( "a", Strings.trim( "  a  " ) );
+    }
+
+
+    @Test
+    public void testTrimLeft()
+    {
+        assertEquals( "", Strings.trimLeft( ( String ) null ) );
+        assertEquals( "", Strings.trimLeft( "" ) );
+        assertEquals( "", Strings.trimLeft( " " ) );
+        assertEquals( "", Strings.trimLeft( "  " ) );
+        assertEquals( "a  ", Strings.trimLeft( "a  " ) );
+        assertEquals( "a", Strings.trimLeft( "  a" ) );
+        assertEquals( "a  ", Strings.trimLeft( "  a  " ) );
+    }
+
+
+    @Test
+    public void testTrimRight()
+    {
+        assertEquals( "", Strings.trimRight( ( String ) null ) );
+        assertEquals( "", Strings.trimRight( "" ) );
+        assertEquals( "", Strings.trimRight( " " ) );
+        assertEquals( "", Strings.trimRight( "  " ) );
+        assertEquals( "a", Strings.trimRight( "a  " ) );
+        assertEquals( "  a", Strings.trimRight( "  a" ) );
+        assertEquals( "  a", Strings.trimRight( "  a  " ) );
+    }
+
+
+    @Test
+    public void testConvertUUID()
+    {
+        UUID uuid = UUID.randomUUID();
+        byte[] bytes = Strings.uuidToBytes( uuid.toString() );
+        String string = Strings.uuidToString( bytes );
+        assertEquals( uuid.toString(), string );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsFull()
+    {
+        // Full compare
+        assertEquals( 6, Strings.areEquals( "azerty".getBytes(), 0, "azerty" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsDiff()
+    {
+        // First character is !=
+        assertEquals( -1, Strings.areEquals( "azerty".getBytes(), 0, "Azerty" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsEmpty()
+    {
+        // Compare to an empty string
+        assertEquals( -1, Strings.areEquals( "azerty".getBytes(), 0, "" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsFirstCharDiff()
+    {
+        // First character is !=
+        assertEquals( -1, Strings.areEquals( "azerty".getBytes(), 0, "Azerty" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsMiddleCharDiff()
+    {
+        // First character is !=
+        assertEquals( -1, Strings.areEquals( "azerty".getBytes(), 0, "azeRty" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsLastCharDiff()
+    {
+        // First character is !=
+        assertEquals( -1, Strings.areEquals( "azerty".getBytes(), 0, "azertY" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsCharByChar()
+    {
+        // Index must be incremented after each comparison
+        assertEquals( 1, Strings.areEquals( "azerty".getBytes(), 0, "a" ) );
+        assertEquals( 2, Strings.areEquals( "azerty".getBytes(), 1, "z" ) );
+        assertEquals( 3, Strings.areEquals( "azerty".getBytes(), 2, "e" ) );
+        assertEquals( 4, Strings.areEquals( "azerty".getBytes(), 3, "r" ) );
+        assertEquals( 5, Strings.areEquals( "azerty".getBytes(), 4, "t" ) );
+        assertEquals( 6, Strings.areEquals( "azerty".getBytes(), 5, "y" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsTooShort()
+    {
+        // length too short
+        assertEquals( -1, Strings.areEquals( "azerty".getBytes(), 0, "azertyiop" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsTooShortMiddle()
+    {
+        // length too short
+        assertEquals( -1, Strings.areEquals( "azerty".getBytes(), 0, "ertyiop" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsLastChar()
+    {
+        // last character
+        assertEquals( 6, Strings.areEquals( "azerty".getBytes(), 5, "y" ) );
+    }
+
+
+    /**
+     * Test the DnUtils AreEquals method
+     */
+    @Test
+    public void testAreEqualsMiddle()
+    {
+        // In the middle
+        assertEquals( 4, Strings.areEquals( "azerty".getBytes(), 2, "er" ) );
+    }
+}
diff --git a/trunk/util/src/test/java/org/apache/directory/api/util/UnicodeTest.java b/trunk/util/src/test/java/org/apache/directory/api/util/UnicodeTest.java
new file mode 100644
index 0000000..36a728f
--- /dev/null
+++ b/trunk/util/src/test/java/org/apache/directory/api/util/UnicodeTest.java
@@ -0,0 +1,236 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.util;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+
+/**
+ * A test case for the UTFUtils methods 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class UnicodeTest
+{
+    /** Uses a temporary folder rule */
+    @Rule 
+    public TemporaryFolder tmpFolder= new TemporaryFolder();
+
+    /** The file stream we use for this test */
+    private FileOutputStream fos = null;
+    private FileInputStream fis = null;
+
+
+    /**
+     * Initialize the temporary folder and the associated streams
+     */
+    @Before
+    public void init()
+    {
+        try
+        {
+            File tmpFile = tmpFolder.newFile( "UTFUtils.test" );
+            fos = new FileOutputStream( tmpFile );
+            fis = new FileInputStream( tmpFile );
+        }
+        catch ( IOException e )
+        {
+        }
+    }
+    
+    
+    /**
+     * Cleanup the streams after each test
+     */
+    @After
+    public void reset()
+    {
+        try
+        {
+            fos.close();
+            fis.close();
+        }
+        catch ( IOException e )
+        {
+        }
+    }
+
+
+    /**
+     * 
+     * Test write/read of a null string
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testNullString() throws Exception
+    {
+        ObjectOutputStream dos = new ObjectOutputStream( fos );
+        ObjectInputStream dis = new ObjectInputStream( fis );
+        String testString = null;
+        Unicode.writeUTF( dos, testString );
+        dos.flush();
+        dos.close();
+        assertEquals( testString, Unicode.readUTF( dis ) );
+        dis.close();
+    }
+
+
+    /**
+     * 
+     * Test write/read of an empty string
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testEmptyString() throws Exception
+    {
+        ObjectOutputStream dos = new ObjectOutputStream( fos );
+        ObjectInputStream dis = new ObjectInputStream( fis );
+        String testString = "";
+        Unicode.writeUTF( dos, testString );
+        dos.flush();
+        dos.close();
+        assertEquals( testString, Unicode.readUTF( dis ) );
+        dis.close();
+    }
+
+
+    /**
+     * 
+     * Test write/read of a large string (> 64Kb)
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLargeString() throws Exception
+    {
+        ObjectOutputStream dos = new ObjectOutputStream( fos );
+        ObjectInputStream dis = new ObjectInputStream( fis );
+        char[] fill = new char[196622]; // 65535 * 3 + 17
+        Arrays.fill( fill, '\u00fc' ); // German &&uuml
+        String testString = new String( fill );
+        Unicode.writeUTF( dos, testString );
+        dos.flush();
+        dos.close();
+        assertEquals( testString, Unicode.readUTF( dis ) );
+        dis.close();
+    }
+
+
+    @Test
+    public void testOneByteChar()
+    {
+        char res = Unicode.bytesToChar( new byte[]
+            { 0x30 } );
+
+        assertEquals( '0', res );
+    }
+
+
+    @Test
+    public void testOneByteChar00()
+    {
+        char res = Unicode.bytesToChar( new byte[]
+            { 0x00 } );
+
+        assertEquals( 0x00, res );
+    }
+
+
+    @Test
+    public void testOneByteChar7F()
+    {
+        char res = Unicode.bytesToChar( new byte[]
+            { 0x7F } );
+
+        assertEquals( 0x7F, res );
+    }
+
+
+    @Test
+    public void testTwoBytesChar()
+    {
+        char res = Unicode.bytesToChar( new byte[]
+            { ( byte ) 0xCE, ( byte ) 0x91 } );
+
+        assertEquals( 0x0391, res );
+    }
+
+
+    @Test
+    public void testThreeBytesChar()
+    {
+        char res = Unicode.bytesToChar( new byte[]
+            { ( byte ) 0xE2, ( byte ) 0x89, ( byte ) 0xA2 } );
+
+        assertEquals( 0x2262, res );
+    }
+
+
+    @Test
+    public void testcharToBytesOne()
+    {
+        assertEquals( "0x00 ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x0000 ) ) );
+        assertEquals( "0x61 ", Strings.dumpBytes( Unicode.charToBytes( 'a' ) ) );
+        assertEquals( "0x7F ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x007F ) ) );
+    }
+
+
+    @Test
+    public void testcharToBytesTwo()
+    {
+        assertEquals( "0xC2 0x80 ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x0080 ) ) );
+        assertEquals( "0xC3 0xBF ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x00FF ) ) );
+        assertEquals( "0xC4 0x80 ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x0100 ) ) );
+        assertEquals( "0xDF 0xBF ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x07FF ) ) );
+    }
+
+
+    @Test
+    public void testcharToBytesThree()
+    {
+        assertEquals( "0xE0 0xA0 0x80 ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x0800 ) ) );
+        assertEquals( "0xE0 0xBF 0xBF ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x0FFF ) ) );
+        assertEquals( "0xE1 0x80 0x80 ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0x1000 ) ) );
+        assertEquals( "0xEF 0xBF 0xBF ", Strings.dumpBytes( Unicode.charToBytes( ( char ) 0xFFFF ) ) );
+    }
+}
diff --git a/trunk/util/src/test/resources/log4j.properties b/trunk/util/src/test/resources/log4j.properties
new file mode 100644
index 0000000..facb3e6
--- /dev/null
+++ b/trunk/util/src/test/resources/log4j.properties
@@ -0,0 +1,21 @@
+#############################################################################
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#############################################################################
+log4j.rootCategory=OFF, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n